func ProcessObjectInfo(oi *gi.ObjectInfo) { parent := "C unsafe.Pointer" parentlike := "" if p := oi.Parent(); p != nil { parent = "" if ns := p.Namespace(); ns != Config.Namespace { parent += strings.ToLower(ns) + "." } parent += p.Name() parentlike = parent + "Like" } // interface that this class and its subclasses implement cprefix := gi.DefaultRepository().CPrefix(Config.Namespace) name := oi.Name() cgotype := CgoTypeForInterface(gi.ToBaseInfo(oi), TypePointer) var interfaces bytes.Buffer for i, n := 0, oi.NumInterface(); i < n; i++ { ii := oi.Interface(i) name := ii.Name() ns := ii.Namespace() if i != 0 { interfaces.WriteString("\n\t") } if ns != Config.Namespace { fmt.Fprintf(&interfaces, "%s.", strings.ToLower(ns)) } fmt.Fprintf(&interfaces, "%sImpl", name) } printf("%s\n", ExecuteTemplate(ObjectTemplate, map[string]string{ "name": name, "cprefix": cprefix, "cgotype": cgotype, "parent": parent, "parentlike": parentlike, "typeinit": oi.TypeInit(), "gobjectns": Config.Sys.GNS, "interfaces": interfaces.String(), })) for i, n := 0, oi.NumMethod(); i < n; i++ { meth := oi.Method(i) if IsMethodBlacklisted(name, meth.Name()) { printf("// blacklisted: %s.%s (method)\n", name, meth.Name()) continue } ProcessFunctionInfo(meth, gi.ToBaseInfo(oi)) } }
func (this *binding_generator) process_object_info(oi *gi.ObjectInfo) { p := printer_to(&this.go_bindings) parent := "C unsafe.Pointer" parentlike := "" if p := oi.Parent(); p != nil { parent = "" if ns := p.Namespace(); ns != config.namespace { parent += strings.ToLower(ns) + "." } parent += p.Name() parentlike = parent + "Like" } // interface that this class and its subclasses implement cprefix := gi.DefaultRepository().CPrefix(config.namespace) name := oi.Name() cgotype := cgo_type_for_interface(gi.ToBaseInfo(oi), type_pointer) var interfaces bytes.Buffer pi := printer_to(&interfaces) for i, n := 0, oi.NumInterface(); i < n; i++ { ii := oi.Interface(i) name := ii.Name() ns := ii.Namespace() if i != 0 { pi("\n\t") } if ns != config.namespace { pi("%s.", strings.ToLower(ns)) } pi("%sImpl", name) } p("%s\n", execute_template(object_template, map[string]string{ "name": name, "cprefix": cprefix, "cgotype": cgotype, "parent": parent, "parentlike": parentlike, "typeinit": oi.TypeInit(), "gobjectns": config.gns, "interfaces": interfaces.String(), })) for i, n := 0, oi.NumMethod(); i < n; i++ { meth := oi.Method(i) if config.is_method_blacklisted(name, meth.Name()) { p("// blacklisted: %s.%s (method)\n", name, meth.Name()) continue } this.process_function_info(meth) } }
func ProcessInterfaceInfo(ii *gi.InterfaceInfo) { name := ii.Name() cprefix := gi.DefaultRepository().CPrefix(ii.Namespace()) cgotype := CgoTypeForInterface(gi.ToBaseInfo(ii), TypePointer) printf("%s\n", ExecuteTemplate(InterfaceTemplate, map[string]string{ "name": name, "cprefix": cprefix, "cgotype": cgotype, "typeinit": ii.TypeInit(), "gobjectns": Config.Sys.GNS, })) for i, n := 0, ii.NumMethod(); i < n; i++ { meth := ii.Method(i) if IsMethodBlacklisted(name, meth.Name()) { printf("// blacklisted: %s.%s (method)\n", name, meth.Name()) continue } ProcessFunctionInfo(meth, gi.ToBaseInfo(ii)) } }
func ProcessUnionInfo(ui *gi.UnionInfo) { name := ui.Name() printf("type %s struct {\n", name) printf("\t_data [%d]byte\n", ui.Size()) printf("}\n") for i, n := 0, ui.NumMethod(); i < n; i++ { meth := ui.Method(i) if IsMethodBlacklisted(name, meth.Name()) { continue } ProcessFunctionInfo(meth, gi.ToBaseInfo(ui)) } }
func (this *binding_generator) process_interface_info(ii *gi.InterfaceInfo) { p := printer_to(&this.go_bindings) name := ii.Name() cprefix := gi.DefaultRepository().CPrefix(ii.Namespace()) cgotype := cgo_type_for_interface(gi.ToBaseInfo(ii), type_pointer) p("%s\n", execute_template(interface_template, map[string]string{ "name": name, "cprefix": cprefix, "cgotype": cgotype, "typeinit": ii.TypeInit(), "gobjectns": config.gns, })) for i, n := 0, ii.NumMethod(); i < n; i++ { meth := ii.Method(i) if config.is_method_blacklisted(name, meth.Name()) { p("// blacklisted: %s.%s (method)\n", name, meth.Name()) continue } this.process_function_info(meth) } }
func ProcessCallbackInfo(ci *gi.CallableInfo) { // list of args var args []*gi.ArgInfo for i, n := 0, ci.NumArg(); i < n; i++ { arg := ci.Arg(i) args = append(args, arg) } userdata := -1 for i, arg := range args { if arg.Closure() != -1 { userdata = i break } // treat any void* as userdata O_o t := arg.Type() if t.Tag() == gi.TYPE_TAG_VOID && t.IsPointer() { userdata = i break } } if userdata == -1 { printf("// blacklisted (no userdata): ") } name := ci.Name() printf("type %s func(", name) for i, ri, n := 0, 0, len(args); i < n; i++ { if i == userdata { continue } // I use here TypeReturn because for closures it's inverted // C code calls closure and it has to be concrete and Go code // returns stuff to C (like calling a C function) arg := args[i] if ri != 0 { printf(", ") } printf("%s %s", arg.Name(), GoType(arg.Type(), TypeReturn)) ri++ } rt := ci.ReturnType() if !rt.IsPointer() && rt.Tag() == gi.TYPE_TAG_VOID { printf(")\n") } else { printf(") %s\n", GoType(rt, TypeNone)) } if userdata == -1 { return } // now we need to generate two wrappers, it's a bit tricky due to cgo // ugliness. // 1. Function signature should consist of basic types and unsafe.Pointer // for any pointer type, cgo cannot export other kinds of functions. // 2. Convert these types to C.* ones. // 3. Convert C.* types to Go values. // 4. Call Go callback (function pointer is in the userdata). // 5. Convert all returned Go values to C.* types and then to basic cgo // friendly types. // signature ctype := CTypeForInterface(gi.ToBaseInfo(ci), TypeNone) printf("//export _%s_c_wrapper\n", ctype) printf("func _%s_c_wrapper(", ctype) for i, arg := range args { if i != 0 { printf(", ") } printf("%s0 %s", arg.Name(), SimpleCgoType(arg.Type(), TypeNone)) } printf(") ") if ret := ci.ReturnType(); ret != nil && ret.Tag() != gi.TYPE_TAG_VOID { printf("%s ", SimpleCgoType(ret, TypeNone)) } printf("{\n") // --- body stage 1 (C to Go conversions) // var declarations for i, arg := range args { gotype := GoType(arg.Type(), TypeReturn) if i == userdata { gotype = name } printf("\tvar %s1 %s\n", arg.Name(), gotype) } // conversions for i, arg := range args { t := arg.Type() aname := arg.Name() if i == userdata { printf("\t%s1 = *(*%s)(%s0)\n", aname, name, aname) continue } ownership := OwnershipToConvFlags(arg.OwnershipTransfer()) conv := SimpleCgoToGo(t, aname+"0", aname+"1", ownership) printf("%s", PrintLinesWithIndent(conv)) } // --- body stage 2 (the callback call) printf("\t") if ret := ci.ReturnType(); ret != nil && ret.Tag() != gi.TYPE_TAG_VOID { printf("ret1 := ") } printf("%s1(", args[userdata].Name()) for i, ri, n := 0, 0, len(args); i < n; i++ { if i == userdata { continue } if ri != 0 { printf(", ") } printf("%s1", args[i].Name()) ri++ } printf(")\n") // --- body stage 3 (return value) if ret := ci.ReturnType(); ret != nil && ret.Tag() != gi.TYPE_TAG_VOID { printf("\tvar ret2 %s\n", CgoType(ret, TypeNone)) ownership := OwnershipToConvFlags(ci.CallerOwns()) conv := GoToCgo(ret, "ret1", "ret2", ownership) printf("%s", PrintLinesWithIndent(conv)) printf("\treturn (%s)(ret2)\n", SimpleCgoType(ret, TypeNone)) } printf("}\n") // and finally add "_once" wrapper printf("//export _%s_c_wrapper_once\n", ctype) printf("func _%s_c_wrapper_once(", ctype) for i, arg := range args { if i != 0 { printf(", ") } printf("%s0 %s", arg.Name(), SimpleCgoType(arg.Type(), TypeNone)) } printf(") ") if ret := ci.ReturnType(); ret != nil && ret.Tag() != gi.TYPE_TAG_VOID { printf("%s ", SimpleCgoType(ret, TypeNone)) } printf("{\n\t") if ret := ci.ReturnType(); ret != nil && ret.Tag() != gi.TYPE_TAG_VOID { printf("ret := ") } printf("_%s_c_wrapper(", ctype) for i, arg := range args { if i != 0 { printf(", ") } printf("%s0", arg.Name()) } printf(")\n") printf("\t%sHolder.Release(%s0)\n", Config.Sys.GNS, args[userdata].Name()) if ret := ci.ReturnType(); ret != nil && ret.Tag() != gi.TYPE_TAG_VOID { printf("\treturn ret\n") } printf("}\n") }
func ProcessStructInfo(si *gi.StructInfo) { name := si.Name() size := si.Size() if si.IsGTypeStruct() { return } if strings.HasSuffix(name, "Private") { return } fullnm := strings.ToLower(si.Namespace()) + "." + name if _, ok := GConfig.Sys.DisguisedTypes[fullnm]; ok { size = -1 } if !IsBlacklisted("structdefs", name) { switch size { case -1: printf("type %s struct { Pointer unsafe.Pointer }\n", name) case 0: printf("type %s struct {}\n", name) default: printf("type %s struct {\n", name) offset := 0 for i, n := 0, si.NumField(); i < n; i++ { field := si.Field(i) fo := field.Offset() ft := field.Type() nm := field.Name() if fo != offset { pad := fo - offset printf("\t_ [%d]byte\n", pad) offset += pad } if TypeNeedsWrapper(ft) { printf("\t%s0 %s\n", nm, CgoType(ft, TypeExact)) } else { printf("\t%s %s\n", LowerCaseToCamelCase(nm), GoType(ft, TypeExact)) } offset += TypeSize(ft, TypeExact) } if size != offset { printf("\t_ [%d]byte\n", size-offset) } printf("}\n") //printf("type %s struct { data [%d]byte }\n", name, size) } // for each field that needs a wrapper, generate it for i, n := 0, si.NumField(); i < n; i++ { field := si.Field(i) ft := field.Type() nm := field.Name() if !TypeNeedsWrapper(ft) { continue } gotype := GoType(ft, TypeReturn) printf("func (this0 *%s) %s() %s {\n", name, LowerCaseToCamelCase(nm), gotype) printf("\tvar %s1 %s\n", nm, gotype) conv := CgoToGo(ft, "this0."+nm+"0", nm+"1", ConvOwnNone) printf("%s", PrintLinesWithIndent(conv)) printf("\treturn %s1\n", nm) printf("}\n") } } for i, n := 0, si.NumMethod(); i < n; i++ { meth := si.Method(i) if IsMethodBlacklisted(name, meth.Name()) { continue } ProcessFunctionInfo(meth, gi.ToBaseInfo(si)) } }
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") }