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