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 }