The ClassGen.genGo function always uses unsafe, contrary to what the check in GenGo says. With this CL, generated code always imports unsafe if there are any classes to be generated. Change-Id: Ic807111a26e494b4941790830b1950bb8b1f73d5 Reviewed-on: https://go-review.googlesource.com/29873 Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
726 lines
18 KiB
Go
726 lines
18 KiB
Go
// Copyright 2016 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"
|
|
"path/filepath"
|
|
"strings"
|
|
"unicode"
|
|
"unicode/utf8"
|
|
|
|
"golang.org/x/mobile/internal/importers/java"
|
|
)
|
|
|
|
type (
|
|
// ClassGen generates Go and C stubs for Java classes so import statements
|
|
// on the form
|
|
//
|
|
//
|
|
// import "Java/classpath/to/Class"
|
|
//
|
|
// will work.
|
|
ClassGen struct {
|
|
*Printer
|
|
imported map[string]struct{}
|
|
// The list of imported Java classes
|
|
classes []*java.Class
|
|
// The list of Go package paths with Java interfaces inside
|
|
jpkgs []string
|
|
// For each Go package path, the list of Java classes.
|
|
typePkgs map[string][]*java.Class
|
|
// For each Go package path, the Java class with static functions
|
|
// or constants.
|
|
clsPkgs map[string]*java.Class
|
|
}
|
|
)
|
|
|
|
func (g *ClassGen) isSupported(t *java.Type) bool {
|
|
switch t.Kind {
|
|
case java.Array:
|
|
// TODO: Support all array types
|
|
return t.Elem.Kind == java.Byte
|
|
default:
|
|
return true
|
|
}
|
|
}
|
|
|
|
func (g *ClassGen) isFuncSupported(f *java.Func) bool {
|
|
for _, a := range f.Params {
|
|
if !g.isSupported(a) {
|
|
return false
|
|
}
|
|
}
|
|
if f.Ret != nil {
|
|
return g.isSupported(f.Ret)
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (g *ClassGen) goType(t *java.Type, local bool) string {
|
|
switch t.Kind {
|
|
case java.Int:
|
|
return "int32"
|
|
case java.Boolean:
|
|
return "bool"
|
|
case java.Short:
|
|
return "int16"
|
|
case java.Char:
|
|
return "uint16"
|
|
case java.Byte:
|
|
return "byte"
|
|
case java.Long:
|
|
return "int64"
|
|
case java.Float:
|
|
return "float32"
|
|
case java.Double:
|
|
return "float64"
|
|
case java.String:
|
|
return "string"
|
|
case java.Array:
|
|
return "[]" + g.goType(t.Elem, local)
|
|
case java.Object:
|
|
if _, exists := g.imported[t.Class]; !exists {
|
|
return "interface{}"
|
|
}
|
|
name := goClsName(t.Class)
|
|
if !local {
|
|
name = "Java." + name
|
|
}
|
|
return name
|
|
default:
|
|
panic("invalid kind")
|
|
}
|
|
}
|
|
|
|
func (g *ClassGen) Init(classes []*java.Class) {
|
|
g.classes = classes
|
|
g.imported = make(map[string]struct{})
|
|
g.typePkgs = make(map[string][]*java.Class)
|
|
g.clsPkgs = make(map[string]*java.Class)
|
|
pkgSet := make(map[string]struct{})
|
|
for _, cls := range classes {
|
|
g.imported[cls.Name] = struct{}{}
|
|
clsPkg := strings.Replace(cls.Name, ".", "/", -1)
|
|
g.clsPkgs[clsPkg] = cls
|
|
typePkg := filepath.Dir(clsPkg)
|
|
g.typePkgs[typePkg] = append(g.typePkgs[typePkg], cls)
|
|
if _, exists := pkgSet[clsPkg]; !exists {
|
|
pkgSet[clsPkg] = struct{}{}
|
|
g.jpkgs = append(g.jpkgs, clsPkg)
|
|
}
|
|
if _, exists := pkgSet[typePkg]; !exists {
|
|
pkgSet[typePkg] = struct{}{}
|
|
g.jpkgs = append(g.jpkgs, typePkg)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Packages return the list of Go packages to be generated.
|
|
func (g *ClassGen) Packages() []string {
|
|
return g.jpkgs
|
|
}
|
|
|
|
func (g *ClassGen) GenPackage(idx int) {
|
|
jpkg := g.jpkgs[idx]
|
|
g.Printf("// File is generated by gobind. Do not edit.\n\n")
|
|
g.Printf("package %s\n\n", filepath.Base(jpkg))
|
|
g.Printf("import \"Java\"\n\n")
|
|
g.Printf("const _ = Java.Dummy\n\n")
|
|
for _, cls := range g.typePkgs[jpkg] {
|
|
g.Printf("type %s Java.%s\n", cls.PkgName, goClsName(cls.Name))
|
|
}
|
|
if cls, ok := g.clsPkgs[jpkg]; ok {
|
|
g.Printf("const (\n")
|
|
g.Indent()
|
|
// Constants
|
|
for _, v := range cls.Vars {
|
|
if g.isSupported(v.Type) && v.Constant() {
|
|
g.Printf("%s = %s\n", initialUpper(v.Name), v.Val)
|
|
}
|
|
}
|
|
g.Outdent()
|
|
g.Printf(")\n\n")
|
|
|
|
g.Printf("var (\n")
|
|
g.Indent()
|
|
// Functions
|
|
for _, f := range cls.Funcs {
|
|
if !f.Public || !g.isFuncSupported(f) {
|
|
continue
|
|
}
|
|
g.Printf("%s func", f.GoName)
|
|
g.genFuncDecl(false, f)
|
|
g.Printf("\n")
|
|
}
|
|
g.Outdent()
|
|
g.Printf(")\n\n")
|
|
}
|
|
}
|
|
|
|
func (g *ClassGen) GenGo() {
|
|
g.Printf(classesGoHeader)
|
|
for _, cls := range g.classes {
|
|
for _, f := range cls.Funcs {
|
|
if f.Public && g.isFuncSupported(f) {
|
|
pkgName := strings.Replace(cls.Name, ".", "/", -1)
|
|
g.Printf("import %q\n", "Java/"+pkgName)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if len(g.classes) > 0 {
|
|
g.Printf("import \"unsafe\"\n\n")
|
|
}
|
|
g.Printf("type proxy interface { Bind_proxy_refnum__() int32 }\n\n")
|
|
g.Printf("// Suppress unused package error\n\n")
|
|
g.Printf("var _ = _seq.FromRefNum\n")
|
|
g.Printf("const _ = Java.Dummy\n\n")
|
|
g.Printf("//export initClasses\n")
|
|
g.Printf("func initClasses() {\n")
|
|
g.Indent()
|
|
g.Printf("C.init_proxies()\n")
|
|
for _, cls := range g.classes {
|
|
g.Printf("init_%s()\n", cls.JNIName)
|
|
}
|
|
g.Outdent()
|
|
g.Printf("}\n\n")
|
|
for _, cls := range g.classes {
|
|
g.genGo(cls)
|
|
}
|
|
}
|
|
|
|
func (g *ClassGen) GenH() {
|
|
g.Printf(classesHHeader)
|
|
for _, tn := range []string{"jint", "jboolean", "jshort", "jchar", "jbyte", "jlong", "jfloat", "jdouble", "nstring", "nbyteslice"} {
|
|
g.Printf("typedef struct ret_%s {\n", tn)
|
|
g.Printf(" %s res;\n", tn)
|
|
g.Printf(" jint exc;\n")
|
|
g.Printf("} ret_%s;\n", tn)
|
|
}
|
|
g.Printf("\n")
|
|
for _, cls := range g.classes {
|
|
for _, f := range cls.AllMethods {
|
|
if !g.isFuncSupported(f) {
|
|
continue
|
|
}
|
|
g.Printf("extern ")
|
|
g.genCMethodDecl("cproxy", cls.JNIName, f)
|
|
g.Printf(";\n")
|
|
if cls.HasSuper() {
|
|
g.Printf("extern ")
|
|
g.genCMethodDecl("csuper", cls.JNIName, f)
|
|
g.Printf(";\n")
|
|
}
|
|
}
|
|
}
|
|
for _, cls := range g.classes {
|
|
g.genH(cls)
|
|
}
|
|
}
|
|
|
|
func (g *ClassGen) GenC() {
|
|
g.Printf(classesCHeader)
|
|
for _, cls := range g.classes {
|
|
g.genC(cls)
|
|
g.Printf("static jclass class_%s;\n", cls.JNIName)
|
|
for _, f := range cls.AllMethods {
|
|
if g.isFuncSupported(f) {
|
|
g.Printf("static jmethodID m_%s_%s;\n", cls.JNIName, f.JNIName)
|
|
}
|
|
}
|
|
}
|
|
g.Printf("\n")
|
|
g.Printf("void init_proxies() {\n")
|
|
g.Indent()
|
|
g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", len(g.classes))
|
|
g.Printf("jclass clazz;\n")
|
|
for _, cls := range g.classes {
|
|
g.Printf("clazz = (*env)->FindClass(env, %q);\n", strings.Replace(cls.FindName, ".", "/", -1))
|
|
g.Printf("class_%s = (*env)->NewGlobalRef(env, clazz);\n", cls.JNIName)
|
|
for _, f := range cls.AllMethods {
|
|
if g.isFuncSupported(f) {
|
|
g.Printf("m_%s_%s = go_seq_get_method_id(clazz, %q, %q);\n", cls.JNIName, f.JNIName, f.Name, f.Desc)
|
|
}
|
|
}
|
|
}
|
|
g.Printf("go_seq_pop_local_frame(env);\n")
|
|
g.Outdent()
|
|
g.Printf("}\n\n")
|
|
for _, cls := range g.classes {
|
|
for _, f := range cls.AllMethods {
|
|
if !g.isFuncSupported(f) {
|
|
continue
|
|
}
|
|
g.genCMethodDecl("cproxy", cls.JNIName, f)
|
|
g.genCMethodBody(cls, f, false)
|
|
if cls.HasSuper() {
|
|
g.genCMethodDecl("csuper", cls.JNIName, f)
|
|
g.genCMethodBody(cls, f, true)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (g *ClassGen) GenInterfaces() {
|
|
g.Printf(classesPkgHeader)
|
|
for _, cls := range g.classes {
|
|
g.genInterface(cls)
|
|
}
|
|
}
|
|
|
|
func (g *ClassGen) genCMethodBody(cls *java.Class, f *java.Func, virtual bool) {
|
|
g.Printf(" {\n")
|
|
g.Indent()
|
|
// Add 1 for the 'this' argument
|
|
g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", len(f.Params)+1)
|
|
g.Printf("// Must be a Java object\n")
|
|
g.Printf("jobject _this = go_seq_from_refnum(env, this, NULL, NULL);\n")
|
|
for i, a := range f.Params {
|
|
g.genCToJava(fmt.Sprintf("a%d", i), a)
|
|
}
|
|
if f.Ret != nil {
|
|
g.Printf("%s res = ", f.Ret.JNIType())
|
|
}
|
|
g.Printf("(*env)->Call")
|
|
if virtual {
|
|
g.Printf("Nonvirtual")
|
|
}
|
|
if f.Ret != nil {
|
|
g.Printf(f.Ret.JNICallType())
|
|
} else {
|
|
g.Printf("Void")
|
|
}
|
|
g.Printf("Method(env, _this, ")
|
|
if virtual {
|
|
g.Printf("class_%s, ", cls.JNIName)
|
|
}
|
|
g.Printf("m_%s_%s", cls.JNIName, f.JNIName)
|
|
for i := range f.Params {
|
|
g.Printf(", _a%d", i)
|
|
}
|
|
g.Printf(");\n")
|
|
g.Printf("jobject _exc = go_seq_wrap_exception(env);\n")
|
|
g.Printf("int32_t _exc_ref = go_seq_to_refnum(env, _exc);\n")
|
|
if f.Ret != nil {
|
|
g.genJavaToC("res", f.Ret)
|
|
}
|
|
g.Printf("go_seq_pop_local_frame(env);\n")
|
|
if f.Ret != nil {
|
|
g.Printf("ret_%s __res = {_res, _exc_ref};\n", f.Ret.CType())
|
|
g.Printf("return __res;\n")
|
|
} else {
|
|
g.Printf("return _exc_ref;\n")
|
|
}
|
|
g.Outdent()
|
|
g.Printf("}\n\n")
|
|
}
|
|
|
|
func initialUpper(s string) string {
|
|
if s == "" {
|
|
return ""
|
|
}
|
|
r, n := utf8.DecodeRuneInString(s)
|
|
return string(unicode.ToUpper(r)) + s[n:]
|
|
}
|
|
|
|
func (g *ClassGen) genFuncDecl(local bool, f *java.Func) {
|
|
g.Printf("(")
|
|
for i, a := range f.Params {
|
|
if i > 0 {
|
|
g.Printf(", ")
|
|
}
|
|
g.Printf("a%d %s", i, g.goType(a, local))
|
|
}
|
|
g.Printf(")")
|
|
if f.Throws != "" {
|
|
if f.Ret != nil {
|
|
g.Printf(" (%s, error)", g.goType(f.Ret, local))
|
|
} else {
|
|
g.Printf(" error")
|
|
}
|
|
} else if f.Ret != nil {
|
|
g.Printf(" %s", g.goType(f.Ret, local))
|
|
}
|
|
}
|
|
|
|
func (g *ClassGen) genC(cls *java.Class) {
|
|
for _, f := range cls.Funcs {
|
|
if !f.Public || !g.isFuncSupported(f) {
|
|
continue
|
|
}
|
|
g.genCFuncDecl(cls.JNIName, f)
|
|
g.Printf(" {\n")
|
|
g.Indent()
|
|
g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", len(f.Params))
|
|
for i, a := range f.Params {
|
|
g.genCToJava(fmt.Sprintf("a%d", i), a)
|
|
}
|
|
if f.Constructor {
|
|
g.Printf("jobject res = (*env)->NewObject(env")
|
|
} else if f.Ret != nil {
|
|
g.Printf("%s res = (*env)->CallStatic%sMethod(env", f.Ret.JNIType(), f.Ret.JNICallType())
|
|
} else {
|
|
g.Printf("(*env)->CallStaticVoidMethod(env")
|
|
}
|
|
g.Printf(", clazz, m")
|
|
for i := range f.Params {
|
|
g.Printf(", _a%d", i)
|
|
}
|
|
g.Printf(");\n")
|
|
g.Printf("jobject _exc = go_seq_wrap_exception(env);\n")
|
|
g.Printf("int32_t _exc_ref = go_seq_to_refnum(env, _exc);\n")
|
|
if f.Ret != nil {
|
|
g.genJavaToC("res", f.Ret)
|
|
}
|
|
g.Printf("go_seq_pop_local_frame(env);\n")
|
|
if f.Ret != nil {
|
|
g.Printf("ret_%s __res = {_res, _exc_ref};\n", f.Ret.CType())
|
|
g.Printf("return __res;\n")
|
|
} else {
|
|
g.Printf("return _exc_ref;\n")
|
|
}
|
|
g.Outdent()
|
|
g.Printf("}\n\n")
|
|
}
|
|
}
|
|
|
|
func (g *ClassGen) genH(cls *java.Class) {
|
|
for _, f := range cls.Funcs {
|
|
if !f.Public || !g.isFuncSupported(f) {
|
|
continue
|
|
}
|
|
g.Printf("extern ")
|
|
g.genCFuncDecl(cls.JNIName, f)
|
|
g.Printf(";\n")
|
|
}
|
|
}
|
|
|
|
func (g *ClassGen) genCMethodDecl(prefix, jniName string, f *java.Func) {
|
|
if f.Ret != nil {
|
|
g.Printf("ret_%s", f.Ret.CType())
|
|
} else {
|
|
// Return only the exception, if any
|
|
g.Printf("jint")
|
|
}
|
|
g.Printf(" %s_%s_%s(jint this", prefix, jniName, f.JNIName)
|
|
for i, a := range f.Params {
|
|
g.Printf(", %s a%d", a.CType(), i)
|
|
}
|
|
g.Printf(")")
|
|
}
|
|
|
|
func (g *ClassGen) genCFuncDecl(jniName string, f *java.Func) {
|
|
if f.Ret != nil {
|
|
g.Printf("ret_%s", f.Ret.CType())
|
|
} else {
|
|
// Return only the exception, if any
|
|
g.Printf("jint")
|
|
}
|
|
g.Printf(" cproxy_s_%s_%s(jclass clazz, jmethodID m", jniName, f.JNIName)
|
|
for i, a := range f.Params {
|
|
g.Printf(", %s a%d", a.CType(), i)
|
|
}
|
|
g.Printf(")")
|
|
}
|
|
|
|
func (g *ClassGen) genGo(cls *java.Class) {
|
|
g.Printf("func init_%s() {\n", cls.JNIName)
|
|
g.Indent()
|
|
g.Printf("cls := C.CString(%q)\n", strings.Replace(cls.FindName, ".", "/", -1))
|
|
g.Printf("clazz := C.go_seq_find_class(cls)\n")
|
|
g.Printf("C.free(unsafe.Pointer(cls))\n")
|
|
g.Printf("if clazz == nil {\n")
|
|
g.Printf(" return\n")
|
|
g.Printf("}\n")
|
|
for _, f := range cls.Funcs {
|
|
if !f.Public || !g.isFuncSupported(f) {
|
|
continue
|
|
}
|
|
g.Printf("{\n")
|
|
g.Indent()
|
|
name := f.Name
|
|
if f.Constructor {
|
|
name = "<init>"
|
|
}
|
|
g.Printf("fn := C.CString(%q)\n", name)
|
|
g.Printf("fd := C.CString(%q)\n", f.Desc)
|
|
if f.Constructor {
|
|
g.Printf("m := C.go_seq_get_method_id(clazz, fn, fd)\n")
|
|
} else {
|
|
g.Printf("m := C.go_seq_get_static_method_id(clazz, fn, fd)\n")
|
|
}
|
|
g.Printf("C.free(unsafe.Pointer(fn))\n")
|
|
g.Printf("C.free(unsafe.Pointer(fd))\n")
|
|
g.Printf("if m != nil {\n")
|
|
g.Indent()
|
|
g.Printf("%s.%s = func", cls.PkgName, f.GoName)
|
|
g.genFuncDecl(false, f)
|
|
g.Printf(" {\n")
|
|
g.Indent()
|
|
for i, a := range f.Params {
|
|
g.genWrite(fmt.Sprintf("a%d", i), a, modeTransient)
|
|
}
|
|
g.Printf("res := C.cproxy_s_%s_%s(clazz, m", cls.JNIName, f.JNIName)
|
|
for i := range f.Params {
|
|
g.Printf(", _a%d", i)
|
|
}
|
|
g.Printf(")\n")
|
|
g.genFuncRet(f)
|
|
g.Outdent()
|
|
g.Printf("}\n")
|
|
g.Outdent()
|
|
g.Printf("}\n")
|
|
g.Outdent()
|
|
g.Printf("}\n")
|
|
}
|
|
g.Outdent()
|
|
g.Printf("}\n\n")
|
|
g.Printf("type proxy_class_%s _seq.Ref\n\n", cls.JNIName)
|
|
g.Printf("func (p *proxy_class_%s) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }\n\n", cls.JNIName)
|
|
for _, f := range cls.AllMethods {
|
|
if !g.isFuncSupported(f) {
|
|
continue
|
|
}
|
|
g.Printf("func (p *proxy_class_%s) %s", cls.JNIName, f.GoName)
|
|
g.genFuncDecl(false, f)
|
|
g.genFuncBody(cls, f, "cproxy")
|
|
}
|
|
if cls.Throwable {
|
|
g.Printf("func (p *proxy_class_%s) Error() string {\n", cls.JNIName)
|
|
g.Printf(" return p.ToString()\n")
|
|
g.Printf("}\n")
|
|
}
|
|
if cls.HasSuper() {
|
|
g.Printf("func (p *proxy_class_%s) Super() Java.%s {\n", cls.JNIName, goClsName(cls.Name))
|
|
g.Printf(" return &super_%s{p}\n", cls.JNIName)
|
|
g.Printf("}\n\n")
|
|
g.Printf("type super_%s struct {*proxy_class_%[1]s}\n\n", cls.JNIName)
|
|
for _, f := range cls.AllMethods {
|
|
if !g.isFuncSupported(f) {
|
|
continue
|
|
}
|
|
g.Printf("func (p *super_%s) %s", cls.JNIName, f.GoName)
|
|
g.genFuncDecl(false, f)
|
|
g.genFuncBody(cls, f, "csuper")
|
|
}
|
|
}
|
|
}
|
|
|
|
func (g *ClassGen) genFuncBody(cls *java.Class, f *java.Func, prefix string) {
|
|
g.Printf(" {\n")
|
|
g.Indent()
|
|
for i, a := range f.Params {
|
|
g.genWrite(fmt.Sprintf("a%d", i), a, modeTransient)
|
|
}
|
|
g.Printf("res := C.%s_%s_%s(C.jint(p.Bind_proxy_refnum__())", prefix, cls.JNIName, f.JNIName)
|
|
for i := range f.Params {
|
|
g.Printf(", _a%d", i)
|
|
}
|
|
g.Printf(")\n")
|
|
g.genFuncRet(f)
|
|
g.Outdent()
|
|
g.Printf("}\n\n")
|
|
}
|
|
|
|
func (g *ClassGen) genFuncRet(f *java.Func) {
|
|
if f.Ret != nil {
|
|
g.genRead("_res", "res.res", f.Ret, modeRetained)
|
|
g.genRefRead("_exc", "res.exc", "error", "proxy_error", true)
|
|
} else {
|
|
g.genRefRead("_exc", "res", "error", "proxy_error", true)
|
|
}
|
|
if f.Throws == "" {
|
|
g.Printf("if (_exc != nil) { panic(_exc) }\n")
|
|
if f.Ret != nil {
|
|
g.Printf("return _res\n")
|
|
}
|
|
} else {
|
|
if f.Ret != nil {
|
|
g.Printf("return _res, _exc\n")
|
|
} else {
|
|
g.Printf("return _exc\n")
|
|
}
|
|
}
|
|
}
|
|
|
|
func (g *ClassGen) genRead(to, from string, t *java.Type, mode varMode) {
|
|
switch t.Kind {
|
|
case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double:
|
|
g.Printf("%s := %s(%s)\n", to, g.goType(t, false), from)
|
|
case java.Boolean:
|
|
g.Printf("%s := %s != C.JNI_FALSE\n", to, from)
|
|
case java.String:
|
|
g.Printf("%s := decodeString(%s)\n", to, from)
|
|
case java.Array:
|
|
if t.Elem.Kind != java.Byte {
|
|
panic("unsupported array type")
|
|
}
|
|
g.Printf("%s := toSlice(%s, %v)\n", to, from, mode == modeRetained)
|
|
case java.Object:
|
|
_, hasProxy := g.imported[t.Class]
|
|
g.genRefRead(to, from, g.goType(t, false), "proxy_class_"+flattenName(t.Class), hasProxy)
|
|
default:
|
|
panic("invalid kind")
|
|
}
|
|
}
|
|
|
|
func (g *ClassGen) genRefRead(to, from string, intfName, proxyName string, hasProxy bool) {
|
|
g.Printf("var %s %s\n", to, intfName)
|
|
g.Printf("%s_ref := _seq.FromRefNum(int32(%s))\n", to, from)
|
|
g.Printf("if %s_ref != nil {\n", to)
|
|
g.Printf(" if %s < 0 { // go object\n", from)
|
|
g.Printf(" %s = %s_ref.Get().(%s)\n", to, to, intfName)
|
|
if hasProxy {
|
|
g.Printf(" } else { // foreign object\n")
|
|
g.Printf(" %s = (*%s)(%s_ref)\n", to, proxyName, to)
|
|
}
|
|
g.Printf(" }\n")
|
|
g.Printf("}\n")
|
|
}
|
|
|
|
func (g *ClassGen) genWrite(v string, t *java.Type, mode varMode) {
|
|
switch t.Kind {
|
|
case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double:
|
|
g.Printf("_%s := C.%s(%s)\n", v, t.CType(), v)
|
|
case java.Boolean:
|
|
g.Printf("_%s := C.jboolean(C.JNI_FALSE)\n", v)
|
|
g.Printf("if %s {\n", v)
|
|
g.Printf(" _%s = C.jboolean(C.JNI_TRUE)\n", v)
|
|
g.Printf("}\n")
|
|
case java.String:
|
|
g.Printf("_%s := encodeString(%s)\n", v, v)
|
|
case java.Array:
|
|
if t.Elem.Kind != java.Byte {
|
|
panic("unsupported array type")
|
|
}
|
|
g.Printf("_%s := fromSlice(%s, %v)\n", v, v, mode == modeRetained)
|
|
case java.Object:
|
|
g.Printf("var _%s C.jint = _seq.NullRefNum\n", v)
|
|
g.Printf("if %s != nil {\n", v)
|
|
g.Printf(" _%s = C.jint(_seq.ToRefNum(%s))\n", v, v)
|
|
g.Printf("}\n")
|
|
default:
|
|
panic("invalid kind")
|
|
}
|
|
}
|
|
|
|
func (g *ClassGen) genJavaToC(v string, t *java.Type) {
|
|
switch t.Kind {
|
|
case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double, java.Boolean:
|
|
g.Printf("%s _%s = %s;\n", t.JNIType(), v, v)
|
|
case java.String:
|
|
g.Printf("nstring _%s = go_seq_from_java_string(env, %s);\n", v, v)
|
|
case java.Array:
|
|
if t.Elem.Kind != java.Byte {
|
|
panic("unsupported array type")
|
|
}
|
|
g.Printf("nbyteslice _%s = go_seq_from_java_bytearray(env, %s, 1);\n", v, v)
|
|
case java.Object:
|
|
g.Printf("jint _%s = go_seq_to_refnum(env, %s);\n", v, v)
|
|
default:
|
|
panic("invalid kind")
|
|
}
|
|
}
|
|
|
|
func (g *ClassGen) genCToJava(v string, t *java.Type) {
|
|
switch t.Kind {
|
|
case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double, java.Boolean:
|
|
g.Printf("%s _%s = %s;\n", t.JNIType(), v, v)
|
|
case java.String:
|
|
g.Printf("jstring _%s = go_seq_to_java_string(env, %s);\n", v, v)
|
|
case java.Array:
|
|
if t.Elem.Kind != java.Byte {
|
|
panic("unsupported array type")
|
|
}
|
|
g.Printf("jbyteArray _%s = go_seq_to_java_bytearray(env, %s, 0);\n", v, v)
|
|
case java.Object:
|
|
g.Printf("jobject _%s = go_seq_from_refnum(env, %s, NULL, NULL);\n", v, v)
|
|
default:
|
|
panic("invalid kind")
|
|
}
|
|
}
|
|
|
|
func goClsName(n string) string {
|
|
return initialUpper(strings.Replace(n, ".", "_", -1))
|
|
}
|
|
|
|
func (g *ClassGen) genInterface(cls *java.Class) {
|
|
g.Printf("type %s interface {\n", goClsName(cls.Name))
|
|
g.Indent()
|
|
// Methods
|
|
for _, f := range cls.AllMethods {
|
|
if !g.isFuncSupported(f) {
|
|
continue
|
|
}
|
|
g.Printf(f.GoName)
|
|
g.genFuncDecl(true, f)
|
|
g.Printf("\n")
|
|
}
|
|
if cls.HasSuper() {
|
|
g.Printf("Super() %s\n", goClsName(cls.Name))
|
|
}
|
|
if cls.Throwable {
|
|
g.Printf("Error() string\n")
|
|
}
|
|
g.Outdent()
|
|
g.Printf("}\n\n")
|
|
}
|
|
|
|
// Flatten java class names. "java.package.Class$Inner" is converted to
|
|
// "java_package_Class_Inner"
|
|
func flattenName(n string) string {
|
|
return strings.Replace(strings.Replace(n, ".", "_", -1), "$", "_", -1)
|
|
}
|
|
|
|
var (
|
|
classesPkgHeader = `// File is generated by gobind. Do not edit.
|
|
|
|
package Java
|
|
|
|
// Used to silence this package not used errors
|
|
const Dummy = 0
|
|
|
|
`
|
|
classesCHeader = `// File is generated by gobind. Do not edit.
|
|
|
|
#include <jni.h>
|
|
#include "seq.h"
|
|
#include "classes.h"
|
|
|
|
`
|
|
classesHHeader = `// File is generated by gobind. Do not edit.
|
|
|
|
#include <jni.h>
|
|
#include "seq.h"
|
|
|
|
extern void init_proxies();
|
|
|
|
`
|
|
|
|
javaImplHeader = `// File is generated by gobind. Do not edit.
|
|
|
|
`
|
|
|
|
classesGoHeader = `// File is generated by gobind. Do not edit.
|
|
|
|
package gomobile_bind
|
|
|
|
/*
|
|
#include <stdlib.h> // for free()
|
|
#include <jni.h>
|
|
#include "seq.h"
|
|
#include "classes.h"
|
|
*/
|
|
import "C"
|
|
|
|
import (
|
|
"Java"
|
|
_seq "golang.org/x/mobile/bind/seq"
|
|
)
|
|
|
|
`
|
|
)
|