// Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package bind import ( "fmt" "go/types" "strings" ) type goGen struct { *generator } const ( goPreamble = `// Package gomobile_bind is an autogenerated binder stub for package %[1]s. // gobind -lang=go %[2]s // // File is generated by gobind. Do not edit. package gomobile_bind /* #include #include #include "seq.h" #include "%[1]s.h" */ import "C" import ( _seq "golang.org/x/mobile/bind/seq" %[2]q ) // suppress the error if seq ends up unused var _ = _seq.FromRefNum ` ) func (g *goGen) genFuncBody(o *types.Func, selectorLHS string) { sig := o.Type().(*types.Signature) params := sig.Params() for i := 0; i < params.Len(); i++ { p := params.At(i) pn := "param_" + paramName(params, i) g.genRead("_"+pn, pn, p.Type(), modeTransient) } res := sig.Results() if res.Len() > 2 || res.Len() == 2 && !isErrorType(res.At(1).Type()) { g.errorf("functions and methods must return either zero or one values, and optionally an error") return } if res.Len() > 0 { for i := 0; i < res.Len(); i++ { if i > 0 { g.Printf(", ") } g.Printf("res_%d", i) } g.Printf(" := ") } g.Printf("%s.%s(", selectorLHS, o.Name()) for i := 0; i < params.Len(); i++ { if i > 0 { g.Printf(", ") } g.Printf("_param_%s", paramName(params, i)) } g.Printf(")\n") for i := 0; i < res.Len(); i++ { pn := fmt.Sprintf("res_%d", i) g.genWrite("_"+pn, pn, res.At(i).Type(), modeReturned) } if res.Len() > 0 { g.Printf("return ") for i := 0; i < res.Len(); i++ { if i > 0 { g.Printf(", ") } g.Printf("_res_%d", i) } g.Printf("\n") } } func (g *goGen) genWrite(toVar, fromVar string, t types.Type, mode varMode) { if isErrorType(t) { g.Printf("var %s_str string\n", toVar) g.Printf("if %s == nil {\n", fromVar) g.Printf(" %s_str = \"\"\n", toVar) g.Printf("} else {\n") g.Printf(" %s_str = %s.Error()\n", toVar, fromVar) g.Printf("}\n") g.genWrite(toVar, toVar+"_str", types.Typ[types.String], mode) return } switch t := t.(type) { case *types.Basic: switch t.Kind() { case types.String: g.Printf("%s := encodeString(%s, %v)\n", toVar, fromVar, mode.copyString()) case types.Bool: g.Printf("var %s C.%s = 0\n", toVar, g.cgoType(t)) g.Printf("if %s { %s = 1 }\n", fromVar, toVar) default: g.Printf("%s := C.%s(%s)\n", toVar, g.cgoType(t), fromVar) } case *types.Slice: switch e := t.Elem().(type) { case *types.Basic: switch e.Kind() { case types.Uint8: // Byte. g.Printf("%s := fromSlice(%s, %v)\n", toVar, fromVar, mode.copySlice()) default: g.errorf("unsupported type: %s", t) } default: g.errorf("unsupported type: %s", t) } case *types.Pointer: // TODO(crawshaw): test *int // TODO(crawshaw): test **Generator switch t := t.Elem().(type) { case *types.Named: obj := t.Obj() if obj.Pkg() != g.pkg { g.errorf("type %s not defined in %s", t, g.pkg) return } g.genToRefNum(toVar, fromVar) default: g.errorf("unsupported type %s", t) } case *types.Named: switch u := t.Underlying().(type) { case *types.Interface, *types.Pointer: g.genToRefNum(toVar, fromVar) default: g.errorf("unsupported, direct named type %s: %s", t, u) } default: g.errorf("unsupported type %s", t) } } // genToRefNum generates Go code for converting a variable to its refnum. // Note that the nil-check cannot be lifted into seq.ToRefNum, because a nil // struct pointer does not convert to a nil interface. func (g *goGen) genToRefNum(toVar, fromVar string) { g.Printf("var %s C.int32_t = _seq.NullRefNum\n", toVar) g.Printf("if %s != nil {\n", fromVar) g.Printf(" %s = C.int32_t(_seq.ToRefNum(%s))\n", toVar, fromVar) g.Printf("}\n") } func (g *goGen) genFuncSignature(o *types.Func, objName string) { g.Printf("//export proxy%s_%s_%s\n", g.pkgPrefix, objName, o.Name()) g.Printf("func proxy%s_%s_%s(", g.pkgPrefix, objName, o.Name()) if objName != "" { g.Printf("refnum C.int32_t") } sig := o.Type().(*types.Signature) params := sig.Params() for i := 0; i < params.Len(); i++ { if objName != "" || i > 0 { g.Printf(", ") } p := params.At(i) g.Printf("param_%s C.%s", paramName(params, i), g.cgoType(p.Type())) } g.Printf(") ") res := sig.Results() if res.Len() > 0 { g.Printf("(") for i := 0; i < res.Len(); i++ { if i > 0 { g.Printf(", ") } g.Printf("C.%s", g.cgoType(res.At(i).Type())) } g.Printf(") ") } g.Printf("{\n") } func (g *goGen) genFunc(o *types.Func) { g.genFuncSignature(o, "") g.Indent() g.genFuncBody(o, g.pkg.Name()) g.Outdent() g.Printf("}\n\n") } func (g *goGen) genStruct(obj *types.TypeName, T *types.Struct) { fields := exportedFields(T) methods := exportedMethodSet(types.NewPointer(obj.Type())) g.Printf("type proxy%s _seq.Ref\n\n", obj.Name()) for _, f := range fields { g.Printf("//export proxy%s_%s_%s_Set\n", g.pkgPrefix, obj.Name(), f.Name()) g.Printf("func proxy%s_%s_%s_Set(refnum C.int32_t, v C.%s) {\n", g.pkgPrefix, obj.Name(), f.Name(), g.cgoType(f.Type())) g.Indent() g.Printf("ref := _seq.FromRefNum(int32(refnum))\n") g.genRead("_v", "v", f.Type(), modeRetained) g.Printf("ref.Get().(*%s.%s).%s = _v\n", g.pkg.Name(), obj.Name(), f.Name()) g.Outdent() g.Printf("}\n\n") g.Printf("//export proxy%s_%s_%s_Get\n", g.pkgPrefix, obj.Name(), f.Name()) g.Printf("func proxy%s_%s_%s_Get(refnum C.int32_t) C.%s {\n", g.pkgPrefix, obj.Name(), f.Name(), g.cgoType(f.Type())) g.Indent() g.Printf("ref := _seq.FromRefNum(int32(refnum))\n") g.Printf("v := ref.Get().(*%s.%s).%s\n", g.pkg.Name(), obj.Name(), f.Name()) g.genWrite("_v", "v", f.Type(), modeReturned) g.Printf("return _v\n") g.Outdent() g.Printf("}\n\n") } for _, m := range methods { g.genFuncSignature(m, obj.Name()) g.Indent() g.Printf("ref := _seq.FromRefNum(int32(refnum))\n") g.Printf("v := ref.Get().(*%s.%s)\n", g.pkg.Name(), obj.Name()) g.genFuncBody(m, "v") g.Outdent() g.Printf("}\n\n") } } func (g *goGen) genVar(o *types.Var) { // TODO(hyangah): non-struct pointer types (*int), struct type. v := fmt.Sprintf("%s.%s", g.pkg.Name(), o.Name()) // var I int // // func var_setI(v int) g.Printf("//export var_set%s_%s\n", g.pkgPrefix, o.Name()) g.Printf("func var_set%s_%s(v C.%s) {\n", g.pkgPrefix, o.Name(), g.cgoType(o.Type())) g.Indent() g.genRead("_v", "v", o.Type(), modeRetained) g.Printf("%s = _v\n", v) g.Outdent() g.Printf("}\n") // func var_getI() int g.Printf("//export var_get%s_%s\n", g.pkgPrefix, o.Name()) g.Printf("func var_get%s_%s() C.%s {\n", g.pkgPrefix, o.Name(), g.cgoType(o.Type())) g.Indent() g.Printf("v := %s\n", v) g.genWrite("_v", "v", o.Type(), modeReturned) g.Printf("return _v\n") g.Outdent() g.Printf("}\n") } func (g *goGen) genInterface(obj *types.TypeName) { iface := obj.Type().(*types.Named).Underlying().(*types.Interface) summary := makeIfaceSummary(iface) // Define the entry points. for _, m := range summary.callable { g.genFuncSignature(m, obj.Name()) g.Indent() g.Printf("ref := _seq.FromRefNum(int32(refnum))\n") g.Printf("v := ref.Get().(%s.%s)\n", g.pkg.Name(), obj.Name()) g.genFuncBody(m, "v") g.Outdent() g.Printf("}\n\n") } // Define a proxy interface. if !summary.implementable { // The interface defines an unexported method or a method that // uses an unexported type. We cannot generate a proxy object // for such a type. return } g.Printf("type proxy%s_%s _seq.Ref\n\n", g.pkgPrefix, obj.Name()) for _, m := range summary.callable { sig := m.Type().(*types.Signature) params := sig.Params() res := sig.Results() if res.Len() > 2 || (res.Len() == 2 && !isErrorType(res.At(1).Type())) { g.errorf("functions and methods must return either zero or one value, and optionally an error: %s.%s", obj.Name(), m.Name()) continue } g.Printf("func (p *proxy%s_%s) %s(", g.pkgPrefix, obj.Name(), m.Name()) for i := 0; i < params.Len(); i++ { if i > 0 { g.Printf(", ") } g.Printf("param_%s %s", paramName(params, i), g.typeString(params.At(i).Type())) } g.Printf(") ") if res.Len() == 1 { g.Printf(g.typeString(res.At(0).Type())) } else if res.Len() == 2 { g.Printf("(%s, error)", g.typeString(res.At(0).Type())) } g.Printf(" {\n") g.Indent() for i := 0; i < params.Len(); i++ { pn := "param_" + paramName(params, i) g.genWrite("_"+pn, pn, params.At(i).Type(), modeTransient) } if res.Len() > 0 { g.Printf("res := ") } g.Printf("C.cproxy%s_%s_%s(C.int32_t(p.Num)", g.pkgPrefix, obj.Name(), m.Name()) for i := 0; i < params.Len(); i++ { g.Printf(", _param_%s", paramName(params, i)) } g.Printf(")\n") var retName string if res.Len() > 0 { if res.Len() == 1 { T := res.At(0).Type() g.genRead("_res", "res", T, modeReturned) retName = "_res" } else { var rvs []string for i := 0; i < res.Len(); i++ { rv := fmt.Sprintf("res_%d", i) g.genRead(rv, fmt.Sprintf("res.r%d", i), res.At(i).Type(), modeReturned) rvs = append(rvs, rv) } retName = strings.Join(rvs, ", ") } g.Printf("return %s\n", retName) } g.Outdent() g.Printf("}\n\n") } } func (g *goGen) genRead(toVar, fromVar string, typ types.Type, mode varMode) { if isErrorType(typ) { g.genRead(toVar+"_str", fromVar, types.Typ[types.String], mode) g.Printf("%s := toError(%s_str)\n", toVar, toVar) return } switch t := typ.(type) { case *types.Basic: switch t.Kind() { case types.String: g.Printf("%s := decodeString(%s, %v)\n", toVar, fromVar, mode.copyString()) case types.Bool: g.Printf("%s := %s != 0\n", toVar, fromVar) default: g.Printf("%s := %s(%s)\n", toVar, t.Underlying().String(), fromVar) } case *types.Slice: switch e := t.Elem().(type) { case *types.Basic: switch e.Kind() { case types.Uint8: // Byte. g.Printf("%s := toSlice(%s, %v)\n", toVar, fromVar, mode.copySlice()) default: g.errorf("unsupported type: %s", t) } default: g.errorf("unsupported type: %s", t) } case *types.Pointer: switch u := t.Elem().(type) { case *types.Named: o := u.Obj() if o.Pkg() != g.pkg { g.errorf("type %s not defined in %s", u, g.pkg) return } g.Printf("// Must be a Go object\n") g.Printf("%s_ref := _seq.FromRefNum(int32(%s))\n", toVar, fromVar) g.Printf("%s := %s_ref.Get().(*%s.%s)\n", toVar, toVar, g.pkg.Name(), o.Name()) default: g.errorf("unsupported pointer type %s", t) } case *types.Named: switch t.Underlying().(type) { case *types.Interface, *types.Pointer: hasProxy := true if iface, ok := t.Underlying().(*types.Interface); ok { hasProxy = makeIfaceSummary(iface).implementable } o := t.Obj() if o.Pkg() != g.pkg { g.errorf("type %s not defined in %s", t, g.pkg) return } g.Printf("var %s %s\n", toVar, g.typeString(t)) g.Printf("%s_ref := _seq.FromRefNum(int32(%s))\n", toVar, fromVar) g.Printf("if %s_ref != nil {\n", toVar) g.Printf(" if %s_ref.Num < 0 { // go object \n", toVar) g.Printf(" %s = %s_ref.Get().(%s.%s)\n", toVar, toVar, g.pkg.Name(), o.Name()) if hasProxy { g.Printf(" } else { // foreign object \n") g.Printf(" %s = (*proxy%s_%s)(%s_ref)\n", toVar, g.pkgPrefix, o.Name(), toVar) } g.Printf(" }\n") g.Printf("}\n") default: g.errorf("unsupported named type %s", t) } default: g.errorf("unsupported type: %s", typ) } } func (g *goGen) typeString(typ types.Type) string { pkg := g.pkg switch t := typ.(type) { case *types.Named: obj := t.Obj() if obj.Pkg() == nil { // e.g. error type is *types.Named. return types.TypeString(typ, types.RelativeTo(pkg)) } if obj.Pkg() != g.pkg { g.errorf("type %s not defined in %s", t, g.pkg) } switch t.Underlying().(type) { case *types.Interface, *types.Struct: return fmt.Sprintf("%s.%s", pkg.Name(), types.TypeString(typ, types.RelativeTo(pkg))) default: g.errorf("unsupported named type %s / %T", t, t) } case *types.Pointer: switch t := t.Elem().(type) { case *types.Named: return fmt.Sprintf("*%s", g.typeString(t)) default: g.errorf("not yet supported, pointer type %s / %T", t, t) } default: return types.TypeString(typ, types.RelativeTo(pkg)) } return "" } func (g *goGen) gen() error { g.Printf(goPreamble, g.pkg.Name(), g.pkg.Path()) for _, s := range g.structs { g.genStruct(s.obj, s.t) } for _, intf := range g.interfaces { g.genInterface(intf.obj) } for _, v := range g.vars { g.genVar(v) } for _, f := range g.funcs { g.genFunc(f) } if len(g.err) > 0 { return g.err } return nil }