Ejemplo n.º 1
0
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")
}
Ejemplo n.º 2
0
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")
}
Ejemplo n.º 3
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")
}
Ejemplo n.º 4
0
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
}
Ejemplo n.º 5
0
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")
}