| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732 |
- // 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/constant"
- "go/types"
- "html"
- "math"
- "reflect"
- "regexp"
- "strings"
- "golang.org/x/mobile/internal/importers/java"
- )
- // TODO(crawshaw): disallow basic android java type names in exported symbols.
- // TODO(crawshaw): consider introducing Java functions for casting to and from interfaces at runtime.
- type JavaGen struct {
- // JavaPkg is the Java package prefix for the generated classes. The prefix is prepended to the Go
- // package name to create the full Java package name.
- JavaPkg string
- *Generator
- jstructs map[*types.TypeName]*javaClassInfo
- clsMap map[string]*java.Class
- // Constructors is a map from Go struct types to a list
- // of exported constructor functions for the type, on the form
- // func New<Type>(...) *Type
- constructors map[*types.TypeName][]*types.Func
- }
- type javaClassInfo struct {
- // The Java class this class extends.
- extends *java.Class
- // All Java classes and interfaces this class extends and implements.
- supers []*java.Class
- methods map[string]*java.FuncSet
- // Does the class need a default no-arg constructor
- genNoargCon bool
- }
- // Init intializes the embedded Generator and initializes the Java class information
- // needed to generate structs that extend Java classes and interfaces.
- func (g *JavaGen) Init(classes []*java.Class) {
- g.Generator.Init()
- g.clsMap = make(map[string]*java.Class)
- for _, cls := range classes {
- g.clsMap[cls.Name] = cls
- }
- g.jstructs = make(map[*types.TypeName]*javaClassInfo)
- g.constructors = make(map[*types.TypeName][]*types.Func)
- for _, s := range g.structs {
- classes := embeddedJavaClasses(s.t)
- if len(classes) == 0 {
- continue
- }
- inf := &javaClassInfo{
- methods: make(map[string]*java.FuncSet),
- genNoargCon: true, // java.lang.Object has a no-arg constructor
- }
- for _, n := range classes {
- cls := g.clsMap[n]
- for _, fs := range cls.AllMethods {
- hasMeth := false
- for _, f := range fs.Funcs {
- if !f.Final {
- hasMeth = true
- }
- }
- if hasMeth {
- inf.methods[fs.GoName] = fs
- }
- }
- inf.supers = append(inf.supers, cls)
- if !cls.Interface {
- if inf.extends != nil {
- g.errorf("%s embeds more than one Java class; only one is allowed.", s.obj)
- }
- if cls.Final {
- g.errorf("%s embeds final Java class %s", s.obj, cls.Name)
- }
- inf.extends = cls
- inf.genNoargCon = cls.HasNoArgCon
- }
- }
- g.jstructs[s.obj] = inf
- }
- for _, f := range g.funcs {
- if t := g.constructorType(f); t != nil {
- jinf := g.jstructs[t]
- if jinf != nil {
- sig := f.Type().(*types.Signature)
- jinf.genNoargCon = jinf.genNoargCon && sig.Params().Len() > 0
- }
- g.constructors[t] = append(g.constructors[t], f)
- }
- }
- }
- func (j *javaClassInfo) toJavaType(T types.Type) *java.Type {
- switch T := T.(type) {
- case *types.Basic:
- var kind java.TypeKind
- switch T.Kind() {
- case types.Bool, types.UntypedBool:
- kind = java.Boolean
- case types.Uint8:
- kind = java.Byte
- case types.Int16:
- kind = java.Short
- case types.Int32, types.UntypedRune: // types.Rune
- kind = java.Int
- case types.Int64, types.UntypedInt:
- kind = java.Long
- case types.Float32:
- kind = java.Float
- case types.Float64, types.UntypedFloat:
- kind = java.Double
- case types.String, types.UntypedString:
- kind = java.String
- default:
- return nil
- }
- return &java.Type{Kind: kind}
- case *types.Slice:
- switch e := T.Elem().(type) {
- case *types.Basic:
- switch e.Kind() {
- case types.Uint8: // Byte.
- return &java.Type{Kind: java.Array, Elem: &java.Type{Kind: java.Byte}}
- }
- }
- return nil
- case *types.Named:
- if isJavaType(T) {
- return &java.Type{Kind: java.Object, Class: classNameFor(T)}
- }
- }
- return nil
- }
- // lookupMethod searches the Java class descriptor for a method
- // that matches the Go method.
- func (j *javaClassInfo) lookupMethod(m *types.Func, hasThis bool) *java.Func {
- jm := j.methods[m.Name()]
- if jm == nil {
- // If an exact match is not found, try the method with trailing underscores
- // stripped. This way, name clashes can be avoided when overriding multiple
- // overloaded methods from Go.
- base := strings.TrimRight(m.Name(), "_")
- jm = j.methods[base]
- if jm == nil {
- return nil
- }
- }
- // A name match was found. Now use the parameter and return types to locate
- // the correct variant.
- sig := m.Type().(*types.Signature)
- params := sig.Params()
- // Convert Go parameter types to their Java counterparts, if possible.
- var jparams []*java.Type
- i := 0
- if hasThis {
- i = 1
- }
- for ; i < params.Len(); i++ {
- jparams = append(jparams, j.toJavaType(params.At(i).Type()))
- }
- var ret *java.Type
- var throws bool
- if results := sig.Results(); results.Len() > 0 {
- ret = j.toJavaType(results.At(0).Type())
- if results.Len() > 1 {
- throws = isErrorType(results.At(1).Type())
- }
- }
- loop:
- for _, f := range jm.Funcs {
- if len(f.Params) != len(jparams) {
- continue
- }
- if throws != (f.Throws != "") {
- continue
- }
- if !reflect.DeepEqual(ret, f.Ret) {
- continue
- }
- for i, p := range f.Params {
- if !reflect.DeepEqual(p, jparams[i]) {
- continue loop
- }
- }
- return f
- }
- return nil
- }
- // ClassNames returns the list of names of the generated Java classes and interfaces.
- func (g *JavaGen) ClassNames() []string {
- var names []string
- for _, s := range g.structs {
- names = append(names, g.javaTypeName(s.obj.Name()))
- }
- for _, iface := range g.interfaces {
- names = append(names, g.javaTypeName(iface.obj.Name()))
- }
- return names
- }
- func (g *JavaGen) GenClass(idx int) error {
- ns := len(g.structs)
- if idx < ns {
- s := g.structs[idx]
- g.genStruct(s)
- } else {
- iface := g.interfaces[idx-ns]
- g.genInterface(iface)
- }
- if len(g.err) > 0 {
- return g.err
- }
- return nil
- }
- func (g *JavaGen) genProxyImpl(name string) {
- g.Printf("private final int refnum;\n\n")
- g.Printf("@Override public final int incRefnum() {\n")
- g.Printf(" Seq.incGoRef(refnum, this);\n")
- g.Printf(" return refnum;\n")
- g.Printf("}\n\n")
- }
- func (g *JavaGen) genStruct(s structInfo) {
- pkgPath := ""
- if g.Pkg != nil {
- pkgPath = g.Pkg.Path()
- }
- n := g.javaTypeName(s.obj.Name())
- g.Printf(javaPreamble, g.javaPkgName(g.Pkg), n, g.gobindOpts(), pkgPath)
- fields := exportedFields(s.t)
- methods := exportedMethodSet(types.NewPointer(s.obj.Type()))
- var impls []string
- jinf := g.jstructs[s.obj]
- if jinf != nil {
- impls = append(impls, "Seq.GoObject")
- for _, cls := range jinf.supers {
- if cls.Interface {
- impls = append(impls, g.javaTypeName(cls.Name))
- }
- }
- } else {
- impls = append(impls, "Seq.Proxy")
- }
- pT := types.NewPointer(s.obj.Type())
- for _, iface := range g.allIntf {
- if types.AssignableTo(pT, iface.obj.Type()) {
- n := iface.obj.Name()
- if p := iface.obj.Pkg(); p != g.Pkg {
- if n == JavaClassName(p) {
- n = n + "_"
- }
- n = fmt.Sprintf("%s.%s", g.javaPkgName(p), n)
- } else {
- n = g.javaTypeName(n)
- }
- impls = append(impls, n)
- }
- }
- doc := g.docs[n]
- g.javadoc(doc.Doc())
- g.Printf("public final class %s", n)
- if jinf != nil {
- if jinf.extends != nil {
- g.Printf(" extends %s", g.javaTypeName(jinf.extends.Name))
- }
- }
- if len(impls) > 0 {
- g.Printf(" implements %s", strings.Join(impls, ", "))
- }
- g.Printf(" {\n")
- g.Indent()
- g.Printf("static { %s.touch(); }\n\n", g.className())
- g.genProxyImpl(n)
- cons := g.constructors[s.obj]
- for _, f := range cons {
- if !g.isConsSigSupported(f.Type()) {
- g.Printf("// skipped constructor %s.%s with unsupported parameter or return types\n\n", n, f.Name())
- continue
- }
- g.genConstructor(f, n, jinf != nil)
- }
- if jinf == nil || jinf.genNoargCon {
- // constructor for Go instantiated instances.
- g.Printf("%s(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); }\n\n", n)
- if len(cons) == 0 {
- // Generate default no-arg constructor
- g.Printf("public %s() { this.refnum = __New(); Seq.trackGoRef(refnum, this); }\n\n", n)
- g.Printf("private static native int __New();\n\n")
- }
- }
- for _, f := range fields {
- if t := f.Type(); !g.isSupported(t) {
- g.Printf("// skipped field %s.%s with unsupported type: %s\n\n", n, f.Name(), t)
- continue
- }
- fdoc := doc.Member(f.Name())
- g.javadoc(fdoc)
- g.Printf("public final native %s get%s();\n", g.javaType(f.Type()), f.Name())
- g.javadoc(fdoc)
- g.Printf("public final native void set%s(%s v);\n\n", f.Name(), g.javaType(f.Type()))
- }
- var isStringer bool
- for _, m := range methods {
- if !g.isSigSupported(m.Type()) {
- g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", n, m.Name())
- continue
- }
- g.javadoc(doc.Member(m.Name()))
- var jm *java.Func
- hasThis := false
- if jinf != nil {
- hasThis = g.hasThis(n, m)
- jm = jinf.lookupMethod(m, hasThis)
- if jm != nil {
- g.Printf("@Override ")
- }
- }
- g.Printf("public native ")
- g.genFuncSignature(m, jm, hasThis)
- t := m.Type().(*types.Signature)
- isStringer = isStringer || (m.Name() == "String" && t.Params().Len() == 0 && t.Results().Len() == 1 &&
- types.Identical(t.Results().At(0).Type(), types.Typ[types.String]))
- }
- if jinf == nil {
- g.genObjectMethods(n, fields, isStringer)
- }
- g.Outdent()
- g.Printf("}\n\n")
- }
- // isConsSigSupported reports whether the generators can handle a given
- // constructor signature.
- func (g *JavaGen) isConsSigSupported(t types.Type) bool {
- if !g.isSigSupported(t) {
- return false
- }
- // Skip constructors taking a single int32 argument
- // since they clash with the proxy constructors that
- // take a refnum.
- params := t.(*types.Signature).Params()
- if params.Len() != 1 {
- return true
- }
- if t, ok := params.At(0).Type().(*types.Basic); ok {
- switch t.Kind() {
- case types.Int32, types.Uint32:
- return false
- }
- }
- return true
- }
- // javaTypeName returns the class name of a given Go type name. If
- // the type name clashes with the package class name, an underscore is
- // appended.
- func (g *JavaGen) javaTypeName(n string) string {
- if n == JavaClassName(g.Pkg) {
- return n + "_"
- }
- return n
- }
- func (g *JavaGen) javadoc(doc string) {
- if doc == "" {
- return
- }
- // JavaDoc expects HTML-escaped documentation.
- g.Printf("/**\n * %s */\n", html.EscapeString(doc))
- }
- // hasThis reports whether a method has an implicit "this" parameter.
- func (g *JavaGen) hasThis(sName string, m *types.Func) bool {
- sig := m.Type().(*types.Signature)
- params := sig.Params()
- if params.Len() == 0 {
- return false
- }
- v := params.At(0)
- if v.Name() != "this" {
- return false
- }
- t, ok := v.Type().(*types.Named)
- if !ok {
- return false
- }
- obj := t.Obj()
- pkg := obj.Pkg()
- if pkgFirstElem(pkg) != "Java" {
- return false
- }
- clsName := classNameFor(t)
- exp := g.javaPkgName(g.Pkg) + "." + sName
- if clsName != exp {
- g.errorf("the type %s of the `this` argument to method %s.%s is not %s", clsName, sName, m.Name(), exp)
- return false
- }
- return true
- }
- func (g *JavaGen) genConstructor(f *types.Func, n string, jcls bool) {
- g.javadoc(g.docs[f.Name()].Doc())
- g.Printf("public %s(", n)
- g.genFuncArgs(f, nil, false)
- g.Printf(") {\n")
- g.Indent()
- sig := f.Type().(*types.Signature)
- params := sig.Params()
- if jcls {
- g.Printf("super(")
- for i := 0; i < params.Len(); i++ {
- if i > 0 {
- g.Printf(", ")
- }
- g.Printf("%s", g.paramName(params, i))
- }
- g.Printf(");\n")
- }
- g.Printf("this.refnum = ")
- g.Printf("__%s(", f.Name())
- for i := 0; i < params.Len(); i++ {
- if i > 0 {
- g.Printf(", ")
- }
- g.Printf("%s", g.paramName(params, i))
- }
- g.Printf(");\n")
- g.Printf("Seq.trackGoRef(refnum, this);\n")
- g.Outdent()
- g.Printf("}\n\n")
- g.Printf("private static native int __%s(", f.Name())
- g.genFuncArgs(f, nil, false)
- g.Printf(");\n\n")
- }
- // genFuncArgs generated Java function arguments declaration for the function f.
- // If the supplied overridden java function is supplied, genFuncArgs omits the implicit
- // this argument.
- func (g *JavaGen) genFuncArgs(f *types.Func, jm *java.Func, hasThis bool) {
- sig := f.Type().(*types.Signature)
- params := sig.Params()
- first := 0
- if hasThis {
- // Skip the implicit this argument to the Go method
- first = 1
- }
- for i := first; i < params.Len(); i++ {
- if i > first {
- g.Printf(", ")
- }
- v := params.At(i)
- name := g.paramName(params, i)
- jt := g.javaType(v.Type())
- g.Printf("%s %s", jt, name)
- }
- }
- func (g *JavaGen) genObjectMethods(n string, fields []*types.Var, isStringer bool) {
- 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 {
- if t := f.Type(); !g.isSupported(t) {
- g.Printf("// skipped field %s.%s with unsupported type: %s\n\n", n, f.Name(), t)
- continue
- }
- 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[] {")
- idx := 0
- for _, f := range fields {
- if t := f.Type(); !g.isSupported(t) {
- continue
- }
- if idx > 0 {
- g.Printf(", ")
- }
- idx++
- g.Printf("get%s()", f.Name())
- }
- g.Printf("});\n")
- g.Printf("}\n\n")
- g.Printf("@Override public String toString() {\n")
- g.Indent()
- if isStringer {
- g.Printf("return string();\n")
- } else {
- g.Printf("StringBuilder b = new StringBuilder();\n")
- g.Printf(`b.append("%s").append("{");`, n)
- g.Printf("\n")
- for _, f := range fields {
- if t := f.Type(); !g.isSupported(t) {
- continue
- }
- 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")
- }
- func (g *JavaGen) genInterface(iface interfaceInfo) {
- pkgPath := ""
- if g.Pkg != nil {
- pkgPath = g.Pkg.Path()
- }
- g.Printf(javaPreamble, g.javaPkgName(g.Pkg), g.javaTypeName(iface.obj.Name()), g.gobindOpts(), pkgPath)
- var exts []string
- numM := iface.t.NumMethods()
- for _, other := range g.allIntf {
- // Only extend interfaces with fewer methods to avoid circular references
- if other.t.NumMethods() < numM && types.AssignableTo(iface.t, other.t) {
- n := other.obj.Name()
- if p := other.obj.Pkg(); p != g.Pkg {
- if n == JavaClassName(p) {
- n = n + "_"
- }
- n = fmt.Sprintf("%s.%s", g.javaPkgName(p), n)
- } else {
- n = g.javaTypeName(n)
- }
- exts = append(exts, n)
- }
- }
- doc := g.docs[iface.obj.Name()]
- g.javadoc(doc.Doc())
- g.Printf("public interface %s", g.javaTypeName(iface.obj.Name()))
- if len(exts) > 0 {
- g.Printf(" extends %s", strings.Join(exts, ", "))
- }
- g.Printf(" {\n")
- g.Indent()
- for _, m := range iface.summary.callable {
- if !g.isSigSupported(m.Type()) {
- g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", iface.obj.Name(), m.Name())
- continue
- }
- g.javadoc(doc.Member(m.Name()))
- g.Printf("public ")
- g.genFuncSignature(m, nil, false)
- }
- g.Printf("\n")
- g.Outdent()
- g.Printf("}\n\n")
- }
- 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
- }
- // jniType returns a string that can be used as a JNI type.
- func (g *JavaGen) jniType(T types.Type) string {
- switch T := T.(type) {
- case *types.Basic:
- switch T.Kind() {
- case types.Bool, types.UntypedBool:
- return "jboolean"
- case types.Int:
- return "jlong"
- case types.Int8:
- return "jbyte"
- case types.Int16:
- return "jshort"
- case types.Int32, types.UntypedRune: // types.Rune
- return "jint"
- case types.Int64, types.UntypedInt:
- return "jlong"
- case types.Uint8: // types.Byte
- // TODO(crawshaw): Java bytes are signed, so this is
- // questionable, but vital.
- return "jbyte"
- // TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64:
- case types.Float32:
- return "jfloat"
- case types.Float64, types.UntypedFloat:
- return "jdouble"
- case types.String, types.UntypedString:
- return "jstring"
- default:
- g.errorf("unsupported basic type: %s", T)
- return "TODO"
- }
- case *types.Slice:
- return "jbyteArray"
- case *types.Pointer:
- if _, ok := T.Elem().(*types.Named); ok {
- return g.jniType(T.Elem())
- }
- g.errorf("unsupported pointer to type: %s", T)
- case *types.Named:
- return "jobject"
- default:
- g.errorf("unsupported jniType: %#+v, %s\n", T, T)
- }
- return "TODO"
- }
- func (g *JavaGen) javaBasicType(T *types.Basic) string {
- switch T.Kind() {
- case types.Bool, types.UntypedBool:
- return "boolean"
- case types.Int:
- return "long"
- case types.Int8:
- return "byte"
- case types.Int16:
- return "short"
- case types.Int32, types.UntypedRune: // types.Rune
- return "int"
- case types.Int64, types.UntypedInt:
- return "long"
- case types.Uint8: // types.Byte
- // 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, types.UntypedFloat:
- return "double"
- case types.String, types.UntypedString:
- return "String"
- default:
- g.errorf("unsupported basic type: %s", T)
- return "TODO"
- }
- }
- // javaType returns a string that can be used as a Java type.
- func (g *JavaGen) javaType(T types.Type) string {
- if isErrorType(T) {
- // The error type is usually translated into an exception in
- // Java, however the type can be exposed in other ways, such
- // as an exported field.
- return "java.lang.Exception"
- } else if isJavaType(T) {
- return classNameFor(T)
- }
- switch T := T.(type) {
- case *types.Basic:
- return g.javaBasicType(T)
- 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())
- }
- g.errorf("unsupported pointer to type: %s", T)
- case *types.Named:
- n := T.Obj()
- nPkg := n.Pkg()
- if !isErrorType(T) && !g.validPkg(nPkg) {
- g.errorf("type %s is in %s, which is not bound", n.Name(), nPkg)
- break
- }
- // TODO(crawshaw): more checking here
- clsName := n.Name()
- if nPkg != g.Pkg {
- if clsName == JavaClassName(nPkg) {
- clsName += "_"
- }
- return fmt.Sprintf("%s.%s", g.javaPkgName(nPkg), clsName)
- } else {
- return g.javaTypeName(clsName)
- }
- default:
- g.errorf("unsupported javaType: %#+v, %s\n", T, T)
- }
- return "TODO"
- }
- func (g *JavaGen) genJNIFuncSignature(o *types.Func, sName string, jm *java.Func, proxy, isjava bool) {
- sig := o.Type().(*types.Signature)
- res := sig.Results()
- var ret string
- switch res.Len() {
- case 2:
- ret = g.jniType(res.At(0).Type())
- case 1:
- if isErrorType(res.At(0).Type()) {
- ret = "void"
- } else {
- ret = g.jniType(res.At(0).Type())
- }
- case 0:
- ret = "void"
- default:
- g.errorf("too many result values: %s", o)
- return
- }
- g.Printf("JNIEXPORT %s JNICALL\n", ret)
- g.Printf("Java_%s_", g.jniPkgName())
- if sName != "" {
- if proxy {
- g.Printf("%s", java.JNIMangle(g.className()))
- // 0024 is the mangled form of $, for naming inner classes.
- g.Printf("_00024proxy%s", sName)
- } else {
- g.Printf("%s", java.JNIMangle(g.javaTypeName(sName)))
- }
- } else {
- g.Printf("%s", java.JNIMangle(g.className()))
- }
- g.Printf("_")
- if jm != nil {
- g.Printf("%s", jm.JNIName)
- } else {
- oName := javaNameReplacer(lowerFirst(o.Name()))
- g.Printf("%s", java.JNIMangle(oName))
- }
- g.Printf("(JNIEnv* env, ")
- if sName != "" {
- g.Printf("jobject __this__")
- } else {
- g.Printf("jclass _clazz")
- }
- params := sig.Params()
- i := 0
- if isjava && params.Len() > 0 && params.At(0).Name() == "this" {
- // Skip the implicit this argument, if any.
- i = 1
- }
- for ; i < params.Len(); i++ {
- g.Printf(", ")
- v := sig.Params().At(i)
- name := g.paramName(params, i)
- jt := g.jniType(v.Type())
- g.Printf("%s %s", jt, name)
- }
- g.Printf(")")
- }
- func (g *JavaGen) jniPkgName() string {
- return strings.Replace(java.JNIMangle(g.javaPkgName(g.Pkg)), ".", "_", -1)
- }
- var javaLetterDigitRE = regexp.MustCompile(`[0-9a-zA-Z$_]`)
- func (g *JavaGen) paramName(params *types.Tuple, pos int) string {
- name := basicParamName(params, pos)
- if !javaLetterDigitRE.MatchString(name) {
- name = fmt.Sprintf("p%d", pos)
- }
- return javaNameReplacer(name)
- }
- func (g *JavaGen) genFuncSignature(o *types.Func, jm *java.Func, hasThis bool) {
- 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()) {
- g.errorf("second result value must be of type error: %s", o)
- return
- }
- 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:
- g.errorf("too many result values: %s", o)
- return
- }
- g.Printf("%s ", ret)
- if jm != nil {
- g.Printf("%s", jm.Name)
- } else {
- g.Printf("%s", javaNameReplacer(lowerFirst(o.Name())))
- }
- g.Printf("(")
- g.genFuncArgs(o, jm, hasThis)
- g.Printf(")")
- if returnsError {
- if jm != nil {
- if jm.Throws == "" {
- g.errorf("%s declares an error return value but the overridden method does not throw", o)
- return
- }
- g.Printf(" throws %s", jm.Throws)
- } else {
- g.Printf(" throws Exception")
- }
- }
- g.Printf(";\n")
- }
- func (g *JavaGen) genVar(o *types.Var) {
- if t := o.Type(); !g.isSupported(t) {
- g.Printf("// skipped variable %s with unsupported type: %s\n\n", o.Name(), t)
- return
- }
- jType := g.javaType(o.Type())
- doc := g.docs[o.Name()].Doc()
- // setter
- g.javadoc(doc)
- g.Printf("public static native void set%s(%s v);\n", o.Name(), jType)
- // getter
- g.javadoc(doc)
- g.Printf("public static native %s get%s();\n\n", jType, o.Name())
- }
- // genCRetClear clears the result value from a JNI call if an exception was
- // raised.
- func (g *JavaGen) genCRetClear(varName string, t types.Type, exc string) {
- g.Printf("if (%s != NULL) {\n", exc)
- g.Indent()
- switch t := t.(type) {
- case *types.Basic:
- switch t.Kind() {
- case types.String:
- g.Printf("%s = NULL;\n", varName)
- default:
- g.Printf("%s = 0;\n", varName)
- }
- case *types.Slice, *types.Named, *types.Pointer:
- g.Printf("%s = NULL;\n", varName)
- }
- g.Outdent()
- g.Printf("}\n")
- }
- func (g *JavaGen) genJavaToC(varName string, t types.Type, mode varMode) {
- switch t := t.(type) {
- case *types.Basic:
- switch t.Kind() {
- case types.String:
- g.Printf("nstring _%s = go_seq_from_java_string(env, %s);\n", varName, varName)
- default:
- g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName)
- }
- case *types.Slice:
- switch e := t.Elem().(type) {
- case *types.Basic:
- switch e.Kind() {
- case types.Uint8: // Byte.
- g.Printf("nbyteslice _%s = go_seq_from_java_bytearray(env, %s, %d);\n", varName, varName, toCFlag(mode == modeRetained))
- default:
- g.errorf("unsupported type: %s", t)
- }
- default:
- g.errorf("unsupported type: %s", t)
- }
- case *types.Named:
- switch u := t.Underlying().(type) {
- case *types.Interface:
- g.Printf("int32_t _%s = go_seq_to_refnum(env, %s);\n", varName, varName)
- default:
- g.errorf("unsupported named type: %s / %T", u, u)
- }
- case *types.Pointer:
- g.Printf("int32_t _%s = go_seq_to_refnum(env, %s);\n", varName, varName)
- default:
- g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName)
- }
- }
- func (g *JavaGen) genCToJava(toName, fromName string, t types.Type, mode varMode) {
- switch t := t.(type) {
- case *types.Basic:
- switch t.Kind() {
- case types.String:
- g.Printf("jstring %s = go_seq_to_java_string(env, %s);\n", toName, fromName)
- case types.Bool:
- g.Printf("jboolean %s = %s ? JNI_TRUE : JNI_FALSE;\n", toName, fromName)
- default:
- g.Printf("%s %s = (%s)%s;\n", g.jniType(t), toName, g.jniType(t), fromName)
- }
- case *types.Slice:
- switch e := t.Elem().(type) {
- case *types.Basic:
- switch e.Kind() {
- case types.Uint8: // Byte.
- g.Printf("jbyteArray %s = go_seq_to_java_bytearray(env, %s, %d);\n", toName, fromName, toCFlag(mode == modeRetained))
- default:
- g.errorf("unsupported type: %s", t)
- }
- default:
- g.errorf("unsupported type: %s", t)
- }
- case *types.Pointer:
- // TODO(crawshaw): test *int
- // TODO(crawshaw): test **Generator
- switch t := t.Elem().(type) {
- case *types.Named:
- g.genFromRefnum(toName, fromName, t, t.Obj())
- default:
- g.errorf("unsupported type %s", t)
- }
- case *types.Named:
- switch t.Underlying().(type) {
- case *types.Interface, *types.Pointer:
- g.genFromRefnum(toName, fromName, t, t.Obj())
- default:
- g.errorf("unsupported, direct named type %s", t)
- }
- default:
- g.Printf("%s %s = (%s)%s;\n", g.jniType(t), toName, g.jniType(t), fromName)
- }
- }
- func (g *JavaGen) genFromRefnum(toName, fromName string, t types.Type, o *types.TypeName) {
- oPkg := o.Pkg()
- isJava := isJavaType(o.Type())
- if !isErrorType(o.Type()) && !g.validPkg(oPkg) && !isJava {
- g.errorf("type %s is defined in package %s, which is not bound", t, oPkg)
- return
- }
- p := pkgPrefix(oPkg)
- g.Printf("jobject %s = go_seq_from_refnum(env, %s, ", toName, fromName)
- if isJava {
- g.Printf("NULL, NULL")
- } else {
- g.Printf("proxy_class_%s_%s, proxy_class_%s_%s_cons", p, o.Name(), p, o.Name())
- }
- g.Printf(");\n")
- }
- func (g *JavaGen) gobindOpts() string {
- opts := []string{"-lang=java"}
- if g.JavaPkg != "" {
- opts = append(opts, "-javapkg="+g.JavaPkg)
- }
- return strings.Join(opts, " ")
- }
- var javaNameReplacer = newNameSanitizer([]string{
- "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char",
- "class", "const", "continue", "default", "do", "double", "else", "enum",
- "extends", "final", "finally", "float", "for", "goto", "if", "implements",
- "import", "instanceof", "int", "interface", "long", "native", "new", "package",
- "private", "protected", "public", "return", "short", "static", "strictfp",
- "super", "switch", "synchronized", "this", "throw", "throws", "transient",
- "try", "void", "volatile", "while", "false", "null", "true"})
- func (g *JavaGen) javaPkgName(pkg *types.Package) string {
- return JavaPkgName(g.JavaPkg, pkg)
- }
- // JavaPkgName returns the Java package name for a Go package
- // given a pkg prefix. If the prefix is empty, "go" is used
- // instead.
- func JavaPkgName(pkgPrefix string, pkg *types.Package) string {
- if pkg == nil {
- return "go"
- }
- s := javaNameReplacer(pkg.Name())
- if pkgPrefix == "" {
- return s
- }
- return pkgPrefix + "." + s
- }
- func (g *JavaGen) className() string {
- return JavaClassName(g.Pkg)
- }
- // JavaClassName returns the name of the Java class that
- // contains Go package level identifiers.
- func JavaClassName(pkg *types.Package) string {
- if pkg == nil {
- return "Universe"
- }
- return javaNameReplacer(strings.Title(pkg.Name()))
- }
- func (g *JavaGen) genConst(o *types.Const) {
- if _, ok := o.Type().(*types.Basic); !ok || !g.isSupported(o.Type()) {
- g.Printf("// skipped const %s with unsupported type: %s\n\n", o.Name(), o.Type())
- return
- }
- // TODO(hyangah): should const names use upper cases + "_"?
- // TODO(hyangah): check invalid names.
- jType := g.javaType(o.Type())
- val := o.Val().ExactString()
- switch b := o.Type().(*types.Basic); b.Kind() {
- case types.Int64, types.UntypedInt:
- i, exact := constant.Int64Val(o.Val())
- if !exact {
- g.errorf("const value %s for %s cannot be represented as %s", val, o.Name(), jType)
- return
- }
- val = fmt.Sprintf("%dL", i)
- case types.Float32:
- f, _ := constant.Float32Val(o.Val())
- val = fmt.Sprintf("%gf", f)
- case types.Float64, types.UntypedFloat:
- f, _ := constant.Float64Val(o.Val())
- if math.IsInf(f, 0) || math.Abs(f) > math.MaxFloat64 {
- g.errorf("const value %s for %s cannot be represented as %s", val, o.Name(), jType)
- return
- }
- val = fmt.Sprintf("%g", f)
- }
- g.javadoc(g.docs[o.Name()].Doc())
- g.Printf("public static final %s %s = %s;\n", g.javaType(o.Type()), o.Name(), val)
- }
- func (g *JavaGen) genJNIField(o *types.TypeName, f *types.Var) {
- if t := f.Type(); !g.isSupported(t) {
- g.Printf("// skipped field %s with unsupported type: %s\n\n", o.Name(), t)
- return
- }
- n := java.JNIMangle(g.javaTypeName(o.Name()))
- // setter
- g.Printf("JNIEXPORT void JNICALL\n")
- g.Printf("Java_%s_%s_set%s(JNIEnv *env, jobject this, %s v) {\n", g.jniPkgName(), n, java.JNIMangle(f.Name()), g.jniType(f.Type()))
- g.Indent()
- g.Printf("int32_t o = go_seq_to_refnum_go(env, this);\n")
- g.genJavaToC("v", f.Type(), modeRetained)
- g.Printf("proxy%s_%s_%s_Set(o, _v);\n", g.pkgPrefix, o.Name(), f.Name())
- g.genRelease("v", f.Type(), modeRetained)
- g.Outdent()
- g.Printf("}\n\n")
- // getter
- g.Printf("JNIEXPORT %s JNICALL\n", g.jniType(f.Type()))
- g.Printf("Java_%s_%s_get%s(JNIEnv *env, jobject this) {\n", g.jniPkgName(), n, java.JNIMangle(f.Name()))
- g.Indent()
- g.Printf("int32_t o = go_seq_to_refnum_go(env, this);\n")
- g.Printf("%s r0 = ", g.cgoType(f.Type()))
- g.Printf("proxy%s_%s_%s_Get(o);\n", g.pkgPrefix, o.Name(), f.Name())
- g.genCToJava("_r0", "r0", f.Type(), modeRetained)
- g.Printf("return _r0;\n")
- g.Outdent()
- g.Printf("}\n\n")
- }
- func (g *JavaGen) genJNIVar(o *types.Var) {
- if t := o.Type(); !g.isSupported(t) {
- g.Printf("// skipped variable %s with unsupported type: %s\n\n", o.Name(), t)
- return
- }
- n := java.JNIMangle(g.javaTypeName(o.Name()))
- // setter
- g.Printf("JNIEXPORT void JNICALL\n")
- g.Printf("Java_%s_%s_set%s(JNIEnv *env, jclass clazz, %s v) {\n", g.jniPkgName(), java.JNIMangle(g.className()), n, g.jniType(o.Type()))
- g.Indent()
- g.genJavaToC("v", o.Type(), modeRetained)
- g.Printf("var_set%s_%s(_v);\n", g.pkgPrefix, o.Name())
- g.genRelease("v", o.Type(), modeRetained)
- g.Outdent()
- g.Printf("}\n\n")
- // getter
- g.Printf("JNIEXPORT %s JNICALL\n", g.jniType(o.Type()))
- g.Printf("Java_%s_%s_get%s(JNIEnv *env, jclass clazz) {\n", g.jniPkgName(), java.JNIMangle(g.className()), n)
- g.Indent()
- g.Printf("%s r0 = ", g.cgoType(o.Type()))
- g.Printf("var_get%s_%s();\n", g.pkgPrefix, o.Name())
- g.genCToJava("_r0", "r0", o.Type(), modeRetained)
- g.Printf("return _r0;\n")
- g.Outdent()
- g.Printf("}\n\n")
- }
- func (g *JavaGen) genJNIConstructor(f *types.Func, sName string) {
- if !g.isConsSigSupported(f.Type()) {
- return
- }
- sig := f.Type().(*types.Signature)
- res := sig.Results()
- g.Printf("JNIEXPORT jint JNICALL\n")
- g.Printf("Java_%s_%s_%s(JNIEnv *env, jclass clazz", g.jniPkgName(), java.JNIMangle(g.javaTypeName(sName)), java.JNIMangle("__"+f.Name()))
- params := sig.Params()
- for i := 0; i < params.Len(); i++ {
- v := params.At(i)
- jt := g.jniType(v.Type())
- g.Printf(", %s %s", jt, g.paramName(params, i))
- }
- g.Printf(") {\n")
- g.Indent()
- for i := 0; i < params.Len(); i++ {
- name := g.paramName(params, i)
- g.genJavaToC(name, params.At(i).Type(), modeTransient)
- }
- // Constructors always return a mandatory *T and an optional error
- if res.Len() == 1 {
- g.Printf("int32_t refnum = proxy%s__%s(", g.pkgPrefix, f.Name())
- } else {
- g.Printf("struct proxy%s__%s_return res = proxy%s__%s(", g.pkgPrefix, f.Name(), g.pkgPrefix, f.Name())
- }
- for i := 0; i < params.Len(); i++ {
- if i > 0 {
- g.Printf(", ")
- }
- g.Printf("_%s", g.paramName(params, i))
- }
- g.Printf(");\n")
- for i := 0; i < params.Len(); i++ {
- g.genRelease(g.paramName(params, i), params.At(i).Type(), modeTransient)
- }
- // Extract multi returns and handle errors
- if res.Len() == 2 {
- g.Printf("int32_t refnum = res.r0;\n")
- g.genCToJava("_err", "res.r1", res.At(1).Type(), modeRetained)
- g.Printf("go_seq_maybe_throw_exception(env, _err);\n")
- }
- g.Printf("return refnum;\n")
- g.Outdent()
- g.Printf("}\n\n")
- }
- func (g *JavaGen) genJNIFunc(o *types.Func, sName string, jm *java.Func, proxy, isjava bool) {
- if !g.isSigSupported(o.Type()) {
- n := o.Name()
- if sName != "" {
- n = sName + "." + n
- }
- g.Printf("// skipped function %s with unsupported parameter or return types\n\n", n)
- return
- }
- g.genJNIFuncSignature(o, sName, jm, proxy, isjava)
- g.Printf(" {\n")
- g.Indent()
- g.genJNIFuncBody(o, sName, jm, isjava)
- g.Outdent()
- g.Printf("}\n\n")
- }
- func (g *JavaGen) genJNIFuncBody(o *types.Func, sName string, jm *java.Func, isjava bool) {
- sig := o.Type().(*types.Signature)
- res := sig.Results()
- if sName != "" {
- g.Printf("int32_t o = go_seq_to_refnum_go(env, __this__);\n")
- }
- params := sig.Params()
- first := 0
- if isjava && params.Len() > 0 && params.At(0).Name() == "this" {
- // Start after the implicit this argument.
- first = 1
- g.Printf("int32_t _%s = go_seq_to_refnum(env, __this__);\n", g.paramName(params, 0))
- }
- for i := first; i < params.Len(); i++ {
- name := g.paramName(params, i)
- g.genJavaToC(name, params.At(i).Type(), modeTransient)
- }
- resPrefix := ""
- if res.Len() > 0 {
- if res.Len() == 1 {
- g.Printf("%s r0 = ", g.cgoType(res.At(0).Type()))
- } else {
- resPrefix = "res."
- g.Printf("struct proxy%s_%s_%s_return res = ", g.pkgPrefix, sName, o.Name())
- }
- }
- g.Printf("proxy%s_%s_%s(", g.pkgPrefix, sName, o.Name())
- if sName != "" {
- g.Printf("o")
- }
- // Pass all arguments, including the implicit this argument.
- for i := 0; i < params.Len(); i++ {
- if i > 0 || sName != "" {
- g.Printf(", ")
- }
- g.Printf("_%s", g.paramName(params, i))
- }
- g.Printf(");\n")
- for i := first; i < params.Len(); i++ {
- g.genRelease(g.paramName(params, i), params.At(i).Type(), modeTransient)
- }
- for i := 0; i < res.Len(); i++ {
- tn := fmt.Sprintf("_r%d", i)
- t := res.At(i).Type()
- g.genCToJava(tn, fmt.Sprintf("%sr%d", resPrefix, i), t, modeRetained)
- }
- // Go backwards so that any exception is thrown before
- // the return.
- for i := res.Len() - 1; i >= 0; i-- {
- t := res.At(i).Type()
- if !isErrorType(t) {
- g.Printf("return _r%d;\n", i)
- } else {
- g.Printf("go_seq_maybe_throw_exception(env, _r%d);\n", i)
- }
- }
- }
- // genRelease cleans up arguments that weren't copied in genJavaToC.
- func (g *JavaGen) genRelease(varName string, t types.Type, mode varMode) {
- switch t := t.(type) {
- case *types.Basic:
- case *types.Slice:
- switch e := t.Elem().(type) {
- case *types.Basic:
- switch e.Kind() {
- case types.Uint8: // Byte.
- if mode == modeTransient {
- g.Printf("go_seq_release_byte_array(env, %s, _%s.ptr);\n", varName, varName)
- }
- }
- }
- }
- }
- func (g *JavaGen) genMethodInterfaceProxy(oName string, m *types.Func) {
- if !g.isSigSupported(m.Type()) {
- g.Printf("// skipped method %s with unsupported parameter or return types\n\n", oName)
- return
- }
- sig := m.Type().(*types.Signature)
- params := sig.Params()
- res := sig.Results()
- g.genInterfaceMethodSignature(m, oName, false, g.paramName)
- g.Indent()
- g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", params.Len())
- g.Printf("jobject o = go_seq_from_refnum(env, refnum, proxy_class_%s_%s, proxy_class_%s_%s_cons);\n", g.pkgPrefix, oName, g.pkgPrefix, oName)
- for i := 0; i < params.Len(); i++ {
- pn := g.paramName(params, i)
- g.genCToJava("_"+pn, pn, params.At(i).Type(), modeTransient)
- }
- if res.Len() > 0 && !isErrorType(res.At(0).Type()) {
- t := res.At(0).Type()
- g.Printf("%s res = (*env)->Call%sMethod(env, o, ", g.jniType(t), g.jniCallType(t))
- } else {
- g.Printf("(*env)->CallVoidMethod(env, o, ")
- }
- g.Printf("mid_%s_%s", oName, m.Name())
- for i := 0; i < params.Len(); i++ {
- g.Printf(", _%s", g.paramName(params, i))
- }
- g.Printf(");\n")
- var retName string
- if res.Len() > 0 {
- t := res.At(0).Type()
- if res.Len() == 2 || isErrorType(t) {
- g.Printf("jobject exc = go_seq_get_exception(env);\n")
- errType := types.Universe.Lookup("error").Type()
- g.genJavaToC("exc", errType, modeRetained)
- retName = "_exc"
- }
- if !isErrorType(t) {
- if res.Len() == 2 {
- g.genCRetClear("res", t, "exc")
- }
- g.genJavaToC("res", t, modeRetained)
- retName = "_res"
- }
- if res.Len() > 1 {
- g.Printf("cproxy%s_%s_%s_return sres = {\n", g.pkgPrefix, oName, m.Name())
- g.Printf(" _res, _exc\n")
- g.Printf("};\n")
- retName = "sres"
- }
- }
- g.Printf("go_seq_pop_local_frame(env);\n")
- if retName != "" {
- g.Printf("return %s;\n", retName)
- }
- g.Outdent()
- g.Printf("}\n\n")
- }
- func (g *JavaGen) GenH() error {
- pkgPath := ""
- if g.Pkg != nil {
- pkgPath = g.Pkg.Path()
- }
- g.Printf(hPreamble, g.gobindOpts(), pkgPath, g.className())
- for _, iface := range g.interfaces {
- g.Printf("extern jclass proxy_class_%s_%s;\n", g.pkgPrefix, iface.obj.Name())
- g.Printf("extern jmethodID proxy_class_%s_%s_cons;\n", g.pkgPrefix, iface.obj.Name())
- g.Printf("\n")
- for _, m := range iface.summary.callable {
- if !g.isSigSupported(m.Type()) {
- g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", iface.obj.Name(), m.Name())
- continue
- }
- g.genInterfaceMethodSignature(m, iface.obj.Name(), true, g.paramName)
- g.Printf("\n")
- }
- }
- for _, s := range g.structs {
- g.Printf("extern jclass proxy_class_%s_%s;\n", g.pkgPrefix, s.obj.Name())
- g.Printf("extern jmethodID proxy_class_%s_%s_cons;\n", g.pkgPrefix, s.obj.Name())
- }
- g.Printf("#endif\n")
- if len(g.err) > 0 {
- return g.err
- }
- return nil
- }
- func (g *JavaGen) jniCallType(t types.Type) string {
- switch t := t.(type) {
- case *types.Basic:
- switch t.Kind() {
- case types.Bool, types.UntypedBool:
- return "Boolean"
- case types.Int:
- return "Long"
- case types.Int8, types.Uint8: // types.Byte
- return "Byte"
- case types.Int16:
- return "Short"
- case types.Int32, types.UntypedRune: // types.Rune
- return "Int"
- case types.Int64, types.UntypedInt:
- return "Long"
- case types.Float32:
- return "Float"
- case types.Float64, types.UntypedFloat:
- return "Double"
- case types.String, types.UntypedString:
- return "Object"
- default:
- g.errorf("unsupported basic type: %s", t)
- }
- case *types.Slice:
- return "Object"
- case *types.Pointer:
- if _, ok := t.Elem().(*types.Named); ok {
- return g.jniCallType(t.Elem())
- }
- g.errorf("unsupported pointer to type: %s", t)
- case *types.Named:
- return "Object"
- default:
- return "Object"
- }
- return "TODO"
- }
- func (g *JavaGen) jniClassSigPrefix(pkg *types.Package) string {
- return strings.Replace(g.javaPkgName(pkg), ".", "/", -1) + "/"
- }
- func (g *JavaGen) jniSigType(T types.Type) string {
- if isErrorType(T) {
- return "Ljava/lang/Exception;"
- }
- switch T := T.(type) {
- case *types.Basic:
- switch T.Kind() {
- case types.Bool, types.UntypedBool:
- return "Z"
- case types.Int:
- return "J"
- case types.Int8:
- return "B"
- case types.Int16:
- return "S"
- case types.Int32, types.UntypedRune: // types.Rune
- return "I"
- case types.Int64, types.UntypedInt:
- return "J"
- case types.Uint8: // types.Byte
- return "B"
- case types.Float32:
- return "F"
- case types.Float64, types.UntypedFloat:
- return "D"
- case types.String, types.UntypedString:
- return "Ljava/lang/String;"
- default:
- g.errorf("unsupported basic type: %s", T)
- return "TODO"
- }
- case *types.Slice:
- return "[" + g.jniSigType(T.Elem())
- case *types.Pointer:
- if _, ok := T.Elem().(*types.Named); ok {
- return g.jniSigType(T.Elem())
- }
- g.errorf("unsupported pointer to type: %s", T)
- case *types.Named:
- return "L" + g.jniClassSigPrefix(T.Obj().Pkg()) + g.javaTypeName(T.Obj().Name()) + ";"
- default:
- g.errorf("unsupported jniType: %#+v, %s\n", T, T)
- }
- return "TODO"
- }
- func (g *JavaGen) GenC() error {
- var pkgName, pkgPath string
- if g.Pkg != nil {
- pkgName = g.Pkg.Name()
- pkgPath = g.Pkg.Path()
- } else {
- pkgName = "universe"
- }
- g.Printf(cPreamble, g.gobindOpts(), pkgPath)
- g.Printf("#include %q\n", pkgName+".h")
- if g.Pkg != nil {
- for _, pkg := range g.Pkg.Imports() {
- if g.validPkg(pkg) {
- g.Printf("#include \"%s.h\"\n", pkg.Name())
- }
- }
- }
- g.Printf("\n")
- for _, iface := range g.interfaces {
- g.Printf("jclass proxy_class_%s_%s;\n", g.pkgPrefix, iface.obj.Name())
- g.Printf("jmethodID proxy_class_%s_%s_cons;\n", g.pkgPrefix, iface.obj.Name())
- for _, m := range iface.summary.callable {
- if !g.isSigSupported(m.Type()) {
- g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", iface.obj.Name(), m.Name())
- continue
- }
- g.Printf("static jmethodID mid_%s_%s;\n", iface.obj.Name(), m.Name())
- }
- }
- for _, s := range g.structs {
- g.Printf("jclass proxy_class_%s_%s;\n", g.pkgPrefix, s.obj.Name())
- g.Printf("jmethodID proxy_class_%s_%s_cons;\n", g.pkgPrefix, s.obj.Name())
- }
- g.Printf("\n")
- g.Printf("JNIEXPORT void JNICALL\n")
- g.Printf("Java_%s_%s__1init(JNIEnv *env, jclass _unused) {\n", g.jniPkgName(), java.JNIMangle(g.className()))
- g.Indent()
- g.Printf("jclass clazz;\n")
- for _, s := range g.structs {
- if jinf, ok := g.jstructs[s.obj]; ok {
- // Leave the class and constructor NULL for Java classes with no
- // default constructor.
- if !jinf.genNoargCon {
- continue
- }
- }
- g.Printf("clazz = (*env)->FindClass(env, %q);\n", g.jniClassSigPrefix(s.obj.Pkg())+g.javaTypeName(s.obj.Name()))
- g.Printf("proxy_class_%s_%s = (*env)->NewGlobalRef(env, clazz);\n", g.pkgPrefix, s.obj.Name())
- g.Printf("proxy_class_%s_%s_cons = (*env)->GetMethodID(env, clazz, \"<init>\", \"(I)V\");\n", g.pkgPrefix, s.obj.Name())
- }
- for _, iface := range g.interfaces {
- pkg := iface.obj.Pkg()
- g.Printf("clazz = (*env)->FindClass(env, %q);\n", g.jniClassSigPrefix(pkg)+JavaClassName(pkg)+"$proxy"+iface.obj.Name())
- g.Printf("proxy_class_%s_%s = (*env)->NewGlobalRef(env, clazz);\n", g.pkgPrefix, iface.obj.Name())
- g.Printf("proxy_class_%s_%s_cons = (*env)->GetMethodID(env, clazz, \"<init>\", \"(I)V\");\n", g.pkgPrefix, iface.obj.Name())
- if isErrorType(iface.obj.Type()) {
- // As a special case, Java Exceptions are passed to Go pretending to implement the Go error interface.
- // To complete the illusion, use the Throwable.getMessage method for proxied calls to the error.Error method.
- g.Printf("clazz = (*env)->FindClass(env, \"java/lang/Throwable\");\n")
- g.Printf("mid_error_Error = (*env)->GetMethodID(env, clazz, \"getMessage\", \"()Ljava/lang/String;\");\n")
- continue
- }
- g.Printf("clazz = (*env)->FindClass(env, %q);\n", g.jniClassSigPrefix(pkg)+g.javaTypeName(iface.obj.Name()))
- for _, m := range iface.summary.callable {
- if !g.isSigSupported(m.Type()) {
- g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", iface.obj.Name(), m.Name())
- continue
- }
- sig := m.Type().(*types.Signature)
- res := sig.Results()
- retSig := "V"
- if res.Len() > 0 {
- if t := res.At(0).Type(); !isErrorType(t) {
- retSig = g.jniSigType(t)
- }
- }
- var jniParams string
- params := sig.Params()
- for i := 0; i < params.Len(); i++ {
- jniParams += g.jniSigType(params.At(i).Type())
- }
- g.Printf("mid_%s_%s = (*env)->GetMethodID(env, clazz, %q, \"(%s)%s\");\n",
- iface.obj.Name(), m.Name(), javaNameReplacer(lowerFirst(m.Name())), jniParams, retSig)
- }
- g.Printf("\n")
- }
- g.Outdent()
- g.Printf("}\n\n")
- for _, f := range g.funcs {
- g.genJNIFunc(f, "", nil, false, false)
- }
- for _, s := range g.structs {
- sName := s.obj.Name()
- cons := g.constructors[s.obj]
- jinf := g.jstructs[s.obj]
- for _, f := range cons {
- g.genJNIConstructor(f, sName)
- }
- if len(cons) == 0 && (jinf == nil || jinf.genNoargCon) {
- g.Printf("JNIEXPORT jint JNICALL\n")
- g.Printf("Java_%s_%s_%s(JNIEnv *env, jclass clazz) {\n", g.jniPkgName(), java.JNIMangle(g.javaTypeName(sName)), java.JNIMangle("__New"))
- g.Indent()
- g.Printf("return new_%s_%s();\n", g.pkgPrefix, sName)
- g.Outdent()
- g.Printf("}\n\n")
- }
- for _, m := range exportedMethodSet(types.NewPointer(s.obj.Type())) {
- var jm *java.Func
- if jinf != nil {
- jm = jinf.lookupMethod(m, g.hasThis(s.obj.Name(), m))
- }
- g.genJNIFunc(m, sName, jm, false, jinf != nil)
- }
- for _, f := range exportedFields(s.t) {
- g.genJNIField(s.obj, f)
- }
- }
- for _, iface := range g.interfaces {
- for _, m := range iface.summary.callable {
- g.genJNIFunc(m, iface.obj.Name(), nil, true, false)
- g.genMethodInterfaceProxy(iface.obj.Name(), m)
- }
- }
- for _, v := range g.vars {
- g.genJNIVar(v)
- }
- if len(g.err) > 0 {
- return g.err
- }
- return nil
- }
- func (g *JavaGen) GenJava() error {
- pkgPath := ""
- if g.Pkg != nil {
- pkgPath = g.Pkg.Path()
- }
- g.Printf(javaPreamble, g.javaPkgName(g.Pkg), g.className(), g.gobindOpts(), pkgPath)
- g.Printf("public abstract class %s {\n", g.className())
- g.Indent()
- g.Printf("static {\n")
- g.Indent()
- g.Printf("Seq.touch(); // for loading the native library\n")
- if g.Pkg != nil {
- for _, p := range g.Pkg.Imports() {
- if g.validPkg(p) {
- g.Printf("%s.%s.touch();\n", g.javaPkgName(p), JavaClassName(p))
- }
- }
- }
- g.Printf("_init();\n")
- g.Outdent()
- g.Printf("}\n\n")
- g.Printf("private %s() {} // uninstantiable\n\n", g.className())
- g.Printf("// touch is called from other bound packages to initialize this package\n")
- g.Printf("public static void touch() {}\n\n")
- g.Printf("private static native void _init();\n\n")
- for _, iface := range g.interfaces {
- n := iface.obj.Name()
- g.Printf("private static final class proxy%s", n)
- if isErrorType(iface.obj.Type()) {
- g.Printf(" extends Exception")
- }
- g.Printf(" implements Seq.Proxy, %s {\n", g.javaTypeName(n))
- g.Indent()
- g.genProxyImpl("proxy" + n)
- g.Printf("proxy%s(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); }\n\n", n)
- if isErrorType(iface.obj.Type()) {
- g.Printf("@Override public String getMessage() { return error(); }\n\n")
- }
- for _, m := range iface.summary.callable {
- if !g.isSigSupported(m.Type()) {
- g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", n, m.Name())
- continue
- }
- g.Printf("public native ")
- g.genFuncSignature(m, nil, false)
- }
- g.Outdent()
- g.Printf("}\n")
- }
- g.Printf("\n")
- for _, c := range g.constants {
- g.genConst(c)
- }
- g.Printf("\n")
- for _, v := range g.vars {
- g.genVar(v)
- }
- for _, f := range g.funcs {
- if !g.isSigSupported(f.Type()) {
- g.Printf("// skipped function %s with unsupported parameter or return types\n\n", f.Name())
- continue
- }
- g.javadoc(g.docs[f.Name()].Doc())
- g.Printf("public static native ")
- g.genFuncSignature(f, nil, false)
- }
- g.Outdent()
- g.Printf("}\n")
- if len(g.err) > 0 {
- return g.err
- }
- return nil
- }
- // embeddedJavaClasses returns the possible empty list of Java types embedded
- // in the given struct type.
- func embeddedJavaClasses(t *types.Struct) []string {
- clsSet := make(map[string]struct{})
- var classes []string
- for i := 0; i < t.NumFields(); i++ {
- f := t.Field(i)
- if !f.Exported() {
- continue
- }
- if t := f.Type(); isJavaType(t) {
- cls := classNameFor(t)
- if _, exists := clsSet[cls]; !exists {
- clsSet[cls] = struct{}{}
- classes = append(classes, cls)
- }
- }
- }
- return classes
- }
- func classNameFor(t types.Type) string {
- obj := t.(*types.Named).Obj()
- pkg := obj.Pkg()
- return strings.Replace(pkg.Path()[len("Java/"):], "/", ".", -1) + "." + obj.Name()
- }
- func isJavaType(t types.Type) bool {
- return typePkgFirstElem(t) == "Java"
- }
- const (
- javaPreamble = gobindPreamble + `// Java class %[1]s.%[2]s is a proxy for talking to a Go program.
- //
- // autogenerated by gobind %[3]s %[4]s
- package %[1]s;
- import go.Seq;
- `
- cPreamble = gobindPreamble + `// JNI functions for the Go <=> Java bridge.
- //
- // autogenerated by gobind %[1]s %[2]s
- #include <android/log.h>
- #include <stdint.h>
- #include "seq.h"
- #include "_cgo_export.h"
- `
- hPreamble = gobindPreamble + `// JNI function headers for the Go <=> Java bridge.
- //
- // autogenerated by gobind %[1]s %[2]s
- #ifndef __%[3]s_H__
- #define __%[3]s_H__
- #include <jni.h>
- `
- )
|