func ProcessFunctionInfo(fi *gi.FunctionInfo, container *gi.BaseInfo) { var fullnm string flags := fi.Flags() name := fi.Name() // --- header fb := NewFunctionBuilder(fi) printf("func ") if flags&gi.FUNCTION_IS_METHOD != 0 { // add receiver if it's a method printf("(this0 %s) ", GoTypeForInterface(container, TypePointer|TypeReceiver)) fullnm = container.Name() + "." } switch { case flags&gi.FUNCTION_IS_CONSTRUCTOR != 0: // special names for constructors name = fmt.Sprintf("New%s%s", container.Name(), CtorSuffix(name)) case flags&gi.FUNCTION_IS_METHOD == 0 && container != nil: name = fmt.Sprintf("%s%s", container.Name(), LowerCaseToCamelCase(name)) default: name = fmt.Sprintf("%s", LowerCaseToCamelCase(name)) } fullnm += name name = Rename(fullnm, name) printf("%s(", name) for i, arg := range fb.Args { printf("%s0 %s", arg.ArgInfo.Name(), GoType(arg.TypeInfo, TypeNone)) if i != len(fb.Args)-1 { printf(", ") } } printf(")") switch len(fb.Rets) { case 0: // do nothing if there are not return values case 1: if flags&gi.FUNCTION_IS_CONSTRUCTOR != 0 { // override return types for constructors, We can't // return generic widget here as C does. Go's type // system is stronger. printf(" %s", GoTypeForInterface(container, TypePointer|TypeReturn)) break } if fb.Rets[0].Index == -2 { printf(" error") } else { printf(" %s", GoType(fb.Rets[0].TypeInfo, TypeReturn)) } default: printf(" (") for i, ret := range fb.Rets { if ret.Index == -2 { // special error type in Go to represent GError printf("error") continue } printf(GoType(ret.TypeInfo, TypeReturn)) if i != len(fb.Rets)-1 { printf(", ") } } printf(")") } printf(" {\n") // --- body stage 1 (Go to C conversions) // var declarations if flags&gi.FUNCTION_IS_METHOD != 0 { printf("\tvar this1 %s\n", CgoTypeForInterface(container, TypePointer)) } for _, arg := range fb.Args { printf("\tvar %s1 %s\n", arg.ArgInfo.Name(), CgoType(arg.TypeInfo, TypeNone)) if al := arg.TypeInfo.ArrayLength(); al != -1 { arg := fb.OrigArgs[al] printf("\tvar %s1 %s\n", arg.Name(), CgoType(arg.Type(), TypeNone)) } } for _, ret := range fb.Rets { if ret.Index == -1 { continue } if ret.Index == -2 { printf("\tvar err1 *C.GError\n") continue } if ret.ArgInfo.Direction() == gi.DIRECTION_INOUT { continue } printf("\tvar %s1 %s\n", ret.ArgInfo.Name(), CgoType(ret.TypeInfo, TypeNone)) if al := ret.TypeInfo.ArrayLength(); al != -1 { arg := fb.OrigArgs[al] printf("\tvar %s1 %s\n", arg.Name(), CgoType(arg.Type(), TypeNone)) } } // conversions if flags&gi.FUNCTION_IS_METHOD != 0 { conv := GoToCgoForInterface(container, "this0", "this1", ConvPointer) printf("%s", PrintLinesWithIndent(conv)) } for _, arg := range fb.Args { nm := arg.ArgInfo.Name() conv := GoToCgo(arg.TypeInfo, nm+"0", nm+"1", ConvNone) printf("%s", PrintLinesWithIndent(conv)) // register callback in the global map if arg.TypeInfo.Tag() == gi.TYPE_TAG_INTERFACE { bi := arg.TypeInfo.Interface() if bi.Type() == gi.INFO_TYPE_CALLBACK { if arg.ArgInfo.Scope() != gi.SCOPE_TYPE_CALL { printf("\t%sHolder.Grab(%s1)\n", Config.Sys.GNS, nm) } } } // array length if len := arg.TypeInfo.ArrayLength(); len != -1 { lenarg := fb.OrigArgs[len] conv = GoToCgo(lenarg.Type(), "len("+nm+"0)", lenarg.Name()+"1", ConvNone) printf("\t%s\n", conv) } } // --- body stage 2 (the function call) printf("\t") if fb.HasReturnValue() { printf("ret1 := ") } userdata, destroy, scope := fb.HasClosureArgument() printf("C.") if scope != gi.SCOPE_TYPE_INVALID { printf("_") } printf("%s(", fi.Symbol()) if flags&gi.FUNCTION_IS_METHOD != 0 { printf("this1") if len(fb.OrigArgs) > 0 { printf(", ") } } for i, ri, n := 0, 0, len(fb.OrigArgs); i < n; i++ { if i == userdata || i == destroy { continue } oarg := fb.OrigArgs[i] var arg string dir := oarg.Direction() if dir == gi.DIRECTION_INOUT || dir == gi.DIRECTION_OUT { arg = fmt.Sprintf("&%s1", oarg.Name()) } else { arg = fmt.Sprintf("%s1", oarg.Name()) } if ri != 0 { printf(", ") } printf("%s", arg) ri++ } if flags&gi.FUNCTION_THROWS != 0 { printf(", &err1") } printf(")\n") // --- body stage 3 (C to Go conversions) // var declarations for _, ret := range fb.Rets { switch ret.Index { case -1: if flags&gi.FUNCTION_IS_CONSTRUCTOR != 0 { printf("\tvar ret2 %s\n", GoTypeForInterface(container, TypePointer|TypeReturn)) } else { printf("\tvar ret2 %s\n", GoType(ret.TypeInfo, TypeReturn)) } case -2: printf("\tvar err2 error\n") default: printf("\tvar %s2 %s\n", ret.ArgInfo.Name(), GoType(ret.TypeInfo, TypeReturn)) } } // conversions for _, ret := range fb.Rets { if ret.Index == -2 { printf("\tif err1 != nil {\n") printf("\t\terr2 = errors.New(C.GoString(((*_GError)(unsafe.Pointer(err1))).message))\n") printf("\t\tC.g_error_free(err1)\n") printf("\t}\n") continue } var nm string if ret.Index == -1 { nm = "ret" } else { nm = ret.ArgInfo.Name() } // array length if len := ret.TypeInfo.ArrayLength(); len != -1 { lenarg := fb.OrigArgs[len] printf("\t%s2 = make(%s, %s)\n", nm, GoType(ret.TypeInfo, TypeReturn), lenarg.Name()+"1") } var ownership gi.Transfer if ret.Index == -1 { ownership = fi.CallerOwns() } else { ownership = ret.ArgInfo.OwnershipTransfer() if ret.ArgInfo.Direction() == gi.DIRECTION_INOUT { // not sure if it's true in all cases, but so far ownership = gi.TRANSFER_NOTHING } } var conv string if flags&gi.FUNCTION_IS_CONSTRUCTOR != 0 && ret.Index == -1 { conv = CgoToGoForInterface(container, "ret1", "ret2", ConvPointer|OwnershipToConvFlags(ownership)) } else { conv = CgoToGo(ret.TypeInfo, nm+"1", nm+"2", OwnershipToConvFlags(ownership)) } printf("%s", PrintLinesWithIndent(conv)) } // --- body stage 4 (return) if len(fb.Rets) == 0 { printf("}\n") return } printf("\treturn ") for i, ret := range fb.Rets { var nm string switch ret.Index { case -1: nm = "ret2" case -2: nm = "err2" default: nm = ret.ArgInfo.Name() + "2" } if i != 0 { printf(", ") } printf(nm) } printf("\n}\n") }
func CFuncForwardDeclaration(fi *gi.FunctionInfo, container *gi.BaseInfo) { symbol := fi.Symbol() if _, declared := declared_c_funcs[symbol]; declared { return } declared_c_funcs[symbol] = true flags := fi.Flags() narg := fi.NumArg() if flags&gi.FUNCTION_THROWS != 0 { narg++ } printf("extern %s %s(", CType(fi.ReturnType(), TypeNone), symbol) if flags&gi.FUNCTION_IS_METHOD != 0 { printf("%s", CTypeForInterface(container, TypePointer)) if narg > 0 { printf(", ") } } var closure_scope gi.ScopeType = gi.SCOPE_TYPE_INVALID var closure_userdata int = -1 var closure_destroy int = -1 var closure_callback int = -1 for i, n := 0, narg; i < n; i++ { if i != 0 { printf(", ") } if i == n-1 && flags&gi.FUNCTION_THROWS != 0 { printf("GError**") continue } arg := fi.Arg(i) t := arg.Type() if uarg := arg.Closure(); uarg != -1 { if t.Tag() == gi.TYPE_TAG_INTERFACE { if t.Interface().Type() == gi.INFO_TYPE_CALLBACK { if darg := arg.Destroy(); darg != -1 { closure_destroy = darg } closure_userdata = uarg closure_callback = i closure_scope = arg.Scope() } } } printf("%s", CType(t, TypeNone)) switch arg.Direction() { case gi.DIRECTION_INOUT, gi.DIRECTION_OUT: printf("*") } } printf(");\n") if closure_scope == gi.SCOPE_TYPE_INVALID { return } // in case if the function takes callback, generate appropriate wrappers // for Go (gc compiler mainly) printf("#pragma GCC diagnostic ignored \"-Wunused-function\"\n") printf("static %s _%s(", CType(fi.ReturnType(), TypeNone), symbol) if flags&gi.FUNCTION_IS_METHOD != 0 { printf("%s this", CTypeForInterface(container, TypePointer)) if narg > 0 { printf(", ") } } for i, n := 0, narg; i < n; i++ { if i == closure_userdata || i == closure_destroy { // skip userdata and destroy func in the wrapper continue } if i != 0 { printf(", ") } if i == closure_callback { // replace callback argument with Go function pointer // and optional unique id (if scope is not CALL) printf("void* gofunc") continue } if i == n-1 && flags&gi.FUNCTION_THROWS != 0 { printf("GError** arg%d", i) continue } arg := fi.Arg(i) printf("%s", CType(arg.Type(), TypeNone)) switch arg.Direction() { case gi.DIRECTION_INOUT, gi.DIRECTION_OUT: printf("*") } printf(" arg%d", i) } printf(") {\n") // body defcall := func(argprint func(i int, t *gi.TypeInfo)) { printf("\t\t") if ret := fi.ReturnType(); !(ret.Tag() == gi.TYPE_TAG_VOID && !ret.IsPointer()) { printf("return ") } printf("%s(", symbol) if flags&gi.FUNCTION_IS_METHOD != 0 { printf("this") if narg > 0 { printf(", ") } } for i, n := 0, narg; i < n; i++ { arg := fi.Arg(i) t := arg.Type() if i != 0 { printf(", ") } argprint(i, t) } printf(");\n") } printf("\tif (gofunc) {\n") defcall(func(i int, t *gi.TypeInfo) { switch i { case closure_userdata: printf("gofunc") case closure_destroy: printf("_c_callback_cleanup") case closure_callback: printf("_%s_c_wrapper", CType(t, TypeNone)) if closure_scope == gi.SCOPE_TYPE_ASYNC { printf("_once") } default: printf("arg%d", i) } }) printf("\t} else {\n") defcall(func(i int, t *gi.TypeInfo) { switch i { case closure_userdata, closure_destroy, closure_callback: printf("0") default: printf("arg%d", i) } }) printf("\t}\n") printf("}\n") }
func (this *binding_generator) c_func_forward_declaration(fi *gi.FunctionInfo) { symbol := fi.Symbol() if _, declared := this.declared_c_funcs[symbol]; declared { return } this.declared_c_funcs[symbol] = true container := fi.Container() ph := printer_to(this.out_h) pc := printer_to(this.out_c) flags := fi.Flags() narg := fi.NumArg() if flags&gi.FUNCTION_THROWS != 0 { narg++ } ph("extern %s %s(", c_type(fi.ReturnType(), type_none), symbol) if flags&gi.FUNCTION_IS_METHOD != 0 { ph("%s", c_type_for_interface(container, type_pointer)) if narg > 0 { ph(", ") } } var closure_scope gi.ScopeType = gi.SCOPE_TYPE_INVALID var closure_userdata int = -1 var closure_destroy int = -1 var closure_callback int = -1 for i, n := 0, narg; i < n; i++ { if i != 0 { ph(", ") } if i == n-1 && flags&gi.FUNCTION_THROWS != 0 { ph("GError**") continue } arg := fi.Arg(i) t := arg.Type() if uarg := arg.Closure(); uarg != -1 { if t.Tag() == gi.TYPE_TAG_INTERFACE { if t.Interface().Type() == gi.INFO_TYPE_CALLBACK { if darg := arg.Destroy(); darg != -1 { closure_destroy = darg } closure_userdata = uarg closure_callback = i closure_scope = arg.Scope() } } } ph("%s", c_type(t, type_none)) switch arg.Direction() { case gi.DIRECTION_INOUT, gi.DIRECTION_OUT: ph("*") } } ph(");\n") if closure_scope == gi.SCOPE_TYPE_INVALID { return } // Also if this function is actually blacklisted, we don't want to // generate wrappers if config.is_object_blacklisted(gi.ToBaseInfo(fi)) { return } // Or maybe this is a method and method's owner is blacklisted if container != nil && config.is_object_blacklisted(container) { return } // in case if the function takes callback, generate appropriate wrappers // for Go (gc compiler mainly) var tmp bytes.Buffer p := printer_to(&tmp) p("%s _%s(", c_type(fi.ReturnType(), type_none), symbol) if flags&gi.FUNCTION_IS_METHOD != 0 { p("%s this", c_type_for_interface(container, type_pointer)) if narg > 0 { p(", ") } } for i, n := 0, narg; i < n; i++ { if i == closure_userdata || i == closure_destroy { // skip userdata and destroy func in the wrapper continue } if i != 0 { p(", ") } if i == closure_callback { // replace callback argument with Go function pointer // and optional unique id (if scope is not CALL) p("void* gofunc") continue } if i == n-1 && flags&gi.FUNCTION_THROWS != 0 { p("GError** arg%d", i) continue } arg := fi.Arg(i) p("%s", c_type(arg.Type(), type_none)) switch arg.Direction() { case gi.DIRECTION_INOUT, gi.DIRECTION_OUT: p("*") } p(" arg%d", i) } p(")") ph("extern %s;\n", tmp.String()) pc("%s {\n", tmp.String()) // body defcall := func(argprint func(i int, t *gi.TypeInfo)) { pc("\t\t") if ret := fi.ReturnType(); !(ret.Tag() == gi.TYPE_TAG_VOID && !ret.IsPointer()) { pc("return ") } pc("%s(", symbol) if flags&gi.FUNCTION_IS_METHOD != 0 { pc("this") if narg > 0 { pc(", ") } } for i, n := 0, narg; i < n; i++ { arg := fi.Arg(i) t := arg.Type() if i != 0 { pc(", ") } argprint(i, t) } pc(");\n") } pc("\tif (gofunc) {\n") defcall(func(i int, t *gi.TypeInfo) { switch i { case closure_userdata: pc("gofunc") case closure_destroy: pc("_c_callback_cleanup") case closure_callback: pc("_%s_c_wrapper", c_type(t, type_none)) if closure_scope == gi.SCOPE_TYPE_ASYNC { pc("_once") } default: pc("arg%d", i) } }) pc("\t} else {\n") defcall(func(i int, t *gi.TypeInfo) { switch i { case closure_userdata, closure_destroy, closure_callback: pc("0") default: pc("arg%d", i) } }) pc("\t}\n") pc("}\n") }
func NewFunctionBuilder(fi *gi.FunctionInfo) *FunctionBuilder { fb := new(FunctionBuilder) fb.Function = fi // prepare an array of ArgInfos for i, n := 0, fi.NumArg(); i < n; i++ { arg := fi.Arg(i) fb.OrigArgs = append(fb.OrigArgs, arg) } // build skip list var skiplist []int for _, arg := range fb.OrigArgs { ti := arg.Type() len := ti.ArrayLength() if len != -1 { skiplist = append(skiplist, len) } clo := arg.Closure() if clo != -1 { skiplist = append(skiplist, clo) } des := arg.Destroy() if des != -1 { skiplist = append(skiplist, des) } } // then walk over arguments for i, ai := range fb.OrigArgs { if IntSliceContains(skiplist, i) { continue } ti := ai.Type() switch ai.Direction() { case gi.DIRECTION_IN: fb.Args = append(fb.Args, FunctionBuilderArg{i, ai, ti}) case gi.DIRECTION_INOUT: fb.Args = append(fb.Args, FunctionBuilderArg{i, ai, ti}) fb.Rets = append(fb.Rets, FunctionBuilderArg{i, ai, ti}) case gi.DIRECTION_OUT: fb.Rets = append(fb.Rets, FunctionBuilderArg{i, ai, ti}) } } // add return value if it exists to 'rets' if ret := fi.ReturnType(); ret != nil && ret.Tag() != gi.TYPE_TAG_VOID { fb.Rets = append(fb.Rets, FunctionBuilderArg{-1, nil, ret}) } // add GError special argument (if any) if fi.Flags()&gi.FUNCTION_THROWS != 0 { fb.Rets = append(fb.Rets, FunctionBuilderArg{-2, nil, nil}) } return fb }
func (this *binding_generator) process_function_info(fi *gi.FunctionInfo) { p := printer_to(&this.go_bindings) var fullnm string flags := fi.Flags() name := fi.Name() container := fi.Container() // --- header fb := new_function_builder(fi) p("func ") if flags&gi.FUNCTION_IS_METHOD != 0 { // add receiver if it's a method p("(this0 %s) ", go_type_for_interface(container, type_pointer|type_receiver)) fullnm = container.Name() + "." } switch { case flags&gi.FUNCTION_IS_CONSTRUCTOR != 0: // special names for constructors name = fmt.Sprintf("New%s%s", container.Name(), ctor_suffix(name)) case flags&gi.FUNCTION_IS_METHOD == 0 && container != nil: name = fmt.Sprintf("%s%s", container.Name(), lower_case_to_camel_case(name)) default: name = fmt.Sprintf("%s", lower_case_to_camel_case(name)) } fullnm += name name = config.rename(fullnm, name) p("%s(", name) for i, arg := range fb.args { if i != 0 { p(", ") } p("%s0 %s", arg.arg_info.Name(), go_type(arg.type_info, type_none)) } p(")") switch len(fb.rets) { case 0: // do nothing if there are not return values case 1: if flags&gi.FUNCTION_IS_CONSTRUCTOR != 0 { // override return types for constructors, We can't // return generic widget here as C does. Go's type // system is stronger. p(" %s", go_type_for_interface(container, type_pointer|type_return)) break } if fb.rets[0].index == -2 { p(" error") } else { p(" %s", go_type(fb.rets[0].type_info, type_return)) } default: p(" (") for i, ret := range fb.rets { if ret.index == -2 { // special error type in Go to represent GError p("error") continue } p(go_type(ret.type_info, type_return)) if i != len(fb.rets)-1 { p(", ") } } p(")") } p(" {\n") // --- body stage 1 (Go to C conversions) // var declarations if flags&gi.FUNCTION_IS_METHOD != 0 { p("\tvar this1 %s\n", cgo_type_for_interface(container, type_pointer)) } for _, arg := range fb.args { p("\tvar %s1 %s\n", arg.arg_info.Name(), cgo_type(arg.type_info, type_none)) if al := arg.type_info.ArrayLength(); al != -1 { arg := fb.orig_args[al] p("\tvar %s1 %s\n", arg.Name(), cgo_type(arg.Type(), type_none)) } } for _, ret := range fb.rets { if ret.index == -1 { continue } if ret.index == -2 { p("\tvar err1 *C.GError\n") continue } if ret.arg_info.Direction() == gi.DIRECTION_INOUT { continue } p("\tvar %s1 %s\n", ret.arg_info.Name(), cgo_type(ret.type_info, type_none)) if al := ret.type_info.ArrayLength(); al != -1 { arg := fb.orig_args[al] p("\tvar %s1 %s\n", arg.Name(), cgo_type(arg.Type(), type_none)) } } // conversions if flags&gi.FUNCTION_IS_METHOD != 0 { conv := go_to_cgo_for_interface(container, "this0", "this1", conv_pointer) p("%s", print_lines_with_indent(conv)) } for _, arg := range fb.args { nm := arg.arg_info.Name() conv := go_to_cgo(arg.type_info, nm+"0", nm+"1", conv_none) p("%s", print_lines_with_indent(conv)) // register callback in the global map if arg.type_info.Tag() == gi.TYPE_TAG_INTERFACE { bi := arg.type_info.Interface() if bi.Type() == gi.INFO_TYPE_CALLBACK { if arg.arg_info.Scope() != gi.SCOPE_TYPE_CALL { p("\t%sHolder.Grab(%s1)\n", config.gns, nm) } } } // array length if len := arg.type_info.ArrayLength(); len != -1 { lenarg := fb.orig_args[len] conv = go_to_cgo(lenarg.Type(), "len("+nm+"0)", lenarg.Name()+"1", conv_none) p("\t%s\n", conv) } } // --- body stage 2 (the function call) p("\t") if fb.has_return_value() { p("ret1 := ") } userdata, destroy, scope := fb.has_closure_argument() p("C.") if scope != gi.SCOPE_TYPE_INVALID { p("_") } p("%s(", fi.Symbol()) if flags&gi.FUNCTION_IS_METHOD != 0 { p("this1") if len(fb.orig_args) > 0 { p(", ") } } for i, ri, n := 0, 0, len(fb.orig_args); i < n; i++ { if i == userdata || i == destroy { continue } oarg := fb.orig_args[i] var arg string dir := oarg.Direction() if dir == gi.DIRECTION_INOUT || dir == gi.DIRECTION_OUT { arg = fmt.Sprintf("&%s1", oarg.Name()) } else { arg = fmt.Sprintf("%s1", oarg.Name()) } if ri != 0 { p(", ") } p("%s", arg) ri++ } if flags&gi.FUNCTION_THROWS != 0 { p(", &err1") } p(")\n") // --- body stage 3 (C to Go conversions) // var declarations for _, ret := range fb.rets { switch ret.index { case -1: if flags&gi.FUNCTION_IS_CONSTRUCTOR != 0 { p("\tvar ret2 %s\n", go_type_for_interface(container, type_pointer|type_return)) } else { p("\tvar ret2 %s\n", go_type(ret.type_info, type_return)) } case -2: p("\tvar err2 error\n") default: p("\tvar %s2 %s\n", ret.arg_info.Name(), go_type(ret.type_info, type_return)) } } // conversions for _, ret := range fb.rets { if ret.index == -2 { p("\tif err1 != nil {\n") p("\t\terr2 = errors.New(C.GoString(((*_GError)(unsafe.Pointer(err1))).message))\n") p("\t\tC.g_error_free(err1)\n") p("\t}\n") continue } var nm string if ret.index == -1 { nm = "ret" } else { nm = ret.arg_info.Name() } // array length if len := ret.type_info.ArrayLength(); len != -1 { lenarg := fb.orig_args[len] p("\t%s2 = make(%s, %s)\n", nm, go_type(ret.type_info, type_return), lenarg.Name()+"1") } var ownership gi.Transfer if ret.index == -1 { ownership = fi.CallerOwns() } else { ownership = ret.arg_info.OwnershipTransfer() if ret.arg_info.Direction() == gi.DIRECTION_INOUT { // not sure if it's true in all cases, but so far ownership = gi.TRANSFER_NOTHING } } var conv string if flags&gi.FUNCTION_IS_CONSTRUCTOR != 0 && ret.index == -1 { conv = cgo_to_go_for_interface(container, "ret1", "ret2", conv_pointer|ownership_to_conv_flags(ownership)) } else { conv = cgo_to_go(ret.type_info, nm+"1", nm+"2", ownership_to_conv_flags(ownership)) } p("%s", print_lines_with_indent(conv)) } // --- body stage 4 (return) if len(fb.rets) == 0 { p("}\n") return } p("\treturn ") for i, ret := range fb.rets { var nm string switch ret.index { case -1: nm = "ret2" case -2: nm = "err2" default: nm = ret.arg_info.Name() + "2" } if i != 0 { p(", ") } p(nm) } p("\n}\n") }