github.com/c-darwin/mobile@v0.0.0-20160313183840-ff625c46f7c9/bind/genjava.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  	"bytes"
     9  	"fmt"
    10  	"go/token"
    11  	"go/types"
    12  	"io"
    13  	"regexp"
    14  	"strings"
    15  )
    16  
    17  // TODO(crawshaw): disallow basic android java type names in exported symbols.
    18  // TODO(crawshaw): generate all relevant "implements" relationships for interfaces.
    19  // TODO(crawshaw): consider introducing Java functions for casting to and from interfaces at runtime.
    20  
    21  type ErrorList []error
    22  
    23  func (list ErrorList) Error() string {
    24  	buf := new(bytes.Buffer)
    25  	for i, err := range list {
    26  		if i > 0 {
    27  			buf.WriteRune('\n')
    28  		}
    29  		io.WriteString(buf, err.Error())
    30  	}
    31  	return buf.String()
    32  }
    33  
    34  type javaGen struct {
    35  	*printer
    36  	fset *token.FileSet
    37  	pkg  *types.Package
    38  	err  ErrorList
    39  }
    40  
    41  func (g *javaGen) genStruct(obj *types.TypeName, T *types.Struct) {
    42  	fields := exportedFields(T)
    43  	methods := exportedMethodSet(types.NewPointer(obj.Type()))
    44  
    45  	g.Printf("public static final class %s implements go.Seq.Object {\n", obj.Name())
    46  	g.Indent()
    47  	g.Printf("private static final String DESCRIPTOR = \"go.%s.%s\";\n", g.pkg.Name(), obj.Name())
    48  	for i, f := range fields {
    49  		g.Printf("private static final int FIELD_%s_GET = 0x%x0f;\n", f.Name(), i)
    50  		g.Printf("private static final int FIELD_%s_SET = 0x%x1f;\n", f.Name(), i)
    51  	}
    52  	for i, m := range methods {
    53  		g.Printf("private static final int CALL_%s = 0x%x0c;\n", m.Name(), i)
    54  	}
    55  	g.Printf("\n")
    56  
    57  	g.Printf("private go.Seq.Ref ref;\n\n")
    58  
    59  	n := obj.Name()
    60  	g.Printf("private %s(go.Seq.Ref ref) { this.ref = ref; }\n\n", n)
    61  	g.Printf(`public go.Seq.Ref ref() { return ref; }
    62  
    63  public void call(int code, go.Seq in, go.Seq out) {
    64      throw new RuntimeException("internal error: cycle: cannot call concrete proxy");
    65  }
    66  
    67  `)
    68  
    69  	for _, f := range fields {
    70  		g.Printf("public %s get%s() {\n", g.javaType(f.Type()), f.Name())
    71  		g.Indent()
    72  		g.Printf("Seq in = new Seq();\n")
    73  		g.Printf("Seq out = new Seq();\n")
    74  		g.Printf("in.writeRef(ref);\n")
    75  		g.Printf("Seq.send(DESCRIPTOR, FIELD_%s_GET, in, out);\n", f.Name())
    76  		if seqType(f.Type()) == "Ref" {
    77  			g.Printf("return new %s(out.read%s);\n", g.javaType(f.Type()), seqRead(f.Type()))
    78  		} else {
    79  			g.Printf("return out.read%s;\n", seqRead(f.Type()))
    80  		}
    81  		g.Outdent()
    82  		g.Printf("}\n\n")
    83  
    84  		g.Printf("public void set%s(%s v) {\n", f.Name(), g.javaType(f.Type()))
    85  		g.Indent()
    86  		g.Printf("Seq in = new Seq();\n")
    87  		g.Printf("Seq out = new Seq();\n")
    88  		g.Printf("in.writeRef(ref);\n")
    89  		g.Printf("in.write%s;\n", seqWrite(f.Type(), "v"))
    90  		g.Printf("Seq.send(DESCRIPTOR, FIELD_%s_SET, in, out);\n", f.Name())
    91  		g.Outdent()
    92  		g.Printf("}\n\n")
    93  	}
    94  
    95  	for _, m := range methods {
    96  		g.genFunc(m, true)
    97  	}
    98  
    99  	g.Printf("@Override public boolean equals(Object o) {\n")
   100  	g.Indent()
   101  	g.Printf("if (o == null || !(o instanceof %s)) {\n    return false;\n}\n", n)
   102  	g.Printf("%s that = (%s)o;\n", n, n)
   103  	for _, f := range fields {
   104  		nf := f.Name()
   105  		g.Printf("%s this%s = get%s();\n", g.javaType(f.Type()), nf, nf)
   106  		g.Printf("%s that%s = that.get%s();\n", g.javaType(f.Type()), nf, nf)
   107  		if isJavaPrimitive(f.Type()) {
   108  			g.Printf("if (this%s != that%s) {\n    return false;\n}\n", nf, nf)
   109  		} else {
   110  			g.Printf("if (this%s == null) {\n", nf)
   111  			g.Indent()
   112  			g.Printf("if (that%s != null) {\n    return false;\n}\n", nf)
   113  			g.Outdent()
   114  			g.Printf("} else if (!this%s.equals(that%s)) {\n    return false;\n}\n", nf, nf)
   115  		}
   116  	}
   117  	g.Printf("return true;\n")
   118  	g.Outdent()
   119  	g.Printf("}\n\n")
   120  
   121  	g.Printf("@Override public int hashCode() {\n")
   122  	g.Printf("    return java.util.Arrays.hashCode(new Object[] {")
   123  	for i, f := range fields {
   124  		if i > 0 {
   125  			g.Printf(", ")
   126  		}
   127  		g.Printf("get%s()", f.Name())
   128  	}
   129  	g.Printf("});\n")
   130  	g.Printf("}\n\n")
   131  
   132  	// TODO(crawshaw): use String() string if it is defined.
   133  	g.Printf("@Override public String toString() {\n")
   134  	g.Indent()
   135  	g.Printf("StringBuilder b = new StringBuilder();\n")
   136  	g.Printf(`b.append("%s").append("{");`, obj.Name())
   137  	g.Printf("\n")
   138  	for _, f := range fields {
   139  		n := f.Name()
   140  		g.Printf(`b.append("%s:").append(get%s()).append(",");`, n, n)
   141  		g.Printf("\n")
   142  	}
   143  	g.Printf(`return b.append("}").toString();`)
   144  	g.Printf("\n")
   145  	g.Outdent()
   146  	g.Printf("}\n\n")
   147  
   148  	g.Outdent()
   149  	g.Printf("}\n\n")
   150  }
   151  
   152  func (g *javaGen) genInterfaceStub(o *types.TypeName, m *types.Interface) {
   153  	g.Printf("public static abstract class Stub implements %s {\n", o.Name())
   154  	g.Indent()
   155  
   156  	g.Printf("static final String DESCRIPTOR = \"go.%s.%s\";\n\n", g.pkg.Name(), o.Name())
   157  	g.Printf("private final go.Seq.Ref ref;\n")
   158  	g.Printf("public Stub() {\n    ref = go.Seq.createRef(this);\n}\n\n")
   159  	g.Printf("public go.Seq.Ref ref() { return ref; }\n\n")
   160  
   161  	g.Printf("public void call(int code, go.Seq in, go.Seq out) {\n")
   162  	g.Indent()
   163  	g.Printf("switch (code) {\n")
   164  
   165  	for i := 0; i < m.NumMethods(); i++ {
   166  		f := m.Method(i)
   167  		g.Printf("case Proxy.CALL_%s: {\n", f.Name())
   168  		g.Indent()
   169  
   170  		sig := f.Type().(*types.Signature)
   171  		params := sig.Params()
   172  		for i := 0; i < params.Len(); i++ {
   173  			p := sig.Params().At(i)
   174  			jt := g.javaType(p.Type())
   175  			g.Printf("%s param_%s;\n", jt, paramName(params, i))
   176  			g.genRead("param_"+paramName(params, i), "in", p.Type())
   177  		}
   178  
   179  		res := sig.Results()
   180  		var returnsError bool
   181  		var numRes = res.Len()
   182  		if (res.Len() == 1 && isErrorType(res.At(0).Type())) ||
   183  			(res.Len() == 2 && isErrorType(res.At(1).Type())) {
   184  			numRes -= 1
   185  			returnsError = true
   186  		}
   187  
   188  		if returnsError {
   189  			g.Printf("try {\n")
   190  			g.Indent()
   191  		}
   192  
   193  		if numRes > 0 {
   194  			g.Printf("%s result = ", g.javaType(res.At(0).Type()))
   195  		}
   196  
   197  		g.Printf("this.%s(", f.Name())
   198  		for i := 0; i < params.Len(); i++ {
   199  			if i > 0 {
   200  				g.Printf(", ")
   201  			}
   202  			g.Printf("param_%s", paramName(params, i))
   203  		}
   204  		g.Printf(");\n")
   205  
   206  		if numRes > 0 {
   207  			g.Printf("out.write%s;\n", seqWrite(res.At(0).Type(), "result"))
   208  		}
   209  		if returnsError {
   210  			g.Printf("out.writeString(null);\n")
   211  			g.Outdent()
   212  			g.Printf("} catch (Exception e) {\n")
   213  			g.Indent()
   214  			if numRes > 0 {
   215  				resTyp := res.At(0).Type()
   216  				g.Printf("%s result = %s;\n", g.javaType(resTyp), g.javaTypeDefault(resTyp))
   217  				g.Printf("out.write%s;\n", seqWrite(resTyp, "result"))
   218  			}
   219  			g.Printf("out.writeString(e.getMessage());\n")
   220  			g.Outdent()
   221  			g.Printf("}\n")
   222  		}
   223  		g.Printf("return;\n")
   224  		g.Outdent()
   225  		g.Printf("}\n")
   226  	}
   227  
   228  	g.Printf("default:\n    throw new RuntimeException(\"unknown code: \"+ code);\n")
   229  	g.Printf("}\n")
   230  	g.Outdent()
   231  	g.Printf("}\n")
   232  
   233  	g.Outdent()
   234  	g.Printf("}\n\n")
   235  }
   236  
   237  const javaProxyPreamble = `static final class Proxy implements %s {
   238      static final String DESCRIPTOR = Stub.DESCRIPTOR;
   239  
   240      private go.Seq.Ref ref;
   241  
   242      Proxy(go.Seq.Ref ref) { this.ref = ref; }
   243  
   244      public go.Seq.Ref ref() { return ref; }
   245  
   246      public void call(int code, go.Seq in, go.Seq out) {
   247          throw new RuntimeException("cycle: cannot call proxy");
   248      }
   249  
   250  `
   251  
   252  func (g *javaGen) genInterface(o *types.TypeName) {
   253  	iface := o.Type().(*types.Named).Underlying().(*types.Interface)
   254  
   255  	summary := makeIfaceSummary(iface)
   256  
   257  	g.Printf("public interface %s extends go.Seq.Object {\n", o.Name())
   258  	g.Indent()
   259  
   260  	methodSigErr := false
   261  	for _, m := range summary.callable {
   262  		if err := g.funcSignature(m, false); err != nil {
   263  			methodSigErr = true
   264  			g.errorf("%v", err)
   265  		}
   266  		g.Printf(";\n\n")
   267  	}
   268  	if methodSigErr {
   269  		return // skip stub generation, more of the same errors
   270  	}
   271  
   272  	if summary.implementable {
   273  		g.genInterfaceStub(o, iface)
   274  	}
   275  
   276  	g.Printf(javaProxyPreamble, o.Name())
   277  	g.Indent()
   278  
   279  	for _, m := range summary.callable {
   280  		g.genFunc(m, true)
   281  	}
   282  	for i, m := range summary.callable {
   283  		g.Printf("static final int CALL_%s = 0x%x0a;\n", m.Name(), i+1)
   284  	}
   285  
   286  	g.Outdent()
   287  	g.Printf("}\n")
   288  
   289  	g.Outdent()
   290  	g.Printf("}\n\n")
   291  }
   292  
   293  func isJavaPrimitive(T types.Type) bool {
   294  	b, ok := T.(*types.Basic)
   295  	if !ok {
   296  		return false
   297  	}
   298  	switch b.Kind() {
   299  	case types.Bool, types.Uint8, types.Float32, types.Float64,
   300  		types.Int, types.Int8, types.Int16, types.Int32, types.Int64:
   301  		return true
   302  	}
   303  	return false
   304  }
   305  
   306  // javaType returns a string that can be used as a Java type.
   307  func (g *javaGen) javaType(T types.Type) string {
   308  	if isErrorType(T) {
   309  		// The error type is usually translated into an exception in
   310  		// Java, however the type can be exposed in other ways, such
   311  		// as an exported field.
   312  		return "String"
   313  	}
   314  	switch T := T.(type) {
   315  	case *types.Basic:
   316  		switch T.Kind() {
   317  		case types.Bool:
   318  			return "boolean"
   319  		case types.Int:
   320  			return "long"
   321  		case types.Int8:
   322  			return "byte"
   323  		case types.Int16:
   324  			return "short"
   325  		case types.Int32:
   326  			return "int"
   327  		case types.Int64:
   328  			return "long"
   329  		case types.Uint8:
   330  			// TODO(crawshaw): Java bytes are signed, so this is
   331  			// questionable, but vital.
   332  			return "byte"
   333  		// TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64:
   334  		case types.Float32:
   335  			return "float"
   336  		case types.Float64:
   337  			return "double"
   338  		case types.String:
   339  			return "String"
   340  		default:
   341  			g.errorf("unsupported return type: %s", T)
   342  			return "TODO"
   343  		}
   344  	case *types.Slice:
   345  		elem := g.javaType(T.Elem())
   346  		return elem + "[]"
   347  
   348  	case *types.Pointer:
   349  		if _, ok := T.Elem().(*types.Named); ok {
   350  			return g.javaType(T.Elem())
   351  		}
   352  		panic(fmt.Sprintf("unsupporter pointer to type: %s", T))
   353  	case *types.Named:
   354  		n := T.Obj()
   355  		if n.Pkg() != g.pkg {
   356  			nPkgName := "<nilpkg>"
   357  			if nPkg := n.Pkg(); nPkg != nil {
   358  				nPkgName = nPkg.Name()
   359  			}
   360  			panic(fmt.Sprintf("type %s is in package %s, must be defined in package %s", n.Name(), nPkgName, g.pkg.Name()))
   361  		}
   362  		// TODO(crawshaw): more checking here
   363  		return n.Name()
   364  	default:
   365  		g.errorf("unsupported javaType: %#+v, %s\n", T, T)
   366  		return "TODO"
   367  	}
   368  }
   369  
   370  // javaTypeDefault returns a string that represents the default value of the mapped java type.
   371  // TODO(hyangah): Combine javaType and javaTypeDefault?
   372  func (g *javaGen) javaTypeDefault(T types.Type) string {
   373  	switch T := T.(type) {
   374  	case *types.Basic:
   375  		switch T.Kind() {
   376  		case types.Bool:
   377  			return "false"
   378  		case types.Int, types.Int8, types.Int16, types.Int32,
   379  			types.Int64, types.Uint8, types.Float32, types.Float64:
   380  			return "0"
   381  		case types.String:
   382  			return "null"
   383  		default:
   384  			g.errorf("unsupported return type: %s", T)
   385  			return "TODO"
   386  		}
   387  	case *types.Slice, *types.Pointer, *types.Named:
   388  		return "null"
   389  
   390  	default:
   391  		g.errorf("unsupported javaType: %#+v, %s\n", T, T)
   392  		return "TODO"
   393  	}
   394  }
   395  
   396  var paramRE = regexp.MustCompile(`^p[0-9]*$`)
   397  
   398  // paramName replaces incompatible name with a p0-pN name.
   399  // Missing names, or existing names of the form p[0-9] are incompatible.
   400  // TODO(crawshaw): Replace invalid unicode names.
   401  func paramName(params *types.Tuple, pos int) string {
   402  	name := params.At(pos).Name()
   403  	if name == "" || name == "_" || paramRE.MatchString(name) {
   404  		name = fmt.Sprintf("p%d", pos)
   405  	}
   406  	return name
   407  }
   408  
   409  func (g *javaGen) funcSignature(o *types.Func, static bool) error {
   410  	sig := o.Type().(*types.Signature)
   411  	res := sig.Results()
   412  
   413  	var returnsError bool
   414  	var ret string
   415  	switch res.Len() {
   416  	case 2:
   417  		if !isErrorType(res.At(1).Type()) {
   418  			return fmt.Errorf("second result value must be of type error: %s", o)
   419  		}
   420  		returnsError = true
   421  		ret = g.javaType(res.At(0).Type())
   422  	case 1:
   423  		if isErrorType(res.At(0).Type()) {
   424  			returnsError = true
   425  			ret = "void"
   426  		} else {
   427  			ret = g.javaType(res.At(0).Type())
   428  		}
   429  	case 0:
   430  		ret = "void"
   431  	default:
   432  		return fmt.Errorf("too many result values: %s", o)
   433  	}
   434  
   435  	g.Printf("public ")
   436  	if static {
   437  		g.Printf("static ")
   438  	}
   439  	g.Printf("%s %s(", ret, o.Name())
   440  	params := sig.Params()
   441  	for i := 0; i < params.Len(); i++ {
   442  		if i > 0 {
   443  			g.Printf(", ")
   444  		}
   445  		v := sig.Params().At(i)
   446  		name := paramName(params, i)
   447  		jt := g.javaType(v.Type())
   448  		g.Printf("%s %s", jt, name)
   449  	}
   450  	g.Printf(")")
   451  	if returnsError {
   452  		g.Printf(" throws Exception")
   453  	}
   454  	return nil
   455  }
   456  
   457  func (g *javaGen) genFunc(o *types.Func, method bool) {
   458  	if err := g.funcSignature(o, !method); err != nil {
   459  		g.errorf("%v", err)
   460  		return
   461  	}
   462  	sig := o.Type().(*types.Signature)
   463  	res := sig.Results()
   464  
   465  	g.Printf(" {\n")
   466  	g.Indent()
   467  	g.Printf("go.Seq _in = new go.Seq();\n")
   468  	g.Printf("go.Seq _out = new go.Seq();\n")
   469  
   470  	returnsError := false
   471  	var resultType types.Type
   472  	if res.Len() > 0 {
   473  		if !isErrorType(res.At(0).Type()) {
   474  			resultType = res.At(0).Type()
   475  		}
   476  		if res.Len() > 1 || isErrorType(res.At(0).Type()) {
   477  			returnsError = true
   478  		}
   479  	}
   480  	if resultType != nil {
   481  		t := g.javaType(resultType)
   482  		g.Printf("%s _result;\n", t)
   483  	}
   484  
   485  	if method {
   486  		g.Printf("_in.writeRef(ref);\n")
   487  	}
   488  	params := sig.Params()
   489  	for i := 0; i < params.Len(); i++ {
   490  		p := params.At(i)
   491  		g.Printf("_in.write%s;\n", seqWrite(p.Type(), paramName(params, i)))
   492  	}
   493  	g.Printf("Seq.send(DESCRIPTOR, CALL_%s, _in, _out);\n", o.Name())
   494  	if resultType != nil {
   495  		g.genRead("_result", "_out", resultType)
   496  	}
   497  	if returnsError {
   498  		g.Printf(`String _err = _out.readString();
   499  if (_err != null) {
   500      throw new Exception(_err);
   501  }
   502  `)
   503  	}
   504  	if resultType != nil {
   505  		g.Printf("return _result;\n")
   506  	}
   507  	g.Outdent()
   508  	g.Printf("}\n\n")
   509  }
   510  
   511  func (g *javaGen) genRead(resName, seqName string, T types.Type) {
   512  	switch T := T.(type) {
   513  	case *types.Pointer:
   514  		// TODO(crawshaw): test *int
   515  		// TODO(crawshaw): test **Generator
   516  		switch T := T.Elem().(type) {
   517  		case *types.Named:
   518  			o := T.Obj()
   519  			if o.Pkg() != g.pkg {
   520  				g.errorf("type %s not defined in package %s", T, g.pkg)
   521  				return
   522  			}
   523  			g.Printf("%s = new %s(%s.readRef());\n", resName, o.Name(), seqName)
   524  		default:
   525  			g.errorf("unsupported type %s", T)
   526  		}
   527  	case *types.Named:
   528  		switch T.Underlying().(type) {
   529  		case *types.Interface, *types.Pointer:
   530  			o := T.Obj()
   531  			if o.Pkg() != g.pkg {
   532  				g.errorf("type %s not defined in package %s", T, g.pkg)
   533  				return
   534  			}
   535  			g.Printf("%s = new %s.Proxy(%s.readRef());\n", resName, o.Name(), seqName)
   536  		default:
   537  			g.errorf("unsupported, direct named type %s", T)
   538  		}
   539  	default:
   540  		g.Printf("%s = %s.read%s();\n", resName, seqName, seqType(T))
   541  	}
   542  }
   543  
   544  func (g *javaGen) errorf(format string, args ...interface{}) {
   545  	g.err = append(g.err, fmt.Errorf(format, args...))
   546  }
   547  
   548  const javaPreamble = `// Java Package %s is a proxy for talking to a Go program.
   549  //   gobind -lang=java %s
   550  //
   551  // File is generated by gobind. Do not edit.
   552  package go.%s;
   553  
   554  import go.Seq;
   555  
   556  `
   557  
   558  var javaNameReplacer = strings.NewReplacer(
   559  	"-", "_",
   560  	".", "_",
   561  )
   562  
   563  func (g *javaGen) javaPkgName() string {
   564  	s := javaNameReplacer.Replace(g.pkg.Name())
   565  	// Look for Java keywords that are not Go keywords, and avoid using
   566  	// them as a package name.
   567  	//
   568  	// This is not a problem for normal Go identifiers as we only expose
   569  	// exported symbols. The upper case first letter saves everything
   570  	// from accidentally matching except for the package name.
   571  	//
   572  	// Note that basic type names (like int) are not keywords in Go.
   573  	switch s {
   574  	case "abstract", "assert", "boolean", "byte", "catch", "char", "class",
   575  		"do", "double", "enum", "extends", "final", "finally", "float",
   576  		"implements", "instanceof", "int", "long", "native", "private",
   577  		"protected", "public", "short", "static", "strictfp", "super",
   578  		"synchronized", "this", "throw", "throws", "transient", "try",
   579  		"void", "volatile", "while":
   580  		s += "_"
   581  	}
   582  	return s
   583  }
   584  
   585  func (g *javaGen) className() string {
   586  	return strings.Title(javaNameReplacer.Replace(g.pkg.Name()))
   587  }
   588  
   589  func (g *javaGen) gen() error {
   590  	g.Printf(javaPreamble, g.javaPkgName(), g.pkg.Path(), g.javaPkgName())
   591  
   592  	g.Printf("public abstract class %s {\n", g.className())
   593  	g.Indent()
   594  	g.Printf("private %s() {} // uninstantiable\n\n", g.className())
   595  	scope := g.pkg.Scope()
   596  	names := scope.Names()
   597  	var funcs []string
   598  	for _, name := range names {
   599  		obj := scope.Lookup(name)
   600  		if !obj.Exported() {
   601  			continue
   602  		}
   603  
   604  		switch o := obj.(type) {
   605  		// TODO(crawshaw): case *types.Const:
   606  		// TODO(crawshaw): case *types.Var:
   607  		case *types.Func:
   608  			if isCallable(o) {
   609  				g.genFunc(o, false)
   610  				funcs = append(funcs, o.Name())
   611  			}
   612  		case *types.TypeName:
   613  			named := o.Type().(*types.Named)
   614  			switch t := named.Underlying().(type) {
   615  			case *types.Struct:
   616  				g.genStruct(o, t)
   617  			case *types.Interface:
   618  				g.genInterface(o)
   619  			default:
   620  				g.errorf("%s: cannot generate binding for %s: %T", g.fset.Position(o.Pos()), o.Name(), t)
   621  				continue
   622  			}
   623  		default:
   624  			g.errorf("unsupported exported type: ", obj)
   625  		}
   626  	}
   627  
   628  	for i, name := range funcs {
   629  		g.Printf("private static final int CALL_%s = %d;\n", name, i+1)
   630  	}
   631  
   632  	g.Printf("private static final String DESCRIPTOR = %q;\n", g.pkg.Name())
   633  	g.Outdent()
   634  	g.Printf("}\n")
   635  
   636  	if len(g.err) > 0 {
   637  		return g.err
   638  	}
   639  	return nil
   640  }