| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593 |
- // 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 (
- "bytes"
- "fmt"
- "go/types"
- "strings"
- )
- type goGen struct {
- *Generator
- // imports is the list of imports, in the form
- // "the/package/path"
- //
- // or
- //
- // name "the/package/path"
- //
- // in case of duplicates.
- imports []string
- // The set of taken import names.
- importNames map[string]struct{}
- // importMap is a map from packages to their names. The name of a package is the last
- // segment of its path, with duplicates resolved by appending a underscore and a unique
- // number.
- importMap map[*types.Package]string
- }
- const (
- goPreamble = gobindPreamble + `// Package main is an autogenerated binder stub for package %[1]s.
- //
- // autogenerated by gobind -lang=go %[2]s
- package main
- /*
- #include <stdlib.h>
- #include <stdint.h>
- #include "seq.h"
- #include "%[1]s.h"
- */
- import "C"
- `
- )
- 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_" + g.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", g.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(), modeRetained)
- }
- 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) {
- switch t := t.(type) {
- case *types.Basic:
- switch t.Kind() {
- case types.String:
- g.Printf("%s := encodeString(%s)\n", toVar, fromVar)
- 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 == modeRetained)
- 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:
- 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", g.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) paramName(params *types.Tuple, pos int) string {
- return basicParamName(params, pos)
- }
- func (g *goGen) genFunc(o *types.Func) {
- if !g.isSigSupported(o.Type()) {
- g.Printf("// skipped function %s with unsupported parameter or result types\n", o.Name())
- return
- }
- g.genFuncSignature(o, "")
- g.Indent()
- g.genFuncBody(o, g.pkgName(g.Pkg))
- 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()))
- for _, f := range fields {
- if t := f.Type(); !g.isSupported(t) {
- g.Printf("// skipped field %s.%s with unsupported type: %s\n\n", obj.Name(), f.Name(), t)
- continue
- }
- 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.pkgName(g.Pkg), 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.pkgName(g.Pkg), obj.Name(), f.Name())
- g.genWrite("_v", "v", f.Type(), modeRetained)
- g.Printf("return _v\n")
- g.Outdent()
- g.Printf("}\n\n")
- }
- for _, m := range methods {
- if !g.isSigSupported(m.Type()) {
- g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name())
- continue
- }
- g.genFuncSignature(m, obj.Name())
- g.Indent()
- g.Printf("ref := _seq.FromRefNum(int32(refnum))\n")
- g.Printf("v := ref.Get().(*%s%s)\n", g.pkgName(g.Pkg), obj.Name())
- g.genFuncBody(m, "v.")
- g.Outdent()
- g.Printf("}\n\n")
- }
- // Export constructor for ObjC and Java default no-arg constructors
- g.Printf("//export new_%s_%s\n", g.Pkg.Name(), obj.Name())
- g.Printf("func new_%s_%s() C.int32_t {\n", g.Pkg.Name(), obj.Name())
- g.Indent()
- g.Printf("return C.int32_t(_seq.ToRefNum(new(%s%s)))\n", g.pkgName(g.Pkg), obj.Name())
- g.Outdent()
- g.Printf("}\n")
- }
- func (g *goGen) genVar(o *types.Var) {
- if t := o.Type(); !g.isSupported(t) {
- g.Printf("// skipped variable %s with unsupported type %s\n\n", o.Name(), t)
- return
- }
- // TODO(hyangah): non-struct pointer types (*int), struct type.
- v := fmt.Sprintf("%s%s", g.pkgName(g.Pkg), 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(), modeRetained)
- 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 {
- if !g.isSigSupported(m.Type()) {
- g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name())
- continue
- }
- g.genFuncSignature(m, obj.Name())
- g.Indent()
- g.Printf("ref := _seq.FromRefNum(int32(refnum))\n")
- g.Printf("v := ref.Get().(%s%s)\n", g.pkgName(g.Pkg), 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())
- g.Printf("func (p *proxy%s_%s) Bind_proxy_refnum__() int32 {\n", g.pkgPrefix, obj.Name())
- g.Indent()
- g.Printf("return (*_seq.Ref)(p).Bind_IncNum()\n")
- g.Outdent()
- g.Printf("}\n\n")
- for _, m := range summary.callable {
- if !g.isSigSupported(m.Type()) {
- g.Printf("// skipped method %s.%s with unsupported parameter or result types\n", obj.Name(), m.Name())
- continue
- }
- 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", g.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_" + g.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.Bind_proxy_refnum__())", g.pkgPrefix, obj.Name(), m.Name())
- for i := 0; i < params.Len(); i++ {
- g.Printf(", _param_%s", g.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, modeRetained)
- 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(), modeRetained)
- 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) {
- switch t := typ.(type) {
- case *types.Basic:
- switch t.Kind() {
- case types.String:
- g.Printf("%s := decodeString(%s)\n", toVar, fromVar)
- 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 == modeRetained)
- 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()
- oPkg := o.Pkg()
- if !g.validPkg(oPkg) {
- g.errorf("type %s is defined in %s, which is not bound", u, oPkg)
- return
- }
- g.Printf("// Must be a Go object\n")
- g.Printf("var %s *%s%s\n", toVar, g.pkgName(oPkg), o.Name())
- g.Printf("if %s_ref := _seq.FromRefNum(int32(%s)); %s_ref != nil {\n", toVar, fromVar, toVar)
- g.Printf(" %s = %s_ref.Get().(*%s%s)\n", toVar, toVar, g.pkgName(oPkg), o.Name())
- g.Printf("}\n")
- 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
- }
- pkgFirst := typePkgFirstElem(t)
- isWrapper := pkgFirst == "Java" || pkgFirst == "ObjC"
- o := t.Obj()
- oPkg := o.Pkg()
- if !isErrorType(t) && !g.validPkg(oPkg) && !isWrapper {
- g.errorf("type %s is defined in %s, which is not bound", t, oPkg)
- 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 < 0 { // go object \n", fromVar)
- g.Printf(" %s = %s_ref.Get().(%s%s)\n", toVar, toVar, g.pkgName(oPkg), o.Name())
- if hasProxy {
- g.Printf(" } else { // foreign object \n")
- if isWrapper {
- var clsName string
- switch pkgFirst {
- case "Java":
- clsName = flattenName(classNameFor(t))
- case "ObjC":
- clsName = t.Obj().Name()
- }
- g.Printf(" %s = (*proxy_class_%s)(%s_ref)\n", toVar, clsName, toVar)
- } else {
- g.Printf(" %s = (*proxy%s_%s)(%s_ref)\n", toVar, pkgPrefix(oPkg), 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))
- }
- oPkg := obj.Pkg()
- if !g.validPkg(oPkg) && !isWrapperType(t) {
- g.errorf("type %s is defined in %s, which is not bound", t, oPkg)
- return "TODO"
- }
- switch t.Underlying().(type) {
- case *types.Interface, *types.Struct:
- return fmt.Sprintf("%s%s", g.pkgName(oPkg), types.TypeString(typ, types.RelativeTo(oPkg)))
- 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 ""
- }
- // genPreamble generates the preamble. It is generated after everything
- // else, where we know which bound packages to import.
- func (g *goGen) genPreamble() {
- pkgName := ""
- pkgPath := ""
- if g.Pkg != nil {
- pkgName = g.Pkg.Name()
- pkgPath = g.Pkg.Path()
- } else {
- pkgName = "universe"
- }
- g.Printf(goPreamble, pkgName, pkgPath)
- g.Printf("import (\n")
- g.Indent()
- g.Printf("_seq \"golang.org/x/mobile/bind/seq\"\n")
- for _, imp := range g.imports {
- g.Printf("%s\n", imp)
- }
- g.Outdent()
- g.Printf(")\n\n")
- }
- func (g *goGen) gen() error {
- g.importNames = make(map[string]struct{})
- g.importMap = make(map[*types.Package]string)
- // Switch to a temporary buffer so the preamble can be
- // written last.
- oldBuf := g.Printer.Buf
- newBuf := new(bytes.Buffer)
- g.Printer.Buf = newBuf
- g.Printf("// suppress the error if seq ends up unused\n")
- g.Printf("var _ = _seq.FromRefNum\n")
- 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)
- }
- // Switch to the original buffer, write the preamble
- // and append the rest of the file.
- g.Printer.Buf = oldBuf
- g.genPreamble()
- g.Printer.Buf.Write(newBuf.Bytes())
- if len(g.err) > 0 {
- return g.err
- }
- return nil
- }
- // pkgName returns the package name and adds the package to the list of
- // imports.
- func (g *goGen) pkgName(pkg *types.Package) string {
- // The error type has no package
- if pkg == nil {
- return ""
- }
- if name, exists := g.importMap[pkg]; exists {
- return name + "."
- }
- i := 0
- pname := pkg.Name()
- name := pkg.Name()
- for {
- if _, exists := g.importNames[name]; !exists {
- g.importNames[name] = struct{}{}
- g.importMap[pkg] = name
- var imp string
- if pname != name {
- imp = fmt.Sprintf("%s %q", name, pkg.Path())
- } else {
- imp = fmt.Sprintf("%q", pkg.Path())
- }
- g.imports = append(g.imports, imp)
- break
- }
- i++
- name = fmt.Sprintf("%s_%d", pname, i)
- }
- g.importMap[pkg] = name
- return name + "."
- }
|