From ca463f01a493901c9cdeb6a033a2a18ab8c9479c Mon Sep 17 00:00:00 2001 From: Alexander Oster Date: Thu, 23 Jul 2020 12:13:06 +0200 Subject: [PATCH 1/2] Cgo (#118) * support structarray * update readme * use cgo for go bindings * ensure comments finish with a dot * update readme go support * simplify cast and return strings * do not specify LDFLAGS Co-authored-by: Quim Muntal Diaz Co-authored-by: qmuntal --- README.md | 2 +- Source/buildbindinggo.go | 1405 +++++++++++++++----------------------- Source/languagec.go | 4 + 3 files changed, 537 insertions(+), 874 deletions(-) diff --git a/README.md b/README.md index bc4ce645..661795e1 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ ACT supports generation of bindings or implementation stubs for C++, C, Pascal, | C Dynamic | ![](Documentation/images/Tick.png) mature | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | in,out | in,out | in | + | - | | Pascal | ![](Documentation/images/Tick.png) mature | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | in,out | in,out | in | + | + | | Python3 | ![](Documentation/images/Tick.png) complete (but not very pythonic) | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | in,out | in,out | in | + | + | -| Golang | ![](Documentation/images/O.png) partial support | Win, Linux, MacOS | in,return | in,out,return | ? | ? | ? | ? | ? | - | - | - | +| Golang | ![](Documentation/images/Tick.png) mature | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | in,out | in,out | in | + | + | | NodeJS | ![](Documentation/images/O.png) partial support | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | ? | ? | - | + | - | | C# | ![](Documentation/images/O.png) experimental | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | - | - | - | + | - | | Java | ![](Documentation/images/Tick.png) experimental | Win, Linux, MacOS | in,return | in,out,return | in,out,return | in,out,return | in,out,return | in,out | in,out | in | + | + | diff --git a/Source/buildbindinggo.go b/Source/buildbindinggo.go index 5dabe5fe..7d6c1f29 100644 --- a/Source/buildbindinggo.go +++ b/Source/buildbindinggo.go @@ -39,44 +39,60 @@ import ( "log" "path" "strings" + "unicode" + "unicode/utf8" ) // BuildBindingGo builds Go-bindings of a library's API func BuildBindingGo(component ComponentDefinition, outputFolder string, outputFolderExample string) error { forceRecreation := false - NameSpace := component.NameSpace - LibraryName := component.LibraryName - BaseName := component.BaseName + CTypesHeaderName := path.Join(outputFolder, component.BaseName+"_types.h") + err := CreateCTypesHeader(component, CTypesHeaderName) + if err != nil { + return err + } - GoIntfName := path.Join(outputFolder, BaseName+".go") - log.Printf("Creating \"%s\"", GoIntfName) - gofile, err := CreateLanguageFile(GoIntfName, " ") + CHeaderName := path.Join(outputFolder, component.BaseName+"_abi.h") + err = CreateCAbiHeader(component, CHeaderName) if err != nil { return err } - GoImplName := path.Join(outputFolder, BaseName+"_impl.go") - log.Printf("Creating \"%s\"", GoImplName) - goimplfile, err := CreateLanguageFile(GoImplName, " ") + fnFile, err := CreateLanguageFile(path.Join(outputFolder, "cfunc.go"), " ") if err != nil { return err } - gofile.WriteCLicenseHeader(component, - fmt.Sprintf("This is an autogenerated Go wrapper file in order to allow an easy\n use of %s", LibraryName), + fnFile.WriteCLicenseHeader(component, + fmt.Sprintf("This is an autogenerated Go wrapper file in order to allow an easy\nuse of %s.", component.LibraryName), true) - goimplfile.WriteCLicenseHeader(component, - fmt.Sprintf("This is an autogenerated Go implementation file in order to allow an easy\n use of %s", LibraryName), + + fnFile.Writeln("// Code generated by Automatic Component Toolkit (ACT); DO NOT EDIT.") + err = buildCFuncsWrapper(component, fnFile) + if err != nil { + return err + } + GoIntfName := path.Join(outputFolder, component.BaseName+".go") + log.Printf("Creating \"%s\"", GoIntfName) + gofile, err := CreateLanguageFile(GoIntfName, " ") + if err != nil { + return err + } + + gofile.WriteCLicenseHeader(component, + fmt.Sprintf("This is an autogenerated Go wrapper file in order to allow an easy\nuse of %s.", component.LibraryName), true) - err = buildGoWrapper(component, gofile, goimplfile) + gofile.Writeln("// Code generated by Automatic Component Toolkit (ACT); DO NOT EDIT.") + + err = buildGoWrapper(component, gofile) if err != nil { return err } if len(outputFolderExample) > 0 { - goExample := path.Join(outputFolderExample, NameSpace+"_example"+".go") + goExample := path.Join(outputFolderExample, component.NameSpace+"_example"+".go") if forceRecreation || !FileExists(goExample) { log.Printf("Creating \"%s\"", goExample) goExampleFile, err := CreateLanguageFile(goExample, " ") @@ -84,7 +100,7 @@ func BuildBindingGo(component ComponentDefinition, outputFolder string, outputFo return err } goExampleFile.WriteCLicenseHeader(component, - fmt.Sprintf("This is an autogenerated Go application that demonstrates the\n usage of the Go bindings of %s", LibraryName), + fmt.Sprintf("This is an autogenerated Go application that demonstrates the\n usage of the Go bindings of %s", component.LibraryName), true) buildGoExample(component, goExampleFile, outputFolder) } else { @@ -94,9 +110,26 @@ func BuildBindingGo(component ComponentDefinition, outputFolder string, outputFo return nil } +func buildCFuncsWrapper(component ComponentDefinition, w LanguageWriter) error { + packageName := strings.ToLower(component.BaseName) + + w.Writeln("") + w.Writeln("package %s", packageName) + w.Writeln("") + w.Writeln("/*") + w.Writeln("#include \"%s_types.h\"", packageName) + err := buildCFuncs(component, w) + if err != nil { + return err + } + w.Writeln("*/") + w.Writeln("import \"C\"") + w.Writeln("") + return nil +} + func buildGoExample(component ComponentDefinition, w LanguageWriter, outputFolder string) { - packageName := component.BaseName - NameSpace := component.NameSpace + packageName := lowerFirst(component.BaseName) w.Writeln("") w.Writeln("package main") @@ -108,33 +141,28 @@ func buildGoExample(component ComponentDefinition, w LanguageWriter, outputFolde w.Writeln(")") w.Writeln("") w.Writeln("func main() {") - w.Writeln(" wrapper, err := %s.%sLoadWrapper(\"../../Implementations/Cpp/build/Debug/%s.dll\") // TODO: add-path here", packageName, NameSpace, component.BaseName) - w.Writeln(" if (err != nil) {") - w.Writeln(" log.Fatal(err)") - w.Writeln(" }") - w.Writeln(" ") - w.Writeln(" nMajor, nMinor, nMicro, err := wrapper.%s()", component.Global.VersionMethod) - w.Writeln(" if (err != nil) {") + w.Writeln(" nMajor, nMinor, nMicro, err := %.s%s()", packageName, component.Global.VersionMethod) + w.Writeln(" if err != nil {") w.Writeln(" log.Fatal(err)") w.Writeln(" }") w.Writeln(" versionString := fmt.Sprintf(\"%s.version = %s\", nMajor, nMinor, nMicro)", component.BaseName, "%d.%d.%d") w.Writeln(" ") if len(component.Global.PrereleaseMethod) > 0 { - w.Writeln(" hasInfo, preReleaseInfo, err := wrapper.%s()", component.Global.PrereleaseMethod) - w.Writeln(" if (err != nil) {") + w.Writeln(" hasInfo, preReleaseInfo, err := %s.%s()", packageName, component.Global.PrereleaseMethod) + w.Writeln(" if err != nil {") w.Writeln(" log.Fatal(err)") w.Writeln(" }") - w.Writeln(" if (hasInfo) {") + w.Writeln(" if hasInfo {") w.Writeln(" versionString += \"-\"+preReleaseInfo") w.Writeln(" }") w.Writeln("") } if len(component.Global.BuildinfoMethod) > 0 { - w.Writeln(" hasInfo, buildInfo, err := wrapper.%s()", component.Global.BuildinfoMethod) - w.Writeln(" if (err != nil) {") + w.Writeln(" hasInfo, buildInfo, err := %s()", component.Global.BuildinfoMethod) + w.Writeln(" if err != nil {") w.Writeln(" log.Fatal(err)") w.Writeln(" }") - w.Writeln(" if (hasInfo) {") + w.Writeln(" if hasInfo {") w.Writeln(" versionString += \"+\"+buildInfo") w.Writeln(" }") w.Writeln("") @@ -145,54 +173,129 @@ func buildGoExample(component ComponentDefinition, w LanguageWriter, outputFolde w.Writeln("") } +func buildCFuncsForward(component ComponentDefinition, w LanguageWriter) error { + if len(component.Functions) <= 0 { + return nil + } + + w.Writeln("") + for _, fn := range component.Functions { + var paramTypes []string + for _, param := range fn.Params { + cParams, err := generateCCPPParameter(param, "", fn.FunctionName, component.NameSpace, false) + if err != nil { + return err + } + for _, cParam := range cParams { + paramTypes = append(paramTypes, cParam.ParamType) + } + } + w.Writeln("void %s%s_cgo(%s);", component.NameSpace, fn.FunctionName, strings.Join(paramTypes, ", ")) + } + return nil +} + +func buildCFuncs(component ComponentDefinition, w LanguageWriter) error { + if len(component.Functions) <= 0 { + return nil + } + + for _, fn := range component.Functions { + w.Writeln("") + var paramTypes []string + var paramNames []string + var params []string + for _, param := range fn.Params { + + cParams, err := generateCCPPParameter(param, "", fn.FunctionName, component.NameSpace, false) + if err != nil { + return err + } + for _, cParam := range cParams { + paramTypes = append(paramTypes, cParam.ParamType) + paramNames = append(paramNames, cParam.ParamName) + params = append(params, fmt.Sprintf("%s %s", cParam.ParamType, cParam.ParamName)) + } + } + fnName := lowerFirst(fn.FunctionName) + w.Writeln("extern void %s(%s);", fnName, strings.Join(paramTypes, ", ")) + w.Writeln("void %s%s_cgo(%s){", component.NameSpace, fn.FunctionName, strings.Join(params, ", ")) + w.Writeln(" %s(%s);", fnName, strings.Join(paramNames, ", ")) + w.Writeln("}") + } + return nil +} + +func buildGoFuncs(component ComponentDefinition, w LanguageWriter) error { + if len(component.Functions) <= 0 { + return nil + } + + for _, fn := range component.Functions { + fnName := lowerFirst(fn.FunctionName) + var paramCToGo []string + var params []string + var paramsC []string + for _, param := range fn.Params { + param.ParamName = lowerFirst(param.ParamName) + tp, err := getGoType(param.ParamType, component.NameSpace, param.ParamClass, param.ParamName, param.ParamPass == "return") + if err != nil { + return err + } + params = append(params, fmt.Sprintf("%s %s", param.ParamName, tp.Type)) + paramsC = append(paramsC, fmt.Sprintf("%s %s", param.ParamName, tp.CType)) + paramCToGo = append(paramCToGo, tp.CToGo) + } + w.Writeln("") + w.Writeln("// %sFunc %s", fn.FunctionName, endWithDot(lowerFirst(fn.FunctionDescription))) + w.Writeln("type %sFunc = func(%s)", fn.FunctionName, strings.Join(params, ", ")) + w.Writeln("") + w.Writeln("var %sFunc %sFunc", fnName, fn.FunctionName) + w.Writeln("") + w.Writeln("//export %s", fnName) + w.Writeln("func %s(%s) {", fnName, strings.Join(paramsC, ", ")) + w.Writeln(" if %sFunc == nil {", fnName) + w.Writeln(" return") + w.Writeln(" }") + w.Writeln(" %sFunc(%s)", fnName, strings.Join(paramCToGo, ", ")) + w.Writeln("}") + } + return nil +} func buildGoEnums(component ComponentDefinition, w LanguageWriter) { if len(component.Enums) <= 0 { return } - NameSpace := component.NameSpace w.Writeln("") - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Declaration of enums") - w.Writeln("**************************************************************************************************************************/") - w.Writeln("") - for i := 0; i < len(component.Enums); i++ { - enum := component.Enums[i] - w.Writeln("type E%s%s int", NameSpace, enum.Name) + for _, enum := range component.Enums { + w.Writeln("// %s represents a %s enum.", enum.Name, component.NameSpace) + w.Writeln("type %s int", enum.Name) + w.Writeln("") w.Writeln("const (") for j := 0; j < len(enum.Options); j++ { option := enum.Options[j] - w.Writeln(" e%s_%s = %d", enum.Name, option.Name, option.Value) + w.Writeln(" %s_%s = %d", enum.Name, option.Name, option.Value) } w.Writeln(")") w.Writeln("") } - w.Writeln("") } -func buildGoStructs(component ComponentDefinition, w LanguageWriter) (error) { +func buildGoStructs(component ComponentDefinition, w LanguageWriter) error { if len(component.Structs) <= 0 { return nil } - NameSpace := component.NameSpace - - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Declaration of structs") - w.Writeln("**************************************************************************************************************************/") - w.Writeln("") - for i := 0; i < len(component.Structs); i++ { - structinfo := component.Structs[i] - w.Writeln("type s%s%s struct {", NameSpace, structinfo.Name) - - for j := 0; j < len(structinfo.Members); j++ { - - member := structinfo.Members[j] + for _, structinfo := range component.Structs { + w.Writeln("// %s represents a %s struct.", structinfo.Name, component.NameSpace) + w.Writeln("type %s struct {", structinfo.Name) + for _, member := range structinfo.Members { arraysuffix := "" if member.Rows > 0 { if member.Columns > 0 { @@ -203,299 +306,108 @@ func buildGoStructs(component ComponentDefinition, w LanguageWriter) (error) { } switch member.Type { - case "uint8": - w.Writeln(" %s%s uint8;", member.Name, arraysuffix) - case "uint16": - w.Writeln(" %s%s uint16;", member.Name, arraysuffix) - case "uint32": - w.Writeln(" %s%s uint32;", member.Name, arraysuffix) - case "uint64": - w.Writeln(" %s%s uint64;", member.Name, arraysuffix) - case "int8": - w.Writeln(" %s%s int8;", member.Name, arraysuffix) - case "int16": - w.Writeln(" %s%s int16;", member.Name, arraysuffix) - case "int32": - w.Writeln(" %s%s int32;", member.Name, arraysuffix) - case "int64": - w.Writeln(" %s%s int64;", member.Name, arraysuffix) - case "bool": - w.Writeln(" %s%s bool;", member.Name, arraysuffix) - case "single": - w.Writeln(" %s%s float32;", member.Name, arraysuffix) - case "double": - w.Writeln(" %s%s float64;", member.Name, arraysuffix) - case "pointer": - w.Writeln(" %s%s uint64;", member.Name, arraysuffix) case "string": - return fmt.Errorf("it is not possible for struct s%s%s to contain a string value", NameSpace, structinfo.Name) + return fmt.Errorf("it is not possible for struct %s to contain a string value", structinfo.Name) case "class", "optionalclass": - return fmt.Errorf("it is not possible for struct s%s%s to contain a handle value", NameSpace, structinfo.Name) + return fmt.Errorf("it is not possible for struct %s to contain a ref value", structinfo.Name) case "enum": - w.Writeln(" %s%s E%s%s;", member.Name, arraysuffix, NameSpace, member.Class) + w.Writeln(" %s%s %s", member.Name, arraysuffix, member.Class) + default: + tp, err := getGoType(member.Type, component.NameSpace, member.Class, member.Name, false) + if err != nil { + return err + } + w.Writeln(" %s%s %s", member.Name, arraysuffix, tp.Type) } } w.Writeln("}") w.Writeln("") } - w.Writeln("") return nil } -func buildGoInterfaces(component ComponentDefinition, w LanguageWriter) { - w.Writeln("/*************************************************************************************************************************") - w.Writeln(" Declaration of interfaces") - w.Writeln("**************************************************************************************************************************/") +func buildGoErrorHandling(component ComponentDefinition, w LanguageWriter, packageName string) { + w.Writeln("// WrappedError is an error that wraps a %s error.", component.NameSpace) + w.Writeln("type WrappedError struct {") + w.Writeln(" Code uint32") + w.Writeln(" Message string") + w.Writeln("}") w.Writeln("") - w.Writeln("type %sHandle interface {", component.NameSpace) - w.Writeln(" Close() error") - w.Writeln(" IsValid() bool") + w.Writeln("func (e *WrappedError) Error() string {") + w.Writeln(" return fmt.Sprintf(\"%s: %%s (%%d)\", e.Message, e.Code)", packageName) w.Writeln("}") w.Writeln("") -} - -func buildGoImplementation(component ComponentDefinition, implw LanguageWriter) { - NameSpace := component.NameSpace - - implw.Writeln("type %sImplementation struct {", NameSpace) - implw.Writeln(" Initialized bool") - implw.Writeln(" DLLHandle syscall.Handle") - - for i := 0; i < len(component.Classes); i++ { - class := component.Classes[i] - for j := 0; j < len(class.Methods); j++ { - method := class.Methods[j] - implw.Writeln(" %s_%s_%s uintptr", NameSpace, strings.ToLower(class.ClassName), strings.ToLower(method.MethodName)) - } - } - - for j := 0; j < len(component.Global.Methods); j++ { - method := component.Global.Methods[j] - implw.Writeln(" %s_%s uintptr", NameSpace, strings.ToLower(method.MethodName)) - } - implw.Writeln("}") - implw.Writeln("") -} - -func buildGoImplementationHandle(component ComponentDefinition, implw LanguageWriter) { - NameSpace := component.NameSpace - implw.Writeln("type %sImplementationHandle interface {", NameSpace) - implw.Writeln(" %sHandle", NameSpace) - implw.Writeln("") - implw.Writeln(" GetDLLInHandle() (uintptr)") - implw.Writeln(" GetDLLOutHandle() (uintptr)") - implw.Writeln(" GetWrapper() (*%sImplementation)", NameSpace) - implw.Writeln("}") - implw.Writeln("") - implw.Writeln("type %sImplementationHandleStruct struct {", NameSpace) - implw.Writeln(" Implementation * %sImplementation", NameSpace) - implw.Writeln(" DLLhandle uintptr") - implw.Writeln("}") - implw.Writeln("") - implw.Writeln("func (handle *%sImplementationHandleStruct) Close() (error) {", NameSpace) - implw.Writeln(" if (handle.DLLhandle != 0) {") - implw.Writeln(" if (handle.Implementation == nil) {") - implw.Writeln(" return errors.New(\"Uninitialized DLL Implementation Handle\")") - implw.Writeln(" }") - implw.Writeln(" ") - implw.Writeln(" dllhandle := handle.DLLhandle") - implw.Writeln(" handle.DLLhandle = 0;") - implw.Writeln(" ") - implw.Writeln(" return handle.Implementation.CallFunction(handle.Implementation.%s_%s, dllhandle)", NameSpace, strings.ToLower(component.Global.ReleaseMethod)) - implw.Writeln(" }") - implw.Writeln(" ") - implw.Writeln(" return nil") - implw.Writeln("}") - implw.Writeln("") - implw.Writeln("func (handle *%sImplementationHandleStruct) IsValid() (bool) {", NameSpace) - implw.Writeln(" return (handle.DLLhandle != 0)") - implw.Writeln("}") - implw.Writeln("") - implw.Writeln("func (handle *%sImplementationHandleStruct) GetDLLInHandle() (uintptr) {", NameSpace) - implw.Writeln(" return handle.DLLhandle;") - implw.Writeln("}") - implw.Writeln("") - implw.Writeln("func (handle *%sImplementationHandleStruct) GetDLLOutHandle() (uintptr) {", NameSpace) - implw.Writeln(" return uintptr(unsafe.Pointer(&handle.DLLhandle));") - implw.Writeln("}") - implw.Writeln("") - implw.Writeln("func (handle *%sImplementationHandleStruct) GetWrapper() (*%sImplementation) {", NameSpace, NameSpace) - implw.Writeln(" return handle.Implementation;") - implw.Writeln("}") - implw.Writeln("") -} - -func buildGoHelperFunctions(implw LanguageWriter) { - for _, theIntType := range [2]string{"Int", "UInt"} { - for _, theWidth := range [4]string{"8", "16", "32", "64"} { - implw.Writeln("func %s%sOutValue(reference * %s%s) uintptr {", theIntType, theWidth, strings.ToLower(theIntType), theWidth) - implw.Writeln(" return uintptr(unsafe.Pointer(reference))") - implw.Writeln("}") - - implw.Writeln("func %s%sInValue(value %s%s) uintptr {", theIntType, theWidth, strings.ToLower(theIntType), theWidth) - implw.Writeln(" return uintptr(value)") - implw.Writeln("}") - } - } - - for _, theFloatType := range [1]string{"Float"} { - for _, theWidth := range [2]string{"32", "64"} { - implw.Writeln("func %s%sOutValue(reference * %s%s) uintptr {", theFloatType, theWidth, strings.ToLower(theFloatType), theWidth) - implw.Writeln(" return uintptr(unsafe.Pointer(reference))") - implw.Writeln("}") - - implw.Writeln("func %s%sInValue(value %s%s) uintptr {", theFloatType, theWidth, strings.ToLower(theFloatType), theWidth) - implw.Writeln(" return uintptr(value)") - implw.Writeln("}") - } - } - - implw.Writeln("func StringInValue (value string) uintptr {") - implw.Writeln(" bytePtr, err := syscall.BytePtrFromString(value)") - implw.Writeln(" if err != nil {") - implw.Writeln(" return 0") - implw.Writeln(" }") - implw.Writeln(" return uintptr(unsafe.Pointer(bytePtr))") - implw.Writeln("}") - implw.Writeln("") - implw.Writeln("func PtrOutValue(ptr * uintptr) uintptr {") - implw.Writeln(" return uintptr(unsafe.Pointer(ptr))") - implw.Writeln("}") - implw.Writeln("") - implw.Writeln("func BytesOutValue(bytePtr * []byte) uintptr {") - implw.Writeln(" return uintptr(unsafe.Pointer(bytePtr))") - implw.Writeln("}") - implw.Writeln("") -} - -func buildGoErrorHandling(component ComponentDefinition, implw LanguageWriter) { - implw.Writeln("") - implw.Writeln("func Get%sErrorMessage(errorcode uint32) (string) {", component.NameSpace) - implw.Writeln(" switch (errorcode) {") + w.Writeln("func errorMessage(errorcode uint32) string {") + w.Writeln(" switch (errorcode) {") for i := 0; i < len(component.Errors.Errors); i++ { errorcode := component.Errors.Errors[i] - implw.Writeln(" case %d: return \"%s\";", errorcode.Code, errorcode.Name) + w.Writeln(" case %d:", errorcode.Code) + w.Writeln(" return \"%s\";", errorcode.Name) } - implw.Writeln(" default:") - implw.Writeln(" return \"unknown\";") - implw.Writeln(" }") - implw.Writeln("}") - implw.Writeln("") + w.Writeln(" default:") + w.Writeln(" return \"unknown\";") + w.Writeln(" }") + w.Writeln("}") + w.Writeln("") + w.Writeln("func makeError(errorcode uint32) error {") + w.Writeln(" return &WrappedError{errorcode, errorMessage(uint32(errorcode))}") + w.Writeln("}") } -func buildGoInitialize(component ComponentDefinition, implw LanguageWriter) { - NameSpace := component.NameSpace - global := component.Global - - implw.Writeln("func (implementation *%sImplementation) Initialize(DLLFileName string) error {", NameSpace) - implw.Writeln(" implementation.Initialized = false;") - implw.Writeln(" implementation.DLLHandle = 0;") - implw.Writeln("") - implw.Writeln(" dllHandle, err := syscall.LoadLibrary(DLLFileName);") - implw.Writeln(" if (err != nil) {") - implw.Writeln(" return err;") - implw.Writeln(" }") - implw.Writeln("") - - for i := 0; i < len(component.Classes); i++ { - class := component.Classes[i] - for j := 0; j < len(class.Methods); j++ { - method := class.Methods[j] - functionName := fmt.Sprintf("%s_%s_%s", strings.ToLower(NameSpace), strings.ToLower(class.ClassName), strings.ToLower(method.MethodName)) - implw.Writeln(" implementation.%s_%s_%s, err = syscall.GetProcAddress(dllHandle, \"%s\")", NameSpace, strings.ToLower(class.ClassName), strings.ToLower(method.MethodName), functionName) - implw.Writeln(" if (err != nil) {") - implw.Writeln(" return errors.New(\"Could not get function %s: \" + err.Error())", functionName) - implw.Writeln(" }") - implw.Writeln(" ") +func buildGoClass(component ComponentDefinition, class ComponentDefinitionClass, w LanguageWriter, NameSpace string, packageName string) error { + w.Writeln("") + w.Writeln("// %s represents a %s class.", class.ClassName, NameSpace) + w.Writeln("type %s struct {", class.ClassName) + if component.Global.BaseClassName == class.ClassName { + w.Writeln(" _ [0]func() // uncomparable; to make == not compile") + w.Writeln(" ref ref // identifies a C value, see ref type") + w.Writeln(" gcPtr *ref // used to trigger the finalizer when the Value is not referenced any more") + } else { + if len(class.ParentClass) > 0 { + w.Writeln(" %s", class.ParentClass) + } else { + w.Writeln(" %s", component.Global.BaseClassName) } } - - for j := 0; j < len(global.Methods); j++ { - method := global.Methods[j] - - functionName := fmt.Sprintf("%s_%s", strings.ToLower(NameSpace), strings.ToLower(method.MethodName)) - implw.Writeln(" implementation.%s_%s, err = syscall.GetProcAddress(dllHandle, \"%s\")", NameSpace, strings.ToLower(method.MethodName), functionName) - implw.Writeln(" if (err != nil) {") - implw.Writeln(" return errors.New(\"Could not get function %s: \" + err.Error())", functionName) - implw.Writeln(" }") - implw.Writeln(" ") - } - - implw.Writeln(" implementation.DLLHandle = dllHandle") - implw.Writeln(" implementation.Initialized = true") - implw.Writeln(" return nil") - implw.Writeln("}") -} - -func buildGoCallFunction(component ComponentDefinition, implw LanguageWriter) { - NameSpace := component.NameSpace - - implw.Writeln("func (implementation *%sImplementation) CallFunction(funcptr uintptr, parameters ... uintptr) (error) {", NameSpace) - implw.Writeln(" var ret uintptr;") - implw.Writeln(" if (!implementation.Initialized) {") - implw.Writeln(" return errors.New(\"%s Implementation has not been initialized!\")", NameSpace) - implw.Writeln(" }") - implw.Writeln(" ") - implw.Writeln(" switch len(parameters) { ") - implw.Writeln(" case 0: ret, _, _ = syscall.Syscall(funcptr, 0, 0, 0, 0)") - implw.Writeln(" case 1: ret, _, _ = syscall.Syscall(funcptr, 1, uintptr(parameters[0]), 0, 0)") - implw.Writeln(" case 2: ret, _, _ = syscall.Syscall(funcptr, 2, uintptr(parameters[0]), uintptr(parameters[1]), 0)") - implw.Writeln(" case 3: ret, _, _ = syscall.Syscall(funcptr, 3, uintptr(parameters[0]), uintptr(parameters[1]), uintptr(parameters[2]))") - implw.Writeln(" case 4: ret, _, _ = syscall.Syscall6(funcptr, 4, uintptr(parameters[0]), uintptr(parameters[1]), uintptr(parameters[2]), uintptr(parameters[3]), 0, 0)") - implw.Writeln(" case 5: ret, _, _ = syscall.Syscall6(funcptr, 5, uintptr(parameters[0]), uintptr(parameters[1]), uintptr(parameters[2]), uintptr(parameters[3]), uintptr(parameters[4]), 0)") - implw.Writeln(" case 6: ret, _, _ = syscall.Syscall6(funcptr, 6, uintptr(parameters[0]), uintptr(parameters[1]), uintptr(parameters[2]), uintptr(parameters[3]), uintptr(parameters[4]), uintptr(parameters[5]))") - implw.Writeln(" case 7: ret, _, _ = syscall.Syscall9(funcptr, 7, uintptr(parameters[0]), uintptr(parameters[1]), uintptr(parameters[2]), uintptr(parameters[3]), uintptr(parameters[4]), uintptr(parameters[5]), uintptr(parameters[6]), 0, 0)") - implw.Writeln(" case 8: ret, _, _ = syscall.Syscall9(funcptr, 8, uintptr(parameters[0]), uintptr(parameters[1]), uintptr(parameters[2]), uintptr(parameters[3]), uintptr(parameters[4]), uintptr(parameters[5]), uintptr(parameters[6]), uintptr(parameters[7]), 0)") - implw.Writeln(" case 9: ret, _, _ = syscall.Syscall9(funcptr, 9, uintptr(parameters[0]), uintptr(parameters[1]), uintptr(parameters[2]), uintptr(parameters[3]), uintptr(parameters[4]), uintptr(parameters[5]), uintptr(parameters[6]), uintptr(parameters[7]), uintptr(parameters[8]))") - implw.Writeln(" case 10: ret, _, _ = syscall.Syscall12(funcptr, 10, uintptr(parameters[0]), uintptr(parameters[1]), uintptr(parameters[2]), uintptr(parameters[3]), uintptr(parameters[4]), uintptr(parameters[5]), uintptr(parameters[6]), uintptr(parameters[7]), uintptr(parameters[8]), uintptr(parameters[9]), 0, 0)") - implw.Writeln(" case 11: ret, _, _ = syscall.Syscall12(funcptr, 11, uintptr(parameters[0]), uintptr(parameters[1]), uintptr(parameters[2]), uintptr(parameters[3]), uintptr(parameters[4]), uintptr(parameters[5]), uintptr(parameters[6]), uintptr(parameters[7]), uintptr(parameters[8]), uintptr(parameters[9]), uintptr(parameters[10]), 0)") - implw.Writeln(" case 12: ret, _, _ = syscall.Syscall12(funcptr, 12, uintptr(parameters[0]), uintptr(parameters[1]), uintptr(parameters[2]), uintptr(parameters[3]), uintptr(parameters[4]), uintptr(parameters[5]), uintptr(parameters[6]), uintptr(parameters[7]), uintptr(parameters[8]), uintptr(parameters[9]), uintptr(parameters[10]), uintptr(parameters[11]))") - implw.Writeln(" default: ") - implw.Writeln(" return errors.New(\"Invalid DLL function parameter count!\");") - implw.Writeln(" }") - implw.Writeln(" ") - implw.Writeln(" if (int(ret) != 0) {") - implw.Writeln(" return errors.New(fmt.Sprintf(\"%s Error: %%.04x (%%s)\", int(ret), Get%sErrorMessage(uint32(ret))))", NameSpace, NameSpace) - implw.Writeln(" }") - implw.Writeln(" ") - implw.Writeln(" return nil") - implw.Writeln("}") - implw.Writeln("") -} - - -func buildGoClass(component ComponentDefinition, class ComponentDefinitionClass, w LanguageWriter, implw LanguageWriter, NameSpace string, classdefinitions* []string) (error) { - *classdefinitions = append(*classdefinitions, fmt.Sprintf("")) - *classdefinitions = append(*classdefinitions, fmt.Sprintf("/*************************************************************************************************************************")) - *classdefinitions = append(*classdefinitions, fmt.Sprintf("Class definition %s%s", NameSpace, class.ClassName)) - *classdefinitions = append(*classdefinitions, fmt.Sprintf("**************************************************************************************************************************/")) - *classdefinitions = append(*classdefinitions, fmt.Sprintf("")) - *classdefinitions = append(*classdefinitions, fmt.Sprintf("type %s%s struct {", NameSpace, class.ClassName)) - - if (component.Global.BaseClassName == class.ClassName) { - *classdefinitions = append(*classdefinitions, fmt.Sprintf(" Interface %sGoInterface", NameSpace)) - *classdefinitions = append(*classdefinitions, fmt.Sprintf(" Handle %sHandle", NameSpace)) + w.Writeln("}") + w.Writeln("") + if component.Global.BaseClassName == class.ClassName { + w.Writeln("// New%s creates a new %s.", class.ClassName, class.ClassName) + w.Writeln("// The wrapped C pointer will be freed when the Go pointer is finalized,") + w.Writeln("// but one can release it manually calling Release.") + w.Writeln("func New%s(r ref) %s {", class.ClassName, class.ClassName) + w.Writeln(" gcPtr := new(ref)") + w.Writeln(" *gcPtr = r") + w.Writeln(" runtime.SetFinalizer(gcPtr, releaseC)") + w.Writeln(" return %s{ref: r, gcPtr: gcPtr}", class.ClassName) + w.Writeln("}") + w.Writeln("") + w.Writeln("// Release releases the C pointer.") + w.Writeln("func (inst %s) Release() error {", class.ClassName) + w.Writeln(" err := %s(inst)", component.Global.ReleaseMethod) + w.Writeln(" *inst.gcPtr = nil") + w.Writeln(" return err") + w.Writeln("}") + w.Writeln("") + w.Writeln("// Equal reports whether inst and w refer to the same C pointer.") + w.Writeln("func (inst %s) Equal(w %s) bool {", class.ClassName, class.ClassName) + w.Writeln(" return inst.ref == w.ref") + w.Writeln("}") } else { - if len(class.ParentClass)>0 { - *classdefinitions = append(*classdefinitions, fmt.Sprintf(" %s%s", NameSpace, class.ParentClass)) + w.Writeln("func new%s(r ref) %s {", class.ClassName, class.ClassName) + if class.ParentClass != "" && class.ParentClass != component.Global.BaseClassName { + w.Writeln(" return %s{new%s(r)}", class.ClassName, class.ParentClass) } else { - *classdefinitions = append(*classdefinitions, fmt.Sprintf(" %s%s", NameSpace, component.Global.BaseClassName)) + w.Writeln(" return %s{New%s(r)}", class.ClassName, component.Global.BaseClassName) } + w.Writeln("}") } - - *classdefinitions = append(*classdefinitions, fmt.Sprintf("}")) - *classdefinitions = append(*classdefinitions, fmt.Sprintf("")) - *classdefinitions = append(*classdefinitions, fmt.Sprintf("func (instance *%s%s) Close() (error) {", NameSpace, class.ClassName)) - *classdefinitions = append(*classdefinitions, fmt.Sprintf(" return instance.Handle.Close()")) - *classdefinitions = append(*classdefinitions, fmt.Sprintf("}")) - *classdefinitions = append(*classdefinitions, fmt.Sprintf("")) - for j := 0; j < len(class.Methods); j++ { method := class.Methods[j] - err := writeGoMethod(method, w, implw, NameSpace, class.ClassName, false, classdefinitions) + err := writeGoMethod(method, w, NameSpace, packageName, class.ClassName, false) if err != nil { return err } @@ -503,639 +415,386 @@ func buildGoClass(component ComponentDefinition, class ComponentDefinitionClass, return nil } -func buildGoWrapper(component ComponentDefinition, w LanguageWriter, implw LanguageWriter) error { - NameSpace := component.NameSpace - global := component.Global +func buildGoWrapper(component ComponentDefinition, w LanguageWriter) error { packageName := strings.ToLower(component.BaseName) w.Writeln("") w.Writeln("package %s", packageName) w.Writeln("") + w.Writeln("/*") + w.Writeln("#include \"%s_abi.h\"", packageName) + err := buildCFuncsForward(component, w) + if err != nil { + return err + } + w.Writeln("*/") + w.Writeln("import \"C\"") + w.Writeln("") + w.Writeln("import (") + w.Writeln(" \"fmt\"") + w.Writeln(" \"unsafe\"") + w.Writeln(" \"runtime\"") + w.Writeln(")") + w.Writeln("") + w.Writeln("type ref = C.%sHandle", component.NameSpace) + w.Writeln("") buildGoEnums(component, w) - err := buildGoStructs(component, w) - if (err != nil) { + err = buildGoStructs(component, w) + if err != nil { return err } - buildGoInterfaces(component, w) - - implw.Writeln("") - implw.Writeln("package %s", packageName) - implw.Writeln("") - implw.Writeln("// #include ") - implw.Writeln("import \"C\"") - implw.Writeln("") - implw.Writeln("import (") - implw.Writeln(" \"fmt\"") - implw.Writeln(" \"errors\"") - implw.Writeln(" \"syscall\"") - implw.Writeln(" \"unsafe\"") - implw.Writeln(")") - implw.Writeln("") - - buildGoImplementation(component, implw) - - buildGoImplementationHandle(component, implw) - - buildGoHelperFunctions(implw) - - buildGoErrorHandling(component, implw) - - implw.Writeln("") - implw.Writeln("func (implementation *%sImplementation) GetWrapperHandle(handle %sHandle) (%sImplementationHandle, error) {", NameSpace, NameSpace, NameSpace) - implw.Writeln(" implementation_handle, ok := handle.(%sImplementationHandle)", NameSpace) - implw.Writeln(" if ok {") - implw.Writeln(" handle_implementation := implementation_handle.GetWrapper()") - implw.Writeln(" if (handle_implementation == implementation) {") - implw.Writeln(" return implementation_handle, nil") - implw.Writeln(" }") - implw.Writeln(" return nil, errors.New(\"Invalid Implementation for DLL handle.\")") - implw.Writeln(" }") - implw.Writeln(" return nil, errors.New(\"Could not cast DLL handle.\")") - implw.Writeln("}") - implw.Writeln("") - - buildGoInitialize(component, implw) - - implw.Writeln("") - implw.Writeln("func (implementation *%sImplementation) NewHandle() (%sImplementationHandle) {", NameSpace, NameSpace) - implw.Writeln(" handle := new (%sImplementationHandleStruct)", NameSpace) - implw.Writeln(" handle.Implementation = implementation") - implw.Writeln(" handle.DLLhandle = 0") - implw.Writeln(" return handle") - implw.Writeln("}") - implw.Writeln("") - - buildGoCallFunction(component, implw) - implw.Writeln("") - - var classdefinitions []string - w.Writeln("type %sGoInterface interface {", NameSpace) - - for i := 0; i < len(component.Classes); i++ { - class := component.Classes[i] - - err = buildGoClass(component, class, w, implw, NameSpace, &classdefinitions) + + buildGoErrorHandling(component, w, packageName) + + err = buildGoFuncs(component, w) + if err != nil { + return err + } + + for _, class := range component.Classes { + err = buildGoClass(component, class, w, component.NameSpace, packageName) if err != nil { return err } } - implw.Writeln("") - implw.Writeln("/*************************************************************************************************************************") - implw.Writeln(" Class definition %sWrapper", NameSpace) - implw.Writeln("**************************************************************************************************************************/") - implw.Writeln("type %sWrapper struct {", NameSpace) - implw.Writeln(" Interface %sGoInterface", NameSpace) - implw.Writeln("}") - - global = component.Global - for j := 0; j < len(global.Methods); j++ { - method := global.Methods[j] + w.Writeln("") - err := writeGoMethod(method, w, implw, NameSpace, "Wrapper", true, &classdefinitions) + for _, method := range component.Global.Methods { + err := writeGoMethod(method, w, component.NameSpace, packageName, "Wrapper", true) if err != nil { return err } } + w.Writeln("func releaseC(r *ref) error {") + w.Writeln(" if r == nil || *r == nil {") + w.Writeln(" return nil") + w.Writeln(" }") + w.Writeln(" return %s(%s{ref: *r})", component.Global.ReleaseMethod, component.Global.BaseClassName) + w.Writeln("}") w.Writeln("") + w.Writeln("func CheckBinaryVersion() error {") + w.Writeln(" var nBindingMajor uint32 = %d;", majorVersion(component.Version)) + w.Writeln(" var nBindingMinor uint32 = %d;", minorVersion(component.Version)) + w.Writeln(" nMajor, nMinor, _, err := %s()", component.Global.VersionMethod) + w.Writeln(" if err != nil {") + w.Writeln(" return err;") + w.Writeln(" }") + w.Writeln(" if (nMajor != nBindingMajor) || (nMinor < nBindingMinor) {") + w.Writeln(" return makeError(0)") + w.Writeln(" }") + w.Writeln(" return nil") w.Writeln("}") w.Writeln("") - w.Writelns("", classdefinitions) - - implw.Writeln("") - implw.Writeln("func (implementation *%sImplementation) checkBinaryVersion() (error) {", NameSpace) - implw.Writeln(" var nBindingMajor uint32 = %d;", majorVersion(component.Version)) - implw.Writeln(" var nBindingMinor uint32 = %d;", minorVersion(component.Version)) - implw.Writeln(" nMajor, nMinor, _, err := implementation.%s()", global.VersionMethod) - implw.Writeln(" if (err != nil) {") - implw.Writeln(" return err;") - implw.Writeln(" }") - implw.Writeln(" if ( (nMajor != nBindingMajor) || (nMinor < nBindingMinor) ) {") - implw.Writeln(" return fmt.Errorf(\"%s Error: %.04x (%s)\", int(0), Get%sErrorMessage(uint32(0)));", NameSpace, "%", "%s", NameSpace) - implw.Writeln(" }") - implw.Writeln(" return nil") - implw.Writeln("}") - implw.Writeln("") - - implw.Writeln("func %sLoadWrapper(DllFileName string) (%sWrapper, error) {", NameSpace, NameSpace) - implw.Writeln(" var Wrapper %sWrapper;", NameSpace) - implw.Writeln(" var Instance %sImplementation;", NameSpace) - implw.Writeln(" ") - implw.Writeln(" err := Instance.Initialize(DllFileName);") - implw.Writeln(" if (err != nil) {") - implw.Writeln(" return Wrapper, err;") - implw.Writeln(" }") - - implw.Writeln(" err = Instance.checkBinaryVersion()") - implw.Writeln(" if (err != nil) {") - implw.Writeln(" return Wrapper, err;") - implw.Writeln(" }") - - implw.Writeln(" Wrapper.Interface = &Instance;") - implw.Writeln(" ") - - implw.Writeln(" return Wrapper, nil;") - implw.Writeln("}") - implw.Writeln("") - return nil } -func getGoBasicType(paramType string) (string, error) { +type goType struct { + Type string + CType string + CToGo string + GoToC string + Empty string +} + +func getGoType(paramType, namespace, paramClass, paramName string, isPtr bool) (tp goType, err error) { + var ptrStr string + if isPtr { + ptrStr = "*" + } switch paramType { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool": - return paramType, nil + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "uintptr": + tp.Type = ptrStr + paramType + tp.CType = fmt.Sprintf("%sC.%s_t", ptrStr, paramType) + if isPtr { + tp.CToGo = fmt.Sprintf("(%s)(%s)", tp.Type, paramName) + tp.GoToC = fmt.Sprintf("(%s)(%s)", tp.CType, paramName) + } else { + tp.CToGo = fmt.Sprintf("%s(%s)", tp.Type, paramName) + tp.GoToC = fmt.Sprintf("%s(%s)", tp.CType, paramName) + tp.Empty = "0" + } + case "bool": + tp.Type = ptrStr + paramType + tp.CType = fmt.Sprintf("%sC.%s", ptrStr, paramType) + if isPtr { + tp.CToGo = fmt.Sprintf("(%s)(%s)", tp.Type, paramName) + tp.GoToC = fmt.Sprintf("(%s)(%s)", tp.CType, paramName) + } else { + tp.CToGo = fmt.Sprintf("%s(%s)", tp.Type, paramName) + tp.GoToC = fmt.Sprintf("%s(%s)", tp.CType, paramName) + tp.Empty = "false" + } case "single": - return "float32", nil + tp.Type = ptrStr + "float32" + tp.CType = ptrStr + "C.float" + if isPtr { + tp.CToGo = fmt.Sprintf("(%s)(%s)", tp.Type, paramName) + tp.GoToC = fmt.Sprintf("(%s)(%s)", tp.CType, paramName) + } else { + tp.CToGo = fmt.Sprintf("%s(%s)", tp.Type, paramName) + tp.GoToC = fmt.Sprintf("%s(%s)", tp.CType, paramName) + tp.Empty = "0" + } case "double": - return "float64", nil + tp.Type = ptrStr + "float64" + tp.CType = ptrStr + "C.double" + if isPtr { + tp.CToGo = fmt.Sprintf("(%s)(%s)", tp.Type, paramName) + tp.GoToC = fmt.Sprintf("(%s)(%s)", tp.CType, paramName) + } else { + tp.CToGo = fmt.Sprintf("%s(%s)", tp.Type, paramName) + tp.GoToC = fmt.Sprintf("%s(%s)", tp.CType, paramName) + tp.Empty = "0" + } + case "string": + tp.Type = ptrStr + "string" + tp.CType = ptrStr + "*C.char" + tp.CToGo = "" + tp.GoToC = fmt.Sprintf("(%s)(unsafe.Pointer(&[]byte(%s)[0]))", tp.CType, paramName) + tp.Empty = "\"\"" case "pointer": - return "uint64", nil - } - return "", errors.New("Invalid basic type: " + paramType) -} - -func paramFunction(paramType string, paramPass string) (string, error) { - paramFunctionStr := "" - switch paramType { - case "uint8": paramFunctionStr = "UInt8" - case "uint16": paramFunctionStr = "UInt16" - case "uint32": paramFunctionStr = "UInt32" - case "uint64": paramFunctionStr = "UInt64" - case "int8": paramFunctionStr = "Int8" - case "int16": paramFunctionStr = "Int16" - case "int32": paramFunctionStr = "Int32" - case "int64": paramFunctionStr = "Int64" - case "bool": paramFunctionStr = "bool" - case "single": paramFunctionStr = "Float32" - case "double": paramFunctionStr = "Float64" - case "pointer": paramFunctionStr = "UInt64" + tp.Type = "interface{}" + tp.CType = fmt.Sprintf("C.%s_pvoid", namespace) + tp.CToGo = fmt.Sprintf("*(*%s)(unsafe.Pointer(%s))", tp.Type, paramName) + tp.GoToC = fmt.Sprintf("(%s)(unsafe.Pointer(&%s))", tp.CType, paramName) + tp.Empty = "nil" + case "enum": + tp.Type = ptrStr + paramClass + tp.CType = fmt.Sprintf("%sC.e%s%s", ptrStr, namespace, paramClass) + if isPtr { + tp.CToGo = fmt.Sprintf("(*%s)(%s)", tp.Type, paramName) + tp.GoToC = fmt.Sprintf("(*%s)(%s)", tp.CType, paramName) + } else { + tp.CToGo = fmt.Sprintf("%s(%s)", tp.Type, paramName) + tp.GoToC = fmt.Sprintf("%s(%s)", tp.CType, paramName) + tp.Empty = "0" + } + case "struct": + tp.Type = ptrStr + paramClass + tp.CType = fmt.Sprintf("%sC.s%s%s", ptrStr, namespace, paramClass) + if isPtr { + tp.CToGo = fmt.Sprintf("(*%s)(unsafe.Pointer(%s))", tp.Type, paramName) + } else { + tp.CToGo = fmt.Sprintf("*(*%s)(unsafe.Pointer(&%s))", tp.Type, paramName) + } + tp.GoToC = fmt.Sprintf("(*%s)(unsafe.Pointer(&%s))", tp.CType, paramName) + tp.Empty = paramClass + "{}" + case "class": + tp.Type = paramClass + tp.CType = fmt.Sprintf("C.%s_%s", namespace, paramClass) + tp.CToGo = "" + tp.GoToC = fmt.Sprintf("%s.ref", paramName) + tp.Empty = paramClass + "{}" + case "optionalclass": + tp.Type = "*" + paramClass + tp.CType = fmt.Sprintf("*C.%s_%s", namespace, paramClass) + tp.CToGo = "" + tp.GoToC = fmt.Sprintf("%s.ref", paramName) + tp.Empty = "nil" + case "functiontype": + tp.Type = paramClass + "Func" + tp.CType = fmt.Sprintf("C.%s%s", namespace, paramClass) + tp.CToGo = "" + tp.GoToC = fmt.Sprintf("(%s)(unsafe.Pointer(C.%s%s_cgo))", tp.CType, namespace, paramClass) + tp.Empty = "0" + case "structarray": + tp.Type = fmt.Sprintf("[]%s", paramClass) + tp.CType = fmt.Sprintf("*C.s%s%s", namespace, paramClass) + tp.CToGo = fmt.Sprintf("(%s)(unsafe.Pointer(&%s[0]))", tp.Type, paramName) + tp.GoToC = fmt.Sprintf("(%s)(unsafe.Pointer(&%s[0]))", tp.CType, paramName) + tp.Empty = "nil" + case "basicarray": + btp, err := getGoType(paramClass, namespace, paramClass, paramName, false) + if err != nil { + return goType{}, err + } + tp.Type = ptrStr + fmt.Sprintf("[]%s", btp.Type) + tp.CType = fmt.Sprintf("*%s", btp.CType) + tp.CToGo = fmt.Sprintf("([]%s)(unsafe.Pointer(&%s[0]))", tp.Type, paramName) + tp.GoToC = fmt.Sprintf("(%s)(unsafe.Pointer(&%s[0]))", tp.CType, paramName) + tp.Empty = "nil" default: - return "", errors.New("Invalid basic type: " + paramType) + err = errors.New("Invalid basic type: " + paramType) } - - if paramPass == "in" { - paramFunctionStr += "InValue" - } else { - paramFunctionStr += "OutValue" + if isPtr { + tp.Empty = "nil" } - return paramFunctionStr , nil + return } -func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, implw LanguageWriter, NameSpace string, ClassName string, isGlobal bool, classdefinitions* []string) error { - - parameters := "" - callparameters := "" - returnvalues := "" - - var comments []string - - var implDeclarations []string - implDeclarations = append(implDeclarations, fmt.Sprintf("var err error = nil")) - var implCasts []string - - implReturnValues := "" - - errorReturn := "" - for k := 0; k < len(method.Params); k++ { - param := method.Params[k] - - if (param.ParamPass == "out") || (param.ParamPass == "return") { - switch param.ParamType { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double": - errorReturn = errorReturn + fmt.Sprintf("0, ") - case "pointer": - errorReturn = errorReturn + fmt.Sprintf("0, ") - case "enum": - errorReturn = errorReturn + fmt.Sprintf("0, ") - case "bool": - errorReturn = errorReturn + fmt.Sprintf("false, ") - case "string": - errorReturn = errorReturn + fmt.Sprintf("\"\", ") - case "struct": - errorReturn = errorReturn + fmt.Sprintf("s%s, ", param.ParamName) - case "class", "optionalclass": - errorReturn = errorReturn + fmt.Sprintf("h%s, ", param.ParamName) - case "functiontype": - errorReturn = errorReturn + fmt.Sprintf("0, ") - case "basicarray": - basicType, err := getGoBasicType(param.ParamClass) - if err != nil { - return err - } - errorReturn = errorReturn + fmt.Sprintf("make([]%s, 0), ", basicType) - case "structarray": - errorReturn = errorReturn + fmt.Sprintf("make([]s%s%s, 0), ", NameSpace, param.ParamClass) - default: - return fmt.Errorf("invalid method parameter type \"%s\" for %s.%s(%s)", param.ParamType, ClassName, method.MethodName, param.ParamName) - } - } +func endWithDot(s string) string { + if !strings.HasSuffix(s, ".") { + s += "." } - errorReturn = errorReturn + "err" + return s +} - if !isGlobal { - implCasts = append(implCasts, fmt.Sprintf("")) - implCasts = append(implCasts, fmt.Sprintf("implementation_%s, err := implementation.GetWrapperHandle(%s)", strings.ToLower(ClassName), ClassName)) - implCasts = append(implCasts, fmt.Sprintf("if (err != nil) {")) - implCasts = append(implCasts, fmt.Sprintf(" return %s", errorReturn)) - implCasts = append(implCasts, fmt.Sprintf("}")) +func lowerFirst(s string) string { + if s == "" { + return "" } + r, n := utf8.DecodeRuneInString(s) + return string(unicode.ToLower(r)) + s[n:] +} - requiresInitCall := false - implCallParameters := "" - implInitCallParameters := "" - var implInitCallLines []string - - var classReturnImplementation []string - classReturnVariables := "" - classReturnString := "" - classReturnTypes := "" +func toGoParam(s string) string { + s = lowerFirst(s) + // https://golang.org/ref/spec#Keywords and ref + switch s { + case "break", "default", "func", "interface", "select", "case", "defer", "go", "map", "struct", "chan", + "else", "goto", "package", "switch", "const", "fallthrough", "if", "range", "type", "continue", "for", + "import", "return", "var", "ref": + s = "_" + s + } + return s +} - for k := 0; k < len(method.Params); k++ { - param := method.Params[k] - thisImplCallParamter := "" - thisInitImplCallParamter := "" +func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, packageName string, className string, isGlobal bool) error { + + var errorReturn []string + var requiresInitCall bool + var returnValues []string + var callParameters []string + var initCallParameters []string + var initCallLines []string + var classReturnTypes []string + var parameters []string + var declarations []string + var preOKReturn []string + + for _, param := range method.Params { + param.ParamName = toGoParam(param.ParamName) + tp, err := getGoType(param.ParamType, NameSpace, param.ParamClass, param.ParamName, false) + if err != nil { + return err + } switch param.ParamPass { case "in": - if parameters != "" { - parameters = parameters + ", " - } - if callparameters != "" { - callparameters = callparameters + ", " + parameters = append(parameters, fmt.Sprintf("%s %s", param.ParamName, tp.Type)) + if param.ParamType == "basicarray" || param.ParamType == "structarray" { + callParam := fmt.Sprintf("C.uint64_t(len(%s))", param.ParamName) + callParameters = append(callParameters, callParam) + initCallParameters = append(initCallParameters, callParam) + } else if param.ParamType == "functiontype" { + preOKReturn = append(preOKReturn, fmt.Sprintf("%sFunc = %s", lowerFirst(param.ParamClass), param.ParamName)) } - - switch param.ParamType { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64": - goParamName := "n"+param.ParamName - comments = append(comments, fmt.Sprintf("* @param[in] %s - %s", goParamName, param.ParamDescription)) - parameters = parameters + fmt.Sprintf("%s %s", goParamName, param.ParamType) - goParamFunction, err := paramFunction(param.ParamType, param.ParamPass) - if err != nil { - return err - } - thisImplCallParamter = fmt.Sprintf(", %s(%s)", goParamFunction, goParamName) - callparameters = callparameters + goParamName - - case "bool": - comments = append(comments, fmt.Sprintf("* @param[in] b%s - %s", param.ParamName, param.ParamDescription)) - implDeclarations = append(implDeclarations, fmt.Sprintf("var n%s uint8 = 0", param.ParamName)) - implDeclarations = append(implDeclarations, fmt.Sprintf("if (b%s) {", param.ParamName)) - implDeclarations = append(implDeclarations, fmt.Sprintf(" n%s = 1", param.ParamName)) - implDeclarations = append(implDeclarations, fmt.Sprintf("}")) - implDeclarations = append(implDeclarations, fmt.Sprintf("")) - parameters = parameters + fmt.Sprintf("b%s bool", param.ParamName) - thisImplCallParamter = fmt.Sprintf(", UInt8InValue(n%s)", param.ParamName) - callparameters = callparameters + "b" + param.ParamName - - case "single": - comments = append(comments, fmt.Sprintf("* @param[in] f%s - %s", param.ParamName, param.ParamDescription)) - parameters = parameters + fmt.Sprintf("f%s float32", param.ParamName) - thisImplCallParamter = fmt.Sprintf(", Float32InValue(f%s)", param.ParamName) - callparameters = callparameters + "f" + param.ParamName - - case "double": - comments = append(comments, fmt.Sprintf("* @param[in] d%s - %s", param.ParamName, param.ParamDescription)) - parameters = parameters + fmt.Sprintf("d%s float64", param.ParamName) - thisImplCallParamter = fmt.Sprintf(", Float64InValue(d%s)", param.ParamName) - callparameters = callparameters + "d" + param.ParamName - - case "pointer": - comments = append(comments, fmt.Sprintf("* @param[in] n%s - %s", param.ParamName, param.ParamDescription)) - parameters = parameters + fmt.Sprintf("n%s uint64", param.ParamName) - thisImplCallParamter = fmt.Sprintf(", UInt64InValue(n%s)", param.ParamName) - callparameters = callparameters + "n" + param.ParamName - - case "string": - comments = append(comments, fmt.Sprintf("* @param[in] s%s - %s", param.ParamName, param.ParamDescription)) - parameters = parameters + fmt.Sprintf("s%s string", param.ParamName) - thisImplCallParamter = fmt.Sprintf(", StringInValue(s%s)", param.ParamName) - callparameters = callparameters + "s" + param.ParamName - - case "enum": - comments = append(comments, fmt.Sprintf("* @param[in] e%s - %s", param.ParamName, param.ParamDescription)) - parameters = parameters + fmt.Sprintf("e%s E%s%s", param.ParamName, NameSpace, param.ParamClass) - thisImplCallParamter = fmt.Sprintf(", uintptr(e%s)", param.ParamName) - callparameters = callparameters + "e" + param.ParamName - - case "struct": - comments = append(comments, fmt.Sprintf("* @param[in] s%s - %s", param.ParamName, param.ParamDescription)) - parameters = parameters + fmt.Sprintf("s%s s%s%s", param.ParamName, NameSpace, param.ParamClass) - thisImplCallParamter = fmt.Sprintf(", uintptr(unsafe.Pointer(&s%s))", param.ParamName) - callparameters = callparameters + "s" + param.ParamName - - case "basicarray": - basicType, err := getGoBasicType(param.ParamClass) - if err != nil { - return err - } - comments = append(comments, fmt.Sprintf("* @param[in] %s - %s", param.ParamName, param.ParamDescription)) - parameters = parameters + fmt.Sprintf("%s []%s", param.ParamName, basicType) - thisImplCallParamter = fmt.Sprintf(", 0, 0") - callparameters = callparameters + param.ParamName - - case "structarray": - comments = append(comments, fmt.Sprintf("* @param[in] %s - %s", param.ParamName, param.ParamDescription)) - parameters = parameters + fmt.Sprintf("%s []s%s%s", param.ParamName, NameSpace, param.ParamClass) - thisImplCallParamter = fmt.Sprintf(", 0, 0") - callparameters = callparameters + param.ParamName - - case "functiontype": - comments = append(comments, fmt.Sprintf("* @param[in] p%s - %s", param.ParamName, param.ParamDescription)) - parameters = parameters + fmt.Sprintf("p%s int64", param.ParamName) - thisImplCallParamter = fmt.Sprintf(", 0") - callparameters = callparameters + "p" + param.ParamName - - case "class", "optionalclass": - comments = append(comments, fmt.Sprintf("* @param[in] %s - %s", param.ParamName, param.ParamDescription)) - parameters = parameters + fmt.Sprintf("%s %sHandle", param.ParamName, NameSpace) - - implCasts = append(implCasts, fmt.Sprintf("implementation_%s, err := implementation.GetWrapperHandle(%s)", strings.ToLower(param.ParamName), param.ParamName)) - implCasts = append(implCasts, fmt.Sprintf("if (err != nil) {")) - implCasts = append(implCasts, fmt.Sprintf(" return %s", errorReturn)) - implCasts = append(implCasts, fmt.Sprintf("}")) - implCasts = append(implCasts, fmt.Sprintf("")) - - implCasts = append(implCasts, fmt.Sprintf("%sDLLHandle := implementation_%s.GetDLLInHandle()", param.ParamName, strings.ToLower(param.ParamName))) - if (param.ParamType == "class") { - implCasts = append(implCasts, fmt.Sprintf("if (%sDLLHandle == 0) {", param.ParamName)) - implCasts = append(implCasts, fmt.Sprintf(" err := fmt.Errorf(\"Handle must not be 0.\")", )) - implCasts = append(implCasts, fmt.Sprintf(" return %s", errorReturn)) - implCasts = append(implCasts, fmt.Sprintf("}")) - } - thisImplCallParamter = fmt.Sprintf(", %sDLLHandle", param.ParamName) - callparameters = callparameters + param.ParamName - - default: - return fmt.Errorf("invalid method parameter type \"%s\" for %s.%s (%s)", param.ParamType, ClassName, method.MethodName, param.ParamName) - } - - thisInitImplCallParamter = thisImplCallParamter + callParameters = append(callParameters, tp.GoToC) + initCallParameters = append(initCallParameters, tp.GoToC) case "out", "return": - comments = append(comments, fmt.Sprintf("* @return %s", param.ParamDescription)) - + classReturnTypes = append(classReturnTypes, tp.Type) + errorReturn = append(errorReturn, tp.Empty) switch param.ParamType { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64": - basicType, err := getGoBasicType(param.ParamType) - if err != nil { - return err - } - goParamFunction, err := paramFunction(param.ParamType, param.ParamPass) - if err != nil { - return err - } - goParamName := "n"+param.ParamName - returnvalues = returnvalues + fmt.Sprintf("%s, ", basicType) - implDeclarations = append(implDeclarations, fmt.Sprintf("var %s %s = 0", goParamName, param.ParamType)) - implReturnValues = implReturnValues + fmt.Sprintf("%s(%s), ", basicType, goParamName) + case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", + "pointer", "bool", "single", "double", "enum", "functiontype", "struct": + declarations = append(declarations, fmt.Sprintf("var %s %s", param.ParamName, tp.CType)) + callParam := fmt.Sprintf("&%s", param.ParamName) + callParameters = append(callParameters, callParam) + initCallParameters = append(initCallParameters, callParam) - thisImplCallParamter = fmt.Sprintf(", %s(&%s)", goParamFunction, goParamName) - thisInitImplCallParamter = thisImplCallParamter - - classReturnVariables = classReturnVariables + goParamName + ", " - classReturnString = classReturnString + goParamName + ", " - classReturnTypes = classReturnTypes + fmt.Sprintf("%s, ", basicType) - - case "pointer": - returnvalues = returnvalues + fmt.Sprintf("uint64, ") - implDeclarations = append(implDeclarations, fmt.Sprintf("var n%s uint64 = 0", param.ParamName)) - implReturnValues = implReturnValues + fmt.Sprintf("n%s, ", param.ParamName) - - thisImplCallParamter = fmt.Sprintf(", UInt64OutValue(&n%s)", param.ParamName) - thisInitImplCallParamter = thisImplCallParamter - - classReturnVariables = classReturnVariables + "n" + param.ParamName + ", " - classReturnString = classReturnString + "n" + param.ParamName + ", " - classReturnTypes = classReturnTypes + fmt.Sprintf("uint64, ") - - case "bool": - returnvalues = returnvalues + fmt.Sprintf("bool, ") - implDeclarations = append(implDeclarations, fmt.Sprintf("var b%s int64 = 0", param.ParamName)) - implReturnValues = implReturnValues + fmt.Sprintf("(b%s != 0), ", param.ParamName) - - thisImplCallParamter = fmt.Sprintf(", Int64OutValue(&b%s)", param.ParamName) - thisInitImplCallParamter = thisImplCallParamter - - classReturnVariables = classReturnVariables + "b" + param.ParamName + ", " - classReturnString = classReturnString + "b" + param.ParamName + ", " - classReturnTypes = classReturnTypes + fmt.Sprintf("bool, ") - - case "single": - returnvalues = returnvalues + fmt.Sprintf("float32, ") - implDeclarations = append(implDeclarations, fmt.Sprintf("var f%s float32 = 0", param.ParamName)) - implReturnValues = implReturnValues + fmt.Sprintf("f%s, ", param.ParamName) - - thisImplCallParamter = fmt.Sprintf(", Float32OutValue(&f%s)", param.ParamName) - thisInitImplCallParamter = thisImplCallParamter - - classReturnVariables = classReturnVariables + "f" + param.ParamName + ", " - classReturnString = classReturnString + "f" + param.ParamName + ", " - classReturnTypes = classReturnTypes + fmt.Sprintf("float32, ") - - case "double": - returnvalues = returnvalues + fmt.Sprintf("float64, ") - implDeclarations = append(implDeclarations, fmt.Sprintf("var d%s float64 = 0", param.ParamName)) - implReturnValues = implReturnValues + fmt.Sprintf("d%s, ", param.ParamName) - - thisImplCallParamter = fmt.Sprintf(", Float64OutValue(&d%s)", param.ParamName) - thisInitImplCallParamter = thisImplCallParamter - - classReturnVariables = classReturnVariables + "d" + param.ParamName + ", " - classReturnString = classReturnString + "d" + param.ParamName + ", " - classReturnTypes = classReturnTypes + fmt.Sprintf("float64, ") + returnValues = append(returnValues, tp.CToGo) case "string": requiresInitCall = true - implDeclarations = append(implDeclarations, fmt.Sprintf("var neededfor%s int64 = 0", param.ParamName)) - implDeclarations = append(implDeclarations, fmt.Sprintf("var filledin%s int64 = 0", param.ParamName)) - - thisInitImplCallParamter = fmt.Sprintf(", Int64InValue(0), Int64OutValue(&neededfor%s), Int64InValue(0)", param.ParamName) + declarations = append(declarations, fmt.Sprintf("var neededfor%s C.uint32_t", param.ParamName)) + declarations = append(declarations, fmt.Sprintf("var filledin%s C.uint32_t", param.ParamName)) - implInitCallLines = append(implInitCallLines, fmt.Sprintf("bufferSize%s := neededfor%s", param.ParamName, param.ParamName)) - implInitCallLines = append(implInitCallLines, fmt.Sprintf("buffer%s := make([]byte, bufferSize%s)", param.ParamName, param.ParamName)) + initCallParameters = append(initCallParameters, fmt.Sprintf("0, &neededfor%s, nil", param.ParamName)) + callParameters = append(callParameters, fmt.Sprintf("bufferSize%s, &filledin%s, (%s)(unsafe.Pointer(&buffer%s[0]))", param.ParamName, param.ParamName, tp.CType, param.ParamName)) - thisImplCallParamter = fmt.Sprintf(", Int64InValue(bufferSize%s), Int64OutValue(&filledin%s), uintptr(unsafe.Pointer(&buffer%s[0]))", param.ParamName, param.ParamName, param.ParamName) + initCallLines = append(initCallLines, fmt.Sprintf("bufferSize%s := neededfor%s", param.ParamName, param.ParamName)) + initCallLines = append(initCallLines, fmt.Sprintf("buffer%s := make([]byte, bufferSize%s)", param.ParamName, param.ParamName)) - implReturnValues = implReturnValues + fmt.Sprintf("string(buffer%s[:(filledin%s-1)]), ", param.ParamName, param.ParamName) + returnValues = append(returnValues, fmt.Sprintf("string(buffer%s[:(filledin%s-1)])", param.ParamName, param.ParamName)) - returnvalues = returnvalues + fmt.Sprintf("string, ") - classReturnVariables = classReturnVariables + "s" + param.ParamName + ", " - classReturnString = classReturnString + "s" + param.ParamName + ", " - classReturnTypes = classReturnTypes + fmt.Sprintf("string, ") + case "basicarray", "structarray": + parameters = append(parameters, fmt.Sprintf("%s %s", param.ParamName, tp.Type)) - case "enum": - returnvalues = returnvalues + fmt.Sprintf("E%s%s, ", NameSpace, param.ParamClass) - implDeclarations = append(implDeclarations, fmt.Sprintf("var e%s uint64 = 0", param.ParamName)) - implReturnValues = implReturnValues + fmt.Sprintf("E%s%s (e%s), ", NameSpace, param.ParamClass, param.ParamName) - thisImplCallParamter = fmt.Sprintf(", UInt64OutValue(&e%s)", param.ParamName) - thisInitImplCallParamter = thisImplCallParamter - - classReturnVariables = classReturnVariables + "e" + param.ParamName + ", " - classReturnString = classReturnString + "e" + param.ParamName + ", " - classReturnTypes = classReturnTypes + fmt.Sprintf("E%s%s, ", NameSpace, param.ParamClass) - - case "basicarray": requiresInitCall = true - basicType, err := getGoBasicType(param.ParamClass) - if err != nil { - return err - } - implDeclarations = append(implDeclarations, fmt.Sprintf("var neededfor%s int64 = 0", param.ParamName)) - implDeclarations = append(implDeclarations, fmt.Sprintf("var filledin%s int64 = 0", param.ParamName)) - - bufferName := fmt.Sprintf("buffer%s", param.ParamName) - implDeclarations = append(implDeclarations, fmt.Sprintf("%s := make([]%s, 0)", bufferName, basicType)) - - thisInitImplCallParamter = fmt.Sprintf(", Int64InValue(0), Int64OutValue(&neededfor%s), Int64InValue(0)", param.ParamName) - - implInitCallLines = append(implInitCallLines, fmt.Sprintf("bufferSize%s := neededfor%s", param.ParamName, param.ParamName)) - implInitCallLines = append(implInitCallLines, fmt.Sprintf("%s = make([]%s, bufferSize%s)", bufferName, basicType, param.ParamName)) - - thisImplCallParamter = fmt.Sprintf(", Int64InValue(bufferSize%s), Int64OutValue(&filledin%s), uintptr(unsafe.Pointer(&%s[0]))", param.ParamName, param.ParamName, bufferName) + needSizeVar := fmt.Sprintf("neededfor%s", param.ParamName) + declarations = append(declarations, fmt.Sprintf("var %s C.uint64_t", needSizeVar)) - returnvalues = returnvalues + fmt.Sprintf("[]%s, ", basicType) - implReturnValues = implReturnValues + fmt.Sprintf("%s, ", bufferName) + initCallLines = append(initCallLines, fmt.Sprintf("if len(%s) < int(%s) {", param.ParamName, needSizeVar)) + initCallLines = append(initCallLines, fmt.Sprintf(" %s = append(%s, make(%s, int(%s)-len(%s))...)", param.ParamName, param.ParamName, tp.Type, needSizeVar, param.ParamName)) + initCallLines = append(initCallLines, "}") + initCallParameters = append(initCallParameters, fmt.Sprintf("0, &%s, nil", needSizeVar)) + callParameters = append(callParameters, fmt.Sprintf("%s, nil, (%s)(unsafe.Pointer(&%s[0]))", needSizeVar, tp.CType, param.ParamName)) - classReturnVariables = classReturnVariables + bufferName + ", " - classReturnString = classReturnString + bufferName + ", " - classReturnTypes = classReturnTypes + fmt.Sprintf("[]%s, ", basicType) - - case "structarray": - requiresInitCall = true - returnvalues = returnvalues + fmt.Sprintf("[]s%s%s, ", NameSpace, param.ParamClass) - implDeclarations = append(implDeclarations, fmt.Sprintf("array%s := make([]s%s%s, 0)", param.ParamName, NameSpace, param.ParamClass)) - implReturnValues = implReturnValues + fmt.Sprintf("array%s, ", param.ParamName) - thisImplCallParamter = fmt.Sprintf(", 0, 0, 0") - thisInitImplCallParamter = thisImplCallParamter - - classReturnVariables = classReturnVariables + "array" + param.ParamName + ", " - classReturnString = classReturnString + "array" + param.ParamName + ", " - classReturnTypes = classReturnTypes + fmt.Sprintf("[]s%s%s, ", NameSpace, param.ParamClass) - - case "functiontype": - returnvalues = returnvalues + fmt.Sprintf("uint64, ") - implDeclarations = append(implDeclarations, fmt.Sprintf("var p%s uint64 = 0", param.ParamName)) - implReturnValues = implReturnValues + fmt.Sprintf("p%s, ", param.ParamName) - thisImplCallParamter = fmt.Sprintf(", UInt64OutValue(&p%s)", param.ParamName) - thisInitImplCallParamter = thisImplCallParamter - - classReturnVariables = classReturnVariables + "p" + param.ParamName + ", " - classReturnString = classReturnString + "p" + param.ParamName + ", " - classReturnTypes = classReturnTypes + fmt.Sprintf("uint64, ") - - case "struct": - returnvalues = returnvalues + fmt.Sprintf("s%s%s, ", NameSpace, param.ParamClass) - implDeclarations = append(implDeclarations, fmt.Sprintf("var s%s s%s%s", param.ParamName, NameSpace, param.ParamClass)) - implReturnValues = implReturnValues + fmt.Sprintf("s%s, ", param.ParamName) - thisImplCallParamter = fmt.Sprintf(", 0") - thisInitImplCallParamter = thisImplCallParamter - - classReturnVariables = classReturnVariables + "s" + param.ParamName + ", " - classReturnString = classReturnString + "s" + param.ParamName + ", " - classReturnTypes = classReturnTypes + fmt.Sprintf("s%s%s, ", NameSpace, param.ParamClass) + returnValues = append(returnValues, fmt.Sprintf("%s[:int(%s)]", param.ParamName, needSizeVar)) case "class", "optionalclass": - returnvalues = returnvalues + fmt.Sprintf("%sHandle, ", NameSpace) - implDeclarations = append(implDeclarations, fmt.Sprintf("h%s := implementation.NewHandle()", param.ParamName)) - - thisImplCallParamter = fmt.Sprintf(", h%s.GetDLLOutHandle()", param.ParamName) - thisInitImplCallParamter = thisImplCallParamter - - implReturnValues = implReturnValues + fmt.Sprintf("h%s, ", param.ParamName) - classReturnVariables = classReturnVariables + "h" + param.ParamName + ", " - classReturnImplementation = append(classReturnImplementation, fmt.Sprintf("var c%s %s%s", param.ParamName, NameSpace, param.ParamClass)) - classReturnImplementation = append(classReturnImplementation, fmt.Sprintf("c%s.Interface = instance.Interface", param.ParamName)) - classReturnImplementation = append(classReturnImplementation, fmt.Sprintf("c%s.Handle = h%s", param.ParamName, param.ParamName)) - - classReturnString = classReturnString + "c" + param.ParamName + ", " - classReturnTypes = classReturnTypes + fmt.Sprintf("%s%s, ", NameSpace, param.ParamClass) - + declarations = append(declarations, fmt.Sprintf("var %s ref", param.ParamName)) + callParam := fmt.Sprintf("&%s", param.ParamName) + callParameters = append(callParameters, callParam) + initCallParameters = append(initCallParameters, callParam) + if param.ParamType == "optionalclass" { + preOKReturn = append(preOKReturn, + fmt.Sprintf("var _%sPtr %s", param.ParamName, tp.Type), + fmt.Sprintf("if %s == nil {", param.ParamName), + fmt.Sprintf(" _%sPtrVal := new%s(%s)", param.ParamName, param.ParamClass, param.ParamName), + fmt.Sprintf(" _%sPtr = &_%sPtrVal", param.ParamName, param.ParamName), + "}") + returnValues = append(returnValues, fmt.Sprintf("_%sPtr", param.ParamName)) + } else { + returnValues = append(returnValues, fmt.Sprintf("new%s(%s)", param.ParamClass, param.ParamName)) + } default: - return fmt.Errorf("invalid method parameter type \"%s\" for %s.%s (%s)", param.ParamType, ClassName, method.MethodName, param.ParamName) + return fmt.Errorf("invalid method parameter type \"%s\" for %s.%s (%s)", param.ParamType, className, method.MethodName, param.ParamName) } default: - return fmt.Errorf("invalid method parameter passing \"%s\" for %s.%s (%s)", param.ParamPass, ClassName, method.MethodName, param.ParamName) + return fmt.Errorf("invalid method parameter passing \"%s\" for %s.%s (%s)", param.ParamPass, className, method.MethodName, param.ParamName) } + } - implCallParameters += thisImplCallParamter - implInitCallParameters += thisInitImplCallParamter + // Implementation + implmethodname := "C." + packageName + "_" + returnValues = append(returnValues, "nil") + classReturnTypes = append(classReturnTypes, "error") + errorReturn = append(errorReturn, "makeError(uint32(ret))") + + var returnString string + if len(classReturnTypes) == 1 { + returnString = "error" + } else { + returnString = fmt.Sprintf("(%s)", strings.Join(classReturnTypes, ", ")) } - w.Writeln("") - w.Writeln(" /**") - w.Writeln(" * %s", method.MethodDescription) - w.Writeln(" *") - w.Writeln(" * @param[in] %s - %s instance.", ClassName, ClassName) - w.Writelns(" ", comments) - w.Writeln(" */") - - handleparameter := "" + w.Writeln("// %s %s", method.MethodName, endWithDot(lowerFirst(method.MethodDescription))) if isGlobal { - w.Writeln(" %s(%s) (%serror)\n", method.MethodName, parameters, returnvalues) + w.Writeln("func %s(%s) %s {", method.MethodName, strings.Join(parameters, ", "), returnString) } else { - handleparameter = fmt.Sprintf("%s %sHandle", ClassName, NameSpace) - if parameters != "" { - handleparameter = handleparameter + ", " - } - w.Writeln(" %s_%s(%s%s) (%serror)\n", ClassName, method.MethodName, handleparameter, parameters, returnvalues) + w.Writeln("func (inst %s) %s(%s) %s {", className, method.MethodName, strings.Join(parameters, ", "), returnString) } - - - // Implementation - implmethodname := "implementation." + NameSpace + "_" - implGetHandleFunction := "" if !isGlobal { - implmethodname += strings.ToLower(ClassName) + "_" - implGetHandleFunction = fmt.Sprintf(", implementation_%s.GetDLLInHandle()", strings.ToLower(ClassName)) + initCallParameters = append([]string{"inst.ref"}, initCallParameters...) + callParameters = append([]string{"inst.ref"}, callParameters...) + implmethodname += strings.ToLower(className) + "_" } implmethodname += strings.ToLower(method.MethodName) - - if isGlobal { - implw.Writeln("func (implementation *%sImplementation) %s(%s%s) (%serror) {", NameSpace, method.MethodName, handleparameter, parameters, returnvalues) - } else { - implw.Writeln("func (implementation *%sImplementation) %s_%s(%s%s) (%serror) {", NameSpace, ClassName, method.MethodName, handleparameter, parameters, returnvalues) - } - implw.Writelns(" ", implDeclarations) - implw.Writelns(" ", implCasts) - implw.Writeln("") + w.Writelns(" ", declarations) + retInst := ":" if requiresInitCall { - implw.Writeln(" err = implementation.CallFunction(%s%s%s)", implmethodname, implGetHandleFunction, implInitCallParameters) - implw.Writeln(" if (err != nil) {") - implw.Writeln(" return %s", errorReturn) - implw.Writeln(" }") - implw.Writelns(" ", implInitCallLines) + w.Writeln(" ret := %s(%s)", implmethodname, strings.Join(initCallParameters, ", ")) + w.Writeln(" if ret != 0 {") + w.Writeln(" return %s", strings.Join(errorReturn, ", ")) + w.Writeln(" }") + w.Writelns(" ", initCallLines) + retInst = "" } - implw.Writeln(" err = implementation.CallFunction(%s%s%s)", implmethodname, implGetHandleFunction, implCallParameters) + w.Writeln(" ret %s= %s(%s)", retInst, implmethodname, strings.Join(callParameters, ", ")) - implw.Writeln(" if (err != nil) {") - implw.Writeln(" return %s", errorReturn) - implw.Writeln(" }") - implw.Writeln(" ") - implw.Writeln(" return %serr", implReturnValues) - implw.Writeln("}") - implw.Writeln("") - - if isGlobal { - *classdefinitions = append(*classdefinitions, fmt.Sprintf("func (instance *%s%s) %s(%s) (%serror) {", NameSpace, ClassName, method.MethodName, parameters, classReturnTypes)) - *classdefinitions = append(*classdefinitions, fmt.Sprintf(" %serror := instance.Interface.%s(%s)", classReturnVariables, method.MethodName, callparameters)) - } else { - if callparameters != "" { - callparameters = ", " + callparameters - } - *classdefinitions = append(*classdefinitions, fmt.Sprintf("func (instance *%s%s) %s(%s) (%serror) {", NameSpace, ClassName, method.MethodName, parameters, classReturnTypes)) - *classdefinitions = append(*classdefinitions, fmt.Sprintf(" %serror := instance.Interface.%s_%s(instance.Handle%s)", classReturnVariables, ClassName, method.MethodName, callparameters)) - } - for _, line := range classReturnImplementation { - *classdefinitions = append(*classdefinitions, fmt.Sprintf(" %s", line )) - } - *classdefinitions = append(*classdefinitions, fmt.Sprintf(" return %serror", classReturnString)) - *classdefinitions = append(*classdefinitions, fmt.Sprintf("}")) - *classdefinitions = append(*classdefinitions, fmt.Sprintf("")) + w.Writeln(" if ret != 0 {") + w.Writeln(" return %s", strings.Join(errorReturn, ", ")) + w.Writeln(" }") + w.Writelns(" ", preOKReturn) + w.Writeln(" return %s", strings.Join(returnValues, ", ")) + w.Writeln("}") + w.Writeln("") return nil } - diff --git a/Source/languagec.go b/Source/languagec.go index 57441cd5..21a8a56b 100644 --- a/Source/languagec.go +++ b/Source/languagec.go @@ -343,7 +343,9 @@ func buildCAbiHeader(component ComponentDefinition, w LanguageWriter, NameSpace w.Writeln("") + w.Writeln("#ifdef __cplusplus"); w.Writeln("extern \"C\" {"); + w.Writeln("#endif"); for i := 0; i < len(component.Classes); i++ { class := component.Classes[i]; @@ -368,7 +370,9 @@ func buildCAbiHeader(component ComponentDefinition, w LanguageWriter, NameSpace } w.Writeln(""); + w.Writeln("#ifdef __cplusplus"); w.Writeln("}"); + w.Writeln("#endif"); w.Writeln(""); w.Writeln("#endif // %s", sIncludeGuard); w.Writeln(""); From 2b5f4c05e2ef6b35e5622f9a13f24aa43f656adf Mon Sep 17 00:00:00 2001 From: Alexander Oster Date: Fri, 24 Jul 2020 12:32:04 +0200 Subject: [PATCH 2/2] CGo now loads functions dynamically --- Source/automaticcomponenttoolkit.go | 2 +- Source/buildbindinggo.go | 250 +++++++++++++++++++++++++--- 2 files changed, 225 insertions(+), 27 deletions(-) diff --git a/Source/automaticcomponenttoolkit.go b/Source/automaticcomponenttoolkit.go index f1b73b36..68b41f40 100644 --- a/Source/automaticcomponenttoolkit.go +++ b/Source/automaticcomponenttoolkit.go @@ -233,7 +233,7 @@ func createComponent(component ComponentDefinition, outfolderBase string, bindin } } - err := BuildBindingGo(component, outputFolderBindingGo, outputFolderExampleGo) + err := BuildBindingGo(component, outputFolderBindingGo, outputFolderExampleGo, indentString) if err != nil { return err } diff --git a/Source/buildbindinggo.go b/Source/buildbindinggo.go index 7d6c1f29..04eb1fc8 100644 --- a/Source/buildbindinggo.go +++ b/Source/buildbindinggo.go @@ -44,7 +44,7 @@ import ( ) // BuildBindingGo builds Go-bindings of a library's API -func BuildBindingGo(component ComponentDefinition, outputFolder string, outputFolderExample string) error { +func BuildBindingGo(component ComponentDefinition, outputFolder string, outputFolderExample string, indentString string) error { forceRecreation := false CTypesHeaderName := path.Join(outputFolder, component.BaseName+"_types.h") @@ -53,13 +53,37 @@ func BuildBindingGo(component ComponentDefinition, outputFolder string, outputFo return err } - CHeaderName := path.Join(outputFolder, component.BaseName+"_abi.h") - err = CreateCAbiHeader(component, CHeaderName) + + DynamicCHeader := path.Join(outputFolder, component.BaseName+"_dynamic.h") + log.Printf("Creating \"%s\"", DynamicCHeader) + dynhfile, err := CreateLanguageFile(DynamicCHeader, indentString) + if err != nil { + return err + } + dynhfile.WriteCLicenseHeader(component, + fmt.Sprintf("This is an autogenerated plain C Header file in order to allow an easy\n use of %s", component.LibraryName), + true) + err = buildDynamicCCPPHeader(component, dynhfile, component.NameSpace, component.BaseName, false, false) if err != nil { return err } - fnFile, err := CreateLanguageFile(path.Join(outputFolder, "cfunc.go"), " ") + DynamicCImpl := path.Join(outputFolder, component.BaseName+"_dynamic.cc") + log.Printf("Creating \"%s\"", DynamicCImpl) + dyncppfile, err := CreateLanguageFile(DynamicCImpl, indentString) + if err != nil { + return err + } + dyncppfile.WriteCLicenseHeader(component, + fmt.Sprintf("This is an autogenerated plain C Header file in order to allow an easy\n use of %s", component.LibraryName), + true) + + err = buildDynamicCImplementation(component, dyncppfile, component.NameSpace, component.BaseName, true) + if err != nil { + return err + } + + fnFile, err := CreateLanguageFile(path.Join(outputFolder, component.BaseName+"cfunc.go"), " ") if err != nil { return err } @@ -73,6 +97,7 @@ func BuildBindingGo(component ComponentDefinition, outputFolder string, outputFo if err != nil { return err } + GoIntfName := path.Join(outputFolder, component.BaseName+".go") log.Printf("Creating \"%s\"", GoIntfName) gofile, err := CreateLanguageFile(GoIntfName, " ") @@ -328,6 +353,14 @@ func buildGoStructs(component ComponentDefinition, w LanguageWriter) error { } func buildGoErrorHandling(component ComponentDefinition, w LanguageWriter, packageName string) { + w.Writeln("// Error constants for %s.", component.NameSpace) + for i := 0; i < len(component.Errors.Errors); i++ { + errorcode := component.Errors.Errors[i] + w.Writeln("const %s_ERROR_%s = %d;", strings.ToUpper (component.NameSpace), errorcode.Name, errorcode.Code) + } + w.Writeln("") + + w.Writeln("// WrappedError is an error that wraps a %s error.", component.NameSpace) w.Writeln("type WrappedError struct {") w.Writeln(" Code uint32") @@ -343,8 +376,8 @@ func buildGoErrorHandling(component ComponentDefinition, w LanguageWriter, packa for i := 0; i < len(component.Errors.Errors); i++ { errorcode := component.Errors.Errors[i] - w.Writeln(" case %d:", errorcode.Code) - w.Writeln(" return \"%s\";", errorcode.Name) + w.Writeln(" case %s_ERROR_%s:", strings.ToUpper (component.NameSpace), errorcode.Name) + w.Writeln(" return \"%s\";", errorcode.Description) } w.Writeln(" default:") w.Writeln(" return \"unknown\";") @@ -358,11 +391,13 @@ func buildGoErrorHandling(component ComponentDefinition, w LanguageWriter, packa func buildGoClass(component ComponentDefinition, class ComponentDefinitionClass, w LanguageWriter, NameSpace string, packageName string) error { w.Writeln("") + w.Writeln("// %s represents a %s class.", class.ClassName, NameSpace) w.Writeln("type %s struct {", class.ClassName) if component.Global.BaseClassName == class.ClassName { w.Writeln(" _ [0]func() // uncomparable; to make == not compile") - w.Writeln(" ref ref // identifies a C value, see ref type") + w.Writeln(" ref ref // identifies a C value, see ref type") + w.Writeln(" wrapperRef *Wrapper") w.Writeln(" gcPtr *ref // used to trigger the finalizer when the Value is not referenced any more") } else { if len(class.ParentClass) > 0 { @@ -377,18 +412,23 @@ func buildGoClass(component ComponentDefinition, class ComponentDefinitionClass, w.Writeln("// New%s creates a new %s.", class.ClassName, class.ClassName) w.Writeln("// The wrapped C pointer will be freed when the Go pointer is finalized,") w.Writeln("// but one can release it manually calling Release.") - w.Writeln("func New%s(r ref) %s {", class.ClassName, class.ClassName) + w.Writeln("func (wrapper * Wrapper) New%s(r ref) %s {", class.ClassName, class.ClassName) w.Writeln(" gcPtr := new(ref)") w.Writeln(" *gcPtr = r") - w.Writeln(" runtime.SetFinalizer(gcPtr, releaseC)") - w.Writeln(" return %s{ref: r, gcPtr: gcPtr}", class.ClassName) + w.Writeln(" runtime.SetFinalizer(gcPtr, wrapper.releaseC)") + w.Writeln(" return %s{ref: r, gcPtr: gcPtr, wrapperRef: wrapper}", class.ClassName) w.Writeln("}") w.Writeln("") w.Writeln("// Release releases the C pointer.") w.Writeln("func (inst %s) Release() error {", class.ClassName) - w.Writeln(" err := %s(inst)", component.Global.ReleaseMethod) - w.Writeln(" *inst.gcPtr = nil") - w.Writeln(" return err") + w.Writeln(" if (inst.wrapperRef != nil) {"); + w.Writeln(" err := inst.wrapperRef.%s(inst)", component.Global.ReleaseMethod) + w.Writeln(" *inst.gcPtr = nil") + w.Writeln(" return err") + w.Writeln(" } else {") + w.Writeln(" *inst.gcPtr = nil") + w.Writeln(" return nil;") + w.Writeln(" }") w.Writeln("}") w.Writeln("") w.Writeln("// Equal reports whether inst and w refer to the same C pointer.") @@ -396,11 +436,11 @@ func buildGoClass(component ComponentDefinition, class ComponentDefinitionClass, w.Writeln(" return inst.ref == w.ref") w.Writeln("}") } else { - w.Writeln("func new%s(r ref) %s {", class.ClassName, class.ClassName) + w.Writeln("func (wrapper * Wrapper) new%s(r ref) %s {", class.ClassName, class.ClassName) if class.ParentClass != "" && class.ParentClass != component.Global.BaseClassName { - w.Writeln(" return %s{new%s(r)}", class.ClassName, class.ParentClass) + w.Writeln(" return %s{wrapper.new%s(r)}", class.ClassName, class.ParentClass) } else { - w.Writeln(" return %s{New%s(r)}", class.ClassName, component.Global.BaseClassName) + w.Writeln(" return %s{wrapper.New%s(r)}", class.ClassName, component.Global.BaseClassName) } w.Writeln("}") } @@ -415,6 +455,98 @@ func buildGoClass(component ComponentDefinition, class ComponentDefinitionClass, return nil } + +// WriteCGoAbiMethod writes an ABI method in CGo-Style +func WriteCGoAbiMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, ClassName string, isGlobal bool) (error) { + CMethodName := ""; + parameters := ""; + callParameters := ""; + if (isGlobal) { + CMethodName = fmt.Sprintf ("%s_%s", strings.ToLower (NameSpace), strings.ToLower (method.MethodName)); + } else { + CMethodName = fmt.Sprintf ("%s_%s_%s", strings.ToLower (NameSpace), strings.ToLower (ClassName), strings.ToLower (method.MethodName)); + parameters = fmt.Sprintf ("%s_%s p%s", NameSpace, ClassName, ClassName); + callParameters = fmt.Sprintf ("p%s", ClassName); + } + + for k := 0; k < len(method.Params); k++ { + param := method.Params [k]; + cParams, err := generateCCPPParameter(param, ClassName, method.MethodName, NameSpace, true); + if (err != nil) { + return err; + } + for _, cParam := range cParams { + if (parameters != "") { + parameters = parameters + ", "; + } + parameters = parameters + cParam.ParamType + " " + cParam.ParamName; + + if (callParameters != "") { + callParameters = callParameters + ", "; + } + callParameters = callParameters + cParam.ParamName; + + } + } + + w.Writeln(""); + w.Writeln("%sResult CCall_%s(%sHandle libraryHandle, %s)", NameSpace, CMethodName, NameSpace, parameters); + w.Writeln("{"); + w.Writeln(" if (libraryHandle == 0) "); + w.Writeln(" return %s_ERROR_INVALIDCAST;", strings.ToUpper(NameSpace)); + w.Writeln(" s%sDynamicWrapperTable * wrapperTable = (s%sDynamicWrapperTable *) libraryHandle;", NameSpace, NameSpace); + + if (isGlobal) { + w.Writeln(" return wrapperTable->m_%s (%s); ", method.MethodName, callParameters); + } else { + w.Writeln(" return wrapperTable->m_%s_%s (%s); ", ClassName, method.MethodName, callParameters); + } + w.Writeln("}"); + w.Writeln(""); + + return nil; +} + + +func writeGoCCall(component ComponentDefinition, method ComponentDefinitionMethod, w LanguageWriter, className string, isGlobal bool) error { + + + err := WriteCGoAbiMethod(method, w, component.NameSpace, className, isGlobal) + if err != nil { + return err + } + + return nil; + +} + + +func writeGoCCalls(component ComponentDefinition, w LanguageWriter) error { + + for _, class := range component.Classes { + + for _, method := range class.Methods { + err := writeGoCCall(component, method, w, class.ClassName, false) + if err != nil { + return err + } + } + + + } + + for _, method := range component.Global.Methods { + err := writeGoCCall(component, method, w, "Wrapper", true) + if err != nil { + return err + } + } + + return nil; + +} + + func buildGoWrapper(component ComponentDefinition, w LanguageWriter) error { packageName := strings.ToLower(component.BaseName) @@ -422,11 +554,48 @@ func buildGoWrapper(component ComponentDefinition, w LanguageWriter) error { w.Writeln("package %s", packageName) w.Writeln("") w.Writeln("/*") - w.Writeln("#include \"%s_abi.h\"", packageName) + w.Writeln("#include \"%s_dynamic.cc\"", packageName) + w.Writeln("") + w.Writeln("%sHandle load%sLibrary (const char * pFileName)", component.NameSpace, component.NameSpace) + w.Writeln("{") + w.Writeln(" %sResult nResult;", component.NameSpace) + w.Writeln(" s%sDynamicWrapperTable * pWrapperTable = (s%sDynamicWrapperTable *) malloc (sizeof (s%sDynamicWrapperTable));", component.NameSpace, component.NameSpace, component.NameSpace) + w.Writeln(" if (pWrapperTable != NULL) {") + w.Writeln(" nResult = Init%sWrapperTable (pWrapperTable);", component.NameSpace) + w.Writeln(" if (nResult != %s_SUCCESS) {", strings.ToUpper (component.NameSpace)) + w.Writeln(" free (pWrapperTable);") + w.Writeln(" return 0;") + w.Writeln(" }") + w.Writeln("") + w.Writeln(" nResult = Load%sWrapperTable (pWrapperTable, pFileName);", component.NameSpace) + w.Writeln(" if (nResult != %s_SUCCESS) {", strings.ToUpper (component.NameSpace)) + w.Writeln(" free (pWrapperTable);") + w.Writeln(" return 0;") + w.Writeln(" }") + w.Writeln("") + w.Writeln(" return (%sHandle) pWrapperTable;", component.NameSpace) + w.Writeln(" }") + w.Writeln("}") + w.Writeln("") + w.Writeln("void unload%sLibrary (%sHandle nLibraryHandle)", component.NameSpace, component.NameSpace) + w.Writeln("{") + w.Writeln(" s%sDynamicWrapperTable * pWrapperTable = (s%sDynamicWrapperTable *) malloc (sizeof (s%sDynamicWrapperTable));", component.NameSpace, component.NameSpace, component.NameSpace) + w.Writeln(" if (pWrapperTable != NULL) {") + w.Writeln(" Release%sWrapperTable (pWrapperTable);", component.NameSpace) + w.Writeln(" free (pWrapperTable);") + w.Writeln(" }") + w.Writeln("}") + w.Writeln("") + err := buildCFuncsForward(component, w) if err != nil { return err } + err = writeGoCCalls (component, w); + if err != nil { + return err + } + w.Writeln("*/") w.Writeln("import \"C\"") w.Writeln("") @@ -451,6 +620,14 @@ func buildGoWrapper(component ComponentDefinition, w LanguageWriter) error { if err != nil { return err } + + w.Writeln("// Wrapper represents the number wrapper") + w.Writeln("type Wrapper struct {") + w.Writeln(" _ [0]func() // uncomparable; to make == not compile") + w.Writeln(" LibraryHandle C.%sHandle", component.NameSpace) + w.Writeln("}") + w.Writeln("") + for _, class := range component.Classes { err = buildGoClass(component, class, w, component.NameSpace, packageName) @@ -468,17 +645,17 @@ func buildGoWrapper(component ComponentDefinition, w LanguageWriter) error { } } - w.Writeln("func releaseC(r *ref) error {") + w.Writeln("func (wrapper * Wrapper) releaseC(r *ref) error {") w.Writeln(" if r == nil || *r == nil {") w.Writeln(" return nil") w.Writeln(" }") - w.Writeln(" return %s(%s{ref: *r})", component.Global.ReleaseMethod, component.Global.BaseClassName) + w.Writeln(" return wrapper.%s(%s{ref: *r})", component.Global.ReleaseMethod, component.Global.BaseClassName) w.Writeln("}") w.Writeln("") - w.Writeln("func CheckBinaryVersion() error {") + w.Writeln("func (wrapper * Wrapper) CheckBinaryVersion() error {") w.Writeln(" var nBindingMajor uint32 = %d;", majorVersion(component.Version)) w.Writeln(" var nBindingMinor uint32 = %d;", minorVersion(component.Version)) - w.Writeln(" nMajor, nMinor, _, err := %s()", component.Global.VersionMethod) + w.Writeln(" nMajor, nMinor, _, err := wrapper.%s()", component.Global.VersionMethod) w.Writeln(" if err != nil {") w.Writeln(" return err;") w.Writeln(" }") @@ -489,6 +666,17 @@ func buildGoWrapper(component ComponentDefinition, w LanguageWriter) error { w.Writeln("}") w.Writeln("") + w.Writeln("func LoadLibrary (libraryPath string) (Wrapper, error) {") + w.Writeln(" var wrapper Wrapper;") + w.Writeln(" wrapper.LibraryHandle = C.load%sLibrary (C.CString (libraryPath));", component.NameSpace) + w.Writeln(" if (wrapper.LibraryHandle == nil) {") + w.Writeln(" return wrapper, makeError (%s_ERROR_COULDNOTLOADLIBRARY)", strings.ToUpper (component.NameSpace)) + w.Writeln(" }") + w.Writeln(" ") + w.Writeln(" return wrapper, nil") + w.Writeln(" ") + w.Writeln("}") + return nil } @@ -740,7 +928,7 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace "}") returnValues = append(returnValues, fmt.Sprintf("_%sPtr", param.ParamName)) } else { - returnValues = append(returnValues, fmt.Sprintf("new%s(%s)", param.ParamClass, param.ParamName)) + returnValues = append(returnValues, fmt.Sprintf("wrapper.new%s(%s)", param.ParamClass, param.ParamName)) } default: return fmt.Errorf("invalid method parameter type \"%s\" for %s.%s (%s)", param.ParamType, className, method.MethodName, param.ParamName) @@ -752,7 +940,7 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace } // Implementation - implmethodname := "C." + packageName + "_" + implmethodname := "C.CCall_" + packageName + "_" returnValues = append(returnValues, "nil") classReturnTypes = append(classReturnTypes, "error") errorReturn = append(errorReturn, "makeError(uint32(ret))") @@ -766,7 +954,7 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace w.Writeln("// %s %s", method.MethodName, endWithDot(lowerFirst(method.MethodDescription))) if isGlobal { - w.Writeln("func %s(%s) %s {", method.MethodName, strings.Join(parameters, ", "), returnString) + w.Writeln("func (wrapper Wrapper) %s(%s) %s {", method.MethodName, strings.Join(parameters, ", "), returnString) } else { w.Writeln("func (inst %s) %s(%s) %s {", className, method.MethodName, strings.Join(parameters, ", "), returnString) } @@ -779,14 +967,24 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace w.Writelns(" ", declarations) retInst := ":" if requiresInitCall { - w.Writeln(" ret := %s(%s)", implmethodname, strings.Join(initCallParameters, ", ")) + if (isGlobal) { + w.Writeln(" ret := %s(wrapper.LibraryHandle, %s)", implmethodname, strings.Join(initCallParameters, ", ")) + } else { + w.Writeln(" ret := %s(inst.wrapperRef.LibraryHandle, %s)", implmethodname, strings.Join(initCallParameters, ", ")) + } + w.Writeln(" if ret != 0 {") w.Writeln(" return %s", strings.Join(errorReturn, ", ")) w.Writeln(" }") w.Writelns(" ", initCallLines) retInst = "" } - w.Writeln(" ret %s= %s(%s)", retInst, implmethodname, strings.Join(callParameters, ", ")) + + if (isGlobal) { + w.Writeln(" ret %s= %s(wrapper.LibraryHandle, %s)", retInst, implmethodname, strings.Join(callParameters, ", ")) + } else { + w.Writeln(" ret %s= %s(inst.wrapperRef.LibraryHandle, %s)", retInst, implmethodname, strings.Join(callParameters, ", ")) + } w.Writeln(" if ret != 0 {") w.Writeln(" return %s", strings.Join(errorReturn, ", "))