| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Go Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style | |
| 3 // license that can be found in the LICENSE file. | |
| 4 | |
| 5 package bind | |
| 6 | |
| 7 import ( | |
| 8 "fmt" | |
| 9 "go/token" | |
| 10 "log" | |
| 11 "strings" | |
| 12 | |
| 13 "golang.org/x/tools/go/types" | |
| 14 ) | |
| 15 | |
| 16 type goGen struct { | |
| 17 *printer | |
| 18 fset *token.FileSet | |
| 19 pkg *types.Package | |
| 20 err ErrorList | |
| 21 } | |
| 22 | |
| 23 func (g *goGen) errorf(format string, args ...interface{}) { | |
| 24 g.err = append(g.err, fmt.Errorf(format, args...)) | |
| 25 } | |
| 26 | |
| 27 const goPreamble = `// Package go_%s is an autogenerated binder stub for package
%s. | |
| 28 // gobind -lang=go %s | |
| 29 // | |
| 30 // File is generated by gobind. Do not edit. | |
| 31 package go_%s | |
| 32 | |
| 33 import ( | |
| 34 "golang.org/x/mobile/bind/seq" | |
| 35 %q | |
| 36 ) | |
| 37 | |
| 38 ` | |
| 39 | |
| 40 func (g *goGen) genPreamble() { | |
| 41 n := g.pkg.Name() | |
| 42 g.Printf(goPreamble, n, n, g.pkg.Path(), n, g.pkg.Path()) | |
| 43 } | |
| 44 | |
| 45 func (g *goGen) genFuncBody(o *types.Func, selectorLHS string) { | |
| 46 sig := o.Type().(*types.Signature) | |
| 47 params := sig.Params() | |
| 48 for i := 0; i < params.Len(); i++ { | |
| 49 p := params.At(i) | |
| 50 g.genRead("param_"+p.Name(), "in", p.Type()) | |
| 51 } | |
| 52 | |
| 53 res := sig.Results() | |
| 54 if res.Len() > 2 || res.Len() == 2 && !isErrorType(res.At(1).Type()) { | |
| 55 g.errorf("functions and methods must return either zero or one v
alues, and optionally an error") | |
| 56 return | |
| 57 } | |
| 58 returnsValue := false | |
| 59 returnsError := false | |
| 60 if res.Len() == 1 { | |
| 61 if isErrorType(res.At(0).Type()) { | |
| 62 returnsError = true | |
| 63 g.Printf("err := ") | |
| 64 } else { | |
| 65 returnsValue = true | |
| 66 g.Printf("res := ") | |
| 67 } | |
| 68 } else if res.Len() == 2 { | |
| 69 returnsValue = true | |
| 70 returnsError = true | |
| 71 g.Printf("res, err := ") | |
| 72 } | |
| 73 | |
| 74 g.Printf("%s.%s(", selectorLHS, o.Name()) | |
| 75 for i := 0; i < params.Len(); i++ { | |
| 76 if i > 0 { | |
| 77 g.Printf(", ") | |
| 78 } | |
| 79 g.Printf("param_%s", params.At(i).Name()) | |
| 80 } | |
| 81 g.Printf(")\n") | |
| 82 | |
| 83 if returnsValue { | |
| 84 g.genWrite("res", "out", res.At(0).Type()) | |
| 85 } | |
| 86 if returnsError { | |
| 87 g.genWrite("err", "out", res.At(res.Len()-1).Type()) | |
| 88 } | |
| 89 } | |
| 90 | |
| 91 func (g *goGen) genWrite(valName, seqName string, T types.Type) { | |
| 92 if isErrorType(T) { | |
| 93 g.Printf("if %s == nil {\n", valName) | |
| 94 g.Printf(" %s.WriteUTF16(\"\");\n", seqName) | |
| 95 g.Printf("} else {\n") | |
| 96 g.Printf(" %s.WriteUTF16(%s.Error());\n", seqName, valName) | |
| 97 g.Printf("}\n") | |
| 98 return | |
| 99 } | |
| 100 switch T := T.(type) { | |
| 101 case *types.Pointer: | |
| 102 // TODO(crawshaw): test *int | |
| 103 // TODO(crawshaw): test **Generator | |
| 104 switch T := T.Elem().(type) { | |
| 105 case *types.Named: | |
| 106 obj := T.Obj() | |
| 107 if obj.Pkg() != g.pkg { | |
| 108 g.errorf("type %s not defined in package %s", T,
g.pkg) | |
| 109 return | |
| 110 } | |
| 111 g.Printf("%s.WriteGoRef(%s)\n", seqName, valName) | |
| 112 default: | |
| 113 g.errorf("unsupported type %s", T) | |
| 114 } | |
| 115 case *types.Named: | |
| 116 switch u := T.Underlying().(type) { | |
| 117 case *types.Interface, *types.Pointer: | |
| 118 g.Printf("%s.WriteGoRef(%s)\n", seqName, valName) | |
| 119 default: | |
| 120 g.errorf("unsupported, direct named type %s: %s", T, u) | |
| 121 } | |
| 122 default: | |
| 123 g.Printf("%s.Write%s(%s);\n", seqName, seqType(T), valName) | |
| 124 } | |
| 125 } | |
| 126 | |
| 127 func (g *goGen) genFunc(o *types.Func) { | |
| 128 g.Printf("func proxy_%s(out, in *seq.Buffer) {\n", o.Name()) | |
| 129 g.Indent() | |
| 130 g.genFuncBody(o, g.pkg.Name()) | |
| 131 g.Outdent() | |
| 132 g.Printf("}\n\n") | |
| 133 } | |
| 134 | |
| 135 func exportedMethodSet(T types.Type) []*types.Func { | |
| 136 var methods []*types.Func | |
| 137 methodset := types.NewMethodSet(T) | |
| 138 for i := 0; i < methodset.Len(); i++ { | |
| 139 obj := methodset.At(i).Obj() | |
| 140 if !obj.Exported() { | |
| 141 continue | |
| 142 } | |
| 143 switch obj := obj.(type) { | |
| 144 case *types.Func: | |
| 145 methods = append(methods, obj) | |
| 146 default: | |
| 147 log.Panicf("unexpected methodset obj: %s", obj) | |
| 148 } | |
| 149 } | |
| 150 return methods | |
| 151 } | |
| 152 | |
| 153 func exportedFields(T *types.Struct) []*types.Var { | |
| 154 var fields []*types.Var | |
| 155 for i := 0; i < T.NumFields(); i++ { | |
| 156 f := T.Field(i) | |
| 157 if !f.Exported() { | |
| 158 continue | |
| 159 } | |
| 160 fields = append(fields, f) | |
| 161 } | |
| 162 return fields | |
| 163 } | |
| 164 | |
| 165 func (g *goGen) genStruct(obj *types.TypeName, T *types.Struct) { | |
| 166 fields := exportedFields(T) | |
| 167 methods := exportedMethodSet(types.NewPointer(obj.Type())) | |
| 168 | |
| 169 g.Printf("const (\n") | |
| 170 g.Indent() | |
| 171 g.Printf("proxy%sDescriptor = \"go.%s.%s\"\n", obj.Name(), g.pkg.Name(),
obj.Name()) | |
| 172 for i, f := range fields { | |
| 173 g.Printf("proxy%s%sGetCode = 0x%x0f\n", obj.Name(), f.Name(), i) | |
| 174 g.Printf("proxy%s%sSetCode = 0x%x1f\n", obj.Name(), f.Name(), i) | |
| 175 } | |
| 176 for i, m := range methods { | |
| 177 g.Printf("proxy%s%sCode = 0x%x0c\n", obj.Name(), m.Name(), i) | |
| 178 } | |
| 179 g.Outdent() | |
| 180 g.Printf(")\n\n") | |
| 181 | |
| 182 g.Printf("type proxy%s seq.Ref\n\n", obj.Name()) | |
| 183 | |
| 184 for _, f := range fields { | |
| 185 g.Printf("func proxy%s%sSet(out, in *seq.Buffer) {\n", obj.Name(
), f.Name()) | |
| 186 g.Indent() | |
| 187 g.Printf("ref := in.ReadRef()\n") | |
| 188 g.Printf("v := in.Read%s()\n", seqType(f.Type())) | |
| 189 // TODO(crawshaw): other kinds of non-ptr types. | |
| 190 g.Printf("ref.Get().(*%s.%s).%s = v\n", g.pkg.Name(), obj.Name()
, f.Name()) | |
| 191 g.Outdent() | |
| 192 g.Printf("}\n\n") | |
| 193 | |
| 194 g.Printf("func proxy%s%sGet(out, in *seq.Buffer) {\n", obj.Name(
), f.Name()) | |
| 195 g.Indent() | |
| 196 g.Printf("ref := in.ReadRef()\n") | |
| 197 g.Printf("v := ref.Get().(*%s.%s).%s\n", g.pkg.Name(), obj.Name(
), f.Name()) | |
| 198 g.Printf("out.Write%s(v)\n", seqType(f.Type())) | |
| 199 g.Outdent() | |
| 200 g.Printf("}\n\n") | |
| 201 } | |
| 202 | |
| 203 for _, m := range methods { | |
| 204 g.Printf("func proxy%s%s(out, in *seq.Buffer) {\n", obj.Name(),
m.Name()) | |
| 205 g.Indent() | |
| 206 g.Printf("ref := in.ReadRef()\n") | |
| 207 g.Printf("v := ref.Get().(*%s.%s)\n", g.pkg.Name(), obj.Name()) | |
| 208 g.genFuncBody(m, "v") | |
| 209 g.Outdent() | |
| 210 g.Printf("}\n\n") | |
| 211 } | |
| 212 | |
| 213 g.Printf("func init() {\n") | |
| 214 g.Indent() | |
| 215 for _, f := range fields { | |
| 216 n := f.Name() | |
| 217 g.Printf("seq.Register(proxy%sDescriptor, proxy%s%sSetCode, prox
y%s%sSet)\n", obj.Name(), obj.Name(), n, obj.Name(), n) | |
| 218 g.Printf("seq.Register(proxy%sDescriptor, proxy%s%sGetCode, prox
y%s%sGet)\n", obj.Name(), obj.Name(), n, obj.Name(), n) | |
| 219 } | |
| 220 for _, m := range methods { | |
| 221 n := m.Name() | |
| 222 g.Printf("seq.Register(proxy%sDescriptor, proxy%s%sCode, proxy%s
%s)\n", obj.Name(), obj.Name(), n, obj.Name(), n) | |
| 223 } | |
| 224 g.Outdent() | |
| 225 g.Printf("}\n\n") | |
| 226 } | |
| 227 | |
| 228 func (g *goGen) genInterface(obj *types.TypeName) { | |
| 229 iface := obj.Type().(*types.Named).Underlying().(*types.Interface) | |
| 230 | |
| 231 // Descriptor and code for interface methods. | |
| 232 g.Printf("const (\n") | |
| 233 g.Indent() | |
| 234 g.Printf("proxy%sDescriptor = \"go.%s.%s\"\n", obj.Name(), g.pkg.Name(),
obj.Name()) | |
| 235 for i := 0; i < iface.NumMethods(); i++ { | |
| 236 g.Printf("proxy%s%sCode = 0x%x0a\n", obj.Name(), iface.Method(i)
.Name(), i+1) | |
| 237 } | |
| 238 g.Outdent() | |
| 239 g.Printf(")\n\n") | |
| 240 | |
| 241 // Define the entry points. | |
| 242 for i := 0; i < iface.NumMethods(); i++ { | |
| 243 m := iface.Method(i) | |
| 244 g.Printf("func proxy%s%s(out, in *seq.Buffer) {\n", obj.Name(),
m.Name()) | |
| 245 g.Indent() | |
| 246 g.Printf("ref := in.ReadRef()\n") | |
| 247 g.Printf("v := ref.Get().(%s.%s)\n", g.pkg.Name(), obj.Name()) | |
| 248 g.genFuncBody(m, "v") | |
| 249 g.Outdent() | |
| 250 g.Printf("}\n\n") | |
| 251 } | |
| 252 | |
| 253 // Register the method entry points. | |
| 254 g.Printf("func init() {\n") | |
| 255 g.Indent() | |
| 256 for i := 0; i < iface.NumMethods(); i++ { | |
| 257 g.Printf("seq.Register(proxy%sDescriptor, proxy%s%sCode, proxy%s
%s)\n", | |
| 258 obj.Name(), obj.Name(), iface.Method(i).Name(), obj.Name
(), iface.Method(i).Name()) | |
| 259 } | |
| 260 g.Outdent() | |
| 261 g.Printf("}\n\n") | |
| 262 | |
| 263 // Define a proxy interface. | |
| 264 g.Printf("type proxy%s seq.Ref\n\n", obj.Name()) | |
| 265 | |
| 266 for i := 0; i < iface.NumMethods(); i++ { | |
| 267 m := iface.Method(i) | |
| 268 sig := m.Type().(*types.Signature) | |
| 269 params := sig.Params() | |
| 270 res := sig.Results() | |
| 271 | |
| 272 if res.Len() > 2 || | |
| 273 (res.Len() == 2 && !isErrorType(res.At(1).Type())) { | |
| 274 g.errorf("functions and methods must return either zero
or one value, and optionally an error: %s.%s", obj.Name(), m.Name()) | |
| 275 continue | |
| 276 } | |
| 277 | |
| 278 g.Printf("func (p *proxy%s) %s(", obj.Name(), m.Name()) | |
| 279 for i := 0; i < params.Len(); i++ { | |
| 280 if i > 0 { | |
| 281 g.Printf(", ") | |
| 282 } | |
| 283 g.Printf("%s %s", paramName(params, i), g.typeString(par
ams.At(i).Type())) | |
| 284 } | |
| 285 g.Printf(") ") | |
| 286 | |
| 287 if res.Len() == 1 { | |
| 288 g.Printf(g.typeString(res.At(0).Type())) | |
| 289 } else if res.Len() == 2 { | |
| 290 g.Printf("(%s, error)", g.typeString(res.At(0).Type())) | |
| 291 } | |
| 292 g.Printf(" {\n") | |
| 293 g.Indent() | |
| 294 | |
| 295 g.Printf("in := new(seq.Buffer)\n") | |
| 296 for i := 0; i < params.Len(); i++ { | |
| 297 g.genWrite(paramName(params, i), "in", params.At(i).Type
()) | |
| 298 } | |
| 299 | |
| 300 if res.Len() == 0 { | |
| 301 g.Printf("seq.Transact((*seq.Ref)(p), proxy%s%sCode, in)
\n", obj.Name(), m.Name()) | |
| 302 } else { | |
| 303 g.Printf("out := seq.Transact((*seq.Ref)(p), proxy%s%sCo
de, in)\n", obj.Name(), m.Name()) | |
| 304 var rvs []string | |
| 305 for i := 0; i < res.Len(); i++ { | |
| 306 rv := fmt.Sprintf("res_%d", i) | |
| 307 g.genRead(rv, "out", res.At(i).Type()) | |
| 308 rvs = append(rvs, rv) | |
| 309 } | |
| 310 g.Printf("return %s\n", strings.Join(rvs, ",")) | |
| 311 } | |
| 312 | |
| 313 g.Outdent() | |
| 314 g.Printf("}\n\n") | |
| 315 } | |
| 316 } | |
| 317 | |
| 318 func (g *goGen) genRead(valName, seqName string, typ types.Type) { | |
| 319 if isErrorType(typ) { | |
| 320 g.Printf("%s := %s.ReadError()\n", valName, seqName) | |
| 321 return | |
| 322 } | |
| 323 switch t := typ.(type) { | |
| 324 case *types.Pointer: | |
| 325 switch u := t.Elem().(type) { | |
| 326 case *types.Named: | |
| 327 o := u.Obj() | |
| 328 if o.Pkg() != g.pkg { | |
| 329 g.errorf("type %s not defined in package %s", u,
g.pkg) | |
| 330 return | |
| 331 } | |
| 332 g.Printf("// Must be a Go object\n") | |
| 333 g.Printf("%s_ref := %s.ReadRef()\n", valName, seqName) | |
| 334 g.Printf("%s := %s_ref.Get().(*%s.%s)\n", valName, valNa
me, g.pkg.Name(), o.Name()) | |
| 335 default: | |
| 336 g.errorf("unsupported type %s", t) | |
| 337 } | |
| 338 case *types.Named: | |
| 339 switch t.Underlying().(type) { | |
| 340 case *types.Interface, *types.Pointer: | |
| 341 o := t.Obj() | |
| 342 if o.Pkg() != g.pkg { | |
| 343 g.errorf("type %s not defined in package %s", t,
g.pkg) | |
| 344 return | |
| 345 } | |
| 346 g.Printf("var %s %s\n", valName, g.typeString(t)) | |
| 347 g.Printf("%s_ref := %s.ReadRef()\n", valName, seqName) | |
| 348 g.Printf("if %s_ref.Num < 0 { // go object \n", valName) | |
| 349 g.Printf(" %s = %s_ref.Get().(%s.%s)\n", valName, valN
ame, g.pkg.Name(), o.Name()) | |
| 350 g.Printf("} else { // foreign object \n") | |
| 351 g.Printf(" %s = (*proxy%s)(%s_ref)\n", valName, o.Name
(), valName) | |
| 352 g.Printf("}\n") | |
| 353 } | |
| 354 default: | |
| 355 g.Printf("%s := %s.Read%s()\n", valName, seqName, seqType(t)) | |
| 356 } | |
| 357 } | |
| 358 | |
| 359 func (g *goGen) typeString(typ types.Type) string { | |
| 360 pkg := g.pkg | |
| 361 | |
| 362 switch t := typ.(type) { | |
| 363 case *types.Named: | |
| 364 obj := t.Obj() | |
| 365 if obj.Pkg() == nil { // e.g. error type is *types.Named. | |
| 366 return types.TypeString(pkg, typ) | |
| 367 } | |
| 368 if obj.Pkg() != g.pkg { | |
| 369 g.errorf("type %s not defined in package %s", t, g.pkg) | |
| 370 } | |
| 371 | |
| 372 switch t.Underlying().(type) { | |
| 373 case *types.Interface, *types.Struct: | |
| 374 return fmt.Sprintf("%s.%s", pkg.Name(), types.TypeString
(pkg, typ)) | |
| 375 default: | |
| 376 g.errorf("unsupported named type %s / %T", t, t) | |
| 377 } | |
| 378 case *types.Pointer: | |
| 379 switch t := t.Elem().(type) { | |
| 380 case *types.Named: | |
| 381 return fmt.Sprintf("*%s", g.typeString(t)) | |
| 382 default: | |
| 383 g.errorf("not yet supported, pointer type %s / %T", t, t
) | |
| 384 } | |
| 385 default: | |
| 386 return types.TypeString(pkg, typ) | |
| 387 } | |
| 388 return "" | |
| 389 } | |
| 390 | |
| 391 func (g *goGen) gen() error { | |
| 392 g.genPreamble() | |
| 393 | |
| 394 var funcs []string | |
| 395 | |
| 396 scope := g.pkg.Scope() | |
| 397 names := scope.Names() | |
| 398 for _, name := range names { | |
| 399 obj := scope.Lookup(name) | |
| 400 if !obj.Exported() { | |
| 401 continue | |
| 402 } | |
| 403 | |
| 404 switch obj := obj.(type) { | |
| 405 // TODO(crawshaw): case *types.Const: | |
| 406 // TODO(crawshaw): case *types.Var: | |
| 407 case *types.Func: | |
| 408 g.genFunc(obj) | |
| 409 funcs = append(funcs, obj.Name()) | |
| 410 case *types.TypeName: | |
| 411 named := obj.Type().(*types.Named) | |
| 412 switch T := named.Underlying().(type) { | |
| 413 case *types.Struct: | |
| 414 g.genStruct(obj, T) | |
| 415 case *types.Interface: | |
| 416 g.genInterface(obj) | |
| 417 } | |
| 418 | |
| 419 default: | |
| 420 g.errorf("not yet supported, name for %v / %T", obj, obj
) | |
| 421 continue | |
| 422 } | |
| 423 } | |
| 424 | |
| 425 g.Printf("func init() {\n") | |
| 426 g.Indent() | |
| 427 for i, name := range funcs { | |
| 428 g.Printf("seq.Register(%q, %d, proxy_%s)\n", g.pkg.Name(), i+1,
name) | |
| 429 } | |
| 430 g.Outdent() | |
| 431 g.Printf("}\n") | |
| 432 | |
| 433 if len(g.err) > 0 { | |
| 434 return g.err | |
| 435 } | |
| 436 return nil | |
| 437 } | |
| OLD | NEW |