github.com/c-darwin/mobile@v0.0.0-20160313183840-ff625c46f7c9/bind/gengo.go (about)

     1  // Copyright 2014 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  	"fmt"
     9  	"go/token"
    10  	"go/types"
    11  	"strings"
    12  )
    13  
    14  type goGen struct {
    15  	*printer
    16  	fset *token.FileSet
    17  	pkg  *types.Package
    18  	err  ErrorList
    19  }
    20  
    21  func (g *goGen) errorf(format string, args ...interface{}) {
    22  	g.err = append(g.err, fmt.Errorf(format, args...))
    23  }
    24  
    25  const goPreamble = `// Package go_%s is an autogenerated binder stub for package %s.
    26  //   gobind -lang=go %s
    27  //
    28  // File is generated by gobind. Do not edit.
    29  package go_%s
    30  
    31  import (
    32  	"github.com/c-darwin/mobile/bind/seq"
    33  	%q
    34  )
    35  
    36  `
    37  
    38  func (g *goGen) genPreamble() {
    39  	n := g.pkg.Name()
    40  	g.Printf(goPreamble, n, n, g.pkg.Path(), n, g.pkg.Path())
    41  }
    42  
    43  func (g *goGen) genFuncBody(o *types.Func, selectorLHS string) {
    44  	sig := o.Type().(*types.Signature)
    45  	params := sig.Params()
    46  	for i := 0; i < params.Len(); i++ {
    47  		p := params.At(i)
    48  		g.genRead("param_"+paramName(params, i), "in", p.Type())
    49  	}
    50  
    51  	res := sig.Results()
    52  	if res.Len() > 2 || res.Len() == 2 && !isErrorType(res.At(1).Type()) {
    53  		g.errorf("functions and methods must return either zero or one values, and optionally an error")
    54  		return
    55  	}
    56  	returnsValue := false
    57  	returnsError := false
    58  	if res.Len() == 1 {
    59  		if isErrorType(res.At(0).Type()) {
    60  			returnsError = true
    61  			g.Printf("err := ")
    62  		} else {
    63  			returnsValue = true
    64  			g.Printf("res := ")
    65  		}
    66  	} else if res.Len() == 2 {
    67  		returnsValue = true
    68  		returnsError = true
    69  		g.Printf("res, err := ")
    70  	}
    71  
    72  	g.Printf("%s.%s(", selectorLHS, o.Name())
    73  	for i := 0; i < params.Len(); i++ {
    74  		if i > 0 {
    75  			g.Printf(", ")
    76  		}
    77  		g.Printf("param_%s", paramName(params, i))
    78  	}
    79  	g.Printf(")\n")
    80  
    81  	if returnsValue {
    82  		g.genWrite("res", "out", res.At(0).Type())
    83  	}
    84  	if returnsError {
    85  		g.genWrite("err", "out", res.At(res.Len()-1).Type())
    86  	}
    87  }
    88  
    89  func (g *goGen) genWrite(valName, seqName string, T types.Type) {
    90  	if isErrorType(T) {
    91  		g.Printf("if %s == nil {\n", valName)
    92  		g.Printf("    %s.WriteString(\"\");\n", seqName)
    93  		g.Printf("} else {\n")
    94  		g.Printf("    %s.WriteString(%s.Error());\n", seqName, valName)
    95  		g.Printf("}\n")
    96  		return
    97  	}
    98  	switch T := T.(type) {
    99  	case *types.Pointer:
   100  		// TODO(crawshaw): test *int
   101  		// TODO(crawshaw): test **Generator
   102  		switch T := T.Elem().(type) {
   103  		case *types.Named:
   104  			obj := T.Obj()
   105  			if obj.Pkg() != g.pkg {
   106  				g.errorf("type %s not defined in package %s", T, g.pkg)
   107  				return
   108  			}
   109  			g.Printf("%s.WriteGoRef(%s)\n", seqName, valName)
   110  		default:
   111  			g.errorf("unsupported type %s", T)
   112  		}
   113  	case *types.Named:
   114  		switch u := T.Underlying().(type) {
   115  		case *types.Interface, *types.Pointer:
   116  			g.Printf("%s.WriteGoRef(%s)\n", seqName, valName)
   117  		default:
   118  			g.errorf("unsupported, direct named type %s: %s", T, u)
   119  		}
   120  	default:
   121  		g.Printf("%s.Write%s(%s);\n", seqName, seqType(T), valName)
   122  	}
   123  }
   124  
   125  func (g *goGen) genFunc(o *types.Func) {
   126  	g.Printf("func proxy_%s(out, in *seq.Buffer) {\n", o.Name())
   127  	g.Indent()
   128  	g.genFuncBody(o, g.pkg.Name())
   129  	g.Outdent()
   130  	g.Printf("}\n\n")
   131  }
   132  
   133  func (g *goGen) genStruct(obj *types.TypeName, T *types.Struct) {
   134  	fields := exportedFields(T)
   135  	methods := exportedMethodSet(types.NewPointer(obj.Type()))
   136  
   137  	g.Printf("const (\n")
   138  	g.Indent()
   139  	g.Printf("proxy%s_Descriptor = \"go.%s.%s\"\n", obj.Name(), g.pkg.Name(), obj.Name())
   140  	for i, f := range fields {
   141  		g.Printf("proxy%s_%s_Get_Code = 0x%x0f\n", obj.Name(), f.Name(), i)
   142  		g.Printf("proxy%s_%s_Set_Code = 0x%x1f\n", obj.Name(), f.Name(), i)
   143  	}
   144  	for i, m := range methods {
   145  		g.Printf("proxy%s_%s_Code = 0x%x0c\n", obj.Name(), m.Name(), i)
   146  	}
   147  	g.Outdent()
   148  	g.Printf(")\n\n")
   149  
   150  	g.Printf("type proxy%s seq.Ref\n\n", obj.Name())
   151  
   152  	for _, f := range fields {
   153  		g.Printf("func proxy%s_%s_Set(out, in *seq.Buffer) {\n", obj.Name(), f.Name())
   154  		g.Indent()
   155  		g.Printf("ref := in.ReadRef()\n")
   156  		g.genRead("v", "in", f.Type())
   157  		g.Printf("ref.Get().(*%s.%s).%s = v\n", g.pkg.Name(), obj.Name(), f.Name())
   158  		g.Outdent()
   159  		g.Printf("}\n\n")
   160  
   161  		g.Printf("func proxy%s_%s_Get(out, in *seq.Buffer) {\n", obj.Name(), f.Name())
   162  		g.Indent()
   163  		g.Printf("ref := in.ReadRef()\n")
   164  		g.Printf("v := ref.Get().(*%s.%s).%s\n", g.pkg.Name(), obj.Name(), f.Name())
   165  		g.genWrite("v", "out", f.Type())
   166  		g.Outdent()
   167  		g.Printf("}\n\n")
   168  	}
   169  
   170  	for _, m := range methods {
   171  		g.Printf("func proxy%s_%s(out, in *seq.Buffer) {\n", obj.Name(), m.Name())
   172  		g.Indent()
   173  		g.Printf("ref := in.ReadRef()\n")
   174  		g.Printf("v := ref.Get().(*%s.%s)\n", g.pkg.Name(), obj.Name())
   175  		g.genFuncBody(m, "v")
   176  		g.Outdent()
   177  		g.Printf("}\n\n")
   178  	}
   179  
   180  	g.Printf("func init() {\n")
   181  	g.Indent()
   182  	for _, f := range fields {
   183  		n := f.Name()
   184  		g.Printf("seq.Register(proxy%s_Descriptor, proxy%s_%s_Set_Code, proxy%s_%s_Set)\n", obj.Name(), obj.Name(), n, obj.Name(), n)
   185  		g.Printf("seq.Register(proxy%s_Descriptor, proxy%s_%s_Get_Code, proxy%s_%s_Get)\n", obj.Name(), obj.Name(), n, obj.Name(), n)
   186  	}
   187  	for _, m := range methods {
   188  		n := m.Name()
   189  		g.Printf("seq.Register(proxy%s_Descriptor, proxy%s_%s_Code, proxy%s_%s)\n", obj.Name(), obj.Name(), n, obj.Name(), n)
   190  	}
   191  	g.Outdent()
   192  	g.Printf("}\n\n")
   193  }
   194  
   195  func (g *goGen) genInterface(obj *types.TypeName) {
   196  	iface := obj.Type().(*types.Named).Underlying().(*types.Interface)
   197  	ifaceDesc := fmt.Sprintf("go.%s.%s", g.pkg.Name(), obj.Name())
   198  
   199  	summary := makeIfaceSummary(iface)
   200  
   201  	// Descriptor and code for interface methods.
   202  	g.Printf("const (\n")
   203  	g.Indent()
   204  	g.Printf("proxy%s_Descriptor = %q\n", obj.Name(), ifaceDesc)
   205  	for i, m := range summary.callable {
   206  		g.Printf("proxy%s_%s_Code = 0x%x0a\n", obj.Name(), m.Name(), i+1)
   207  	}
   208  	g.Outdent()
   209  	g.Printf(")\n\n")
   210  
   211  	// Define the entry points.
   212  	for _, m := range summary.callable {
   213  		g.Printf("func proxy%s_%s(out, in *seq.Buffer) {\n", obj.Name(), m.Name())
   214  		g.Indent()
   215  		g.Printf("ref := in.ReadRef()\n")
   216  		g.Printf("v := ref.Get().(%s.%s)\n", g.pkg.Name(), obj.Name())
   217  		g.genFuncBody(m, "v")
   218  		g.Outdent()
   219  		g.Printf("}\n\n")
   220  	}
   221  
   222  	// Register the method entry points.
   223  	if len(summary.callable) > 0 {
   224  		g.Printf("func init() {\n")
   225  		g.Indent()
   226  		for _, m := range summary.callable {
   227  			g.Printf("seq.Register(proxy%s_Descriptor, proxy%s_%s_Code, proxy%s_%s)\n",
   228  				obj.Name(), obj.Name(), m.Name(), obj.Name(), m.Name())
   229  		}
   230  		g.Outdent()
   231  		g.Printf("}\n\n")
   232  	}
   233  
   234  	// Define a proxy interface.
   235  	if !summary.implementable {
   236  		// The interface defines an unexported method or a method that
   237  		// uses an unexported type. We cannot generate a proxy object
   238  		// for such a type.
   239  		return
   240  	}
   241  	g.Printf("type proxy%s seq.Ref\n\n", obj.Name())
   242  
   243  	for i := 0; i < iface.NumMethods(); i++ {
   244  		m := iface.Method(i)
   245  		sig := m.Type().(*types.Signature)
   246  		params := sig.Params()
   247  		res := sig.Results()
   248  
   249  		if res.Len() > 2 ||
   250  			(res.Len() == 2 && !isErrorType(res.At(1).Type())) {
   251  			g.errorf("functions and methods must return either zero or one value, and optionally an error: %s.%s", obj.Name(), m.Name())
   252  			continue
   253  		}
   254  
   255  		g.Printf("func (p *proxy%s) %s(", obj.Name(), m.Name())
   256  		for i := 0; i < params.Len(); i++ {
   257  			if i > 0 {
   258  				g.Printf(", ")
   259  			}
   260  			g.Printf("%s %s", paramName(params, i), g.typeString(params.At(i).Type()))
   261  		}
   262  		g.Printf(") ")
   263  
   264  		if res.Len() == 1 {
   265  			g.Printf(g.typeString(res.At(0).Type()))
   266  		} else if res.Len() == 2 {
   267  			g.Printf("(%s, error)", g.typeString(res.At(0).Type()))
   268  		}
   269  		g.Printf(" {\n")
   270  		g.Indent()
   271  
   272  		g.Printf("in := new(seq.Buffer)\n")
   273  		for i := 0; i < params.Len(); i++ {
   274  			g.genWrite(paramName(params, i), "in", params.At(i).Type())
   275  		}
   276  
   277  		if res.Len() == 0 {
   278  			g.Printf("seq.Transact((*seq.Ref)(p), %q, proxy%s_%s_Code, in)\n", ifaceDesc, obj.Name(), m.Name())
   279  		} else {
   280  			g.Printf("out := seq.Transact((*seq.Ref)(p), %q, proxy%s_%s_Code, in)\n", ifaceDesc, obj.Name(), m.Name())
   281  			var rvs []string
   282  			for i := 0; i < res.Len(); i++ {
   283  				rv := fmt.Sprintf("res_%d", i)
   284  				g.genRead(rv, "out", res.At(i).Type())
   285  				rvs = append(rvs, rv)
   286  			}
   287  			g.Printf("return %s\n", strings.Join(rvs, ","))
   288  		}
   289  
   290  		g.Outdent()
   291  		g.Printf("}\n\n")
   292  	}
   293  }
   294  
   295  func (g *goGen) genRead(valName, seqName string, typ types.Type) {
   296  	if isErrorType(typ) {
   297  		g.Printf("%s := %s.ReadError()\n", valName, seqName)
   298  		return
   299  	}
   300  	switch t := typ.(type) {
   301  	case *types.Pointer:
   302  		switch u := t.Elem().(type) {
   303  		case *types.Named:
   304  			o := u.Obj()
   305  			if o.Pkg() != g.pkg {
   306  				g.errorf("type %s not defined in package %s", u, g.pkg)
   307  				return
   308  			}
   309  			g.Printf("// Must be a Go object\n")
   310  			g.Printf("%s_ref := %s.ReadRef()\n", valName, seqName)
   311  			g.Printf("%s := %s_ref.Get().(*%s.%s)\n", valName, valName, g.pkg.Name(), o.Name())
   312  		default:
   313  			g.errorf("unsupported type %s", t)
   314  		}
   315  	case *types.Named:
   316  		switch t.Underlying().(type) {
   317  		case *types.Interface, *types.Pointer:
   318  			hasProxy := true
   319  			if iface, ok := t.Underlying().(*types.Interface); ok {
   320  				hasProxy = makeIfaceSummary(iface).implementable
   321  			}
   322  			o := t.Obj()
   323  			if o.Pkg() != g.pkg {
   324  				g.errorf("type %s not defined in package %s", t, g.pkg)
   325  				return
   326  			}
   327  			g.Printf("var %s %s\n", valName, g.typeString(t))
   328  			g.Printf("%s_ref := %s.ReadRef()\n", valName, seqName)
   329  			g.Printf("if %s_ref.Num < 0 { // go object \n", valName)
   330  			g.Printf("   %s = %s_ref.Get().(%s.%s)\n", valName, valName, g.pkg.Name(), o.Name())
   331  			if hasProxy {
   332  				g.Printf("} else {  // foreign object \n")
   333  				g.Printf("   %s = (*proxy%s)(%s_ref)\n", valName, o.Name(), valName)
   334  			}
   335  			g.Printf("}\n")
   336  		}
   337  	default:
   338  		g.Printf("%s := %s.Read%s()\n", valName, seqName, seqType(t))
   339  	}
   340  }
   341  
   342  func (g *goGen) typeString(typ types.Type) string {
   343  	pkg := g.pkg
   344  
   345  	switch t := typ.(type) {
   346  	case *types.Named:
   347  		obj := t.Obj()
   348  		if obj.Pkg() == nil { // e.g. error type is *types.Named.
   349  			return types.TypeString(typ, types.RelativeTo(pkg))
   350  		}
   351  		if obj.Pkg() != g.pkg {
   352  			g.errorf("type %s not defined in package %s", t, g.pkg)
   353  		}
   354  
   355  		switch t.Underlying().(type) {
   356  		case *types.Interface, *types.Struct:
   357  			return fmt.Sprintf("%s.%s", pkg.Name(), types.TypeString(typ, types.RelativeTo(pkg)))
   358  		default:
   359  			g.errorf("unsupported named type %s / %T", t, t)
   360  		}
   361  	case *types.Pointer:
   362  		switch t := t.Elem().(type) {
   363  		case *types.Named:
   364  			return fmt.Sprintf("*%s", g.typeString(t))
   365  		default:
   366  			g.errorf("not yet supported, pointer type %s / %T", t, t)
   367  		}
   368  	default:
   369  		return types.TypeString(typ, types.RelativeTo(pkg))
   370  	}
   371  	return ""
   372  }
   373  
   374  func (g *goGen) gen() error {
   375  	g.genPreamble()
   376  
   377  	var funcs []string
   378  
   379  	scope := g.pkg.Scope()
   380  	names := scope.Names()
   381  	for _, name := range names {
   382  		obj := scope.Lookup(name)
   383  		if !obj.Exported() {
   384  			continue
   385  		}
   386  
   387  		switch obj := obj.(type) {
   388  		// TODO(crawshaw): case *types.Const:
   389  		// TODO(crawshaw): case *types.Var:
   390  		case *types.Func:
   391  			// TODO(crawshaw): functions that are not implementable from
   392  			// another language may still be callable.
   393  			if isCallable(obj) {
   394  				g.genFunc(obj)
   395  				funcs = append(funcs, obj.Name())
   396  			}
   397  		case *types.TypeName:
   398  			named := obj.Type().(*types.Named)
   399  			switch T := named.Underlying().(type) {
   400  			case *types.Struct:
   401  				g.genStruct(obj, T)
   402  			case *types.Interface:
   403  				g.genInterface(obj)
   404  			}
   405  
   406  		default:
   407  			g.errorf("not yet supported, name for %v / %T", obj, obj)
   408  			continue
   409  		}
   410  	}
   411  
   412  	if len(funcs) > 0 {
   413  		g.Printf("func init() {\n")
   414  		g.Indent()
   415  		for i, name := range funcs {
   416  			g.Printf("seq.Register(%q, %d, proxy_%s)\n", g.pkg.Name(), i+1, name)
   417  		}
   418  		g.Outdent()
   419  		g.Printf("}\n")
   420  	}
   421  
   422  	if len(g.err) > 0 {
   423  		return g.err
   424  	}
   425  	return nil
   426  }