Пример #1
0
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))
	}
}
Пример #2
0
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)
	}
}
Пример #3
0
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))
	}
}
Пример #4
0
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))
	}
}
Пример #5
0
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)
	}
}
Пример #6
0
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")
}
Пример #7
0
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))
	}
}
Пример #8
0
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")
}