github.com/champo/mobile@v0.0.0-20190107162257-dc0771356504/bind/gen.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package bind
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"go/ast"
    11  	"go/token"
    12  	"go/types"
    13  	"io"
    14  	"regexp"
    15  	"strings"
    16  	"unicode"
    17  	"unicode/utf8"
    18  )
    19  
    20  type (
    21  	ErrorList []error
    22  
    23  	// varMode describes the lifetime of an argument or
    24  	// return value. Modes are used to guide the conversion
    25  	// of string and byte slice values accross the language
    26  	// barrier. The same conversion mode must be used for
    27  	// both the conversion before a foreign call and the
    28  	// corresponding conversion after the call.
    29  	// See the mode* constants for a description of
    30  	// each mode.
    31  	varMode int
    32  )
    33  
    34  const (
    35  	// modeTransient are for function arguments that
    36  	// are not used after the function returns.
    37  	// Transient byte slices don't need copying
    38  	// when passed accross the language barrier.
    39  	modeTransient varMode = iota
    40  	// modeRetained are for returned values and for function
    41  	// arguments that are used after the function returns.
    42  	// Retained byte slices need an intermediate copy.
    43  	modeRetained
    44  )
    45  
    46  func (list ErrorList) Error() string {
    47  	buf := new(bytes.Buffer)
    48  	for i, err := range list {
    49  		if i > 0 {
    50  			buf.WriteRune('\n')
    51  		}
    52  		io.WriteString(buf, err.Error())
    53  	}
    54  	return buf.String()
    55  }
    56  
    57  // interfaceInfo comes from Init and collects the auxillary information
    58  // needed to generate bindings for an exported Go interface in a bound
    59  // package.
    60  type interfaceInfo struct {
    61  	obj     *types.TypeName
    62  	t       *types.Interface
    63  	summary ifaceSummary
    64  }
    65  
    66  // structInfo comes from Init and collects the auxillary information
    67  // needed to generate bindings for an exported Go struct in a bound
    68  // package.
    69  type structInfo struct {
    70  	obj *types.TypeName
    71  	t   *types.Struct
    72  }
    73  
    74  // Generator contains the common Go package information
    75  // needed for the specific Go, Java, ObjC generators.
    76  //
    77  // After setting Printer, Fset, AllPkg, Pkg, the Init
    78  // method is used to initialize the auxiliary information
    79  // about the package to be generated, Pkg.
    80  type Generator struct {
    81  	*Printer
    82  	Fset   *token.FileSet
    83  	AllPkg []*types.Package
    84  	Files  []*ast.File
    85  	Pkg    *types.Package
    86  	err    ErrorList
    87  
    88  	// fields set by init.
    89  	pkgName   string
    90  	pkgPrefix string
    91  	funcs     []*types.Func
    92  	constants []*types.Const
    93  	vars      []*types.Var
    94  
    95  	interfaces []interfaceInfo
    96  	structs    []structInfo
    97  	otherNames []*types.TypeName
    98  	// allIntf contains interfaces from all bound packages.
    99  	allIntf []interfaceInfo
   100  
   101  	docs pkgDocs
   102  }
   103  
   104  // A pkgDocs maps the name of each exported package-level declaration to its extracted documentation.
   105  type pkgDocs map[string]*pkgDoc
   106  
   107  type pkgDoc struct {
   108  	doc string
   109  	// Struct or interface fields and methods.
   110  	members map[string]string
   111  }
   112  
   113  // pkgPrefix returns a prefix that disambiguates symbol names for binding
   114  // multiple packages.
   115  //
   116  // TODO(elias.naur): Avoid (and test) name clashes from multiple packages
   117  // with the same name. Perhaps use the index from the order the package is
   118  // generated.
   119  func pkgPrefix(pkg *types.Package) string {
   120  	// The error type has no package
   121  	if pkg == nil {
   122  		return ""
   123  	}
   124  	return pkg.Name()
   125  }
   126  
   127  func (g *Generator) Init() {
   128  	if g.Pkg != nil {
   129  		g.pkgName = g.Pkg.Name()
   130  	}
   131  	g.pkgPrefix = pkgPrefix(g.Pkg)
   132  
   133  	if g.Pkg != nil {
   134  		g.parseDocs()
   135  		scope := g.Pkg.Scope()
   136  		hasExported := false
   137  		for _, name := range scope.Names() {
   138  			obj := scope.Lookup(name)
   139  			if !obj.Exported() {
   140  				continue
   141  			}
   142  			hasExported = true
   143  			switch obj := obj.(type) {
   144  			case *types.Func:
   145  				if isCallable(obj) {
   146  					g.funcs = append(g.funcs, obj)
   147  				}
   148  			case *types.TypeName:
   149  				named := obj.Type().(*types.Named)
   150  				switch t := named.Underlying().(type) {
   151  				case *types.Struct:
   152  					g.structs = append(g.structs, structInfo{obj, t})
   153  				case *types.Interface:
   154  					g.interfaces = append(g.interfaces, interfaceInfo{obj, t, makeIfaceSummary(t)})
   155  				default:
   156  					g.otherNames = append(g.otherNames, obj)
   157  				}
   158  			case *types.Const:
   159  				g.constants = append(g.constants, obj)
   160  			case *types.Var:
   161  				g.vars = append(g.vars, obj)
   162  			default:
   163  				g.errorf("unsupported exported type for %s: %T", obj.Name(), obj)
   164  			}
   165  		}
   166  		if !hasExported {
   167  			g.errorf("no exported names in the package %q", g.Pkg.Path())
   168  		}
   169  	} else {
   170  		// Bind the single supported type from the universe scope, error.
   171  		errType := types.Universe.Lookup("error").(*types.TypeName)
   172  		t := errType.Type().Underlying().(*types.Interface)
   173  		g.interfaces = append(g.interfaces, interfaceInfo{errType, t, makeIfaceSummary(t)})
   174  	}
   175  	for _, p := range g.AllPkg {
   176  		scope := p.Scope()
   177  		for _, name := range scope.Names() {
   178  			obj := scope.Lookup(name)
   179  			if !obj.Exported() {
   180  				continue
   181  			}
   182  			if obj, ok := obj.(*types.TypeName); ok {
   183  				named := obj.Type().(*types.Named)
   184  				if t, ok := named.Underlying().(*types.Interface); ok {
   185  					g.allIntf = append(g.allIntf, interfaceInfo{obj, t, makeIfaceSummary(t)})
   186  				}
   187  			}
   188  		}
   189  	}
   190  }
   191  
   192  // parseDocs extracts documentation from a package in a form useful for lookups.
   193  func (g *Generator) parseDocs() {
   194  	d := make(pkgDocs)
   195  	for _, f := range g.Files {
   196  		for _, decl := range f.Decls {
   197  			switch decl := decl.(type) {
   198  			case *ast.GenDecl:
   199  				for _, spec := range decl.Specs {
   200  					switch spec := spec.(type) {
   201  					case *ast.TypeSpec:
   202  						d.addType(spec, decl.Doc)
   203  					case *ast.ValueSpec:
   204  						d.addValue(spec, decl.Doc)
   205  					}
   206  				}
   207  			case *ast.FuncDecl:
   208  				d.addFunc(decl)
   209  			}
   210  		}
   211  	}
   212  	g.docs = d
   213  }
   214  
   215  func (d pkgDocs) addValue(t *ast.ValueSpec, outerDoc *ast.CommentGroup) {
   216  	for _, n := range t.Names {
   217  		if !ast.IsExported(n.Name) {
   218  			continue
   219  		}
   220  		doc := t.Doc
   221  		if doc == nil {
   222  			doc = outerDoc
   223  		}
   224  		if doc != nil {
   225  			d[n.Name] = &pkgDoc{doc: doc.Text()}
   226  		}
   227  	}
   228  }
   229  
   230  func (d pkgDocs) addFunc(f *ast.FuncDecl) {
   231  	doc := f.Doc
   232  	if doc == nil {
   233  		return
   234  	}
   235  	fn := f.Name.Name
   236  	if !ast.IsExported(fn) {
   237  		return
   238  	}
   239  	if r := f.Recv; r != nil {
   240  		// f is a method.
   241  		n := typeName(r.List[0].Type)
   242  		pd, exists := d[n]
   243  		if !exists {
   244  			pd = &pkgDoc{members: make(map[string]string)}
   245  			d[n] = pd
   246  		}
   247  		pd.members[fn] = doc.Text()
   248  	} else {
   249  		// f is a function.
   250  		d[fn] = &pkgDoc{doc: doc.Text()}
   251  	}
   252  }
   253  
   254  func (d pkgDocs) addType(t *ast.TypeSpec, outerDoc *ast.CommentGroup) {
   255  	if !ast.IsExported(t.Name.Name) {
   256  		return
   257  	}
   258  	doc := t.Doc
   259  	if doc == nil {
   260  		doc = outerDoc
   261  	}
   262  	pd := d[t.Name.Name]
   263  	pd = &pkgDoc{members: make(map[string]string)}
   264  	d[t.Name.Name] = pd
   265  	if doc != nil {
   266  		pd.doc = doc.Text()
   267  	}
   268  	var fields *ast.FieldList
   269  	switch t := t.Type.(type) {
   270  	case *ast.StructType:
   271  		fields = t.Fields
   272  	case *ast.InterfaceType:
   273  		fields = t.Methods
   274  	}
   275  	if fields != nil {
   276  		for _, field := range fields.List {
   277  			if field.Doc != nil {
   278  				if field.Names == nil {
   279  					// Anonymous field. Extract name from its type.
   280  					if n := typeName(field.Type); ast.IsExported(n) {
   281  						pd.members[n] = field.Doc.Text()
   282  					}
   283  				}
   284  				for _, n := range field.Names {
   285  					if ast.IsExported(n.Name) {
   286  						pd.members[n.Name] = field.Doc.Text()
   287  					}
   288  				}
   289  			}
   290  		}
   291  	}
   292  }
   293  
   294  // typeName returns the type name T for expressions on the
   295  // T, *T, **T (etc.) form.
   296  func typeName(t ast.Expr) string {
   297  	switch t := t.(type) {
   298  	case *ast.StarExpr:
   299  		return typeName(t.X)
   300  	case *ast.Ident:
   301  		return t.Name
   302  	case *ast.SelectorExpr:
   303  		return t.Sel.Name
   304  	default:
   305  		return ""
   306  	}
   307  }
   308  
   309  func (d *pkgDoc) Doc() string {
   310  	if d == nil {
   311  		return ""
   312  	}
   313  	return d.doc
   314  }
   315  
   316  func (d *pkgDoc) Member(n string) string {
   317  	if d == nil {
   318  		return ""
   319  	}
   320  	return d.members[n]
   321  }
   322  
   323  // constructorType returns the type T for a function of the forms:
   324  //
   325  // func NewT...(...) *T
   326  // func NewT...(...) (*T, error)
   327  func (g *Generator) constructorType(f *types.Func) *types.TypeName {
   328  	sig := f.Type().(*types.Signature)
   329  	res := sig.Results()
   330  	if res.Len() != 1 && !(res.Len() == 2 && isErrorType(res.At(1).Type())) {
   331  		return nil
   332  	}
   333  	rt := res.At(0).Type()
   334  	pt, ok := rt.(*types.Pointer)
   335  	if !ok {
   336  		return nil
   337  	}
   338  	nt, ok := pt.Elem().(*types.Named)
   339  	if !ok {
   340  		return nil
   341  	}
   342  	obj := nt.Obj()
   343  	if !strings.HasPrefix(f.Name(), "New"+obj.Name()) {
   344  		return nil
   345  	}
   346  	return obj
   347  }
   348  
   349  func toCFlag(v bool) int {
   350  	if v {
   351  		return 1
   352  	}
   353  	return 0
   354  }
   355  
   356  func (g *Generator) errorf(format string, args ...interface{}) {
   357  	g.err = append(g.err, fmt.Errorf(format, args...))
   358  }
   359  
   360  // cgoType returns the name of a Cgo type suitable for converting a value of
   361  // the given type.
   362  func (g *Generator) cgoType(t types.Type) string {
   363  	switch t := t.(type) {
   364  	case *types.Basic:
   365  		switch t.Kind() {
   366  		case types.Bool, types.UntypedBool:
   367  			return "char"
   368  		case types.Int:
   369  			return "nint"
   370  		case types.Int8:
   371  			return "int8_t"
   372  		case types.Int16:
   373  			return "int16_t"
   374  		case types.Int32, types.UntypedRune: // types.Rune
   375  			return "int32_t"
   376  		case types.Int64, types.UntypedInt:
   377  			return "int64_t"
   378  		case types.Uint8: // types.Byte
   379  			return "uint8_t"
   380  		// TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64:
   381  		case types.Float32:
   382  			return "float"
   383  		case types.Float64, types.UntypedFloat:
   384  			return "double"
   385  		case types.String:
   386  			return "nstring"
   387  		default:
   388  			g.errorf("unsupported basic type: %s", t)
   389  		}
   390  	case *types.Slice:
   391  		switch e := t.Elem().(type) {
   392  		case *types.Basic:
   393  			switch e.Kind() {
   394  			case types.Uint8: // Byte.
   395  				return "nbyteslice"
   396  			default:
   397  				g.errorf("unsupported slice type: %s", t)
   398  			}
   399  		default:
   400  			g.errorf("unsupported slice type: %s", t)
   401  		}
   402  	case *types.Pointer:
   403  		if _, ok := t.Elem().(*types.Named); ok {
   404  			return g.cgoType(t.Elem())
   405  		}
   406  		g.errorf("unsupported pointer to type: %s", t)
   407  	case *types.Named:
   408  		return "int32_t"
   409  	default:
   410  		g.errorf("unsupported type: %s", t)
   411  	}
   412  	return "TODO"
   413  }
   414  
   415  func (g *Generator) genInterfaceMethodSignature(m *types.Func, iName string, header bool, g_paramName func(*types.Tuple, int) string) {
   416  	sig := m.Type().(*types.Signature)
   417  	params := sig.Params()
   418  	res := sig.Results()
   419  
   420  	if res.Len() == 0 {
   421  		g.Printf("void ")
   422  	} else {
   423  		if res.Len() == 1 {
   424  			g.Printf("%s ", g.cgoType(res.At(0).Type()))
   425  		} else {
   426  			if header {
   427  				g.Printf("typedef struct cproxy%s_%s_%s_return {\n", g.pkgPrefix, iName, m.Name())
   428  				g.Indent()
   429  				for i := 0; i < res.Len(); i++ {
   430  					t := res.At(i).Type()
   431  					g.Printf("%s r%d;\n", g.cgoType(t), i)
   432  				}
   433  				g.Outdent()
   434  				g.Printf("} cproxy%s_%s_%s_return;\n", g.pkgPrefix, iName, m.Name())
   435  			}
   436  			g.Printf("struct cproxy%s_%s_%s_return ", g.pkgPrefix, iName, m.Name())
   437  		}
   438  	}
   439  	g.Printf("cproxy%s_%s_%s(int32_t refnum", g.pkgPrefix, iName, m.Name())
   440  	for i := 0; i < params.Len(); i++ {
   441  		t := params.At(i).Type()
   442  		g.Printf(", %s %s", g.cgoType(t), g_paramName(params, i))
   443  	}
   444  	g.Printf(")")
   445  	if header {
   446  		g.Printf(";\n")
   447  	} else {
   448  		g.Printf(" {\n")
   449  	}
   450  }
   451  
   452  func (g *Generator) validPkg(pkg *types.Package) bool {
   453  	for _, p := range g.AllPkg {
   454  		if p == pkg {
   455  			return true
   456  		}
   457  	}
   458  	return false
   459  }
   460  
   461  // isSigSupported reports whether the generators can handle a given
   462  // function signature.
   463  func (g *Generator) isSigSupported(t types.Type) bool {
   464  	sig := t.(*types.Signature)
   465  	params := sig.Params()
   466  	for i := 0; i < params.Len(); i++ {
   467  		if !g.isSupported(params.At(i).Type()) {
   468  			return false
   469  		}
   470  	}
   471  	res := sig.Results()
   472  	for i := 0; i < res.Len(); i++ {
   473  		if !g.isSupported(res.At(i).Type()) {
   474  			return false
   475  		}
   476  	}
   477  	return true
   478  }
   479  
   480  // isSupported reports whether the generators can handle the type.
   481  func (g *Generator) isSupported(t types.Type) bool {
   482  	if isErrorType(t) || isWrapperType(t) {
   483  		return true
   484  	}
   485  	switch t := t.(type) {
   486  	case *types.Basic:
   487  		switch t.Kind() {
   488  		case types.Bool, types.UntypedBool,
   489  			types.Int,
   490  			types.Int8, types.Uint8, // types.Byte
   491  			types.Int16,
   492  			types.Int32, types.UntypedRune, // types.Rune
   493  			types.Int64, types.UntypedInt,
   494  			types.Float32,
   495  			types.Float64, types.UntypedFloat,
   496  			types.String, types.UntypedString:
   497  			return true
   498  		}
   499  		return false
   500  	case *types.Slice:
   501  		switch e := t.Elem().(type) {
   502  		case *types.Basic:
   503  			return e.Kind() == types.Uint8
   504  		}
   505  	case *types.Pointer:
   506  		switch t := t.Elem().(type) {
   507  		case *types.Named:
   508  			return g.validPkg(t.Obj().Pkg())
   509  		}
   510  	case *types.Named:
   511  		switch t.Underlying().(type) {
   512  		case *types.Interface, *types.Pointer:
   513  			return g.validPkg(t.Obj().Pkg())
   514  		}
   515  	}
   516  	return false
   517  }
   518  
   519  var paramRE = regexp.MustCompile(`^p[0-9]*$`)
   520  
   521  // basicParamName replaces incompatible name with a p0-pN name.
   522  // Missing names, or existing names of the form p[0-9] are incompatible.
   523  func basicParamName(params *types.Tuple, pos int) string {
   524  	name := params.At(pos).Name()
   525  	if name == "" || name[0] == '_' || paramRE.MatchString(name) {
   526  		name = fmt.Sprintf("p%d", pos)
   527  	}
   528  	return name
   529  }
   530  
   531  func lowerFirst(s string) string {
   532  	if s == "" {
   533  		return ""
   534  	}
   535  
   536  	var conv []rune
   537  	for len(s) > 0 {
   538  		r, n := utf8.DecodeRuneInString(s)
   539  		if !unicode.IsUpper(r) {
   540  			if l := len(conv); l > 1 {
   541  				conv[l-1] = unicode.ToUpper(conv[l-1])
   542  			}
   543  			return string(conv) + s
   544  		}
   545  		conv = append(conv, unicode.ToLower(r))
   546  		s = s[n:]
   547  	}
   548  	return string(conv)
   549  }
   550  
   551  // newNameSanitizer returns a functions that replaces all dashes and dots
   552  // with underscores, as well as avoiding reserved words by suffixing such
   553  // identifiers with underscores.
   554  func newNameSanitizer(res []string) func(s string) string {
   555  	reserved := make(map[string]bool)
   556  	for _, word := range res {
   557  		reserved[word] = true
   558  	}
   559  	symbols := strings.NewReplacer(
   560  		"-", "_",
   561  		".", "_",
   562  	)
   563  	return func(s string) string {
   564  		if reserved[s] {
   565  			return s + "_"
   566  		}
   567  		return symbols.Replace(s)
   568  	}
   569  }