From 3a0d0627d1a8bfbdd0f95b43cdd8ade1c18038a8 Mon Sep 17 00:00:00 2001 From: Quim Muntal Diaz Date: Wed, 29 Apr 2020 18:37:23 +0200 Subject: [PATCH 1/7] support structarray --- Source/buildbindinggo.go | 143 +++++++++++++++++++-------------------- 1 file changed, 68 insertions(+), 75 deletions(-) diff --git a/Source/buildbindinggo.go b/Source/buildbindinggo.go index 5dabe5fe..812313b4 100644 --- a/Source/buildbindinggo.go +++ b/Source/buildbindinggo.go @@ -145,7 +145,6 @@ func buildGoExample(component ComponentDefinition, w LanguageWriter, outputFolde w.Writeln("") } - func buildGoEnums(component ComponentDefinition, w LanguageWriter) { if len(component.Enums) <= 0 { return @@ -174,7 +173,7 @@ func buildGoEnums(component ComponentDefinition, w LanguageWriter) { w.Writeln("") } -func buildGoStructs(component ComponentDefinition, w LanguageWriter) (error) { +func buildGoStructs(component ComponentDefinition, w LanguageWriter) error { if len(component.Structs) <= 0 { return nil } @@ -278,7 +277,7 @@ func buildGoImplementation(component ComponentDefinition, implw LanguageWriter) implw.Writeln("") } -func buildGoImplementationHandle(component ComponentDefinition, implw LanguageWriter) { +func buildGoImplementationHandle(component ComponentDefinition, implw LanguageWriter) { NameSpace := component.NameSpace implw.Writeln("type %sImplementationHandle interface {", NameSpace) implw.Writeln(" %sHandle", NameSpace) @@ -465,26 +464,25 @@ func buildGoCallFunction(component ComponentDefinition, implw LanguageWriter) { implw.Writeln("") } - -func buildGoClass(component ComponentDefinition, class ComponentDefinitionClass, w LanguageWriter, implw LanguageWriter, NameSpace string, classdefinitions* []string) (error) { +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)) + *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)) + if component.Global.BaseClassName == class.ClassName { + *classdefinitions = append(*classdefinitions, fmt.Sprintf(" Interface %sGoInterface", NameSpace)) *classdefinitions = append(*classdefinitions, fmt.Sprintf(" Handle %sHandle", NameSpace)) } else { - if len(class.ParentClass)>0 { + if len(class.ParentClass) > 0 { *classdefinitions = append(*classdefinitions, fmt.Sprintf(" %s%s", NameSpace, class.ParentClass)) } else { *classdefinitions = append(*classdefinitions, fmt.Sprintf(" %s%s", NameSpace, component.Global.BaseClassName)) } } - + *classdefinitions = append(*classdefinitions, fmt.Sprintf("}")) *classdefinitions = append(*classdefinitions, fmt.Sprintf("")) *classdefinitions = append(*classdefinitions, fmt.Sprintf("func (instance *%s%s) Close() (error) {", NameSpace, class.ClassName)) @@ -514,7 +512,7 @@ func buildGoWrapper(component ComponentDefinition, w LanguageWriter, implw Langu buildGoEnums(component, w) err := buildGoStructs(component, w) - if (err != nil) { + if err != nil { return err } buildGoInterfaces(component, w) @@ -540,7 +538,7 @@ func buildGoWrapper(component ComponentDefinition, w LanguageWriter, implw Langu 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) @@ -661,18 +659,30 @@ func getGoBasicType(paramType string) (string, error) { 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" + 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" default: return "", errors.New("Invalid basic type: " + paramType) } @@ -682,19 +692,19 @@ func paramFunction(paramType string, paramPass string) (string, error) { } else { paramFunctionStr += "OutValue" } - return paramFunctionStr , nil + return paramFunctionStr, nil } -func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, implw LanguageWriter, NameSpace string, ClassName string, isGlobal bool, classdefinitions* []string) error { +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")) + implDeclarations = append(implDeclarations, fmt.Sprintf("var err error")) var implCasts []string implReturnValues := "" @@ -721,14 +731,8 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, implw Lan 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) + case "basicarray", "structarray": + errorReturn = errorReturn + fmt.Sprint("nil, ") default: return fmt.Errorf("invalid method parameter type \"%s\" for %s.%s(%s)", param.ParamType, ClassName, method.MethodName, param.ParamName) } @@ -769,7 +773,7 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, implw Lan switch param.ParamType { case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64": - goParamName := "n"+param.ParamName + 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) @@ -859,9 +863,9 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, implw Lan implCasts = append(implCasts, fmt.Sprintf("")) implCasts = append(implCasts, fmt.Sprintf("%sDLLHandle := implementation_%s.GetDLLInHandle()", param.ParamName, strings.ToLower(param.ParamName))) - if (param.ParamType == "class") { + 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(" err := fmt.Errorf(\"Handle must not be 0.\")")) implCasts = append(implCasts, fmt.Sprintf(" return %s", errorReturn)) implCasts = append(implCasts, fmt.Sprintf("}")) } @@ -887,7 +891,7 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, implw Lan if err != nil { return err } - goParamName := "n"+param.ParamName + 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) @@ -951,7 +955,7 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, implw Lan 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) implInitCallLines = append(implInitCallLines, fmt.Sprintf("bufferSize%s := neededfor%s", param.ParamName, param.ParamName)) @@ -977,43 +981,34 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, implw Lan 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 + case "basicarray", "structarray": + var arrayType string + if param.ParamType == "basicarray" { + var err error + arrayType, err = getGoBasicType(param.ParamClass) + if err != nil { + return err + } + } else { + arrayType = fmt.Sprintf("s%s%s", NameSpace, param.ParamClass) } - implDeclarations = append(implDeclarations, fmt.Sprintf("var neededfor%s int64 = 0", param.ParamName)) - implDeclarations = append(implDeclarations, fmt.Sprintf("var filledin%s int64 = 0", param.ParamName)) + requiresInitCall = true + needSizeVar := fmt.Sprintf("neededfor%s", param.ParamName) + implDeclarations = append(implDeclarations, fmt.Sprintf("var %s int64", needSizeVar)) 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)) + thisInitImplCallParamter = fmt.Sprintf(", 0, Int64OutValue(&%s), 0", needSizeVar) - thisImplCallParamter = fmt.Sprintf(", Int64InValue(bufferSize%s), Int64OutValue(&filledin%s), uintptr(unsafe.Pointer(&%s[0]))", param.ParamName, param.ParamName, bufferName) + implInitCallLines = append(implInitCallLines, fmt.Sprintf("%s := make([]%s, %s)", bufferName, arrayType, needSizeVar)) + thisImplCallParamter = fmt.Sprintf(", Int64InValue(%s), 0, uintptr(unsafe.Pointer(&%s[0]))", needSizeVar, bufferName) - returnvalues = returnvalues + fmt.Sprintf("[]%s, ", basicType) + returnvalues = returnvalues + fmt.Sprintf("[]%s, ", arrayType) implReturnValues = implReturnValues + fmt.Sprintf("%s, ", bufferName) 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) + classReturnTypes = classReturnTypes + fmt.Sprintf("[]%s, ", arrayType) case "functiontype": returnvalues = returnvalues + fmt.Sprintf("uint64, ") @@ -1021,7 +1016,7 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, implw Lan 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, ") @@ -1061,8 +1056,8 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, implw Lan return fmt.Errorf("invalid method parameter passing \"%s\" for %s.%s (%s)", param.ParamPass, ClassName, method.MethodName, param.ParamName) } - implCallParameters += thisImplCallParamter - implInitCallParameters += thisInitImplCallParamter + implCallParameters += thisImplCallParamter + implInitCallParameters += thisInitImplCallParamter } w.Writeln("") @@ -1084,7 +1079,6 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, implw Lan w.Writeln(" %s_%s(%s%s) (%serror)\n", ClassName, method.MethodName, handleparameter, parameters, returnvalues) } - // Implementation implmethodname := "implementation." + NameSpace + "_" implGetHandleFunction := "" @@ -1093,7 +1087,7 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, implw Lan implGetHandleFunction = fmt.Sprintf(", implementation_%s.GetDLLInHandle()", 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 { @@ -1130,7 +1124,7 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, implw Lan *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(" %s", line)) } *classdefinitions = append(*classdefinitions, fmt.Sprintf(" return %serror", classReturnString)) *classdefinitions = append(*classdefinitions, fmt.Sprintf("}")) @@ -1138,4 +1132,3 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, implw Lan return nil } - From 227917548ee0d93233596215c0fd96a19353bc3d Mon Sep 17 00:00:00 2001 From: Quim Muntal Diaz Date: Wed, 29 Apr 2020 18:40:15 +0200 Subject: [PATCH 2/7] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bc4ce645..f79a5a8e 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/O.png) partial support | Win, Linux, MacOS | in,return | in,out,return | ? | ? | in,out,return | in,out | in,out | - | - | - | | 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 | + | + | From 055d1624219fa6353f71d4925329963c608cc116 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Thu, 7 May 2020 15:54:37 +0200 Subject: [PATCH 3/7] use cgo for go bindings --- Source/buildbindinggo.go | 1357 ++++++++++++++------------------------ Source/languagec.go | 4 + 2 files changed, 499 insertions(+), 862 deletions(-) diff --git a/Source/buildbindinggo.go b/Source/buildbindinggo.go index 812313b4..bb9b8bb6 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,53 +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, 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 { 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 { @@ -202,298 +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)) - + w.Writeln("}") + w.Writeln("") if component.Global.BaseClassName == class.ClassName { - *classdefinitions = append(*classdefinitions, fmt.Sprintf(" Interface %sGoInterface", NameSpace)) - *classdefinitions = append(*classdefinitions, fmt.Sprintf(" Handle %sHandle", NameSpace)) + 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 } @@ -501,634 +415,353 @@ 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) + libName := packageName + if strings.HasPrefix(libName, "lib") { + libName = libName[3:] + } + w.Writeln("") w.Writeln("package %s", packageName) w.Writeln("") + w.Writeln("/*") + w.Writeln("#cgo LDFLAGS: -L./ -l%s", libName) + 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) + 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) { - switch paramType { - case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool": - return paramType, nil - case "single": - return "float32", nil - case "double": - return "float64", nil - case "pointer": - return "uint64", nil - } - return "", errors.New("Invalid basic type: " + paramType) +type goType struct { + Type string + CType string + CToGo string + GoToC string + Empty string } -func paramFunction(paramType string, paramPass string) (string, error) { - paramFunctionStr := "" +func getGoType(paramType, namespace, paramClass, paramName string, isPtr bool) (tp goType, err error) { + var ptrStr string + if isPtr { + ptrStr = "*" + } 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 "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "uintptr": + tp.Type = ptrStr + paramType + tp.CType = fmt.Sprintf("%sC.%s_t", ptrStr, paramType) + tp.CToGo = fmt.Sprintf("(%s%s)(%s)", ptrStr, tp.Type, paramName) + tp.GoToC = fmt.Sprintf("(%s%s)(%s)", ptrStr, tp.CType, paramName) + tp.Empty = "0" case "bool": - paramFunctionStr = "bool" + tp.Type = ptrStr + paramType + tp.CType = fmt.Sprintf("%sC.%s", ptrStr, paramType) + tp.CToGo = fmt.Sprintf("(%s)(%s)", tp.Type, paramName) + tp.GoToC = fmt.Sprintf("(%s)(%s)", tp.CType, paramName) + tp.Empty = "false" case "single": - paramFunctionStr = "Float32" + tp.Type = ptrStr + "float32" + tp.CType = ptrStr + "C.float" + tp.CToGo = fmt.Sprintf("(%s)(%s)", tp.Type, paramName) + tp.GoToC = fmt.Sprintf("(%s)(%s)", tp.CType, paramName) + tp.Empty = "0" case "double": - paramFunctionStr = "Float64" + tp.Type = ptrStr + "float64" + tp.CType = ptrStr + "C.double" + 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": - 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) + 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")) - 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", "structarray": - errorReturn = errorReturn + fmt.Sprint("nil, ") - default: - return fmt.Errorf("invalid method parameter type \"%s\" for %s.%s(%s)", param.ParamType, ClassName, method.MethodName, param.ParamName) - } - } +func lowerFirst(s string) string { + if s == "" { + return "" } - errorReturn = errorReturn + "err" + r, n := utf8.DecodeRuneInString(s) + return string(unicode.ToLower(r)) + s[n:] +} - 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 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 +} - requiresInitCall := false - implCallParameters := "" - implInitCallParameters := "" - var implInitCallLines []string - - var classReturnImplementation []string - classReturnVariables := "" - classReturnString := "" - classReturnTypes := "" - - 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 + ", " - } - - 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) + 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)) } - - 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) - - 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) + 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(", 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) - - 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)) - - thisImplCallParamter = fmt.Sprintf(", Int64InValue(bufferSize%s), Int64OutValue(&filledin%s), uintptr(unsafe.Pointer(&buffer%s[0]))", param.ParamName, param.ParamName, 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)) - implReturnValues = implReturnValues + fmt.Sprintf("string(buffer%s[:(filledin%s-1)]), ", 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)) - returnvalues = returnvalues + fmt.Sprintf("string, ") - classReturnVariables = classReturnVariables + "s" + param.ParamName + ", " - classReturnString = classReturnString + "s" + param.ParamName + ", " - classReturnTypes = classReturnTypes + fmt.Sprintf("string, ") + 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)) - 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) + returnValues = append(returnValues, fmt.Sprintf("string(buffer%s[:(filledin%s-1)])", param.ParamName, param.ParamName)) case "basicarray", "structarray": - var arrayType string - if param.ParamType == "basicarray" { - var err error - arrayType, err = getGoBasicType(param.ParamClass) - if err != nil { - return err - } - } else { - arrayType = fmt.Sprintf("s%s%s", NameSpace, param.ParamClass) - } + parameters = append(parameters, fmt.Sprintf("%s %s", param.ParamName, tp.Type)) + requiresInitCall = true needSizeVar := fmt.Sprintf("neededfor%s", param.ParamName) - implDeclarations = append(implDeclarations, fmt.Sprintf("var %s int64", needSizeVar)) - - bufferName := fmt.Sprintf("buffer%s", param.ParamName) - - thisInitImplCallParamter = fmt.Sprintf(", 0, Int64OutValue(&%s), 0", needSizeVar) - - implInitCallLines = append(implInitCallLines, fmt.Sprintf("%s := make([]%s, %s)", bufferName, arrayType, needSizeVar)) - thisImplCallParamter = fmt.Sprintf(", Int64InValue(%s), 0, uintptr(unsafe.Pointer(&%s[0]))", needSizeVar, bufferName) - - returnvalues = returnvalues + fmt.Sprintf("[]%s, ", arrayType) - implReturnValues = implReturnValues + fmt.Sprintf("%s, ", bufferName) + declarations = append(declarations, fmt.Sprintf("var %s C.uint64_t", needSizeVar)) - classReturnVariables = classReturnVariables + bufferName + ", " - classReturnString = classReturnString + bufferName + ", " - classReturnTypes = classReturnTypes + fmt.Sprintf("[]%s, ", arrayType) + 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)) - 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 } - 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 := "" + // Implementation + implmethodname := "C." + packageName + "_" + returnValues = append(returnValues, "nil") + classReturnTypes = append(classReturnTypes, "error") + errorReturn = append(errorReturn, "makeError(uint32(ret))") + + w.Writeln("// %s %s", method.MethodName, 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, ", "), strings.Join(classReturnTypes, ", ")) } 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, ", "), strings.Join(classReturnTypes, ", ")) } - - // 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) - - implw.Writeln(" if (err != nil) {") - implw.Writeln(" return %s", errorReturn) - implw.Writeln(" }") - implw.Writeln(" ") - implw.Writeln(" return %serr", implReturnValues) - implw.Writeln("}") - implw.Writeln("") + w.Writeln(" ret %s= %s(%s)", retInst, implmethodname, strings.Join(callParameters, ", ")) - 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 91b2afcb2cc9853ccdbe11e01835c1450fb44e32 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Thu, 7 May 2020 16:01:46 +0200 Subject: [PATCH 4/7] ensure comments finish with a dot --- Source/buildbindinggo.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Source/buildbindinggo.go b/Source/buildbindinggo.go index bb9b8bb6..ba5b27b0 100644 --- a/Source/buildbindinggo.go +++ b/Source/buildbindinggo.go @@ -247,7 +247,7 @@ func buildGoFuncs(component ComponentDefinition, w LanguageWriter) error { paramCToGo = append(paramCToGo, tp.CToGo) } w.Writeln("") - w.Writeln("// %sFunc %s.", fn.FunctionName, fn.FunctionDescription) + 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) @@ -607,6 +607,13 @@ func getGoType(paramType, namespace, paramClass, paramName string, isPtr bool) ( return } +func endWithDot(s string) string { + if !strings.HasSuffix(s, ".") { + s += "." + } + return s +} + func lowerFirst(s string) string { if s == "" { return "" @@ -731,7 +738,7 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace classReturnTypes = append(classReturnTypes, "error") errorReturn = append(errorReturn, "makeError(uint32(ret))") - w.Writeln("// %s %s", method.MethodName, lowerFirst(method.MethodDescription)) + w.Writeln("// %s %s", method.MethodName, endWithDot(lowerFirst(method.MethodDescription))) if isGlobal { w.Writeln("func %s(%s) (%s) {", method.MethodName, strings.Join(parameters, ", "), strings.Join(classReturnTypes, ", ")) } else { From 52682482c0c7d5d9516b09e6e3b847645707d81c Mon Sep 17 00:00:00 2001 From: qmuntal Date: Thu, 7 May 2020 16:29:40 +0200 Subject: [PATCH 5/7] update readme go support --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f79a5a8e..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 | ? | ? | in,out,return | in,out | in,out | - | - | - | +| 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 | + | + | From 8f4add26f0741b940bdc3de0d6043c99cf4f1486 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Thu, 7 May 2020 18:09:23 +0200 Subject: [PATCH 6/7] simplify cast and return strings --- Source/buildbindinggo.go | 66 +++++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/Source/buildbindinggo.go b/Source/buildbindinggo.go index ba5b27b0..b2ddf477 100644 --- a/Source/buildbindinggo.go +++ b/Source/buildbindinggo.go @@ -515,27 +515,47 @@ func getGoType(paramType, namespace, paramClass, paramName string, isPtr bool) ( case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "uintptr": tp.Type = ptrStr + paramType tp.CType = fmt.Sprintf("%sC.%s_t", ptrStr, paramType) - tp.CToGo = fmt.Sprintf("(%s%s)(%s)", ptrStr, tp.Type, paramName) - tp.GoToC = fmt.Sprintf("(%s%s)(%s)", ptrStr, tp.CType, paramName) - tp.Empty = "0" + 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) - tp.CToGo = fmt.Sprintf("(%s)(%s)", tp.Type, paramName) - tp.GoToC = fmt.Sprintf("(%s)(%s)", tp.CType, paramName) - tp.Empty = "false" + 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": tp.Type = ptrStr + "float32" tp.CType = ptrStr + "C.float" - tp.CToGo = fmt.Sprintf("(%s)(%s)", tp.Type, paramName) - tp.GoToC = fmt.Sprintf("(%s)(%s)", tp.CType, paramName) - tp.Empty = "0" + 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": tp.Type = ptrStr + "float64" tp.CType = ptrStr + "C.double" - tp.CToGo = fmt.Sprintf("(%s)(%s)", tp.Type, paramName) - tp.GoToC = fmt.Sprintf("(%s)(%s)", tp.CType, paramName) - tp.Empty = "0" + 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" @@ -551,9 +571,14 @@ func getGoType(paramType, namespace, paramClass, paramName string, isPtr bool) ( case "enum": tp.Type = ptrStr + paramClass tp.CType = fmt.Sprintf("%sC.e%s%s", ptrStr, namespace, paramClass) - tp.CToGo = fmt.Sprintf("(%s)(%s)", tp.Type, paramName) - tp.GoToC = fmt.Sprintf("(%s)(%s)", tp.CType, paramName) - tp.Empty = "0" + 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) @@ -738,11 +763,18 @@ func writeGoMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace 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("// %s %s", method.MethodName, endWithDot(lowerFirst(method.MethodDescription))) if isGlobal { - w.Writeln("func %s(%s) (%s) {", method.MethodName, strings.Join(parameters, ", "), strings.Join(classReturnTypes, ", ")) + w.Writeln("func %s(%s) %s {", method.MethodName, strings.Join(parameters, ", "), returnString) } else { - w.Writeln("func (inst %s) %s(%s) (%s) {", className, method.MethodName, strings.Join(parameters, ", "), strings.Join(classReturnTypes, ", ")) + w.Writeln("func (inst %s) %s(%s) %s {", className, method.MethodName, strings.Join(parameters, ", "), returnString) } if !isGlobal { initCallParameters = append([]string{"inst.ref"}, initCallParameters...) From 884f48c9e9b7c7322bcad47427bb99c600b43093 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Fri, 8 May 2020 15:47:52 +0200 Subject: [PATCH 7/7] do not specify LDFLAGS --- Source/buildbindinggo.go | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Source/buildbindinggo.go b/Source/buildbindinggo.go index b2ddf477..7d6c1f29 100644 --- a/Source/buildbindinggo.go +++ b/Source/buildbindinggo.go @@ -418,16 +418,10 @@ func buildGoClass(component ComponentDefinition, class ComponentDefinitionClass, func buildGoWrapper(component ComponentDefinition, w LanguageWriter) error { packageName := strings.ToLower(component.BaseName) - libName := packageName - if strings.HasPrefix(libName, "lib") { - libName = libName[3:] - } - w.Writeln("") w.Writeln("package %s", packageName) w.Writeln("") w.Writeln("/*") - w.Writeln("#cgo LDFLAGS: -L./ -l%s", libName) w.Writeln("#include \"%s_abi.h\"", packageName) err := buildCFuncsForward(component, w) if err != nil { @@ -437,9 +431,9 @@ func buildGoWrapper(component ComponentDefinition, w LanguageWriter) error { w.Writeln("import \"C\"") w.Writeln("") w.Writeln("import (") - w.Writeln(" \"fmt\"") - w.Writeln(" \"unsafe\"") - w.Writeln(" \"runtime\"") + w.Writeln(" \"fmt\"") + w.Writeln(" \"unsafe\"") + w.Writeln(" \"runtime\"") w.Writeln(")") w.Writeln("") w.Writeln("type ref = C.%sHandle", component.NameSpace)