go.mobile/bind: language binding generator
Details: http://golang.org/s/gobind LGTM=adonovan R=adonovan CC=golang-codereviews https://golang.org/cl/118240044
This commit is contained in:
parent
1e86c633f3
commit
9f144f9410
56
bind/bind.go
Normal file
56
bind/bind.go
Normal file
@ -0,0 +1,56 @@
|
||||
// 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 implements a code generator for gobind.
|
||||
//
|
||||
// See the documentation on the gobind command for usage details.
|
||||
package bind
|
||||
|
||||
// TODO(crawshaw): slice support
|
||||
// TODO(crawshaw): channel support
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"go/format"
|
||||
"go/token"
|
||||
"io"
|
||||
|
||||
"code.google.com/p/go.tools/go/types"
|
||||
)
|
||||
|
||||
// GenJava generates a Java API from a Go package.
|
||||
func GenJava(w io.Writer, fset *token.FileSet, pkg *types.Package) error {
|
||||
buf := new(bytes.Buffer)
|
||||
g := &javaGen{
|
||||
printer: &printer{buf: buf, indentEach: []byte(" ")},
|
||||
fset: fset,
|
||||
pkg: pkg,
|
||||
}
|
||||
if err := g.gen(); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := io.Copy(w, buf)
|
||||
return err
|
||||
}
|
||||
|
||||
// GenGo generates a Go stub to support foreign language APIs.
|
||||
func GenGo(w io.Writer, fset *token.FileSet, pkg *types.Package) error {
|
||||
buf := new(bytes.Buffer)
|
||||
g := &goGen{
|
||||
printer: &printer{buf: buf, indentEach: []byte("\t")},
|
||||
fset: fset,
|
||||
pkg: pkg,
|
||||
}
|
||||
if err := g.gen(); err != nil {
|
||||
return err
|
||||
}
|
||||
src := buf.Bytes()
|
||||
srcf, err := format.Source(src)
|
||||
if err != nil {
|
||||
w.Write(src) // for debugging
|
||||
return err
|
||||
}
|
||||
_, err = w.Write(srcf)
|
||||
return err
|
||||
}
|
126
bind/bind_test.go
Normal file
126
bind/bind_test.go
Normal file
@ -0,0 +1,126 @@
|
||||
package bind
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io/ioutil"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
_ "code.google.com/p/go.tools/go/gcimporter"
|
||||
"code.google.com/p/go.tools/go/types"
|
||||
)
|
||||
|
||||
var updateFlag = flag.Bool("update", false, "Update the golden files.")
|
||||
|
||||
var tests = []string{
|
||||
"testdata/basictypes.go",
|
||||
"testdata/structs.go",
|
||||
"testdata/interfaces.go",
|
||||
}
|
||||
|
||||
var fset = token.NewFileSet()
|
||||
|
||||
func typeCheck(t *testing.T, filename string) *types.Package {
|
||||
f, err := parser.ParseFile(fset, filename, nil, parser.AllErrors)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: %v", filename, err)
|
||||
}
|
||||
|
||||
pkgName := filepath.Base(filename)
|
||||
pkgName = strings.TrimSuffix(pkgName, ".go")
|
||||
|
||||
// typecheck and collect typechecker errors
|
||||
var conf types.Config
|
||||
conf.Error = func(err error) {
|
||||
t.Error(err)
|
||||
}
|
||||
pkg, err := conf.Check(pkgName, fset, []*ast.File{f}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return pkg
|
||||
}
|
||||
|
||||
// diff runs the command "diff a b" and returns its output
|
||||
func diff(a, b string) string {
|
||||
var buf bytes.Buffer
|
||||
var cmd *exec.Cmd
|
||||
switch runtime.GOOS {
|
||||
case "plan9":
|
||||
cmd = exec.Command("/bin/diff", "-c", a, b)
|
||||
default:
|
||||
cmd = exec.Command("/usr/bin/diff", "-u", a, b)
|
||||
}
|
||||
cmd.Stdout = &buf
|
||||
cmd.Stderr = &buf
|
||||
cmd.Run()
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func writeTempFile(t *testing.T, name string, contents []byte) string {
|
||||
f, err := ioutil.TempFile("", name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := f.Write(contents); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return f.Name()
|
||||
}
|
||||
|
||||
func TestGenJava(t *testing.T) {
|
||||
for _, filename := range tests {
|
||||
var buf bytes.Buffer
|
||||
pkg := typeCheck(t, filename)
|
||||
if err := GenJava(&buf, fset, pkg); err != nil {
|
||||
t.Errorf("%s: %v", filename, err)
|
||||
continue
|
||||
}
|
||||
out := writeTempFile(t, "java", buf.Bytes())
|
||||
golden := filename[:len(filename)-len(".go")] + ".java.golden"
|
||||
if diffstr := diff(golden, out); diffstr != "" {
|
||||
t.Errorf("%s: does not match Java golden:\n%s", filename, diffstr)
|
||||
|
||||
if *updateFlag {
|
||||
t.Logf("Updating %s...", golden)
|
||||
if err := exec.Command("/bin/cp", out, golden).Run(); err != nil {
|
||||
t.Errorf("Update failed: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenGo(t *testing.T) {
|
||||
for _, filename := range tests {
|
||||
var buf bytes.Buffer
|
||||
pkg := typeCheck(t, filename)
|
||||
if err := GenGo(&buf, fset, pkg); err != nil {
|
||||
t.Errorf("%s: %v", filename, err)
|
||||
continue
|
||||
}
|
||||
out := writeTempFile(t, "go", buf.Bytes())
|
||||
golden := filename + ".golden"
|
||||
if diffstr := diff(golden, out); diffstr != "" {
|
||||
t.Errorf("%s: does not match Java golden:\n%s", filename, diffstr)
|
||||
|
||||
if *updateFlag {
|
||||
t.Logf("Updating %s...", golden)
|
||||
if err := exec.Command("/bin/cp", out, golden).Run(); err != nil {
|
||||
t.Errorf("Update failed: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
338
bind/gengo.go
Normal file
338
bind/gengo.go
Normal file
@ -0,0 +1,338 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
"go/token"
|
||||
"log"
|
||||
|
||||
"code.google.com/p/go.tools/go/types"
|
||||
)
|
||||
|
||||
type goGen struct {
|
||||
*printer
|
||||
fset *token.FileSet
|
||||
pkg *types.Package
|
||||
err ErrorList
|
||||
}
|
||||
|
||||
func (g *goGen) errorf(format string, args ...interface{}) {
|
||||
g.err = append(g.err, fmt.Errorf(format, args...))
|
||||
}
|
||||
|
||||
const goPreamble = `// Package go_%s is an autogenerated binder stub for package %s.
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package go_%s
|
||||
|
||||
import (
|
||||
"code.google.com/p/go.mobile/bind/seq"
|
||||
%q
|
||||
)
|
||||
|
||||
`
|
||||
|
||||
func (g *goGen) genPreamble() {
|
||||
n := g.pkg.Name()
|
||||
g.Printf(goPreamble, n, n, n, g.pkg.Path())
|
||||
}
|
||||
|
||||
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)
|
||||
t := seqType(p.Type())
|
||||
if t == "Ref" {
|
||||
name := p.Type().(*types.Named).Obj().Name()
|
||||
g.Printf("var param_%s %s.%s\n", p.Name(), g.pkg.Name(), name)
|
||||
g.Printf("param_%s_ref := in.ReadRef()\n", p.Name())
|
||||
g.Printf("if param_%s_ref.Num < 0 {\n", p.Name())
|
||||
g.Printf(" param_%s = param_%s_ref.Get().(%s.%s)\n", p.Name(), p.Name(), g.pkg.Name(), name)
|
||||
g.Printf("} else {\n")
|
||||
g.Printf(" param_%s = (*proxy%s)(param_%s_ref)\n", p.Name(), name, p.Name())
|
||||
g.Printf("}\n")
|
||||
} else {
|
||||
g.Printf("param_%s := in.Read%s()\n", p.Name(), t)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
returnsValue := false
|
||||
returnsError := false
|
||||
if res.Len() == 1 {
|
||||
if isErrorType(res.At(0).Type()) {
|
||||
returnsError = true
|
||||
g.Printf("err := ")
|
||||
} else {
|
||||
returnsValue = true
|
||||
g.Printf("res := ")
|
||||
}
|
||||
} else if res.Len() == 2 {
|
||||
returnsValue = true
|
||||
returnsError = true
|
||||
g.Printf("res, err := ")
|
||||
}
|
||||
|
||||
g.Printf("%s.%s(", selectorLHS, o.Name())
|
||||
for i := 0; i < params.Len(); i++ {
|
||||
if i > 0 {
|
||||
g.Printf(", ")
|
||||
}
|
||||
g.Printf("param_%s", params.At(i).Name())
|
||||
}
|
||||
g.Printf(")\n")
|
||||
|
||||
if returnsValue {
|
||||
g.genWrite("res", "out", res.At(0).Type())
|
||||
}
|
||||
if returnsError {
|
||||
g.genWrite("err", "out", res.At(res.Len()-1).Type())
|
||||
}
|
||||
}
|
||||
|
||||
func (g *goGen) genWrite(valName, seqName string, T types.Type) {
|
||||
if isErrorType(T) {
|
||||
g.Printf("if %s == nil {\n", valName)
|
||||
g.Printf(" %s.WriteUTF16(\"\");\n", seqName)
|
||||
g.Printf("} else {\n")
|
||||
g.Printf(" %s.WriteUTF16(%s.Error());\n", seqName, valName)
|
||||
g.Printf("}\n")
|
||||
return
|
||||
}
|
||||
switch T := T.(type) {
|
||||
case *types.Pointer:
|
||||
// TODO(crawshaw): test *int
|
||||
// TODO(crawshaw): test **Generator
|
||||
switch T := T.Elem().(type) {
|
||||
case *types.Named:
|
||||
obj := T.Obj()
|
||||
if obj.Pkg() != g.pkg {
|
||||
g.errorf("type %s not defined in package %s", T, g.pkg)
|
||||
return
|
||||
}
|
||||
g.Printf("%s.WriteGoRef(%s)\n", seqName, valName)
|
||||
default:
|
||||
g.errorf("unsupported type %s", T)
|
||||
}
|
||||
case *types.Named:
|
||||
switch u := T.Underlying().(type) {
|
||||
case *types.Interface, *types.Pointer:
|
||||
g.Printf("%s.WriteGoRef(%s)\n", seqName, valName)
|
||||
default:
|
||||
g.errorf("unsupported, direct named type %s: %s", T, u)
|
||||
}
|
||||
default:
|
||||
g.Printf("%s.Write%s(%s);\n", seqName, seqType(T), valName)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *goGen) genFunc(o *types.Func) {
|
||||
g.Printf("func proxy_%s(out, in *seq.Buffer) {\n", o.Name())
|
||||
g.Indent()
|
||||
g.genFuncBody(o, g.pkg.Name())
|
||||
g.Outdent()
|
||||
g.Printf("}\n\n")
|
||||
}
|
||||
|
||||
func exportedMethodSet(T types.Type) []*types.Func {
|
||||
var methods []*types.Func
|
||||
methodset := types.NewMethodSet(T)
|
||||
for i := 0; i < methodset.Len(); i++ {
|
||||
obj := methodset.At(i).Obj()
|
||||
if !obj.Exported() {
|
||||
continue
|
||||
}
|
||||
switch obj := obj.(type) {
|
||||
case *types.Func:
|
||||
methods = append(methods, obj)
|
||||
default:
|
||||
log.Panicf("unexpected methodset obj: %s", obj)
|
||||
}
|
||||
}
|
||||
return methods
|
||||
}
|
||||
|
||||
func exportedFields(T *types.Struct) []*types.Var {
|
||||
var fields []*types.Var
|
||||
for i := 0; i < T.NumFields(); i++ {
|
||||
f := T.Field(i)
|
||||
if !f.Exported() {
|
||||
continue
|
||||
}
|
||||
fields = append(fields, f)
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
func (g *goGen) genStruct(obj *types.TypeName, T *types.Struct) {
|
||||
fields := exportedFields(T)
|
||||
methods := exportedMethodSet(types.NewPointer(obj.Type()))
|
||||
|
||||
g.Printf("const (\n")
|
||||
g.Indent()
|
||||
g.Printf("proxy%sDescriptor = \"go.%s.%s\"\n", obj.Name(), g.pkg.Name(), obj.Name())
|
||||
for i, f := range fields {
|
||||
g.Printf("proxy%s%sGetCode = 0x%x0f\n", obj.Name(), f.Name(), i)
|
||||
g.Printf("proxy%s%sSetCode = 0x%x1f\n", obj.Name(), f.Name(), i)
|
||||
}
|
||||
for i, m := range methods {
|
||||
g.Printf("proxy%s%sCode = 0x%x0c\n", obj.Name(), m.Name(), i)
|
||||
}
|
||||
g.Outdent()
|
||||
g.Printf(")\n\n")
|
||||
|
||||
g.Printf("type proxy%s seq.Ref\n\n", obj.Name())
|
||||
|
||||
for _, f := range fields {
|
||||
g.Printf("func proxy%s%sSet(out, in *seq.Buffer) {\n", obj.Name(), f.Name())
|
||||
g.Indent()
|
||||
g.Printf("ref := in.ReadRef()\n")
|
||||
g.Printf("v := in.Read%s()\n", seqType(f.Type()))
|
||||
// TODO(crawshaw): other kinds of non-ptr types.
|
||||
g.Printf("ref.Get().(*%s.%s).%s = v\n", g.pkg.Name(), obj.Name(), f.Name())
|
||||
g.Outdent()
|
||||
g.Printf("}\n\n")
|
||||
|
||||
g.Printf("func proxy%s%sGet(out, in *seq.Buffer) {\n", obj.Name(), f.Name())
|
||||
g.Indent()
|
||||
g.Printf("ref := in.ReadRef()\n")
|
||||
g.Printf("v := ref.Get().(*%s.%s).%s\n", g.pkg.Name(), obj.Name(), f.Name())
|
||||
g.Printf("out.Write%s(v)\n", seqType(f.Type()))
|
||||
g.Outdent()
|
||||
g.Printf("}\n\n")
|
||||
}
|
||||
|
||||
for _, m := range methods {
|
||||
g.Printf("func proxy%s%s(out, in *seq.Buffer) {\n", obj.Name(), m.Name())
|
||||
g.Indent()
|
||||
g.Printf("ref := in.ReadRef()\n")
|
||||
g.Printf("v := ref.Get().(*%s.%s)\n", g.pkg.Name(), obj.Name())
|
||||
g.genFuncBody(m, "v")
|
||||
g.Outdent()
|
||||
g.Printf("}\n\n")
|
||||
}
|
||||
|
||||
g.Printf("func init() {\n")
|
||||
g.Indent()
|
||||
for _, f := range fields {
|
||||
n := f.Name()
|
||||
g.Printf("seq.Register(proxy%sDescriptor, proxy%s%sSetCode, proxy%s%sSet)\n", obj.Name(), obj.Name(), n, obj.Name(), n)
|
||||
g.Printf("seq.Register(proxy%sDescriptor, proxy%s%sGetCode, proxy%s%sGet)\n", obj.Name(), obj.Name(), n, obj.Name(), n)
|
||||
}
|
||||
for _, m := range methods {
|
||||
n := m.Name()
|
||||
g.Printf("seq.Register(proxy%sDescriptor, proxy%s%sCode, proxy%s%s)\n", obj.Name(), obj.Name(), n, obj.Name(), n)
|
||||
}
|
||||
g.Outdent()
|
||||
g.Printf("}\n\n")
|
||||
}
|
||||
|
||||
func (g *goGen) genInterface(obj *types.TypeName) {
|
||||
iface := obj.Type().(*types.Named).Underlying().(*types.Interface)
|
||||
|
||||
g.Printf("const (\n")
|
||||
g.Indent()
|
||||
g.Printf("proxy%sDescriptor = \"go.%s.%s\"\n", obj.Name(), g.pkg.Name(), obj.Name())
|
||||
for i := 0; i < iface.NumMethods(); i++ {
|
||||
g.Printf("proxy%s%sCode = 0x%x0a\n", obj.Name(), iface.Method(i).Name(), i+1)
|
||||
}
|
||||
g.Outdent()
|
||||
g.Printf(")\n\n")
|
||||
|
||||
g.Printf("type proxy%s seq.Ref\n\n", obj.Name())
|
||||
|
||||
for i := 0; i < iface.NumMethods(); i++ {
|
||||
m := iface.Method(i)
|
||||
sig := m.Type().(*types.Signature)
|
||||
params := sig.Params()
|
||||
g.Printf("func (p *proxy%s) %s(", obj.Name(), m.Name())
|
||||
for i := 0; i < params.Len(); i++ {
|
||||
if i > 0 {
|
||||
g.Printf(", ")
|
||||
}
|
||||
g.Printf("%s %s", paramName(params, i), params.At(i).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("res_%d %s", i, res.At(i).Type())
|
||||
}
|
||||
if res.Len() > 0 {
|
||||
g.Printf(")")
|
||||
}
|
||||
g.Printf(" {\n")
|
||||
g.Indent()
|
||||
|
||||
g.Printf("out := new(seq.Buffer)\n")
|
||||
for i := 0; i < params.Len(); i++ {
|
||||
p := params.At(i)
|
||||
g.Printf("out.Write%s\n", seqWrite(p.Type(), paramName(params, i)))
|
||||
}
|
||||
g.Printf("seq.Transact((*seq.Ref)(p), proxy%s%sCode, out)\n", obj.Name(), m.Name())
|
||||
|
||||
g.Outdent()
|
||||
g.Printf("}\n\n")
|
||||
}
|
||||
}
|
||||
|
||||
func (g *goGen) gen() error {
|
||||
g.genPreamble()
|
||||
|
||||
var funcs []string
|
||||
|
||||
scope := g.pkg.Scope()
|
||||
names := scope.Names()
|
||||
for _, name := range names {
|
||||
obj := scope.Lookup(name)
|
||||
if !obj.Exported() {
|
||||
continue
|
||||
}
|
||||
|
||||
switch obj := obj.(type) {
|
||||
// TODO(crawshaw): case *types.Const:
|
||||
// TODO(crawshaw): case *types.Var:
|
||||
case *types.Func:
|
||||
g.genFunc(obj)
|
||||
funcs = append(funcs, obj.Name())
|
||||
case *types.TypeName:
|
||||
named := obj.Type().(*types.Named)
|
||||
switch T := named.Underlying().(type) {
|
||||
case *types.Struct:
|
||||
g.genStruct(obj, T)
|
||||
case *types.Interface:
|
||||
g.genInterface(obj)
|
||||
}
|
||||
|
||||
default:
|
||||
g.errorf("not yet supported, name for %v / %T", obj, obj)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
g.Printf("func init() {\n")
|
||||
g.Indent()
|
||||
for i, name := range funcs {
|
||||
g.Printf("seq.Register(%q, %d, proxy_%s)\n", g.pkg.Name(), i+1, name)
|
||||
}
|
||||
g.Outdent()
|
||||
g.Printf("}\n")
|
||||
|
||||
if len(g.err) > 0 {
|
||||
return g.err
|
||||
}
|
||||
return nil
|
||||
}
|
541
bind/genjava.go
Normal file
541
bind/genjava.go
Normal file
@ -0,0 +1,541 @@
|
||||
// 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/token"
|
||||
"io"
|
||||
"regexp"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"code.google.com/p/go.tools/go/types"
|
||||
)
|
||||
|
||||
// TODO(crawshaw): disallow basic android java type names in exported symbols.
|
||||
// TODO(crawshaw): generate all relevant "implements" relationships for interfaces.
|
||||
// TODO(crawshaw): consider introducing Java functions for casting to and from interfaces at runtime.
|
||||
|
||||
type ErrorList []error
|
||||
|
||||
func (list ErrorList) Error() string {
|
||||
buf := new(bytes.Buffer)
|
||||
for i, err := range list {
|
||||
if i > 0 {
|
||||
buf.WriteRune('\n')
|
||||
}
|
||||
io.WriteString(buf, err.Error())
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
type javaGen struct {
|
||||
*printer
|
||||
nextCode int
|
||||
fset *token.FileSet
|
||||
pkg *types.Package
|
||||
err ErrorList
|
||||
}
|
||||
|
||||
func (g *javaGen) genStruct(obj *types.TypeName, T *types.Struct) {
|
||||
fields := exportedFields(T)
|
||||
methods := exportedMethodSet(types.NewPointer(obj.Type()))
|
||||
|
||||
g.Printf("public static final class %s implements go.Seq.Object {\n", obj.Name())
|
||||
g.Indent()
|
||||
g.Printf("private static final String DESCRIPTOR = \"go.%s.%s\";\n", g.pkg.Name(), obj.Name())
|
||||
for i, f := range fields {
|
||||
g.Printf("private static final int FIELD_%s_GET = 0x%x0f;\n", f.Name(), i)
|
||||
g.Printf("private static final int FIELD_%s_SET = 0x%x1f;\n", f.Name(), i)
|
||||
}
|
||||
for i, m := range methods {
|
||||
g.Printf("private static final int CALL_%s = 0x%x0c;\n", m.Name(), i)
|
||||
}
|
||||
g.Printf("\n")
|
||||
|
||||
g.Printf("private go.Seq.Ref ref;\n\n")
|
||||
|
||||
n := obj.Name()
|
||||
g.Printf("private %s(go.Seq.Ref ref) { this.ref = ref; }\n\n", n)
|
||||
g.Printf(`public go.Seq.Ref ref() { return ref; }
|
||||
|
||||
public void call(int code, go.Seq in, go.Seq out) {
|
||||
throw new RuntimeException("internal error: cycle: cannot call concrete proxy");
|
||||
}
|
||||
|
||||
`)
|
||||
|
||||
for _, f := range fields {
|
||||
g.Printf("public %s get%s() {\n", g.javaType(f.Type()), f.Name())
|
||||
g.Indent()
|
||||
g.Printf("Seq in = new Seq();\n")
|
||||
g.Printf("Seq out = new Seq();\n")
|
||||
g.Printf("in.writeRef(ref);\n")
|
||||
g.Printf("Seq.send(DESCRIPTOR, FIELD_%s_GET, in, out);\n", f.Name())
|
||||
g.Printf("return out.read%s;\n", seqRead(f.Type()))
|
||||
g.Outdent()
|
||||
g.Printf("}\n\n")
|
||||
|
||||
g.Printf("public void set%s(%s v) {\n", f.Name(), g.javaType(f.Type()))
|
||||
g.Indent()
|
||||
g.Printf("Seq in = new Seq();\n")
|
||||
g.Printf("Seq out = new Seq();\n")
|
||||
g.Printf("in.writeRef(ref);\n")
|
||||
g.Printf("in.write%s;\n", seqWrite(f.Type(), "v"))
|
||||
g.Printf("Seq.send(DESCRIPTOR, FIELD_%s_SET, in, out);\n", f.Name())
|
||||
g.Outdent()
|
||||
g.Printf("}\n")
|
||||
}
|
||||
g.Printf("\n")
|
||||
|
||||
for _, m := range methods {
|
||||
g.genFunc(m, true)
|
||||
}
|
||||
|
||||
g.Printf("@Override public boolean equals(Object o) {\n")
|
||||
g.Indent()
|
||||
g.Printf("if (o == null || !(o instanceof %s)) {\n return false;\n}\n", n)
|
||||
g.Printf("%s that = (%s)o;\n", n, n)
|
||||
for _, f := range fields {
|
||||
nf := f.Name()
|
||||
g.Printf("%s this%s = get%s();\n", g.javaType(f.Type()), nf, nf)
|
||||
g.Printf("%s that%s = that.get%s();\n", g.javaType(f.Type()), nf, nf)
|
||||
if isJavaPrimitive(f.Type()) {
|
||||
g.Printf("if (this%s != that%s) {\n return false;\n}\n", nf, nf)
|
||||
} else {
|
||||
g.Printf("if (this%s == null) {\n", nf)
|
||||
g.Indent()
|
||||
g.Printf("if (that%s != null) {\n return false;\n}\n", nf)
|
||||
g.Outdent()
|
||||
g.Printf("} else if (!this%s.equals(that%s)) {\n return false;\n}\n", nf, nf)
|
||||
}
|
||||
}
|
||||
g.Printf("return true;\n")
|
||||
g.Outdent()
|
||||
g.Printf("}\n\n")
|
||||
|
||||
g.Printf("@Override public int hashCode() {\n")
|
||||
g.Printf(" return java.util.Arrays.hashCode(new Object[] {")
|
||||
for i, f := range fields {
|
||||
if i > 0 {
|
||||
g.Printf(", ")
|
||||
}
|
||||
g.Printf("get%s()", f.Name())
|
||||
}
|
||||
g.Printf("});\n")
|
||||
g.Printf("}\n\n")
|
||||
|
||||
// TODO(crawshaw): use String() string if it is defined.
|
||||
g.Printf("@Override public String toString() {\n")
|
||||
g.Indent()
|
||||
g.Printf("StringBuilder b = new StringBuilder();\n")
|
||||
g.Printf(`b.append("%s").append("{");`, obj.Name())
|
||||
g.Printf("\n")
|
||||
for _, f := range fields {
|
||||
n := f.Name()
|
||||
g.Printf(`b.append("%s:").append(get%s()).append(",");`, n, n)
|
||||
g.Printf("\n")
|
||||
}
|
||||
g.Printf(`return b.append("}").toString();`)
|
||||
g.Printf("\n")
|
||||
g.Outdent()
|
||||
g.Printf("}\n\n")
|
||||
|
||||
g.Outdent()
|
||||
g.Printf("}\n\n")
|
||||
}
|
||||
|
||||
func (g *javaGen) genInterfaceStub(o *types.TypeName, m *types.Interface) {
|
||||
g.Printf("public static abstract class Stub implements %s {\n", o.Name())
|
||||
g.Indent()
|
||||
|
||||
g.Printf("static final String DESCRIPTOR = \"go.%s.%s\";\n\n", g.pkg.Name(), o.Name())
|
||||
g.Printf("private final go.Seq.Ref ref;\n")
|
||||
g.Printf("public Stub() {\n ref = go.Seq.createRef(this);\n}\n\n")
|
||||
g.Printf("public go.Seq.Ref ref() { return ref; }\n\n")
|
||||
|
||||
g.Printf("public void call(int code, go.Seq in, go.Seq out) {\n")
|
||||
g.Indent()
|
||||
g.Printf("switch (code) {\n")
|
||||
|
||||
for i := 0; i < m.NumMethods(); i++ {
|
||||
f := m.Method(i)
|
||||
g.Printf("case Proxy.CALL_%s: {\n", f.Name())
|
||||
g.Indent()
|
||||
|
||||
sig := f.Type().(*types.Signature)
|
||||
for i := 0; i < sig.Params().Len(); i++ {
|
||||
p := sig.Params().At(i)
|
||||
jt := g.javaType(p.Type())
|
||||
g.Printf("%s param_%s = in.read%s;\n", jt, p.Name(), seqRead(p.Type()))
|
||||
}
|
||||
|
||||
// TODO(crawshaw): handle catching a Exception
|
||||
res := sig.Results()
|
||||
if res.Len() > 0 {
|
||||
g.Printf("%s result = ", g.javaType(res.At(0).Type()))
|
||||
}
|
||||
|
||||
g.Printf("this.%s(", f.Name())
|
||||
for i := 0; i < sig.Params().Len(); i++ {
|
||||
if i > 0 {
|
||||
g.Printf(", ")
|
||||
}
|
||||
g.Printf("param_%s", sig.Params().At(i).Name())
|
||||
}
|
||||
g.Printf(");\n")
|
||||
g.Printf("return;\n")
|
||||
g.Outdent()
|
||||
g.Printf("}\n")
|
||||
}
|
||||
|
||||
g.Printf("default:\n throw new RuntimeException(\"unknown code: \"+ code);\n")
|
||||
g.Printf("}\n")
|
||||
g.Outdent()
|
||||
g.Printf("}\n")
|
||||
|
||||
g.Outdent()
|
||||
g.Printf("}\n\n")
|
||||
}
|
||||
|
||||
const javaProxyPreamble = `static final class Proxy implements %s {
|
||||
static final String DESCRIPTOR = Stub.DESCRIPTOR;
|
||||
|
||||
private go.Seq.Ref ref;
|
||||
|
||||
Proxy(go.Seq.Ref ref) { this.ref = ref; }
|
||||
|
||||
public go.Seq.Ref ref() { return ref; }
|
||||
|
||||
public void call(int code, go.Seq in, go.Seq out) {
|
||||
throw new RuntimeException("cycle: cannot call proxy");
|
||||
}
|
||||
|
||||
`
|
||||
|
||||
func (g *javaGen) genInterface(o *types.TypeName) {
|
||||
iface := o.Type().(*types.Named).Underlying().(*types.Interface)
|
||||
|
||||
g.Printf("public interface %s extends go.Seq.Object {\n", o.Name())
|
||||
g.Indent()
|
||||
|
||||
methodSigErr := false
|
||||
for i := 0; i < iface.NumMethods(); i++ {
|
||||
if err := g.funcSignature(iface.Method(i), false); err != nil {
|
||||
methodSigErr = true
|
||||
g.errorf("%v", err)
|
||||
}
|
||||
g.Printf(";\n\n")
|
||||
}
|
||||
if methodSigErr {
|
||||
return // skip stub generation, more of the same errors
|
||||
}
|
||||
|
||||
g.genInterfaceStub(o, iface)
|
||||
|
||||
g.Printf(javaProxyPreamble, o.Name())
|
||||
g.Indent()
|
||||
|
||||
for i := 0; i < iface.NumMethods(); i++ {
|
||||
g.genFunc(iface.Method(i), true)
|
||||
}
|
||||
for i := 0; i < iface.NumMethods(); i++ {
|
||||
g.Printf("static final int CALL_%s = 0x%x0a;\n", iface.Method(i).Name(), i+1)
|
||||
}
|
||||
|
||||
g.Outdent()
|
||||
g.Printf("}\n")
|
||||
|
||||
g.Outdent()
|
||||
g.Printf("}\n\n")
|
||||
}
|
||||
|
||||
func isErrorType(T types.Type) bool {
|
||||
return T == types.Universe.Lookup("error").Type()
|
||||
}
|
||||
|
||||
func isJavaPrimitive(T types.Type) bool {
|
||||
b, ok := T.(*types.Basic)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
switch b.Kind() {
|
||||
case types.Bool, types.Uint8, types.Float32, types.Float64,
|
||||
types.Int, types.Int8, types.Int16, types.Int32, types.Int64:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// javaType returns a string that can be used as a Java type.
|
||||
func (g *javaGen) javaType(T types.Type) string {
|
||||
switch T := T.(type) {
|
||||
case *types.Basic:
|
||||
switch T.Kind() {
|
||||
case types.Bool:
|
||||
return "boolean"
|
||||
case types.Int:
|
||||
return "long"
|
||||
case types.Int8:
|
||||
return "byte"
|
||||
case types.Int16:
|
||||
return "short"
|
||||
case types.Int32:
|
||||
return "int"
|
||||
case types.Int64:
|
||||
return "long"
|
||||
case types.Uint8:
|
||||
// TODO(crawshaw): Java bytes are signed, so this is
|
||||
// questionable, but vital.
|
||||
return "byte"
|
||||
// TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64:
|
||||
case types.Float32:
|
||||
return "float"
|
||||
case types.Float64:
|
||||
return "double"
|
||||
case types.String:
|
||||
return "String"
|
||||
default:
|
||||
g.errorf("unsupported return type: %s", T)
|
||||
return "TODO"
|
||||
}
|
||||
case *types.Slice:
|
||||
elem := g.javaType(T.Elem())
|
||||
return elem + "[]"
|
||||
|
||||
case *types.Pointer:
|
||||
if _, ok := T.Elem().(*types.Named); ok {
|
||||
return g.javaType(T.Elem())
|
||||
}
|
||||
panic(fmt.Sprintf("unsupporter pointer to type: %s", T))
|
||||
case *types.Named:
|
||||
n := T.Obj()
|
||||
if n.Pkg() != g.pkg {
|
||||
panic(fmt.Sprintf("type %s is in package %s, must be defined in package %s", n.Name(), n.Pkg().Name(), g.pkg.Name()))
|
||||
}
|
||||
// TODO(crawshaw): more checking here
|
||||
return n.Name()
|
||||
default:
|
||||
g.errorf("unsupported javaType: %#+v, %s\n", T, T)
|
||||
return "TODO"
|
||||
}
|
||||
}
|
||||
|
||||
var paramRE = regexp.MustCompile(`^p[0-9]+$`)
|
||||
|
||||
// paramName replaces incompatible name with a p0-pN name.
|
||||
// Missing names, or existing names of the form p[0-9] are incompatible.
|
||||
// TODO(crawshaw): Replace invalid unicode names.
|
||||
func paramName(params *types.Tuple, pos int) string {
|
||||
name := params.At(pos).Name()
|
||||
if name == "" || paramRE.MatchString(name) {
|
||||
name = fmt.Sprintf("p%d", pos)
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func (g *javaGen) funcSignature(o *types.Func, static bool) error {
|
||||
sig := o.Type().(*types.Signature)
|
||||
res := sig.Results()
|
||||
|
||||
var returnsError bool
|
||||
var ret string
|
||||
switch res.Len() {
|
||||
case 2:
|
||||
if !isErrorType(res.At(1).Type()) {
|
||||
return fmt.Errorf("second result value must be of type error: %s", o)
|
||||
}
|
||||
returnsError = true
|
||||
ret = g.javaType(res.At(0).Type())
|
||||
case 1:
|
||||
if isErrorType(res.At(0).Type()) {
|
||||
returnsError = true
|
||||
ret = "void"
|
||||
} else {
|
||||
ret = g.javaType(res.At(0).Type())
|
||||
}
|
||||
case 0:
|
||||
ret = "void"
|
||||
default:
|
||||
return fmt.Errorf("too many result values: %s", o)
|
||||
}
|
||||
|
||||
g.Printf("public ")
|
||||
if static {
|
||||
g.Printf("static ")
|
||||
}
|
||||
g.Printf("%s %s(", ret, o.Name())
|
||||
params := sig.Params()
|
||||
for i := 0; i < params.Len(); i++ {
|
||||
if i > 0 {
|
||||
g.Printf(", ")
|
||||
}
|
||||
v := sig.Params().At(i)
|
||||
name := paramName(params, i)
|
||||
jt := g.javaType(v.Type())
|
||||
g.Printf("%s %s", jt, name)
|
||||
}
|
||||
g.Printf(")")
|
||||
if returnsError {
|
||||
g.Printf(" throws Exception")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *javaGen) genFunc(o *types.Func, method bool) {
|
||||
if err := g.funcSignature(o, !method); err != nil {
|
||||
g.errorf("%v", err)
|
||||
return
|
||||
}
|
||||
sig := o.Type().(*types.Signature)
|
||||
res := sig.Results()
|
||||
|
||||
g.Printf(" {\n")
|
||||
g.Indent()
|
||||
g.Printf("go.Seq _in = new go.Seq();\n")
|
||||
g.Printf("go.Seq _out = new go.Seq();\n")
|
||||
|
||||
returnsError := false
|
||||
var resultType types.Type
|
||||
if res.Len() > 0 {
|
||||
if !isErrorType(res.At(0).Type()) {
|
||||
resultType = res.At(0).Type()
|
||||
}
|
||||
if res.Len() > 1 || isErrorType(res.At(0).Type()) {
|
||||
returnsError = true
|
||||
}
|
||||
}
|
||||
if resultType != nil {
|
||||
t := g.javaType(resultType)
|
||||
g.Printf("%s _result;\n", t)
|
||||
}
|
||||
|
||||
if method {
|
||||
g.Printf("_in.writeRef(ref);\n")
|
||||
}
|
||||
params := sig.Params()
|
||||
for i := 0; i < params.Len(); i++ {
|
||||
p := params.At(i)
|
||||
g.Printf("_in.write%s;\n", seqWrite(p.Type(), p.Name()))
|
||||
}
|
||||
g.Printf("Seq.send(DESCRIPTOR, CALL_%s, _in, _out);\n", o.Name())
|
||||
if resultType != nil {
|
||||
g.genRead("_result", "_out", resultType)
|
||||
}
|
||||
if returnsError {
|
||||
g.Printf(`String _err = _out.readUTF16();
|
||||
if (_err != null) {
|
||||
throw new Exception(_err);
|
||||
}
|
||||
`)
|
||||
}
|
||||
if resultType != nil {
|
||||
g.Printf("return _result;\n")
|
||||
}
|
||||
g.Outdent()
|
||||
g.Printf("}\n\n")
|
||||
}
|
||||
|
||||
func (g *javaGen) genRead(resName, seqName string, T types.Type) {
|
||||
switch T := T.(type) {
|
||||
case *types.Pointer:
|
||||
// TODO(crawshaw): test *int
|
||||
// TODO(crawshaw): test **Generator
|
||||
switch T := T.Elem().(type) {
|
||||
case *types.Named:
|
||||
o := T.Obj()
|
||||
if o.Pkg() != g.pkg {
|
||||
g.errorf("type %s not defined in package %s", T, g.pkg)
|
||||
return
|
||||
}
|
||||
g.Printf("%s = new %s(%s.readRef());\n", resName, o.Name(), seqName)
|
||||
default:
|
||||
g.errorf("unsupported type %s", T)
|
||||
}
|
||||
case *types.Named:
|
||||
switch T.Underlying().(type) {
|
||||
case *types.Interface, *types.Pointer:
|
||||
o := T.Obj()
|
||||
if o.Pkg() != g.pkg {
|
||||
g.errorf("type %s not defined in package %s", T, g.pkg)
|
||||
return
|
||||
}
|
||||
g.Printf("%s = new %s.Proxy(%s.readRef());\n", resName, o.Name(), seqName)
|
||||
default:
|
||||
g.errorf("unsupported, direct named type %s", T)
|
||||
}
|
||||
default:
|
||||
g.Printf("%s = %s.read%s();\n", resName, seqName, seqType(T))
|
||||
}
|
||||
}
|
||||
|
||||
func (g *javaGen) errorf(format string, args ...interface{}) {
|
||||
g.err = append(g.err, fmt.Errorf(format, args...))
|
||||
}
|
||||
|
||||
const javaPreamble = `// Java Package %s is a proxy for talking to a Go program.
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package go.%s;
|
||||
|
||||
import go.Seq;
|
||||
|
||||
`
|
||||
|
||||
func (g *javaGen) gen() error {
|
||||
g.Printf(javaPreamble, g.pkg.Name(), g.pkg.Name())
|
||||
|
||||
firstRune, size := utf8.DecodeRuneInString(g.pkg.Name())
|
||||
className := string(unicode.ToUpper(firstRune)) + g.pkg.Name()[size:]
|
||||
|
||||
g.Printf("public abstract class %s {\n", className)
|
||||
g.Indent()
|
||||
g.Printf("private %s() {} // uninstantiable\n\n", className)
|
||||
scope := g.pkg.Scope()
|
||||
names := scope.Names()
|
||||
var funcs []string
|
||||
for _, name := range names {
|
||||
obj := scope.Lookup(name)
|
||||
if !obj.Exported() {
|
||||
continue
|
||||
}
|
||||
|
||||
switch o := obj.(type) {
|
||||
// TODO(crawshaw): case *types.Const:
|
||||
// TODO(crawshaw): case *types.Var:
|
||||
case *types.Func:
|
||||
g.genFunc(o, false)
|
||||
funcs = append(funcs, o.Name())
|
||||
case *types.TypeName:
|
||||
named := o.Type().(*types.Named)
|
||||
switch t := named.Underlying().(type) {
|
||||
case *types.Struct:
|
||||
g.genStruct(o, t)
|
||||
case *types.Interface:
|
||||
g.genInterface(o)
|
||||
default:
|
||||
g.errorf("%s: cannot generate binding for %s: %T", g.fset.Position(o.Pos()), o.Name(), t)
|
||||
continue
|
||||
}
|
||||
default:
|
||||
g.errorf("unsupported exported type: ", obj)
|
||||
}
|
||||
}
|
||||
|
||||
for i, name := range funcs {
|
||||
g.Printf("private static final int CALL_%s = %d;\n", name, i+1)
|
||||
}
|
||||
|
||||
g.Printf("private static final String DESCRIPTOR = %q;\n", g.pkg.Name())
|
||||
g.Outdent()
|
||||
g.Printf("}\n")
|
||||
|
||||
if len(g.err) > 0 {
|
||||
return g.err
|
||||
}
|
||||
return nil
|
||||
}
|
67
bind/printer.go
Normal file
67
bind/printer.go
Normal file
@ -0,0 +1,67 @@
|
||||
// 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"
|
||||
)
|
||||
|
||||
type printer struct {
|
||||
buf *bytes.Buffer
|
||||
indentEach []byte
|
||||
indentText []byte
|
||||
needIndent bool
|
||||
}
|
||||
|
||||
func (p *printer) writeIndent() error {
|
||||
if !p.needIndent {
|
||||
return nil
|
||||
}
|
||||
p.needIndent = false
|
||||
_, err := p.buf.Write(p.indentText)
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *printer) Write(b []byte) (n int, err error) {
|
||||
wrote := 0
|
||||
for len(b) > 0 {
|
||||
if err := p.writeIndent(); err != nil {
|
||||
return wrote, err
|
||||
}
|
||||
i := bytes.IndexByte(b, '\n')
|
||||
if i < 0 {
|
||||
break
|
||||
}
|
||||
n, err = p.buf.Write(b[0 : i+1])
|
||||
wrote += n
|
||||
if err != nil {
|
||||
return wrote, err
|
||||
}
|
||||
b = b[i+1:]
|
||||
p.needIndent = true
|
||||
}
|
||||
if len(b) > 0 {
|
||||
n, err = p.buf.Write(b)
|
||||
wrote += n
|
||||
}
|
||||
return wrote, err
|
||||
}
|
||||
|
||||
func (p *printer) Printf(format string, args ...interface{}) {
|
||||
if _, err := fmt.Fprintf(p, format, args...); err != nil {
|
||||
panic(fmt.Sprintf("printer: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *printer) Indent() {
|
||||
p.indentText = append(p.indentText, p.indentEach...)
|
||||
}
|
||||
|
||||
func (p *printer) Outdent() {
|
||||
if len(p.indentText) > len(p.indentEach)-1 {
|
||||
p.indentText = p.indentText[len(p.indentEach):]
|
||||
}
|
||||
}
|
66
bind/seq.go
Normal file
66
bind/seq.go
Normal file
@ -0,0 +1,66 @@
|
||||
package bind
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"code.google.com/p/go.tools/go/types"
|
||||
)
|
||||
|
||||
// seqType returns a string that can be used for reading and writing a
|
||||
// type using the seq library.
|
||||
func seqType(t types.Type) string {
|
||||
if isErrorType(t) {
|
||||
return "UTF16"
|
||||
}
|
||||
switch t := t.(type) {
|
||||
case *types.Basic:
|
||||
switch t.Kind() {
|
||||
case types.Int:
|
||||
return "Int"
|
||||
case types.Int8:
|
||||
return "Int8"
|
||||
case types.Int16:
|
||||
return "Int16"
|
||||
case types.Int32:
|
||||
return "Int32"
|
||||
case types.Int64:
|
||||
return "Int64"
|
||||
case types.Uint8:
|
||||
// TODO(crawshaw): questionable, but vital?
|
||||
return "Byte"
|
||||
// TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64:
|
||||
case types.Float32:
|
||||
return "Float32"
|
||||
case types.Float64:
|
||||
return "Float64"
|
||||
case types.String:
|
||||
return "UTF16"
|
||||
default:
|
||||
// Should be caught earlier in processing.
|
||||
panic(fmt.Sprintf("unsupported return type: %s", t))
|
||||
}
|
||||
case *types.Named:
|
||||
switch u := t.Underlying().(type) {
|
||||
case *types.Interface:
|
||||
return "Ref"
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported named seqType: %s / %T", u, u))
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported seqType: %s / %T", t, t))
|
||||
}
|
||||
}
|
||||
|
||||
func seqRead(o types.Type) string {
|
||||
t := seqType(o)
|
||||
return t + "()"
|
||||
}
|
||||
|
||||
func seqWrite(o types.Type, name string) string {
|
||||
t := seqType(o)
|
||||
if t == "Ref" {
|
||||
// TODO(crawshaw): do something cleaner, i.e. genWrite.
|
||||
return t + "(" + name + ".ref())"
|
||||
}
|
||||
return t + "(" + name + ")"
|
||||
}
|
11
bind/testdata/basictypes.go
vendored
Normal file
11
bind/testdata/basictypes.go
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
// 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 basictypes
|
||||
|
||||
func Ints(x int8, y int16, z int32, t int64, u int) {}
|
||||
|
||||
func Error() error { return nil }
|
||||
|
||||
func ErrorPair() (int, error) { return 0, nil }
|
43
bind/testdata/basictypes.go.golden
vendored
Normal file
43
bind/testdata/basictypes.go.golden
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
// Package go_basictypes is an autogenerated binder stub for package basictypes.
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package go_basictypes
|
||||
|
||||
import (
|
||||
"basictypes"
|
||||
"code.google.com/p/go.mobile/bind/seq"
|
||||
)
|
||||
|
||||
func proxy_Error(out, in *seq.Buffer) {
|
||||
err := basictypes.Error()
|
||||
if err == nil {
|
||||
out.WriteUTF16("")
|
||||
} else {
|
||||
out.WriteUTF16(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func proxy_ErrorPair(out, in *seq.Buffer) {
|
||||
res, err := basictypes.ErrorPair()
|
||||
out.WriteInt(res)
|
||||
if err == nil {
|
||||
out.WriteUTF16("")
|
||||
} else {
|
||||
out.WriteUTF16(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func proxy_Ints(out, in *seq.Buffer) {
|
||||
param_x := in.ReadInt8()
|
||||
param_y := in.ReadInt16()
|
||||
param_z := in.ReadInt32()
|
||||
param_t := in.ReadInt64()
|
||||
param_u := in.ReadInt()
|
||||
basictypes.Ints(param_x, param_y, param_z, param_t, param_u)
|
||||
}
|
||||
|
||||
func init() {
|
||||
seq.Register("basictypes", 1, proxy_Error)
|
||||
seq.Register("basictypes", 2, proxy_ErrorPair)
|
||||
seq.Register("basictypes", 3, proxy_Ints)
|
||||
}
|
49
bind/testdata/basictypes.java.golden
vendored
Normal file
49
bind/testdata/basictypes.java.golden
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
// Java Package basictypes is a proxy for talking to a Go program.
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package go.basictypes;
|
||||
|
||||
import go.Seq;
|
||||
|
||||
public abstract class Basictypes {
|
||||
private Basictypes() {} // uninstantiable
|
||||
|
||||
public static void Error() throws Exception {
|
||||
go.Seq _in = new go.Seq();
|
||||
go.Seq _out = new go.Seq();
|
||||
Seq.send(DESCRIPTOR, CALL_Error, _in, _out);
|
||||
String _err = _out.readUTF16();
|
||||
if (_err != null) {
|
||||
throw new Exception(_err);
|
||||
}
|
||||
}
|
||||
|
||||
public static long ErrorPair() throws Exception {
|
||||
go.Seq _in = new go.Seq();
|
||||
go.Seq _out = new go.Seq();
|
||||
long _result;
|
||||
Seq.send(DESCRIPTOR, CALL_ErrorPair, _in, _out);
|
||||
_result = _out.readInt();
|
||||
String _err = _out.readUTF16();
|
||||
if (_err != null) {
|
||||
throw new Exception(_err);
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
public static void Ints(byte x, short y, int z, long t, long u) {
|
||||
go.Seq _in = new go.Seq();
|
||||
go.Seq _out = new go.Seq();
|
||||
_in.writeInt8(x);
|
||||
_in.writeInt16(y);
|
||||
_in.writeInt32(z);
|
||||
_in.writeInt64(t);
|
||||
_in.writeInt(u);
|
||||
Seq.send(DESCRIPTOR, CALL_Ints, _in, _out);
|
||||
}
|
||||
|
||||
private static final int CALL_Error = 1;
|
||||
private static final int CALL_ErrorPair = 2;
|
||||
private static final int CALL_Ints = 3;
|
||||
private static final String DESCRIPTOR = "basictypes";
|
||||
}
|
21
bind/testdata/interfaces.go
vendored
Normal file
21
bind/testdata/interfaces.go
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
// 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 interfaces
|
||||
|
||||
type I interface {
|
||||
Rand() int32
|
||||
}
|
||||
|
||||
func Add3(r I) int32 {
|
||||
return r.Rand() + r.Rand() + r.Rand()
|
||||
}
|
||||
|
||||
// chosen by fair dice roll.
|
||||
// guaranteed to be random.
|
||||
type seven struct{}
|
||||
|
||||
func (seven) Rand() int32 { return 7 }
|
||||
|
||||
func Seven() I { return seven{} }
|
43
bind/testdata/interfaces.go.golden
vendored
Normal file
43
bind/testdata/interfaces.go.golden
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
// Package go_interfaces is an autogenerated binder stub for package interfaces.
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package go_interfaces
|
||||
|
||||
import (
|
||||
"code.google.com/p/go.mobile/bind/seq"
|
||||
"interfaces"
|
||||
)
|
||||
|
||||
func proxy_Add3(out, in *seq.Buffer) {
|
||||
var param_r interfaces.I
|
||||
param_r_ref := in.ReadRef()
|
||||
if param_r_ref.Num < 0 {
|
||||
param_r = param_r_ref.Get().(interfaces.I)
|
||||
} else {
|
||||
param_r = (*proxyI)(param_r_ref)
|
||||
}
|
||||
res := interfaces.Add3(param_r)
|
||||
out.WriteInt32(res)
|
||||
}
|
||||
|
||||
const (
|
||||
proxyIDescriptor = "go.interfaces.I"
|
||||
proxyIRandCode = 0x10a
|
||||
)
|
||||
|
||||
type proxyI seq.Ref
|
||||
|
||||
func (p *proxyI) Rand() (res_0 int32) {
|
||||
out := new(seq.Buffer)
|
||||
seq.Transact((*seq.Ref)(p), proxyIRandCode, out)
|
||||
}
|
||||
|
||||
func proxy_Seven(out, in *seq.Buffer) {
|
||||
res := interfaces.Seven()
|
||||
out.WriteGoRef(res)
|
||||
}
|
||||
|
||||
func init() {
|
||||
seq.Register("interfaces", 1, proxy_Add3)
|
||||
seq.Register("interfaces", 2, proxy_Seven)
|
||||
}
|
85
bind/testdata/interfaces.java.golden
vendored
Normal file
85
bind/testdata/interfaces.java.golden
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
// Java Package interfaces is a proxy for talking to a Go program.
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package go.interfaces;
|
||||
|
||||
import go.Seq;
|
||||
|
||||
public abstract class Interfaces {
|
||||
private Interfaces() {} // uninstantiable
|
||||
|
||||
public static int Add3(I r) {
|
||||
go.Seq _in = new go.Seq();
|
||||
go.Seq _out = new go.Seq();
|
||||
int _result;
|
||||
_in.writeRef(r.ref());
|
||||
Seq.send(DESCRIPTOR, CALL_Add3, _in, _out);
|
||||
_result = _out.readInt32();
|
||||
return _result;
|
||||
}
|
||||
|
||||
public interface I extends go.Seq.Object {
|
||||
public int Rand();
|
||||
|
||||
public static abstract class Stub implements I {
|
||||
static final String DESCRIPTOR = "go.interfaces.I";
|
||||
|
||||
private final go.Seq.Ref ref;
|
||||
public Stub() {
|
||||
ref = go.Seq.createRef(this);
|
||||
}
|
||||
|
||||
public go.Seq.Ref ref() { return ref; }
|
||||
|
||||
public void call(int code, go.Seq in, go.Seq out) {
|
||||
switch (code) {
|
||||
case Proxy.CALL_Rand: {
|
||||
int result = this.Rand();
|
||||
return;
|
||||
}
|
||||
default:
|
||||
throw new RuntimeException("unknown code: "+ code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final class Proxy implements I {
|
||||
static final String DESCRIPTOR = Stub.DESCRIPTOR;
|
||||
|
||||
private go.Seq.Ref ref;
|
||||
|
||||
Proxy(go.Seq.Ref ref) { this.ref = ref; }
|
||||
|
||||
public go.Seq.Ref ref() { return ref; }
|
||||
|
||||
public void call(int code, go.Seq in, go.Seq out) {
|
||||
throw new RuntimeException("cycle: cannot call proxy");
|
||||
}
|
||||
|
||||
public int Rand() {
|
||||
go.Seq _in = new go.Seq();
|
||||
go.Seq _out = new go.Seq();
|
||||
int _result;
|
||||
_in.writeRef(ref);
|
||||
Seq.send(DESCRIPTOR, CALL_Rand, _in, _out);
|
||||
_result = _out.readInt32();
|
||||
return _result;
|
||||
}
|
||||
|
||||
static final int CALL_Rand = 0x10a;
|
||||
}
|
||||
}
|
||||
|
||||
public static I Seven() {
|
||||
go.Seq _in = new go.Seq();
|
||||
go.Seq _out = new go.Seq();
|
||||
I _result;
|
||||
Seq.send(DESCRIPTOR, CALL_Seven, _in, _out);
|
||||
_result = new I.Proxy(_out.readRef());
|
||||
return _result;
|
||||
}
|
||||
|
||||
private static final int CALL_Add3 = 1;
|
||||
private static final int CALL_Seven = 2;
|
||||
private static final String DESCRIPTOR = "interfaces";
|
||||
}
|
14
bind/testdata/structs.go
vendored
Normal file
14
bind/testdata/structs.go
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
// 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 structs
|
||||
|
||||
type S struct {
|
||||
X, Y float64
|
||||
unexported bool
|
||||
}
|
||||
|
||||
func (s *S) Sum() float64 {
|
||||
return s.X + s.Y
|
||||
}
|
62
bind/testdata/structs.go.golden
vendored
Normal file
62
bind/testdata/structs.go.golden
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
// Package go_structs is an autogenerated binder stub for package structs.
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package go_structs
|
||||
|
||||
import (
|
||||
"code.google.com/p/go.mobile/bind/seq"
|
||||
"structs"
|
||||
)
|
||||
|
||||
const (
|
||||
proxySDescriptor = "go.structs.S"
|
||||
proxySXGetCode = 0x00f
|
||||
proxySXSetCode = 0x01f
|
||||
proxySYGetCode = 0x10f
|
||||
proxySYSetCode = 0x11f
|
||||
proxySSumCode = 0x00c
|
||||
)
|
||||
|
||||
type proxyS seq.Ref
|
||||
|
||||
func proxySXSet(out, in *seq.Buffer) {
|
||||
ref := in.ReadRef()
|
||||
v := in.ReadFloat64()
|
||||
ref.Get().(*structs.S).X = v
|
||||
}
|
||||
|
||||
func proxySXGet(out, in *seq.Buffer) {
|
||||
ref := in.ReadRef()
|
||||
v := ref.Get().(*structs.S).X
|
||||
out.WriteFloat64(v)
|
||||
}
|
||||
|
||||
func proxySYSet(out, in *seq.Buffer) {
|
||||
ref := in.ReadRef()
|
||||
v := in.ReadFloat64()
|
||||
ref.Get().(*structs.S).Y = v
|
||||
}
|
||||
|
||||
func proxySYGet(out, in *seq.Buffer) {
|
||||
ref := in.ReadRef()
|
||||
v := ref.Get().(*structs.S).Y
|
||||
out.WriteFloat64(v)
|
||||
}
|
||||
|
||||
func proxySSum(out, in *seq.Buffer) {
|
||||
ref := in.ReadRef()
|
||||
v := ref.Get().(*structs.S)
|
||||
res := v.Sum()
|
||||
out.WriteFloat64(res)
|
||||
}
|
||||
|
||||
func init() {
|
||||
seq.Register(proxySDescriptor, proxySXSetCode, proxySXSet)
|
||||
seq.Register(proxySDescriptor, proxySXGetCode, proxySXGet)
|
||||
seq.Register(proxySDescriptor, proxySYSetCode, proxySYSet)
|
||||
seq.Register(proxySDescriptor, proxySYGetCode, proxySYGet)
|
||||
seq.Register(proxySDescriptor, proxySSumCode, proxySSum)
|
||||
}
|
||||
|
||||
func init() {
|
||||
}
|
103
bind/testdata/structs.java.golden
vendored
Normal file
103
bind/testdata/structs.java.golden
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
// Java Package structs is a proxy for talking to a Go program.
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
package go.structs;
|
||||
|
||||
import go.Seq;
|
||||
|
||||
public abstract class Structs {
|
||||
private Structs() {} // uninstantiable
|
||||
|
||||
public static final class S implements go.Seq.Object {
|
||||
private static final String DESCRIPTOR = "go.structs.S";
|
||||
private static final int FIELD_X_GET = 0x00f;
|
||||
private static final int FIELD_X_SET = 0x01f;
|
||||
private static final int FIELD_Y_GET = 0x10f;
|
||||
private static final int FIELD_Y_SET = 0x11f;
|
||||
private static final int CALL_Sum = 0x00c;
|
||||
|
||||
private go.Seq.Ref ref;
|
||||
|
||||
private S(go.Seq.Ref ref) { this.ref = ref; }
|
||||
|
||||
public go.Seq.Ref ref() { return ref; }
|
||||
|
||||
public void call(int code, go.Seq in, go.Seq out) {
|
||||
throw new RuntimeException("internal error: cycle: cannot call concrete proxy");
|
||||
}
|
||||
|
||||
public double getX() {
|
||||
Seq in = new Seq();
|
||||
Seq out = new Seq();
|
||||
in.writeRef(ref);
|
||||
Seq.send(DESCRIPTOR, FIELD_X_GET, in, out);
|
||||
return out.readFloat64();
|
||||
}
|
||||
|
||||
public void setX(double v) {
|
||||
Seq in = new Seq();
|
||||
Seq out = new Seq();
|
||||
in.writeRef(ref);
|
||||
in.writeFloat64(v);
|
||||
Seq.send(DESCRIPTOR, FIELD_X_SET, in, out);
|
||||
}
|
||||
public double getY() {
|
||||
Seq in = new Seq();
|
||||
Seq out = new Seq();
|
||||
in.writeRef(ref);
|
||||
Seq.send(DESCRIPTOR, FIELD_Y_GET, in, out);
|
||||
return out.readFloat64();
|
||||
}
|
||||
|
||||
public void setY(double v) {
|
||||
Seq in = new Seq();
|
||||
Seq out = new Seq();
|
||||
in.writeRef(ref);
|
||||
in.writeFloat64(v);
|
||||
Seq.send(DESCRIPTOR, FIELD_Y_SET, in, out);
|
||||
}
|
||||
|
||||
public double Sum() {
|
||||
go.Seq _in = new go.Seq();
|
||||
go.Seq _out = new go.Seq();
|
||||
double _result;
|
||||
_in.writeRef(ref);
|
||||
Seq.send(DESCRIPTOR, CALL_Sum, _in, _out);
|
||||
_result = _out.readFloat64();
|
||||
return _result;
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object o) {
|
||||
if (o == null || !(o instanceof S)) {
|
||||
return false;
|
||||
}
|
||||
S that = (S)o;
|
||||
double thisX = getX();
|
||||
double thatX = that.getX();
|
||||
if (thisX != thatX) {
|
||||
return false;
|
||||
}
|
||||
double thisY = getY();
|
||||
double thatY = that.getY();
|
||||
if (thisY != thatY) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
return java.util.Arrays.hashCode(new Object[] {getX(), getY()});
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("S").append("{");
|
||||
b.append("X:").append(getX()).append(",");
|
||||
b.append("Y:").append(getY()).append(",");
|
||||
return b.append("}").toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final String DESCRIPTOR = "structs";
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user