github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/amino/genproto/bindings.go (about) 1 package genproto 2 3 import ( 4 "bytes" 5 "fmt" 6 "go/ast" 7 "go/printer" 8 "go/token" 9 "os" 10 "path" 11 "reflect" 12 "regexp" 13 "strconv" 14 "strings" 15 16 "github.com/gnolang/gno/tm2/pkg/amino" 17 "github.com/gnolang/gno/tm2/pkg/amino/genproto/stringutil" 18 "github.com/gnolang/gno/tm2/pkg/amino/pkg" 19 ) 20 21 const ( 22 uint8Str = "uint8" 23 ) 24 25 // Given genproto generated schema files for Go objects, generate 26 // mappers to and from pb messages. The purpose of this is to let Amino 27 // use already-optimized probuf logic for serialization. 28 func GenerateProtoBindingsForTypes(pkg *amino.Package, rtz ...reflect.Type) (file *ast.File, err error) { 29 // for TypeInfos. 30 cdc := amino.NewCodec() 31 cdc.RegisterPackage(pkg) 32 33 file = &ast.File{ 34 Name: _i(pkg.GoPkgName), 35 Decls: nil, 36 Imports: nil, 37 } 38 39 // Generate Imports 40 scope := ast.NewScope(nil) 41 imports := _imports( 42 "proto", "google.golang.org/protobuf/proto", 43 "amino", "github.com/gnolang/gno/tm2/pkg/amino") 44 addImportAuto(imports, scope, pkg.GoPkgName+"pb", pkg.P3GoPkgPath) 45 file.Decls = append(file.Decls, imports) 46 47 // Generate Decls 48 for _, type_ := range rtz { 49 info, err := cdc.GetTypeInfo(type_) 50 if err != nil { 51 return file, err 52 } 53 if info.Type.Kind() == reflect.Interface { 54 continue 55 } 56 57 // Generate methods for each type. 58 methods, err := generateMethodsForType(imports, scope, pkg, info) 59 if err != nil { 60 return file, err 61 } 62 file.Decls = append(file.Decls, methods...) 63 } 64 return file, nil 65 } 66 67 // Writes in the same directory as the origin package. 68 // Assumes pb imports in origGoPkgPath+"/pb". 69 func WriteProtoBindings(pkg *amino.Package) { 70 filename := path.Join(pkg.DirName, "pbbindings.go") 71 fmt.Printf("writing proto3 bindings to %v for package %v\n", filename, pkg) 72 err := WriteProtoBindingsForTypes(filename, pkg, pkg.ReflectTypes()...) 73 if err != nil { 74 panic(err) 75 } 76 } 77 78 func WriteProtoBindingsForTypes(filename string, pkg *amino.Package, rtz ...reflect.Type) (err error) { 79 var buf bytes.Buffer 80 fset := token.NewFileSet() 81 var file *ast.File 82 file, err = GenerateProtoBindingsForTypes(pkg, rtz...) 83 if err != nil { 84 return 85 } 86 err = printer.Fprint(&buf, fset, file) 87 if err != nil { 88 return 89 } 90 err = os.WriteFile(filename, buf.Bytes(), 0o644) 91 if err != nil { 92 return 93 } 94 return 95 } 96 97 // modified imports if necessary. 98 func generateMethodsForType(imports *ast.GenDecl, scope *ast.Scope, pkg *amino.Package, info *amino.TypeInfo) (methods []ast.Decl, err error) { 99 if info.Type.Kind() == reflect.Interface { 100 panic("should not happen") 101 } 102 103 pbote_ := p3goTypeExprString(pkg, imports, scope, info, amino.FieldOptions{}) 104 if pbote_[0] != '*' { 105 panic("expected pointer kind for p3goTypeExprString (of registered type)") 106 } 107 dpbote_ := pbote_[1:] 108 109 // ----------- 110 // ToPBMessage() 111 { 112 scope2 := ast.NewScope(scope) 113 addVars(scope2, "cdc", "goo", "pbo", "msg", "err") 114 // Set toProto function. 115 methods = append(methods, _func("ToPBMessage", 116 "goo", info.Type.Name(), 117 _fields("cdc", "*amino.Codec"), 118 _fields("msg", "proto.Message", "err", "error"), 119 _block( 120 // Body: declaration for pb message. 121 _var("pbo", _x(pbote_), nil), 122 // Body: copying over fields. 123 _block(go2pbStmts(pkg, true, imports, scope2, _i("pbo"), _i("goo"), false, info, amino.FieldOptions{}, 0)...), 124 // Body: return value. 125 _a("msg", "=", "pbo"), 126 _return(), 127 ), 128 )) 129 } 130 131 // ----------- 132 // EmptyPBMessage() 133 // Use to create the pbm to proto.Unmarshal to before FromPBMessage. 134 { 135 scope2 := ast.NewScope(scope) 136 addVars(scope2, "cdc", "goo", "pbo", "msg", "err") 137 // Set toProto function. 138 methods = append(methods, _func("EmptyPBMessage", 139 "goo", info.Type.Name(), 140 _fields("cdc", "*amino.Codec"), 141 _fields("msg", "proto.Message"), 142 _block( 143 // Body: declaration for pb message. 144 _a("pbo", ":=", _x("new~(~%v~)", dpbote_)), 145 // Body: return value. 146 _a("msg", "=", "pbo"), 147 _return(), 148 ), 149 )) 150 } 151 152 // ----------- 153 // FromPBMessage() 154 { 155 scope2 := ast.NewScope(scope) 156 addVars(scope2, "cdc", "goo", "pbo", "msg", "err") 157 methods = append(methods, _func("FromPBMessage", 158 "goo", "*"+info.Type.Name(), 159 _fields("cdc", "*amino.Codec", "msg", "proto.Message"), 160 _fields("err", "error"), 161 _block( 162 // Body: declaration for pb message. 163 _var("pbo", _x(pbote_), 164 _x("%v.~(~%v~)", "msg", pbote_)), 165 // Body: copying over fields. 166 _block(pb2goStmts(pkg, true, imports, scope2, _i("goo"), true, info, _i("pbo"), amino.FieldOptions{}, 0)...), 167 // Body: return. 168 _return(), 169 ), 170 )) 171 } 172 173 // ----------- 174 // TypeUrl() 175 { 176 methods = append(methods, _func("GetTypeURL", 177 "", info.Type.Name(), 178 _fields(), 179 _fields("typeURL", "string"), 180 _block( 181 _return(_s(info.TypeURL)), 182 ), 183 )) 184 } 185 186 // ----------- 187 // Is*ReprEmpty() 188 { 189 rinfo := info.ReprType 190 scope2 := ast.NewScope(scope) 191 addVars(scope2, "goo", "empty") 192 goorte := goTypeExpr(pkg, rinfo.Type, imports, scope2) 193 methods = append(methods, _func(fmt.Sprintf("Is%vReprEmpty", info.Name), 194 "", "", 195 _fields("goor", goorte), 196 _fields("empty", "bool"), 197 _block( 198 // Body: check fields. 199 _block(append( 200 []ast.Stmt{_a("empty", "=", "true")}, 201 isReprEmptyStmts(pkg, true, imports, scope2, _i("goor"), false, info)..., 202 )...), 203 // Body: return. 204 _return(), 205 ), 206 )) 207 } 208 return 209 } 210 211 // These don't have ToPBMessage functions. 212 // TODO make this a property of the package? 213 var noBindings = struct{}{} 214 215 var noBindingsPkgs = map[string]struct{}{ 216 "": noBindings, 217 "time": noBindings, 218 } 219 220 func hasPBBindings(info *amino.TypeInfo) bool { 221 if info.Type.Kind() == reflect.Ptr { 222 return false 223 } 224 pkg := info.Package.GoPkgPath 225 _, ok := noBindingsPkgs[pkg] 226 return !ok 227 } 228 229 // END 230 231 // isRoot: false for fields and list elements. 232 // imports: global imports -- may be modified. 233 // pbo: protobuf variable or field. 234 // goo: native go variable or field. 235 // gooIsPtr: whether goo is ptr. 236 // gooType: type info for goo's type (elem type if pointer). 237 // CONTRACT: pbo is assignable. 238 // - The general case is `_a(pbo, "=", goo)` 239 // - The struct case is like `_a(_sel(pbo, field.Name), "=", goo)` 240 // 241 // CONTRACT: for arrays and lists, memory must be allocated beforehand, but new 242 // instances are created within this function. 243 func go2pbStmts(rootPkg *amino.Package, isRoot bool, imports *ast.GenDecl, scope *ast.Scope, pbo ast.Expr, goo ast.Expr, gooIsPtr bool, gooType *amino.TypeInfo, fopts amino.FieldOptions, options uint64) (b []ast.Stmt) { 244 const ( 245 option_bytes = 0x01 // if goo's repr is uint8 as an element of bytes. 246 option_implicit_list = 0x02 // if goo is a repeated list & also an element. 247 ) 248 249 // Special case if nil-pointer. 250 if gooIsPtr || gooType.Type.Kind() == reflect.Interface { 251 defer func() { 252 // Wrap penultimate b with if statement. 253 b = []ast.Stmt{_if(_b(goo, "!=", _i("nil")), 254 b..., 255 )} 256 }() 257 } 258 // Below, we can assume that goo isn't nil. 259 260 // External case. 261 // If gooType is registered and repr is struct, just call ToPBMessage. 262 // TODO If not registered? 263 if !isRoot && 264 gooType.Registered && hasPBBindings(gooType) && 265 gooType.ReprType.Type.Kind() == reflect.Struct && 266 (options&option_bytes == 0) { 267 // Call ToPBMessage(). 268 pbote_ := p3goTypeExprString(rootPkg, imports, scope, gooType, fopts) 269 pbom_ := addVarUniq(scope, "pbom") 270 b = append(b, 271 _a(pbom_, ":=", _x("proto.Message~(~nil~)")), 272 _a(pbom_, _i("err"), "=", _call(_sel(goo, "ToPBMessage"), _i("cdc"))), 273 _if(_x("err__!=__nil"), 274 _return(), 275 ), 276 _a(pbo, "=", _x("%v.~(~%v~)", pbom_, pbote_)), 277 ) 278 if gooIsPtr { 279 if pbote_[0] != '*' { 280 panic("expected pointer kind for p3goTypeExprString (of registered type)") 281 } 282 dpbote_ := pbote_[1:] 283 b = append(b, 284 _if(_b(pbo, "==", "nil"), 285 _a(pbo, "=", _x("new~(~%v~)", dpbote_)))) 286 } 287 return 288 } 289 290 // Use *goor* for goo's repr. 291 var goor ast.Expr 292 var goorType *amino.TypeInfo 293 294 // Maybe wrap pbo. 295 // NOTE: Instead of writing code to determine the .Value type, 296 // just lazily construct before assigning to pbo. 297 var wrapImplicitStruct bool 298 maybeWrap := func(goor ast.Expr) ast.Expr { 299 if wrapImplicitStruct { 300 pbote_ := p3goTypeExprString(rootPkg, imports, scope, gooType, fopts) 301 if pbote_[0] != '*' { 302 panic("expected pointer kind for p3goTypeExprString (of type to be wrapped)") 303 } 304 dpbote_ := pbote_[1:] 305 return _ref(&ast.CompositeLit{ 306 Type: _x(dpbote_), 307 Elts: []ast.Expr{_kv("Value", goor)}, 308 Incomplete: false, 309 }) 310 } else { 311 return goor 312 } 313 } 314 315 // Special case if IsAminoMarshaler. 316 if gooType.IsAminoMarshaler { 317 // First, derive repr instance. 318 goor_ := addVarUniq(scope, "goor") 319 err_ := addVarUniq(scope, "err") // do not shadow original err 320 b = append(b, 321 _a(goor_, err_, ":=", _call(_sel(goo, "MarshalAmino"))), 322 _if(_x("%v__!=__nil", err_), 323 _return(_x("nil"), _i(err_)), 324 ), 325 ) 326 // If isRoot and repr type isn't struct, an implicit struct is needed. 327 // If option_bytes, special case as we will encode as uint8. 328 if isRoot && 329 gooType.ReprType.Type.Kind() != reflect.Struct && 330 options&option_bytes == 0 { 331 if gooType.ReprType.Type.Kind() == reflect.Interface { 332 panic("not yet tested") 333 } 334 wrapImplicitStruct = true 335 } 336 // Assign *goor*. 337 goor = _i(goor_) 338 goorType = gooType.ReprType 339 } else { 340 // If isRoot and gooType isn't struct nor interface, an implicit 341 // struct wrapper is needed. 342 if isRoot && 343 gooType.Type.Kind() != reflect.Struct && 344 gooType.Type.Kind() != reflect.Interface { 345 wrapImplicitStruct = true 346 } 347 // Assign *goor*. 348 goor = goo 349 goorType = gooType 350 if gooIsPtr { 351 dgoor_ := addVarUniq(scope, "dgoor") 352 b = append(b, 353 _a(dgoor_, ":=", _deref(goor)), 354 _a(dgoor_, "=", dgoor_)) // XXX 355 goor = _i(dgoor_) 356 } 357 } 358 // Below, goor is dereferenced if goo is pointer.. 359 360 // Special case, time & duration. 361 switch goorType.Type { 362 case timeType: 363 pkgName := addImportAuto( 364 imports, scope, "timestamppb", "google.golang.org/protobuf/types/known/timestamppb") 365 if gooIsPtr { // (non-nil) 366 b = append(b, 367 _a(pbo, "=", _call(_sel(_x(pkgName), "New"), goor))) 368 } else { 369 b = append(b, 370 _if(_not(_call(_x("amino.IsEmptyTime"), goor)), 371 _a(pbo, "=", _call(_sel(_x(pkgName), "New"), goor)))) 372 } 373 return 374 case durationType: 375 pkgName := addImportAuto( 376 imports, scope, "durationpb", "google.golang.org/protobuf/types/known/durationpb") 377 if gooIsPtr { // (non-nil) 378 b = append(b, 379 _a(pbo, "=", _call(_sel(_x(pkgName), "New"), goor))) 380 } else { 381 b = append(b, 382 _if(_b(_call(_sel(goor, "Nanoseconds")), "!=", "0"), 383 _a(pbo, "=", _call(_sel(_x(pkgName), "New"), goor)))) 384 } 385 return 386 } 387 388 // Special case, external empty types. 389 if gooType.Registered && hasPBBindings(gooType) { 390 if isRoot { 391 pbote_ := p3goTypeExprString(rootPkg, imports, scope, gooType, fopts) 392 pbov_ := addVarUniq(scope, "pbov") 393 b = append(b, 394 _if(_call(_x("Is%vReprEmpty", gooType.Name), goor), 395 _var(pbov_, _x(pbote_), nil), 396 _a("msg", "=", pbov_), 397 _return())) 398 } else if !gooIsPtr { 399 pkgPrefix := goPkgPrefix(rootPkg, gooType.Type, gooType, imports, scope) 400 // b switcharoo pattern 401 // statements after this pattern appended to b 402 // will come after the injected if-condition. 403 oldb := b 404 b = []ast.Stmt(nil) 405 defer func() { 406 newb := b // named for clarity 407 b = append(oldb, 408 _if(_not(_call(_x("%vIs%vReprEmpty", pkgPrefix, gooType.Name), goor)), 409 newb...)) 410 }() 411 // end b switcharoo pattern 412 } 413 } 414 415 // General case 416 switch goork := goorType.Type.Kind(); goork { 417 case reflect.Interface: 418 typeUrl_ := addVarUniq(scope, "typeUrl") 419 bz_ := addVarUniq(scope, "bz") 420 anyte_ := p3goTypeExprString(rootPkg, imports, scope, gooType, fopts) 421 if anyte_[0] != '*' { 422 panic("expected pointer kind for p3goTypeExprString (of interface type)") 423 } 424 danyte_ := anyte_[1:] 425 b = append(b, 426 _a(typeUrl_, ":=", _call(_x("cdc.GetTypeURL"), goo)), 427 _a(bz_, ":=", "[]byte~(~nil~)"), 428 _a(bz_, "err", "=", _call(_x("cdc.Marshal"), goor)), 429 _if(_x("err__!=__nil"), 430 _return(), 431 ), 432 _a(pbo, "=", _x("&%v~{~TypeUrl:typeUrl,Value:bz~}", danyte_)), 433 ) 434 435 case reflect.Int: 436 b = append(b, 437 _a(pbo, "=", maybeWrap(_call(_i("int64"), goor)))) 438 case reflect.Int16, reflect.Int8: 439 b = append(b, 440 _a(pbo, "=", maybeWrap(_call(_i("int32"), goor)))) 441 case reflect.Uint: 442 b = append(b, 443 _a(pbo, "=", maybeWrap(_call(_i("uint64"), goor)))) 444 case reflect.Uint16: 445 b = append(b, 446 _a(pbo, "=", maybeWrap(_call(_i("uint32"), goor)))) 447 case reflect.Uint8: 448 if options&option_bytes == 0 { 449 b = append(b, 450 _a(pbo, "=", maybeWrap(_call(_i("uint32"), goor)))) 451 } else { 452 b = append(b, 453 _a(pbo, "=", _call(_i("byte"), goor))) 454 } 455 case reflect.Array, reflect.Slice: 456 var newoptions uint64 457 gooreIsPtr := goorType.ElemIsPtr 458 gooreType := goorType.Elem 459 var dpbote_ string 460 pboIsImplicit := isImplicitList(goorType, fopts) 461 pboeIsImplicit := isImplicitList(gooreType, fopts) 462 pbote_ := p3goTypeExprString(rootPkg, imports, scope, gooType, fopts) 463 pboete_ := p3goTypeExprString(rootPkg, imports, scope, gooreType, fopts) 464 465 if gooreType.ReprType.Type.Kind() == reflect.Uint8 { 466 // Special bytes optimization for recursive case. 467 pboete_ = uint8Str 468 newoptions |= option_bytes 469 } else if pboeIsImplicit { 470 // Special implicit list struct for recursive call. 471 newoptions |= option_implicit_list 472 } 473 474 // Iff also option & option_implicit_list, wrap with implicit list struct. 475 if pboIsImplicit { 476 if pbote_[0] != '*' { 477 panic("expected pointer kind for p3goTypeExprString (of implicit list-struct type)") 478 } 479 dpbote_ = pbote_[1:] 480 } else { 481 dpbote_ = "XXX" // needed for _x() parsing regardless of _ctif condition. 482 } 483 484 // Construct, translate, assign. 485 goorl_ := addVarUniq(scope, "goorl") 486 pbos_ := addVarUniq(scope, "pbos") 487 scope2 := ast.NewScope(scope) 488 addVars(scope2, "i", "goore", "pbose") 489 b = append(b, 490 _a(goorl_, ":=", _len(goor)), 491 _ife(_x("%v__==__0", goorl_), 492 _block( // then 493 // Prefer nil for empty slices for less gc overhead. 494 _a(pbo, "=", _i("nil")), 495 ), 496 _block( // else 497 _var(pbos_, nil, _x("make~(~[]%v,%v~)", pboete_, goorl_)), 498 _for( 499 _a("i", ":=", "0"), 500 _x("i__<__%v", goorl_), 501 _a("i", "+=", "1"), 502 _block( 503 // Translate in place. 504 _a("goore", ":=", _idx(goor, _i("i"))), 505 _block(go2pbStmts(rootPkg, false, imports, scope2, _x("%v~[~i~]", pbos_), _i("goore"), gooreIsPtr, gooreType, fopts, newoptions)...), 506 ), 507 ), 508 _ctif((pboIsImplicit && options&option_implicit_list != 0), // compile time if 509 _a(pbo, "=", _x("&%v~{~Value:%v~}", dpbote_, pbos_)), // then 510 _a(pbo, "=", maybeWrap(_i(pbos_))), // else 511 ), 512 ))) 513 514 case reflect.Struct: 515 pbote_ := p3goTypeExprString(rootPkg, imports, scope, gooType, fopts) 516 if pbote_[0] != '*' { 517 panic("expected pointer kind for p3goTypeExprString of struct type") 518 } 519 dpbote_ := pbote_[1:] 520 521 b = append(b, 522 _a(pbo, "=", _x("new~(~%v~)", dpbote_))) 523 524 for _, field := range goorType.Fields { 525 goorfIsPtr := field.IsPtr() 526 goorfType := field.TypeInfo 527 goorf := _sel(goor, field.Name) // next goo 528 // The protobuf field is lower_snake_case and protoc converts it to CamelCase. 529 pbof := _sel(pbo, CamelCase(stringutil.ToLowerSnakeCase(field.Name))) // next pbo 530 531 // Translate in place. 532 scope2 := ast.NewScope(scope) 533 b = append(b, 534 _block(go2pbStmts(rootPkg, false, imports, scope2, pbof, goorf, goorfIsPtr, goorfType, field.FieldOptions, 0)...), 535 ) 536 } 537 538 default: 539 // General translation. 540 b = append(b, 541 _a(pbo, "=", maybeWrap(_call(_i(goork.String()), goor)))) 542 } 543 return b 544 } 545 546 // package: the package for the concrete type for which we are generating go2pbStmts. 547 // isRoot: false for fields and list elements. 548 // imports: global imports -- used to look up package names. 549 // goo: native go variable or field. 550 // gooIsPtr: is goo a pointer? 551 // gooType: type info for goo's ultimate type (elem if pointer).. 552 // pbo: protobuf variable or field. 553 // CONTRACT: goo is addressable. 554 // CONTRACT: for arrays and lists, memory must be allocated beforehand, but new 555 // instances are created within this function. 556 func pb2goStmts(rootPkg *amino.Package, isRoot bool, imports *ast.GenDecl, scope *ast.Scope, goo ast.Expr, gooIsPtr bool, gooType *amino.TypeInfo, pbo ast.Expr, fopts amino.FieldOptions, options uint64) (b []ast.Stmt) { 557 const ( 558 option_bytes = 0x01 // if goo's repr is uint8 as an element of bytes. 559 // option_implicit_list = 0x02 // if goo is a repeated list & also an element. 560 ) 561 562 // Special case if pbo is a nil struct pointer (that isn't timestamp) 563 // 564 // We especially want this behavior (and optimization) for for 565 // amino.Marshalers, because of the construction cost. 566 switch gooType.ReprType.Type.Kind() { 567 case reflect.Struct: 568 if gooType.ReprType.Type != timeType { 569 defer func(pbo ast.Expr) { 570 // Wrap penultimate b with if statement. 571 b = []ast.Stmt{_if(_b(pbo, "!=", "nil"), 572 b..., 573 )} 574 }(pbo) 575 } 576 } 577 // Below, we can assume that pbo isn't a nil struct (that isn't timestamp). 578 579 if !isRoot { 580 // First we need to construct the goo. 581 // NOTE Unlike go2pb, due to the asymmetry of FromPBMessage/ToPBMessage, 582 // and MarshalAmino/UnmarshalAmino, both pairs which require that goo not 583 // be nil (so we must instantiate new() here). On the other hand, go2pb's 584 // instantiation of corresponding pb objects depends on the kind, so it 585 // cannot be done before the switch cases like here. 586 if gooIsPtr { 587 dgoote_ := goTypeExprString(rootPkg, imports, scope, false, gooType) 588 b = append(b, 589 _a(goo, "=", _x("new~(~%v~)", dgoote_))) 590 } 591 592 // External case. 593 // If gooType is registered and repr is struct, just call FromPBMessage. 594 // TODO If not registered? 595 if gooType.Registered && hasPBBindings(gooType) && 596 gooType.ReprType.Type.Kind() == reflect.Struct && 597 (options&option_bytes == 0) { 598 b = append(b, 599 _a(_i("err"), "=", _call(_sel(goo, "FromPBMessage"), _i("cdc"), pbo)), 600 _if(_x("err__!=__nil"), 601 _return(), 602 ), 603 ) 604 return 605 } 606 } 607 608 // Use *goor* for goo's repr. 609 var goor ast.Expr 610 var goorType *amino.TypeInfo 611 var goorteFn func() string 612 613 // Maybe unwrap pbo. 614 var unwrapImplicitStruct bool 615 maybeUnwrap := func(pbo ast.Expr) ast.Expr { 616 if unwrapImplicitStruct { 617 return _sel(pbo, "Value") 618 } else { 619 return pbo 620 } 621 } 622 623 // Special case if IsAminoMarshaler. 624 // NOTE: doesn't matter whether goo is ptr or not. 625 if gooType.IsAminoMarshaler { 626 // First, construct new repr instance. 627 goorteFn = goTypeExprStringFn(rootPkg, imports, scope, false, gooType.ReprType) 628 goorte_ := goorteFn() // goorteFn maybe still needed later. 629 goor_ := addVarUniq(scope, "goor") 630 b = append(b, 631 _var(goor_, _x(goorte_), nil)) 632 // After doing what we'd normally do w/ repr, 633 // unmarshal amino onto goo. 634 defer func() { 635 // Finally, unmarshal to goo. 636 b = append(b, 637 _a("err", "=", _call(_sel(goo, "UnmarshalAmino"), _i(goor_))), 638 _if(_x("err__!=__nil"), 639 _return(), 640 ), 641 ) 642 }() 643 // If isRoot and repr type isn't struct, an implicit struct is needed. 644 if isRoot && 645 gooType.ReprType.Type.Kind() != reflect.Struct && 646 options&option_bytes == 0 { 647 if gooType.ReprType.Type.Kind() == reflect.Interface { 648 panic("not yet tested") 649 } 650 unwrapImplicitStruct = true 651 } 652 // Assign *goor* 653 goor = _i(goor_) 654 goorType = gooType.ReprType 655 // goorte_ already set. 656 } else { 657 // If isRoot and gooType isn't struct nor interface, an implicit 658 // struct wrapper is needed. 659 if isRoot && 660 gooType.Type.Kind() != reflect.Struct && 661 gooType.Type.Kind() != reflect.Interface { 662 unwrapImplicitStruct = true 663 } 664 // Assign *goor* 665 goor = goo 666 if gooIsPtr { 667 goor = _deref(goo) 668 } 669 goorType = gooType 670 goorteFn = goTypeExprStringFn(rootPkg, imports, scope, false, gooType) 671 } 672 673 // Special case for time/duration. 674 switch goorType.Type { 675 case timeType: 676 b = append(b, 677 _a(goor, "=", _call(_sel(pbo, "AsTime")))) 678 return 679 case durationType: 680 b = append(b, 681 _a(goor, "=", _call(_sel(pbo, "AsDuration")))) 682 return 683 } 684 685 // General case 686 switch goorType.Type.Kind() { 687 case reflect.Interface: 688 typeUrl_ := addVarUniq(scope, "typeUrl") 689 bz_ := addVarUniq(scope, "bz") 690 goorp_ := addVarUniq(scope, "goorp") 691 b = append(b, 692 _a(typeUrl_, ":=", _sel(pbo, "TypeUrl")), 693 _a(bz_, ":=", _sel(pbo, "Value")), 694 _a(goorp_, ":=", _ref(goor)), // goor is addressable. NOTE &*a == a if a != nil. 695 _a("err", "=", _x("cdc.UnmarshalAny2~(~%v,%v,%v~)", 696 typeUrl_, bz_, goorp_)), 697 _if(_x("err__!=__nil"), 698 _return(), 699 ), 700 ) 701 // wrap b with if stmt. 702 b = []ast.Stmt{_if(_b(pbo, "!=", "nil"), 703 b..., 704 )} 705 706 case reflect.Int: 707 b = append(b, 708 _a(goor, "=", _call(_i(goorteFn()), _call(_i("int"), maybeUnwrap(pbo))))) 709 case reflect.Int16: 710 b = append(b, 711 _a(goor, "=", _call(_i(goorteFn()), _call(_i("int16"), maybeUnwrap(pbo))))) 712 case reflect.Int8: 713 b = append(b, 714 _a(goor, "=", _call(_i(goorteFn()), _call(_i("int8"), maybeUnwrap(pbo))))) 715 case reflect.Uint: 716 b = append(b, 717 _a(goor, "=", _call(_i(goorteFn()), _call(_i("uint"), maybeUnwrap(pbo))))) 718 case reflect.Uint16: 719 b = append(b, 720 _a(goor, "=", _call(_i(goorteFn()), _call(_i("uint16"), maybeUnwrap(pbo))))) 721 case reflect.Uint8: 722 b = append(b, 723 _a(goor, "=", _call(_i(goorteFn()), _call(_i(uint8Str), maybeUnwrap(pbo))))) 724 725 case reflect.Array: 726 var newoptions uint64 727 goorLen := goorType.Type.Len() 728 gooreType := goorType.Elem 729 gooreIsPtr := goorType.ElemIsPtr 730 goorete_ := goTypeExprString(rootPkg, imports, scope, gooreIsPtr, gooreType) 731 pboeIsImplicit := isImplicitList(gooreType, fopts) 732 733 // Special bytes optimization for recursive case. 734 if gooreType.ReprType.Type.Kind() == reflect.Uint8 { 735 newoptions |= option_bytes 736 } 737 738 // Construct, translate, assign. 739 goors_ := addVarUniq(scope, "goors") 740 scope2 := ast.NewScope(scope) 741 addVars(scope2, "i", "pboe", "pboev") 742 subStmts := pb2goStmts(rootPkg, false, imports, scope2, _x("%v~[~i~]", goors_), gooreIsPtr, gooreType, _i("pboev"), fopts, newoptions) 743 b = append(b, 744 _var(goors_, nil, _x("[%v]%v~{~~}", goorLen, goorete_)), 745 _for( 746 _a("i", ":=", "0"), 747 _x("i__<__%v", goorLen), 748 _a("i", "+=", "1"), 749 _block( 750 // Translate in place. 751 _a("pboe", ":=", _idx(maybeUnwrap(pbo), _i("i"))), 752 _ctif(pboeIsImplicit, 753 _if(_x("pboe__!=__nil"), 754 _block(append([]ast.Stmt{ 755 _a("pboev", ":=", "pboe.Value"), 756 }, 757 subStmts...)...), 758 ), 759 _block(append([]ast.Stmt{ 760 _a("pboev", ":=", "pboe"), 761 }, 762 subStmts...)...), 763 ), 764 ), 765 ), 766 _a(goor, "=", goors_), 767 ) 768 769 case reflect.Slice: 770 var newoptions uint64 771 gooreType := goorType.Elem 772 gooreIsPtr := goorType.ElemIsPtr 773 goorete_ := goTypeExprString(rootPkg, imports, scope, gooreIsPtr, gooreType) 774 pboeIsImplicit := isImplicitList(gooreType, fopts) 775 776 // Special bytes optimization for recursive case. 777 if gooreType.ReprType.Type.Kind() == reflect.Uint8 { 778 newoptions |= option_bytes 779 } 780 781 // Construct, translate, assign. 782 pbol_ := addVarUniq(scope, "pbol") 783 goors_ := addVarUniq(scope, "goors") 784 scope2 := ast.NewScope(scope) 785 addVars(scope2, "i", "pboe", "pboev") 786 subStmts := pb2goStmts(rootPkg, false, imports, scope2, _x("%v~[~i~]", goors_), gooreIsPtr, gooreType, _i("pboev"), fopts, newoptions) 787 b = append(b, 788 _var(pbol_, _i("int"), _x("0")), 789 _if(_b(pbo, "!=", "nil"), 790 _a(pbol_, "=", _len(maybeUnwrap(pbo))), 791 ), 792 _ife(_x("%v__==__0", pbol_), 793 _block( // then 794 // Prefer nil for empty slices for less gc overhead. 795 _a(goor, "=", _i("nil")), 796 ), 797 _block( // else 798 _var(goors_, nil, _x("make~(~[]%v,%v~)", goorete_, pbol_)), 799 _for( 800 _a("i", ":=", "0"), 801 _x("i__<__%v", pbol_), 802 _a("i", "+=", "1"), 803 _block( 804 // Translate in place. 805 _a("pboe", ":=", _idx(maybeUnwrap(pbo), _i("i"))), 806 _ctif(pboeIsImplicit, 807 _if(_x("pboe__!=__nil"), 808 _block(append([]ast.Stmt{ 809 _a("pboev", ":=", "pboe.Value"), 810 }, 811 subStmts...)...)), 812 _block(append([]ast.Stmt{ 813 _a("pboev", ":=", "pboe"), 814 }, 815 subStmts...)...), 816 ), 817 ), 818 ), 819 _a(goor, "=", goors_), 820 ), 821 ), 822 ) 823 824 case reflect.Struct: 825 for _, field := range goorType.Fields { 826 // The protobuf field is lower_snake_case and protoc converts it to CamelCase. 827 pbof := _sel(pbo, CamelCase(stringutil.ToLowerSnakeCase(field.Name))) // next pbo. 828 goorfIsPtr := field.IsPtr() 829 goorfType := field.TypeInfo 830 goorf := _sel(goor, field.Name) // next goor. 831 832 // Translate in place. 833 scope2 := ast.NewScope(scope) 834 b = append(b, 835 _block(pb2goStmts(rootPkg, false, imports, scope2, goorf, goorfIsPtr, goorfType, pbof, field.FieldOptions, 0)...), 836 ) 837 } 838 839 default: 840 // General translation. 841 b = append(b, _a(goor, "=", _call(_i(goorteFn()), maybeUnwrap(pbo)))) 842 } 843 return b 844 } 845 846 func isReprEmptyStmts(rootPkg *amino.Package, isRoot bool, imports *ast.GenDecl, scope *ast.Scope, goo ast.Expr, gooIsPtr bool, gooType *amino.TypeInfo) (b []ast.Stmt) { 847 // Special case if non-nil struct-pointer. 848 // TODO: this could be precompiled and optimized (when !isRoot). 849 if gooIsPtr && gooType.ReprType.Type.Kind() == reflect.Struct { 850 b = []ast.Stmt{_if(_b(goo, "!=", _i("nil")), 851 _return(_i("false")), 852 )} 853 return 854 } 855 856 // Special case if nil-pointer. 857 if gooIsPtr || gooType.Type.Kind() == reflect.Interface { 858 defer func(goo ast.Expr) { 859 // Wrap penultimate b with if statement. 860 b = []ast.Stmt{_if(_b(goo, "!=", _i("nil")), 861 b..., 862 )} 863 }(goo) 864 } 865 // Below, we can assume that goo isn't nil. 866 // NOTE: just because it's not nil doesn't mean it's empty, specifically 867 // for time. Amino marshallers are empty iff nil. 868 869 // Use *goor* for goo's repr. 870 var goor ast.Expr 871 var goorType *amino.TypeInfo 872 873 // Special case if IsAminoMarshaler. 874 // NOTE: That this calls MarshalAminop due to the possible nested repr 875 // elements, means checking for empty will potentially be inefficient for 876 // complex structures, possibly doubling the encoding cost for some of 877 // these structures. This is a proto3 issue where empty structs are encoded 878 // or not only depending on the nil-ness of a pointer to a struct. Amino2 879 // doesn't need this restriction, if we are detaching from proto3. 880 if gooType.IsAminoMarshaler { 881 if isRoot { 882 // If isRoot, goo is already the repr type. 883 goor = goo 884 goorType = gooType.ReprType 885 } else { 886 // First, derive repr instance. 887 goor_ := addVarUniq(scope, "goor") 888 err_ := addVarUniq(scope, "err") // do not shadow original err 889 b = append(b, 890 _a(goor_, err_, ":=", _call(_sel(goo, "MarshalAmino"))), 891 _if(_x("%v__!=__nil", err_), 892 _return(_x("false")), 893 ), 894 ) 895 // Assign *goor*. 896 goor = _i(goor_) 897 goorType = gooType.ReprType 898 } 899 } else { 900 // Assign *goor*. 901 goor = goo 902 goorType = gooType 903 if gooIsPtr { 904 dgoor_ := addVarUniq(scope, "dgoor") 905 b = append(b, 906 _a(dgoor_, ":=", _deref(goor)), 907 _a(dgoor_, "=", dgoor_)) // XXX 908 goor = _i(dgoor_) 909 } 910 } 911 // Below, goor is dereferenced if goo is pointer. 912 913 // External case. 914 // If gooType is registered, just call is*ReprEmpty 915 // TODO If not registered? 916 if !isRoot && gooType.Registered && hasPBBindings(gooType) { 917 pkgPrefix := goPkgPrefix(rootPkg, gooType.Type, gooType, imports, scope) 918 e_ := addVarUniq(scope, "e") 919 b = append(b, 920 _a(e_, ":=", _call(_x("%vIs%vReprEmpty", pkgPrefix, gooType.Name), goor)), 921 _if(_x("%v__==__false", e_), 922 _return(_i("false")), 923 ), 924 ) 925 return 926 } 927 928 // General case 929 switch goorType.Type.Kind() { 930 case reflect.Interface: 931 b = append(b, 932 _return(_i("false"))) 933 934 case reflect.Array, reflect.Slice: 935 b = append(b, 936 _if(_b(_len(goor), "!=", "0"), 937 _return(_i("false")))) 938 939 case reflect.Struct: 940 // Special case for time. The default behavior is fine for time.Duration. 941 switch goorType.Type { 942 case timeType: 943 b = append(b, 944 _if(_not(_call(_x("amino.IsEmptyTime"), goor)), 945 _return(_x("false")))) 946 return 947 default: 948 for _, field := range goorType.Fields { 949 goorf := _sel(goor, field.Name) // next goo 950 goorfIsPtr := field.IsPtr() 951 goorfType := field.TypeInfo 952 953 // Translate in place. 954 scope2 := ast.NewScope(scope) 955 b = append(b, 956 _block(isReprEmptyStmts(rootPkg, false, imports, scope2, goorf, goorfIsPtr, goorfType)...), 957 ) 958 } 959 } 960 961 default: 962 // General translation. 963 goorte := goTypeExprString(rootPkg, imports, scope, false, goorType) 964 b = append(b, 965 _if(_b(goor, "!=", _call(_x(goorte), defaultExpr(goorType.Type.Kind()))), 966 _return(_i("false")))) 967 } 968 return b 969 } 970 971 // ---------------------------------------- 972 // other.... 973 974 // Splits a Go expression into left and right parts. 975 // Returns ok=false if not a binary operator. 976 // Never panics. 977 // If ok=true, left+op+right == expr. 978 // 979 // Examples: 980 // - "5 * 2": left="5 ", op="*", right=" 2", ok=true 981 // - " 5*2 ": left=" 5", op="*", right="2 ", ok=true 982 // - "1*2+ 3": left="1*2", op="+", right=" 3", ok=true 983 // - "1*2+(3+ 4)": left="1*2", op="+", right="(3+ 4)", ok=true 984 // - "'foo'+'bar'": left="'foo'", op="+", right="'bar'", ok=true 985 // - "'x'": ok=false 986 func chopBinary(expr string) (left, op, right string, ok bool) { 987 // XXX implementation redacted for CHALLENGE1. 988 // TODO restore implementation and replace '__' 989 parts := strings.Split(expr, "__") 990 if len(parts) != 3 { 991 return 992 } 993 left = parts[0] 994 op = parts[1] 995 right = parts[2] 996 ok = true 997 return 998 } 999 1000 // Given that 'in' ends with ')', '}', or ']', 1001 // find the matching opener, while processing escape 1002 // sequences of strings and rune literals. 1003 // `tok` is the corresponding opening token. 1004 // `right` excludes the last character (closer). 1005 func chopRight(expr string) (left string, tok rune, right string) { 1006 // XXX implementation redacted for CHALLENGE1. 1007 // TODO restore implementation and replace '~' 1008 parts := strings.Split(expr, "~") 1009 if len(parts) != 4 { 1010 return 1011 } 1012 left = parts[0] 1013 tok = rune(parts[1][0]) 1014 right = parts[2] 1015 // close = parts[3] 1016 return 1017 } 1018 1019 // ---------------------------------------- 1020 // AST Construction (Expr) 1021 1022 func _i(name string) *ast.Ident { 1023 if name == "" { 1024 panic("unexpected empty identifier") 1025 } 1026 return &ast.Ident{Name: name} 1027 } 1028 1029 // recvTypeName is empty if there are no receivers. 1030 // recvTypeName cannot contain any dots. 1031 func _func(name string, recvRef string, recvTypeName string, params *ast.FieldList, results *ast.FieldList, b *ast.BlockStmt) *ast.FuncDecl { 1032 fn := &ast.FuncDecl{ 1033 Name: _i(name), 1034 Type: &ast.FuncType{ 1035 Params: params, 1036 Results: results, 1037 }, 1038 Body: b, 1039 } 1040 if recvRef == "" { 1041 recvRef = "_" 1042 } 1043 if recvTypeName != "" { 1044 fn.Recv = &ast.FieldList{ 1045 List: []*ast.Field{ 1046 { 1047 Names: []*ast.Ident{_i(recvRef)}, 1048 Type: _i(recvTypeName), 1049 }, 1050 }, 1051 } 1052 } 1053 return fn 1054 } 1055 1056 // Usage: _fields("a", "int", "b", "int32", ...) and so on. 1057 // The name and types get parsed by _i()/_x() unless they are already ast.Expr. 1058 // Identical type (instances or strings) are compressed into Names automatically. 1059 // args must always be even in length. 1060 func _fields(args ...interface{}) *ast.FieldList { 1061 list := []*ast.Field{} 1062 names := []*ast.Ident{} 1063 lasti := interface{}(nil) 1064 maybePop := func() { 1065 if len(names) > 0 { 1066 var last ast.Expr 1067 if lastte_, ok := lasti.(string); ok { 1068 last = _x(lastte_) 1069 } else { 1070 last = lasti.(ast.Expr) 1071 } 1072 list = append(list, &ast.Field{ 1073 Names: names, 1074 Type: last, 1075 }) 1076 names = []*ast.Ident{} 1077 } 1078 } 1079 for i := 0; i < len(args); i++ { 1080 name, ok := args[i].(*ast.Ident) 1081 if !ok { 1082 name = _i(args[i].(string)) 1083 } 1084 te_ := args[i+1] 1085 i += 1 1086 // NOTE: This comparison could be improved, to say, deep equality, 1087 // but is that the behavior we want? 1088 if lasti == te_ { 1089 names = append(names, name) 1090 continue 1091 } else { 1092 maybePop() 1093 names = append(names, name) 1094 lasti = te_ 1095 } 1096 } 1097 maybePop() 1098 return &ast.FieldList{ 1099 List: list, 1100 } 1101 } 1102 1103 // Parses simple expressions (but not all). 1104 // Useful for parsing strings to ast nodes, like foo.bar["qwe"](), 1105 // new(bytes.Buffer), *bytes.Buffer, package.MyStruct{FieldA:1}, numeric 1106 // 1107 // - num/char (e.g. e.g. 42, 0x7f, 3.14, 1e-9, 2.4i, 'a', '\x7f') 1108 // - strings (e.g. "foo" or `\m\n\o`), nil, function calls 1109 // - square bracket indexing 1110 // - dot notation 1111 // - star expression for pointers 1112 // - struct construction 1113 // - nil 1114 // - type assertions, for EXPR.(EXPR) and also EXPR.(type) 1115 // - []type slice types 1116 // - [n]type array types 1117 // - &something referencing 1118 // - unary operations, namely 1119 // "+" | "-" | "!" | "^" | "*" | "&" | "<-" . 1120 // - binary operations, namely 1121 // "||", "&&", 1122 // "==" | "!=" | "<" | "<=" | ">" | ">=" 1123 // "+" | "-" | "|" | "^" 1124 // "*" | "/" | "%" | "<<" | ">>" | "&" | "&^" . 1125 // 1126 // NOTE: This isn't trying to implement everything -- just what is 1127 // intuitively elegant to implement. Why don't we use a parser generator? 1128 // Cuz I'm testing the hypothesis that for the scope of what we're trying 1129 // to do here, given this language, that this is easier to understand and 1130 // maintain than using advanced tooling. 1131 func _x(expr string, args ...interface{}) ast.Expr { 1132 if expr == "" { 1133 panic("_x requires argument") 1134 } 1135 expr = fmt.Sprintf(expr, args...) 1136 expr = strings.TrimSpace(expr) 1137 first := expr[0] 1138 1139 // 1: Binary operators have a lower precedence than unary operators (or 1140 // monoids). 1141 left, op, right, ok := chopBinary(expr) 1142 if ok { 1143 return _b(_x(left), op, _x(right)) 1144 } 1145 1146 // 2: Unary operators that depend on the first letter. 1147 switch first { 1148 case '*': 1149 return &ast.StarExpr{ 1150 X: _x(expr[1:]), 1151 } 1152 case '+', '-', '!', '^', '&': 1153 return &ast.UnaryExpr{ 1154 Op: _op(expr[:1]), 1155 X: _x(expr[1:]), 1156 } 1157 case '<': 1158 second := expr[1] // is required. 1159 if second != '-' { 1160 panic("unparseable expression " + expr) 1161 } 1162 return &ast.UnaryExpr{ 1163 Op: _op("<-"), 1164 X: _x(expr[2:]), 1165 } 1166 } 1167 1168 // 3: Unary operators or literals that don't depend on the first letter, 1169 // and have some distinct suffix. 1170 if len(expr) > 1 { 1171 last := expr[len(expr)-1] 1172 switch last { 1173 case 'l': 1174 if expr == "nil" { 1175 return _i("nil") 1176 } 1177 case 'i': 1178 if '0' <= expr[0] && expr[0] <= '9' { 1179 num := _x(expr[:len(expr)-1]).(*ast.BasicLit) 1180 if num.Kind != token.INT && num.Kind != token.FLOAT { 1181 panic("expected int or float before 'i'") 1182 } 1183 num.Kind = token.IMAG 1184 return num 1185 } 1186 case '\'': 1187 if first != last { 1188 panic("unmatched quote") 1189 } 1190 return &ast.BasicLit{ 1191 Kind: token.CHAR, 1192 Value: expr[1 : len(expr)-1], 1193 } 1194 case '"', '`': 1195 if first != last { 1196 panic("unmatched quote") 1197 } 1198 return &ast.BasicLit{ 1199 Kind: token.STRING, 1200 Value: expr, 1201 } 1202 case ')': 1203 left, _, right := chopRight(expr) 1204 if left == "" { 1205 // Special case, not a function call. 1206 return _x(right) 1207 } else if left[len(left)-1] == '.' { 1208 // Special case, a type assert. 1209 var x, t ast.Expr = _x(left[:len(left)-1]), nil 1210 if right == "type" { 1211 t = nil 1212 } else { 1213 t = _x(right) 1214 } 1215 return &ast.TypeAssertExpr{ 1216 X: x, 1217 Type: t, 1218 } 1219 } 1220 1221 fn := _x(left) 1222 args := []ast.Expr{} 1223 parts := strings.Split(right, ",") 1224 for _, part := range parts { 1225 // NOTE: repeated commas have no effect, 1226 // nor do trailing commas. 1227 if len(part) > 0 { 1228 args = append(args, _x(part)) 1229 } 1230 } 1231 return &ast.CallExpr{ 1232 Fun: fn, 1233 Args: args, 1234 } 1235 case '}': 1236 left, _, right := chopRight(expr) 1237 ty := _x(left) 1238 elts := []ast.Expr{} 1239 parts := strings.Split(right, ",") 1240 for _, part := range parts { 1241 if strings.TrimSpace(part) != "" { 1242 parts := strings.Split(part, ":") 1243 if len(parts) != 2 { 1244 panic("key:value requires 1 colon") 1245 } 1246 elts = append(elts, _kv(parts[0], parts[1])) 1247 } 1248 } 1249 return &ast.CompositeLit{ 1250 Type: ty, 1251 Elts: elts, 1252 Incomplete: false, 1253 } 1254 case ']': 1255 left, _, right := chopRight(expr) 1256 return &ast.IndexExpr{ 1257 X: _x(left), 1258 Index: _x(right), 1259 } 1260 } 1261 } 1262 // 4. Monoids of array or slice type. 1263 // NOTE: []foo.bar requires this to have lower precedence than dots. 1264 switch first { 1265 case '[': 1266 if expr[1] == ']' { 1267 return &ast.ArrayType{ 1268 Len: nil, 1269 Elt: _x(expr[2:]), 1270 } 1271 } else { 1272 idx := strings.Index(expr, "]") 1273 if idx == -1 { 1274 panic(fmt.Sprintf( 1275 "mismatched '[' in slice expr %v", 1276 expr)) 1277 } 1278 return &ast.ArrayType{ 1279 Len: _x(expr[1:idx]), 1280 Elt: _x(expr[idx+1:]), 1281 } 1282 } 1283 } 1284 // Numeric int? We do these before dots, because dots are legal in numbers. 1285 const ( 1286 DGTS = `(?:[0-9]+)` 1287 HExX = `(?:0[xX][0-9a-fA-F]+)` 1288 PSCI = `(?:[eE]+?[0-9]+)` 1289 NSCI = `(?:[eE]-[1-9][0-9]+)` 1290 ASCI = `(?:[eE][-+]?[0-9]+)` 1291 ) 1292 isInt, err := regexp.Match( 1293 `^-?(?:`+ 1294 DGTS+`|`+ 1295 HExX+`)`+PSCI+`?$`, 1296 []byte(expr), 1297 ) 1298 if err != nil { 1299 panic("should not happen") 1300 } 1301 if isInt { 1302 return &ast.BasicLit{ 1303 Kind: token.INT, 1304 Value: expr, 1305 } 1306 } 1307 // Numeric float? We do these before dots, because dots are legal in floats. 1308 isFloat, err := regexp.Match( 1309 `^-?(?:`+ 1310 DGTS+`\.`+DGTS+ASCI+`?|`+ 1311 DGTS+NSCI+`)$`, 1312 []byte(expr), 1313 ) 1314 if err != nil { 1315 panic("should not happen") 1316 } 1317 if isFloat { 1318 return &ast.BasicLit{ 1319 Kind: token.FLOAT, 1320 Value: expr, 1321 } 1322 } 1323 // Last case, handle dots. 1324 // It's last, meaning it's got the highest precedence. 1325 if idx := strings.LastIndex(expr, "."); idx != -1 { 1326 return &ast.SelectorExpr{ 1327 X: _x(expr[:idx]), 1328 Sel: _i(expr[idx+1:]), 1329 } 1330 } 1331 return _i(expr) 1332 } 1333 1334 // Returns idx=-1 if not a binary operator. 1335 // Precedence Operator 1336 // 1337 // 5 * / % << >> & &^ 1338 // 4 + - | ^ 1339 // 3 == != < <= > >= 1340 // 2 && 1341 // 1 || 1342 func _kv(k, v interface{}) *ast.KeyValueExpr { 1343 var kx, vx ast.Expr 1344 if ks, ok := k.(string); ok { 1345 kx = _x(ks) 1346 } else { 1347 kx = k.(ast.Expr) 1348 } 1349 if vs, ok := v.(string); ok { 1350 vx = _x(vs) 1351 } else { 1352 vx = v.(ast.Expr) 1353 } 1354 return &ast.KeyValueExpr{ 1355 Key: kx, 1356 Value: vx, 1357 } 1358 } 1359 1360 func _block(b ...ast.Stmt) *ast.BlockStmt { 1361 return &ast.BlockStmt{ 1362 List: b, 1363 } 1364 } 1365 1366 // Usage: _a(lhs1, lhs2, ..., ":=", rhs1, rhs2, ...) 1367 // Token can be ":=", "=", "+=", etc. 1368 // Other strings are automatically parsed as _x(arg). 1369 func _a(args ...interface{}) *ast.AssignStmt { 1370 lhs := []ast.Expr(nil) 1371 tok := token.ILLEGAL 1372 rhs := []ast.Expr(nil) 1373 1374 setTok := func(t token.Token) { 1375 if tok != token.ILLEGAL { 1376 panic("too many assignment operators") 1377 } 1378 tok = t 1379 } 1380 1381 for _, arg := range args { 1382 if s, ok := arg.(string); ok { 1383 switch s { 1384 case "=", ":=", "+=", "-=", "*=", "/=", "%=", 1385 "&=", "|=", "^=", "<<=", ">>=", "&^=": 1386 setTok(_aop(s)) 1387 continue 1388 default: 1389 arg = _x(s) 1390 } 1391 } 1392 // append to lhs or rhs depending on tok. 1393 if tok == token.ILLEGAL { 1394 lhs = append(lhs, arg.(ast.Expr)) 1395 } else { 1396 rhs = append(rhs, arg.(ast.Expr)) 1397 } 1398 } 1399 1400 return &ast.AssignStmt{ 1401 Lhs: lhs, 1402 Tok: tok, 1403 Rhs: rhs, 1404 } 1405 } 1406 1407 func _not(x ast.Expr) *ast.UnaryExpr { 1408 return &ast.UnaryExpr{ 1409 Op: _op("!"), 1410 X: x, 1411 } 1412 } 1413 1414 // Binary expression. x, y can be ast.Expr or string. 1415 func _b(x interface{}, op string, y interface{}) ast.Expr { 1416 var xx, yx ast.Expr 1417 if xstr, ok := x.(string); ok { 1418 xx = _x(xstr) 1419 } else { 1420 xx = x.(ast.Expr) 1421 } 1422 if ystr, ok := y.(string); ok { 1423 yx = _x(ystr) 1424 } else { 1425 yx = y.(ast.Expr) 1426 } 1427 return &ast.BinaryExpr{ 1428 X: xx, 1429 Op: _op(op), 1430 Y: yx, 1431 } 1432 } 1433 1434 func _call(fn ast.Expr, args ...ast.Expr) *ast.CallExpr { 1435 return &ast.CallExpr{ 1436 Fun: fn, 1437 Args: args, 1438 } 1439 } 1440 1441 func _sel(x ast.Expr, sel string) *ast.SelectorExpr { 1442 return &ast.SelectorExpr{ 1443 X: x, 1444 Sel: _i(sel), 1445 } 1446 } 1447 1448 func _idx(x ast.Expr, idx ast.Expr) *ast.IndexExpr { 1449 return &ast.IndexExpr{ 1450 X: x, 1451 Index: idx, 1452 } 1453 } 1454 1455 func _s(s string) *ast.BasicLit { 1456 return &ast.BasicLit{ 1457 Kind: token.STRING, 1458 Value: strconv.Quote(s), 1459 } 1460 } 1461 1462 func _ref(x ast.Expr) *ast.UnaryExpr { 1463 return &ast.UnaryExpr{ 1464 Op: token.AND, 1465 X: x, 1466 } 1467 } 1468 1469 func _deref(x ast.Expr) *ast.StarExpr { 1470 return &ast.StarExpr{ 1471 X: x, 1472 } 1473 } 1474 1475 // NOTE: Same as _deref, but different contexts. 1476 func _ptr(x ast.Expr) *ast.StarExpr { 1477 return &ast.StarExpr{ 1478 X: x, 1479 } 1480 } 1481 1482 func _arr(l int, x ast.Expr) *ast.ArrayType { 1483 return &ast.ArrayType{ 1484 Len: _x(fmt.Sprintf("%v", l)), 1485 Elt: x, 1486 } 1487 } 1488 1489 func _sl(x ast.Expr) *ast.ArrayType { 1490 return &ast.ArrayType{ 1491 Len: nil, 1492 Elt: x, 1493 } 1494 } 1495 1496 // ---------------------------------------- 1497 // AST Construction (Stmt) 1498 1499 func _if(cond ast.Expr, b ...ast.Stmt) *ast.IfStmt { 1500 return &ast.IfStmt{ 1501 Cond: cond, 1502 Body: _block(b...), 1503 } 1504 } 1505 1506 func _ife(cond ast.Expr, bdy, els ast.Stmt) *ast.IfStmt { 1507 if _, ok := bdy.(*ast.BlockStmt); !ok { 1508 bdy = _block(bdy) 1509 } 1510 if _, ok := els.(*ast.BlockStmt); !ok { 1511 if _, ok := els.(*ast.IfStmt); !ok { 1512 els = _block(els) 1513 } 1514 } 1515 return &ast.IfStmt{ 1516 Cond: cond, 1517 Body: bdy.(*ast.BlockStmt), 1518 Else: els, 1519 } 1520 } 1521 1522 func _return(results ...ast.Expr) *ast.ReturnStmt { 1523 return &ast.ReturnStmt{ 1524 Results: results, 1525 } 1526 } 1527 1528 // even/odd args are paired, 1529 // name1, path1, name2, path2, etc. 1530 func _imports(nameAndPaths ...string) *ast.GenDecl { 1531 decl := &ast.GenDecl{ 1532 Tok: token.IMPORT, 1533 Specs: []ast.Spec{}, 1534 } 1535 for i := 0; i < len(nameAndPaths); i += 2 { 1536 spec := &ast.ImportSpec{ 1537 Name: _i(nameAndPaths[i]), 1538 Path: _s(nameAndPaths[i+1]), 1539 } 1540 decl.Specs = append(decl.Specs, spec) 1541 } 1542 return decl 1543 } 1544 1545 func _for(init ast.Stmt, cond ast.Expr, post ast.Stmt, b ...ast.Stmt) *ast.ForStmt { 1546 return &ast.ForStmt{ 1547 Init: init, 1548 Cond: cond, 1549 Post: post, 1550 Body: _block(b...), 1551 } 1552 } 1553 1554 func _len(x ast.Expr) *ast.CallExpr { 1555 return _call(_i("len"), x) 1556 } 1557 1558 func _var(name string, type_ ast.Expr, value ast.Expr) *ast.DeclStmt { 1559 if value == nil { 1560 return &ast.DeclStmt{ 1561 Decl: &ast.GenDecl{ 1562 Tok: token.VAR, 1563 Specs: []ast.Spec{ 1564 &ast.ValueSpec{ 1565 Names: []*ast.Ident{_i(name)}, 1566 Type: type_, 1567 Values: nil, 1568 }, 1569 }, 1570 }, 1571 } 1572 } else { 1573 return &ast.DeclStmt{ 1574 Decl: &ast.GenDecl{ 1575 Tok: token.VAR, 1576 Specs: []ast.Spec{ 1577 &ast.ValueSpec{ 1578 Names: []*ast.Ident{_i(name)}, 1579 Type: type_, 1580 Values: []ast.Expr{value}, 1581 }, 1582 }, 1583 }, 1584 } 1585 } 1586 } 1587 1588 func defaultExpr(k reflect.Kind) ast.Expr { 1589 switch k { 1590 case reflect.Interface, reflect.Ptr, reflect.Slice: 1591 return _x("nil") 1592 case reflect.String: 1593 return _x("\"\"") 1594 case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, 1595 reflect.Int8, reflect.Uint, reflect.Uint64, reflect.Uint32, 1596 reflect.Uint16, reflect.Uint8: 1597 return _x("0") 1598 case reflect.Bool: 1599 return _x("false") 1600 default: 1601 panic(fmt.Sprintf("no fixed default expression for kind %v", k)) 1602 } 1603 } 1604 1605 // binary and unary operators, excluding assignment operators. 1606 func _op(op string) token.Token { 1607 switch op { 1608 case "+": 1609 return token.ADD 1610 case "-": 1611 return token.SUB 1612 case "*": 1613 return token.MUL 1614 case "/": 1615 return token.QUO 1616 case "%": 1617 return token.REM 1618 case "&": 1619 return token.AND 1620 case "|": 1621 return token.OR 1622 case "^": 1623 return token.XOR 1624 case "<<": 1625 return token.SHL 1626 case ">>": 1627 return token.SHR 1628 case "&^": 1629 return token.AND_NOT 1630 case "&&": 1631 return token.LAND 1632 case "||": 1633 return token.LOR 1634 case "<-": 1635 return token.ARROW 1636 case "++": 1637 return token.INC 1638 case "--": 1639 return token.DEC 1640 case "==": 1641 return token.EQL 1642 case "<": 1643 return token.LSS 1644 case ">": 1645 return token.GTR 1646 case "!": 1647 return token.NOT 1648 case "!=": 1649 return token.NEQ 1650 case "<=": 1651 return token.LEQ 1652 case ">=": 1653 return token.GEQ 1654 default: 1655 panic("unrecognized binary/unary operator " + op) 1656 } 1657 } 1658 1659 // assignment operators. 1660 func _aop(op string) token.Token { 1661 switch op { 1662 case "=": 1663 return token.ASSIGN 1664 case ":=": 1665 return token.DEFINE 1666 case "+=": 1667 return token.ADD_ASSIGN 1668 case "-=": 1669 return token.SUB_ASSIGN 1670 case "*=": 1671 return token.MUL_ASSIGN 1672 case "/=": 1673 return token.QUO_ASSIGN 1674 case "%=": 1675 return token.REM_ASSIGN 1676 case "&=": 1677 return token.AND_ASSIGN 1678 case "|=": 1679 return token.OR_ASSIGN 1680 case "^=": 1681 return token.XOR_ASSIGN 1682 case "<<=": 1683 return token.SHL_ASSIGN 1684 case ">>=": 1685 return token.SHR_ASSIGN 1686 case "&^=": 1687 return token.AND_NOT_ASSIGN 1688 default: 1689 panic("unrecognized assignment operator " + op) 1690 } 1691 } 1692 1693 // ---------------------------------------- 1694 // AST Compile-Time 1695 1696 func _ctif(cond bool, then_, else_ ast.Stmt) ast.Stmt { 1697 if cond { 1698 return then_ 1699 } else if else_ != nil { 1700 return else_ 1701 } else { 1702 return &ast.EmptyStmt{Implicit: true} // TODO 1703 } 1704 } 1705 1706 // ---------------------------------------- 1707 // AST query and manipulation. 1708 1709 func importPathForName(name string, imports *ast.GenDecl) (path string, exists bool) { 1710 if imports.Tok != token.IMPORT { 1711 panic("unexpected ast.GenDecl token " + imports.Tok.String()) 1712 } 1713 for _, spec := range imports.Specs { 1714 if ispec, ok := spec.(*ast.ImportSpec); ok { 1715 if ispec.Name.Name == name { 1716 path, err := strconv.Unquote(ispec.Path.Value) 1717 if err != nil { 1718 panic("malformed path " + ispec.Path.Value) 1719 } 1720 return path, true 1721 } 1722 } 1723 } 1724 return "", false 1725 } 1726 1727 func rootScope(scope *ast.Scope) *ast.Scope { 1728 for scope.Outer != nil { 1729 scope = scope.Outer 1730 } 1731 return scope 1732 } 1733 1734 func addImport(imports *ast.GenDecl, scope *ast.Scope, name, path string) { 1735 epath, exists := importPathForName(name, imports) 1736 if path == epath { 1737 return 1738 } else if exists { 1739 panic(fmt.Sprintf("import already exists for name %v", name)) 1740 } else { 1741 imports.Specs = append(imports.Specs, &ast.ImportSpec{ 1742 Name: _i(name), 1743 Path: _s(path), 1744 }) 1745 addPkgNameToRootScope(name, rootScope(scope)) 1746 } 1747 } 1748 1749 func addImportAuto(imports *ast.GenDecl, scope *ast.Scope, name, path string) string { 1750 if path0, exists := importPathForName(name, imports); exists { 1751 if path0 == path { 1752 return name 1753 } 1754 for i := 1; ; i++ { 1755 n := fmt.Sprintf("%v%v", name, i) 1756 if _, exists := importPathForName(n, imports); !exists { 1757 addImport(imports, scope, n, path) 1758 return n 1759 } 1760 } 1761 } else { 1762 addImport(imports, scope, name, path) 1763 return name 1764 } 1765 } 1766 1767 func addPkgNameToRootScope(name string, scope *ast.Scope) { 1768 if scope.Outer != nil { 1769 panic("should not happen") 1770 } 1771 scope.Insert(ast.NewObj(ast.Pkg, name)) 1772 } 1773 1774 func addVars(scope *ast.Scope, names ...string) { 1775 for _, name := range names { 1776 if scope.Lookup(name) != nil { 1777 panic("already declared in scope") 1778 } else { 1779 scope.Insert(ast.NewObj(ast.Var, name)) 1780 } 1781 } 1782 } 1783 1784 func addVarUniq(scope *ast.Scope, name string) string { 1785 OUTER: 1786 for i := 0; ; i++ { 1787 tryName := name 1788 if i > 0 { 1789 tryName = fmt.Sprintf("%v%v", name, i) 1790 } 1791 s := scope 1792 for { 1793 if s.Lookup(tryName) != nil { 1794 continue OUTER 1795 } 1796 if s.Outer == nil { 1797 break 1798 } else { 1799 s = s.Outer 1800 } 1801 } 1802 scope.Insert(ast.NewObj(ast.Var, tryName)) 1803 return tryName 1804 } 1805 } 1806 1807 // If rt.PkgPath() is "", 1808 func goPkgPrefix(rootPkg *amino.Package, rt reflect.Type, info *amino.TypeInfo, imports *ast.GenDecl, scope *ast.Scope) (pkgPrefix string) { 1809 if rt.Name() == "" { 1810 panic("expected rt to have name") 1811 } 1812 if rt.PkgPath() == "" { 1813 return "" // native type. 1814 } 1815 var pkgName string 1816 pkgPath := rt.PkgPath() 1817 if pkgPath == "" || rootPkg.GoPkgPath == pkgPath { 1818 return "" 1819 } 1820 if info != nil && info.Package != nil { 1821 if info.Package.GoPkgPath != pkgPath { 1822 panic("conflicting package paths") 1823 } 1824 pkgName = info.Package.GoPkgName 1825 } else { 1826 pkgName = pkg.DefaultPkgName(pkgPath) 1827 } 1828 pkgName = addImportAuto(imports, scope, pkgName, pkgPath) 1829 return pkgName + "." 1830 } 1831 1832 func goTypeExprStringFn(rootPkg *amino.Package, imports *ast.GenDecl, scope *ast.Scope, isPtr bool, info *amino.TypeInfo) func() string { 1833 memo := "" 1834 return func() string { // lazy. 1835 if memo == "" { 1836 memo = goTypeExprString(rootPkg, imports, scope, isPtr, info) 1837 } 1838 return memo // cached. 1839 } 1840 } 1841 1842 func goTypeExprString(rootPkg *amino.Package, imports *ast.GenDecl, scope *ast.Scope, isPtr bool, info *amino.TypeInfo) string { 1843 if isPtr { 1844 return "*" + goTypeExprString(rootPkg, imports, scope, false, info) 1845 } 1846 // Below, assume isPtr is false. 1847 rt := info.Type 1848 // Below, the logic mirrors that of goTypeExpr. 1849 name := rt.Name() 1850 if name != "" { 1851 // If name exists, use the name rather than the kind. 1852 pkgPath := rt.PkgPath() 1853 // Sanity check 1854 if info.Package != nil && pkgPath != info.Package.GoPkgPath { 1855 panic(fmt.Sprintf("mismatching packages. info says %v, reflect says %v", info.Package.GoPkgPath, pkgPath)) 1856 } 1857 // END Sanity check 1858 pkgPrefix := goPkgPrefix(rootPkg, rt, info, imports, scope) 1859 return fmt.Sprintf("%v%v", pkgPrefix, name) 1860 } 1861 switch info.Type.Kind() { 1862 case reflect.Array: 1863 return fmt.Sprintf("[%v]%v", info.Type.Len(), goTypeExprString(rootPkg, imports, scope, info.ElemIsPtr, info.Elem)) 1864 case reflect.Slice: 1865 return fmt.Sprintf("[]%v", goTypeExprString(rootPkg, imports, scope, info.ElemIsPtr, info.Elem)) 1866 default: 1867 expr := rt.String() 1868 if strings.Contains(expr, ".") { 1869 panic("does not work (yet) with anonymous interface/struct types with imports") 1870 } 1871 return expr 1872 } 1873 } 1874 1875 func goTypeExpr(rootPkg *amino.Package, rt reflect.Type, imports *ast.GenDecl, scope *ast.Scope) ast.Expr { 1876 name := rt.Name() 1877 if name != "" { 1878 pkgPrefix := goPkgPrefix(rootPkg, rt, nil, imports, scope) 1879 return _x(fmt.Sprintf("%v%v", pkgPrefix, name)) 1880 } 1881 switch rt.Kind() { 1882 case reflect.Array: 1883 return _arr(rt.Len(), goTypeExpr(rootPkg, rt.Elem(), imports, scope)) 1884 case reflect.Slice: 1885 return _sl(goTypeExpr(rootPkg, rt.Elem(), imports, scope)) 1886 case reflect.Ptr: 1887 return _ptr(goTypeExpr(rootPkg, rt.Elem(), imports, scope)) 1888 default: 1889 expr := rt.String() 1890 if strings.Contains(expr, ".") { 1891 panic("does not work (yet) with anonymous interface/struct types with imports") 1892 } 1893 return _x(expr) 1894 } 1895 } 1896 1897 // The relevant p3-protoc generated go-type's type-expr given pre-repr info. 1898 // This is used for construction. 1899 func p3goTypeExprString(rootPkg *amino.Package, imports *ast.GenDecl, scope *ast.Scope, info *amino.TypeInfo, fopts amino.FieldOptions) (typeExpr string) { 1900 // If registered non-native type: 1901 pkg := info.Package 1902 if pkg != nil && pkg.GoPkgPath != "" && info.Type.Kind() != reflect.Interface { 1903 // Special cases. 1904 // TODO: somehow refactor into wellknown.go 1905 switch info.Type { 1906 case timeType: 1907 pkgName := addImportAuto( 1908 imports, scope, "timestamppb", "google.golang.org/protobuf/types/known/timestamppb") 1909 return fmt.Sprintf("*%v.%v", pkgName, "Timestamp") 1910 case durationType: 1911 pkgName := addImportAuto( 1912 imports, scope, "durationpb", "google.golang.org/protobuf/types/known/durationpb") 1913 return fmt.Sprintf("*%v.%v", pkgName, "Duration") 1914 } 1915 pkgName := addImportAuto(imports, scope, pkg.GoPkgName+"pb", pkg.P3GoPkgPath) 1916 typeExpr = fmt.Sprintf("*%v.%v", pkgName, CamelCase(info.Name)) 1917 return 1918 } 1919 // Else, if unregistered or non-concrete type: 1920 k := info.Type.Kind() 1921 switch k { 1922 case reflect.Array, reflect.Slice: 1923 // As a special case, if the repr-type's type is bytes, 1924 // we prefer bytes/[]byte instead of []struct{Value byte}. 1925 if info.Elem.ReprType.Type.Kind() == reflect.Uint8 { 1926 return "[]byte" 1927 } else { 1928 nl := newNList(rootPkg, info, fopts) 1929 return nl.P3GoExprString(imports, scope) 1930 } 1931 case reflect.String: 1932 return "string" 1933 case reflect.Interface: 1934 anypb := addImportAuto(imports, scope, "anypb", "google.golang.org/protobuf/types/known/anypb") 1935 return fmt.Sprintf("*%v.Any", anypb) 1936 case reflect.Struct: 1937 panic(fmt.Sprintf("package not registered for type %v", info)) 1938 case reflect.Int: 1939 return "int64" 1940 case reflect.Uint: 1941 return "uint64" 1942 case reflect.Int8: 1943 return "int32" 1944 case reflect.Uint8: 1945 return uint8Str // bytes 1946 case reflect.Int16: 1947 return "int32" 1948 case reflect.Uint16: 1949 return "uint32" 1950 default: 1951 if info.Type.PkgPath() != "" { 1952 panic("unexpected unregistered type " + info.Type.String()) 1953 } 1954 typeExpr = info.Type.String() 1955 if typeExpr == "" { 1956 panic("unexpected empty type expr string") 1957 } 1958 return 1959 } 1960 } 1961 1962 // Returns true if when info's repr is an unpacked list, thus requiring an 1963 // implicit struct for an array of info when info is further an element of an 1964 // array or slice. 1965 // 1966 // In other words, returns true when an implicit struct{Value []SomethingList} 1967 // is required in a parent list, required for the following transform: 1968 // 1969 // go: struct{NestedList: [][]SomethingList} --> 1970 // p3go: struct{NestedList: []struct{Value []SomethingListRepr}} 1971 func isImplicitList(info *amino.TypeInfo, fopts amino.FieldOptions) (implicit bool) { 1972 k := info.ReprType.Type.Kind() 1973 switch k { 1974 case reflect.Array, reflect.Slice: 1975 if info.ReprType.Elem.ReprType.Type.Kind() == reflect.Uint8 { 1976 return false 1977 } else { 1978 nl := newNList(nil, info, fopts) 1979 return nl.Dimensions >= 1 1980 } 1981 default: 1982 return false 1983 } 1984 }