github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/cmd/compile/internal/gc/bimport.go (about) 1 // Copyright 2015 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 // Binary package import. 6 // Based loosely on x/tools/go/importer. 7 8 package gc 9 10 import ( 11 "bufio" 12 "cmd/compile/internal/big" 13 "encoding/binary" 14 "fmt" 15 ) 16 17 // The overall structure of Import is symmetric to Export: For each 18 // export method in bexport.go there is a matching and symmetric method 19 // in bimport.go. Changing the export format requires making symmetric 20 // changes to bimport.go and bexport.go. 21 22 type importer struct { 23 in *bufio.Reader 24 buf []byte // for reading strings 25 bufarray [64]byte // initial underlying array for buf, large enough to avoid allocation when compiling std lib 26 pkgList []*Pkg 27 typList []*Type 28 inlined []*Node // functions with pending inlined function bodies 29 30 // debugging support 31 debugFormat bool 32 read int // bytes read 33 } 34 35 // Import populates importpkg from the serialized package data. 36 func Import(in *bufio.Reader) { 37 p := importer{in: in} 38 p.buf = p.bufarray[:] 39 40 // read low-level encoding format 41 switch format := p.byte(); format { 42 case 'c': 43 // compact format - nothing to do 44 case 'd': 45 p.debugFormat = true 46 default: 47 Fatalf("importer: invalid encoding format in export data: got %q; want 'c' or 'd'", format) 48 } 49 50 // --- generic export data --- 51 52 if v := p.string(); v != exportVersion { 53 Fatalf("importer: unknown export data version: %s", v) 54 } 55 56 // populate typList with predeclared "known" types 57 p.typList = append(p.typList, predeclared()...) 58 59 // read package data 60 p.pkg() 61 if p.pkgList[0] != importpkg { 62 Fatalf("importer: imported package not found in pkgList[0]") 63 } 64 65 // read compiler-specific flags 66 importpkg.Safe = p.string() == "safe" 67 68 // defer some type-checking until all types are read in completely 69 // (parser.go:import_package) 70 tcok := typecheckok 71 typecheckok = true 72 defercheckwidth() 73 74 // read objects 75 76 // Phase 1 77 objcount := 0 78 for { 79 tag := p.tagOrIndex() 80 if tag == endTag { 81 break 82 } 83 p.obj(tag) 84 objcount++ 85 } 86 87 // self-verification 88 if count := p.int(); count != objcount { 89 Fatalf("importer: got %d objects; want %d", objcount, count) 90 } 91 92 // --- compiler-specific export data --- 93 94 // Phase 2 95 objcount = 0 96 for { 97 tag := p.tagOrIndex() 98 if tag == endTag { 99 break 100 } 101 p.obj(tag) 102 objcount++ 103 } 104 105 // self-verification 106 if count := p.int(); count != objcount { 107 Fatalf("importer: got %d objects; want %d", objcount, count) 108 } 109 110 // read inlined functions bodies 111 if dclcontext != PEXTERN { 112 Fatalf("importer: unexpected context %d", dclcontext) 113 } 114 115 bcount := p.int() // consistency check only 116 if bcount != len(p.inlined) { 117 Fatalf("importer: expected %d inlined function bodies; got %d", bcount, len(p.inlined)) 118 } 119 for _, f := range p.inlined { 120 if Funcdepth != 0 { 121 Fatalf("importer: unexpected Funcdepth %d", Funcdepth) 122 } 123 if f != nil { 124 // function body not yet imported - read body and set it 125 funchdr(f) 126 f.Func.Inl.Set(p.stmtList()) 127 funcbody(f) 128 } else { 129 // function already imported - read body but discard declarations 130 dclcontext = PDISCARD // throw away any declarations 131 p.stmtList() 132 dclcontext = PEXTERN 133 } 134 } 135 136 if dclcontext != PEXTERN { 137 Fatalf("importer: unexpected context %d", dclcontext) 138 } 139 140 // --- end of export data --- 141 142 typecheckok = tcok 143 resumecheckwidth() 144 145 testdclstack() // debugging only 146 } 147 148 func (p *importer) pkg() *Pkg { 149 // if the package was seen before, i is its index (>= 0) 150 i := p.tagOrIndex() 151 if i >= 0 { 152 return p.pkgList[i] 153 } 154 155 // otherwise, i is the package tag (< 0) 156 if i != packageTag { 157 Fatalf("importer: expected package tag, found tag = %d", i) 158 } 159 160 // read package data 161 name := p.string() 162 path := p.string() 163 164 // we should never see an empty package name 165 if name == "" { 166 Fatalf("importer: empty package name in import") 167 } 168 169 // we should never see a bad import path 170 if isbadimport(path) { 171 Fatalf("importer: bad path in import: %q", path) 172 } 173 174 // an empty path denotes the package we are currently importing 175 pkg := importpkg 176 if path != "" { 177 pkg = mkpkg(path) 178 } 179 if pkg.Name == "" { 180 pkg.Name = name 181 } else if pkg.Name != name { 182 Fatalf("importer: conflicting names %s and %s for package %q", pkg.Name, name, path) 183 } 184 p.pkgList = append(p.pkgList, pkg) 185 186 return pkg 187 } 188 189 func idealType(typ *Type) *Type { 190 if typ.IsUntyped() { 191 // canonicalize ideal types 192 typ = Types[TIDEAL] 193 } 194 return typ 195 } 196 197 func (p *importer) obj(tag int) { 198 switch tag { 199 case constTag: 200 sym := p.qualifiedName() 201 typ := p.typ() 202 val := p.value(typ) 203 importconst(sym, idealType(typ), nodlit(val)) 204 205 case typeTag: 206 p.typ() 207 208 case varTag: 209 sym := p.qualifiedName() 210 typ := p.typ() 211 importvar(sym, typ) 212 213 case funcTag: 214 sym := p.qualifiedName() 215 params := p.paramList() 216 result := p.paramList() 217 inl := p.int() 218 219 sig := functype(nil, params, result) 220 importsym(sym, ONAME) 221 if sym.Def != nil && sym.Def.Op == ONAME { 222 if Eqtype(sig, sym.Def.Type) { 223 // function was imported before (via another import) 224 dclcontext = PDISCARD // since we skip funchdr below 225 } else { 226 Fatalf("importer: inconsistent definition for func %v during import\n\t%v\n\t%v", sym, sym.Def.Type, sig) 227 } 228 } 229 230 var n *Node 231 if dclcontext != PDISCARD { 232 n = newfuncname(sym) 233 n.Type = sig 234 declare(n, PFUNC) 235 if inl < 0 { 236 funchdr(n) 237 } 238 } 239 240 if inl >= 0 { 241 // function has inlined body - collect for later 242 if inl != len(p.inlined) { 243 Fatalf("importer: inlined index = %d; want %d", inl, len(p.inlined)) 244 } 245 p.inlined = append(p.inlined, n) 246 } 247 248 // parser.go:hidden_import 249 if dclcontext == PDISCARD { 250 dclcontext = PEXTERN // since we skip the funcbody below 251 break 252 } 253 254 if inl < 0 { 255 funcbody(n) 256 } 257 importlist = append(importlist, n) // TODO(gri) may only be needed for inlineable functions 258 259 if Debug['E'] > 0 { 260 fmt.Printf("import [%q] func %v \n", importpkg.Path, n) 261 if Debug['m'] > 2 && len(n.Func.Inl.Slice()) != 0 { 262 fmt.Printf("inl body: %v\n", n.Func.Inl) 263 } 264 } 265 266 default: 267 Fatalf("importer: unexpected object tag") 268 } 269 } 270 271 func (p *importer) newtyp(etype EType) *Type { 272 t := typ(etype) 273 p.typList = append(p.typList, t) 274 return t 275 } 276 277 func (p *importer) typ() *Type { 278 // if the type was seen before, i is its index (>= 0) 279 i := p.tagOrIndex() 280 if i >= 0 { 281 return p.typList[i] 282 } 283 284 // otherwise, i is the type tag (< 0) 285 var t *Type 286 switch i { 287 case namedTag: 288 // parser.go:hidden_importsym 289 tsym := p.qualifiedName() 290 291 // parser.go:hidden_pkgtype 292 t = pkgtype(tsym) 293 p.typList = append(p.typList, t) 294 295 // read underlying type 296 // parser.go:hidden_type 297 t0 := p.typ() 298 importtype(t, t0) // parser.go:hidden_import 299 300 // interfaces don't have associated methods 301 if t0.IsInterface() { 302 break 303 } 304 305 // set correct import context (since p.typ() may be called 306 // while importing the body of an inlined function) 307 savedContext := dclcontext 308 dclcontext = PEXTERN 309 310 // read associated methods 311 for i := p.int(); i > 0; i-- { 312 // parser.go:hidden_fndcl 313 314 sym := p.fieldSym() 315 316 recv := p.paramList() // TODO(gri) do we need a full param list for the receiver? 317 params := p.paramList() 318 result := p.paramList() 319 inl := p.int() 320 321 n := methodname1(newname(sym), recv[0].Right) 322 n.Type = functype(recv[0], params, result) 323 checkwidth(n.Type) 324 addmethod(sym, n.Type, tsym.Pkg, false, false) 325 if inl < 0 { 326 funchdr(n) 327 } 328 329 if inl >= 0 { 330 // method has inlined body - collect for later 331 if inl != len(p.inlined) { 332 Fatalf("importer: inlined index = %d; want %d", inl, len(p.inlined)) 333 } 334 p.inlined = append(p.inlined, n) 335 } 336 337 // (comment from parser.go) 338 // inl.C's inlnode in on a dotmeth node expects to find the inlineable body as 339 // (dotmeth's type).Nname.Inl, and dotmeth's type has been pulled 340 // out by typecheck's lookdot as this $$.ttype. So by providing 341 // this back link here we avoid special casing there. 342 n.Type.SetNname(n) 343 344 // parser.go:hidden_import 345 if inl < 0 { 346 funcbody(n) 347 } 348 importlist = append(importlist, n) // TODO(gri) may only be needed for inlineable functions 349 350 if Debug['E'] > 0 { 351 fmt.Printf("import [%q] meth %v \n", importpkg.Path, n) 352 if Debug['m'] > 2 && len(n.Func.Inl.Slice()) != 0 { 353 fmt.Printf("inl body: %v\n", n.Func.Inl) 354 } 355 } 356 } 357 358 dclcontext = savedContext 359 360 case arrayTag, sliceTag: 361 t = p.newtyp(TARRAY) 362 if i == arrayTag { 363 t.SetNumElem(p.int64()) 364 } else { 365 t.SetNumElem(sliceBound) 366 } 367 t.Type = p.typ() 368 369 case dddTag: 370 t = p.newtyp(TDDDFIELD) 371 t.Type = p.typ() 372 373 case structTag: 374 t = p.newtyp(TSTRUCT) 375 tostruct0(t, p.fieldList()) 376 377 case pointerTag: 378 t = p.newtyp(Tptr) 379 t.Type = p.typ() 380 381 case signatureTag: 382 t = p.newtyp(TFUNC) 383 params := p.paramList() 384 result := p.paramList() 385 functype0(t, nil, params, result) 386 387 case interfaceTag: 388 t = p.newtyp(TINTER) 389 if p.int() != 0 { 390 Fatalf("importer: unexpected embedded interface") 391 } 392 tointerface0(t, p.methodList()) 393 394 case mapTag: 395 t = p.newtyp(TMAP) 396 t.Down = p.typ() // key 397 t.Type = p.typ() // val 398 399 case chanTag: 400 t = p.newtyp(TCHAN) 401 t.Chan = ChanDir(p.int()) 402 t.Type = p.typ() 403 404 default: 405 Fatalf("importer: unexpected type (tag = %d)", i) 406 } 407 408 if t == nil { 409 Fatalf("importer: nil type (type tag = %d)", i) 410 } 411 412 return t 413 } 414 415 func (p *importer) qualifiedName() *Sym { 416 name := p.string() 417 pkg := p.pkg() 418 return pkg.Lookup(name) 419 } 420 421 // parser.go:hidden_structdcl_list 422 func (p *importer) fieldList() []*Node { 423 i := p.int() 424 if i == 0 { 425 return nil 426 } 427 n := make([]*Node, i) 428 for i := range n { 429 n[i] = p.field() 430 } 431 return n 432 } 433 434 // parser.go:hidden_structdcl 435 func (p *importer) field() *Node { 436 sym := p.fieldName() 437 typ := p.typ() 438 note := p.note() 439 440 var n *Node 441 if sym.Name != "" { 442 n = Nod(ODCLFIELD, newname(sym), typenod(typ)) 443 } else { 444 // anonymous field - typ must be T or *T and T must be a type name 445 s := typ.Sym 446 if s == nil && typ.IsPtr() { 447 s = typ.Type.Sym // deref 448 } 449 pkg := importpkg 450 if sym != nil { 451 pkg = sym.Pkg 452 } 453 n = embedded(s, pkg) 454 n.Right = typenod(typ) 455 } 456 n.SetVal(note) 457 458 return n 459 } 460 461 func (p *importer) note() (v Val) { 462 if s := p.string(); s != "" { 463 v.U = s 464 } 465 return 466 } 467 468 // parser.go:hidden_interfacedcl_list 469 func (p *importer) methodList() []*Node { 470 i := p.int() 471 if i == 0 { 472 return nil 473 } 474 n := make([]*Node, i) 475 for i := range n { 476 n[i] = p.method() 477 } 478 return n 479 } 480 481 // parser.go:hidden_interfacedcl 482 func (p *importer) method() *Node { 483 sym := p.fieldName() 484 params := p.paramList() 485 result := p.paramList() 486 return Nod(ODCLFIELD, newname(sym), typenod(functype(fakethis(), params, result))) 487 } 488 489 // parser.go:sym,hidden_importsym 490 func (p *importer) fieldName() *Sym { 491 name := p.string() 492 pkg := localpkg 493 if name == "_" { 494 // During imports, unqualified non-exported identifiers are from builtinpkg 495 // (see parser.go:sym). The binary exporter only exports blank as a non-exported 496 // identifier without qualification. 497 pkg = localpkg 498 } else if name == "?" || name != "" && !exportname(name) { 499 if name == "?" { 500 name = "" 501 } 502 pkg = p.pkg() 503 } 504 return pkg.Lookup(name) 505 } 506 507 // parser.go:ohidden_funarg_list 508 func (p *importer) paramList() []*Node { 509 i := p.int() 510 if i == 0 { 511 return nil 512 } 513 // negative length indicates unnamed parameters 514 named := true 515 if i < 0 { 516 i = -i 517 named = false 518 } 519 // i > 0 520 n := make([]*Node, i) 521 for i := range n { 522 n[i] = p.param(named) 523 } 524 return n 525 } 526 527 // parser.go:hidden_funarg 528 func (p *importer) param(named bool) *Node { 529 typ := p.typ() 530 531 isddd := false 532 if typ.Etype == TDDDFIELD { 533 // TDDDFIELD indicates wrapped ... slice type 534 typ = typSlice(typ.Wrapped()) 535 isddd = true 536 } 537 538 n := Nod(ODCLFIELD, nil, typenod(typ)) 539 n.Isddd = isddd 540 541 if named { 542 name := p.string() 543 if name == "" { 544 Fatalf("importer: expected named parameter") 545 } 546 // TODO(gri) Supply function/method package rather than 547 // encoding the package for each parameter repeatedly. 548 pkg := p.pkg() 549 n.Left = newname(pkg.Lookup(name)) 550 } 551 552 // TODO(gri) This is compiler-specific (escape info). 553 // Move into compiler-specific section eventually? 554 n.SetVal(p.note()) 555 556 return n 557 } 558 559 func (p *importer) value(typ *Type) (x Val) { 560 switch tag := p.tagOrIndex(); tag { 561 case falseTag: 562 x.U = false 563 564 case trueTag: 565 x.U = true 566 567 case int64Tag: 568 u := new(Mpint) 569 u.SetInt64(p.int64()) 570 u.Rune = typ == idealrune 571 x.U = u 572 573 case floatTag: 574 f := newMpflt() 575 p.float(f) 576 if typ == idealint || typ.IsInteger() { 577 // uncommon case: large int encoded as float 578 u := new(Mpint) 579 u.SetFloat(f) 580 x.U = u 581 break 582 } 583 x.U = f 584 585 case complexTag: 586 u := new(Mpcplx) 587 p.float(&u.Real) 588 p.float(&u.Imag) 589 x.U = u 590 591 case stringTag: 592 x.U = p.string() 593 594 case unknownTag: 595 Fatalf("importer: unknown constant (importing package with errors)") 596 597 case nilTag: 598 x.U = new(NilVal) 599 600 default: 601 Fatalf("importer: unexpected value tag %d", tag) 602 } 603 604 // verify ideal type 605 if typ.IsUntyped() && untype(x.Ctype()) != typ { 606 Fatalf("importer: value %v and type %v don't match", x, typ) 607 } 608 609 return 610 } 611 612 func (p *importer) float(x *Mpflt) { 613 sign := p.int() 614 if sign == 0 { 615 x.SetFloat64(0) 616 return 617 } 618 619 exp := p.int() 620 mant := new(big.Int).SetBytes([]byte(p.string())) 621 622 m := x.Val.SetInt(mant) 623 m.SetMantExp(m, exp-mant.BitLen()) 624 if sign < 0 { 625 m.Neg(m) 626 } 627 } 628 629 // ---------------------------------------------------------------------------- 630 // Inlined function bodies 631 632 // Approach: Read nodes and use them to create/declare the same data structures 633 // as done originally by the (hidden) parser by closely following the parser's 634 // original code. In other words, "parsing" the import data (which happens to 635 // be encoded in binary rather textual form) is the best way at the moment to 636 // re-establish the syntax tree's invariants. At some future point we might be 637 // able to avoid this round-about way and create the rewritten nodes directly, 638 // possibly avoiding a lot of duplicate work (name resolution, type checking). 639 640 func (p *importer) stmtList() []*Node { 641 var list []*Node 642 for { 643 n := p.node() 644 if n == nil { 645 break 646 } 647 // OBLOCK nodes may be created when importing ODCL nodes - unpack them 648 if n.Op == OBLOCK { 649 list = append(list, n.List.Slice()...) 650 } else { 651 list = append(list, n) 652 } 653 } 654 return list 655 } 656 657 func (p *importer) exprList() []*Node { 658 var list []*Node 659 for { 660 n := p.expr() 661 if n == nil { 662 break 663 } 664 list = append(list, n) 665 } 666 return list 667 } 668 669 func (p *importer) elemList() []*Node { 670 c := p.int() 671 list := make([]*Node, c) 672 for i := range list { 673 list[i] = Nod(OKEY, mkname(p.fieldSym()), p.expr()) 674 } 675 return list 676 } 677 678 func (p *importer) expr() *Node { 679 n := p.node() 680 if n != nil && n.Op == OBLOCK { 681 Fatalf("unexpected block node: %v", n) 682 } 683 return n 684 } 685 686 // TODO(gri) split into expr and stmt 687 func (p *importer) node() *Node { 688 switch op := p.op(); op { 689 // expressions 690 // case OPAREN: 691 // unreachable - unpacked by exporter 692 693 // case ODDDARG: 694 // unimplemented 695 696 // case OREGISTER: 697 // unimplemented 698 699 case OLITERAL: 700 typ := p.typ() 701 n := nodlit(p.value(typ)) 702 if !typ.IsUntyped() { 703 conv := Nod(OCALL, typenod(typ), nil) 704 conv.List.Set1(n) 705 n = conv 706 } 707 return n 708 709 case ONAME: 710 if p.bool() { 711 // "_" 712 // TODO(gri) avoid repeated "_" lookup 713 return mkname(Pkglookup("_", localpkg)) 714 } 715 return NodSym(OXDOT, typenod(p.typ()), p.fieldSym()) 716 717 case OPACK, ONONAME: 718 return mkname(p.sym()) 719 720 case OTYPE: 721 if p.bool() { 722 return mkname(p.sym()) 723 } 724 return typenod(p.typ()) 725 726 // case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC: 727 // unreachable - should have been resolved by typechecking 728 729 // case OCLOSURE: 730 // unimplemented 731 732 // case OCOMPLIT: 733 // unimplemented 734 735 case OPTRLIT: 736 n := p.expr() 737 if !p.bool() /* !implicit, i.e. '&' operator*/ { 738 if n.Op == OCOMPLIT { 739 // Special case for &T{...}: turn into (*T){...}. 740 n.Right = Nod(OIND, n.Right, nil) 741 n.Right.Implicit = true 742 } else { 743 n = Nod(OADDR, n, nil) 744 } 745 } 746 return n 747 748 case OSTRUCTLIT: 749 n := Nod(OCOMPLIT, nil, nil) 750 if !p.bool() { 751 n.Right = typenod(p.typ()) 752 } 753 n.List.Set(p.elemList()) 754 return n 755 756 case OARRAYLIT, OMAPLIT: 757 n := Nod(OCOMPLIT, nil, nil) 758 if !p.bool() { 759 n.Right = typenod(p.typ()) 760 } 761 n.List.Set(p.exprList()) 762 return n 763 764 case OKEY: 765 left, right := p.exprsOrNil() 766 return Nod(OKEY, left, right) 767 768 // case OCALLPART: 769 // unimplemented 770 771 // case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH: 772 // unreachable - mapped to case OXDOT below by exporter 773 774 case OXDOT: 775 // see parser.new_dotname 776 obj := p.expr() 777 sel := p.fieldSym() 778 if obj.Op == OPACK { 779 s := restrictlookup(sel.Name, obj.Name.Pkg) 780 obj.Used = true 781 return oldname(s) 782 } 783 return NodSym(OXDOT, obj, sel) 784 785 // case ODOTTYPE, ODOTTYPE2: 786 // unreachable - mapped to case ODOTTYPE below by exporter 787 788 case ODOTTYPE: 789 n := Nod(ODOTTYPE, p.expr(), nil) 790 if p.bool() { 791 n.Right = p.expr() 792 } else { 793 n.Right = typenod(p.typ()) 794 } 795 return n 796 797 // case OINDEX, OINDEXMAP, OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR: 798 // unreachable - mapped to cases below by exporter 799 800 case OINDEX, OSLICE, OSLICE3: 801 return Nod(op, p.expr(), p.expr()) 802 803 case OCOPY, OCOMPLEX: 804 n := builtinCall(op) 805 n.List.Set([]*Node{p.expr(), p.expr()}) 806 return n 807 808 // case OCONV, OCONVIFACE, OCONVNOP, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, ORUNESTR: 809 // unreachable - mapped to OCONV case below by exporter 810 811 case OCONV: 812 n := Nod(OCALL, typenod(p.typ()), nil) 813 if p.bool() { 814 n.List.Set1(p.expr()) 815 } else { 816 n.List.Set(p.exprList()) 817 } 818 return n 819 820 case OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN: 821 n := builtinCall(op) 822 if p.bool() { 823 n.List.Set1(p.expr()) 824 } else { 825 n.List.Set(p.exprList()) 826 n.Isddd = p.bool() 827 } 828 return n 829 830 // case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG: 831 // unreachable - mapped to OCALL case below by exporter 832 833 case OCALL: 834 n := Nod(OCALL, p.expr(), nil) 835 n.List.Set(p.exprList()) 836 n.Isddd = p.bool() 837 return n 838 839 case OMAKEMAP, OMAKECHAN, OMAKESLICE: 840 n := builtinCall(OMAKE) 841 n.List.Append(typenod(p.typ())) 842 n.List.Append(p.exprList()...) 843 return n 844 845 // unary expressions 846 case OPLUS, OMINUS, OADDR, OCOM, OIND, ONOT, ORECV: 847 return Nod(op, p.expr(), nil) 848 849 // binary expressions 850 case OADD, OAND, OANDAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE, OLT, 851 OLSH, OMOD, OMUL, ONE, OOR, OOROR, ORSH, OSEND, OSUB, OXOR: 852 return Nod(op, p.expr(), p.expr()) 853 854 case OADDSTR: 855 list := p.exprList() 856 x := list[0] 857 for _, y := range list[1:] { 858 x = Nod(OADD, x, y) 859 } 860 return x 861 862 // case OCMPSTR, OCMPIFACE: 863 // unreachable - mapped to std comparison operators by exporter 864 865 case ODCLCONST: 866 // TODO(gri) these should not be exported in the first place 867 return Nod(OEMPTY, nil, nil) 868 869 // -------------------------------------------------------------------- 870 // statements 871 case ODCL: 872 var lhs *Node 873 if p.bool() { 874 lhs = p.expr() 875 } else { 876 lhs = dclname(p.sym()) 877 } 878 // TODO(gri) avoid list created here! 879 return liststmt(variter([]*Node{lhs}, typenod(p.typ()), nil)) 880 881 // case ODCLFIELD: 882 // unimplemented 883 884 case OAS, OASWB: 885 if p.bool() { 886 lhs := p.expr() 887 rhs := p.expr() 888 return Nod(OAS, lhs, rhs) 889 } 890 // TODO(gri) we should not have emitted anything here 891 return Nod(OEMPTY, nil, nil) 892 893 case OASOP: 894 n := Nod(OASOP, nil, nil) 895 n.Etype = EType(p.int()) 896 n.Left = p.expr() 897 if !p.bool() { 898 n.Right = Nodintconst(1) 899 n.Implicit = true 900 } else { 901 n.Right = p.expr() 902 } 903 return n 904 905 case OAS2: 906 lhs := p.exprList() 907 rhs := p.exprList() 908 n := Nod(OAS2, nil, nil) 909 n.List.Set(lhs) 910 n.Rlist.Set(rhs) 911 return n 912 913 case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV: 914 n := Nod(OAS2, nil, nil) 915 n.List.Set(p.exprList()) 916 n.Rlist.Set(p.exprList()) 917 return n 918 919 case ORETURN: 920 n := Nod(ORETURN, nil, nil) 921 n.List.Set(p.exprList()) 922 return n 923 924 // case ORETJMP: 925 // unreachable - generated by compiler for trampolin routines (not exported) 926 927 case OPROC, ODEFER: 928 return Nod(op, p.expr(), nil) 929 930 case OIF: 931 markdcl() 932 n := Nod(OIF, nil, nil) 933 n.Ninit.Set(p.stmtList()) 934 n.Left = p.expr() 935 n.Nbody.Set(p.stmtList()) 936 n.Rlist.Set(p.stmtList()) 937 popdcl() 938 return n 939 940 case OFOR: 941 markdcl() 942 n := Nod(OFOR, nil, nil) 943 n.Ninit.Set(p.stmtList()) 944 n.Left, n.Right = p.exprsOrNil() 945 n.Nbody.Set(p.stmtList()) 946 popdcl() 947 return n 948 949 case ORANGE: 950 markdcl() 951 n := Nod(ORANGE, nil, nil) 952 n.List.Set(p.stmtList()) 953 n.Right = p.expr() 954 n.Nbody.Set(p.stmtList()) 955 popdcl() 956 return n 957 958 case OSELECT, OSWITCH: 959 markdcl() 960 n := Nod(op, nil, nil) 961 n.Ninit.Set(p.stmtList()) 962 n.Left, _ = p.exprsOrNil() 963 n.List.Set(p.stmtList()) 964 popdcl() 965 return n 966 967 case OCASE, OXCASE: 968 markdcl() 969 n := Nod(OXCASE, nil, nil) 970 n.List.Set(p.exprList()) 971 // TODO(gri) eventually we must declare variables for type switch 972 // statements (type switch statements are not yet exported) 973 n.Nbody.Set(p.stmtList()) 974 popdcl() 975 return n 976 977 case OBREAK, OCONTINUE, OGOTO, OFALL, OXFALL: 978 if op == OFALL { 979 op = OXFALL 980 } 981 left, _ := p.exprsOrNil() 982 return Nod(op, left, nil) 983 984 // case OEMPTY: 985 // unreachable - not emitted by exporter 986 987 case OLABEL: 988 n := Nod(OLABEL, p.expr(), nil) 989 n.Left.Sym = dclstack // context, for goto restrictions 990 return n 991 992 case OEND: 993 return nil 994 995 default: 996 Fatalf("importer: %s (%d) node not yet supported", opnames[op], op) 997 panic("unreachable") // satisfy compiler 998 } 999 } 1000 1001 func builtinCall(op Op) *Node { 1002 return Nod(OCALL, mkname(builtinpkg.Lookup(goopnames[op])), nil) 1003 } 1004 1005 func (p *importer) exprsOrNil() (a, b *Node) { 1006 ab := p.int() 1007 if ab&1 != 0 { 1008 a = p.expr() 1009 } 1010 if ab&2 != 0 { 1011 b = p.expr() 1012 } 1013 return 1014 } 1015 1016 func (p *importer) fieldSym() *Sym { 1017 name := p.string() 1018 pkg := localpkg 1019 if !exportname(name) { 1020 pkg = p.pkg() 1021 } 1022 return pkg.Lookup(name) 1023 } 1024 1025 func (p *importer) sym() *Sym { 1026 name := p.string() 1027 pkg := localpkg 1028 if name != "_" { 1029 pkg = p.pkg() 1030 } 1031 return pkg.Lookup(name) 1032 } 1033 1034 func (p *importer) bool() bool { 1035 return p.int() != 0 1036 } 1037 1038 func (p *importer) op() Op { 1039 return Op(p.int()) 1040 } 1041 1042 // ---------------------------------------------------------------------------- 1043 // Low-level decoders 1044 1045 func (p *importer) tagOrIndex() int { 1046 if p.debugFormat { 1047 p.marker('t') 1048 } 1049 1050 return int(p.rawInt64()) 1051 } 1052 1053 func (p *importer) int() int { 1054 x := p.int64() 1055 if int64(int(x)) != x { 1056 Fatalf("importer: exported integer too large") 1057 } 1058 return int(x) 1059 } 1060 1061 func (p *importer) int64() int64 { 1062 if p.debugFormat { 1063 p.marker('i') 1064 } 1065 1066 return p.rawInt64() 1067 } 1068 1069 func (p *importer) string() string { 1070 if p.debugFormat { 1071 p.marker('s') 1072 } 1073 1074 // TODO(gri) should we intern strings here? 1075 1076 if n := int(p.rawInt64()); n > 0 { 1077 if cap(p.buf) < n { 1078 p.buf = make([]byte, n) 1079 } else { 1080 p.buf = p.buf[:n] 1081 } 1082 for i := range p.buf { 1083 p.buf[i] = p.byte() 1084 } 1085 return string(p.buf) 1086 } 1087 1088 return "" 1089 } 1090 1091 func (p *importer) marker(want byte) { 1092 if got := p.byte(); got != want { 1093 Fatalf("importer: incorrect marker: got %c; want %c (pos = %d)", got, want, p.read) 1094 } 1095 1096 pos := p.read 1097 if n := int(p.rawInt64()); n != pos { 1098 Fatalf("importer: incorrect position: got %d; want %d", n, pos) 1099 } 1100 } 1101 1102 // rawInt64 should only be used by low-level decoders 1103 func (p *importer) rawInt64() int64 { 1104 i, err := binary.ReadVarint(p) 1105 if err != nil { 1106 Fatalf("importer: read error: %v", err) 1107 } 1108 return i 1109 } 1110 1111 // needed for binary.ReadVarint in rawInt64 1112 func (p *importer) ReadByte() (byte, error) { 1113 return p.byte(), nil 1114 } 1115 1116 // byte is the bottleneck interface for reading from p.in. 1117 // It unescapes '|' 'S' to '$' and '|' '|' to '|'. 1118 func (p *importer) byte() byte { 1119 c, err := p.in.ReadByte() 1120 p.read++ 1121 if err != nil { 1122 Fatalf("importer: read error: %v", err) 1123 } 1124 if c == '|' { 1125 c, err = p.in.ReadByte() 1126 p.read++ 1127 if err != nil { 1128 Fatalf("importer: read error: %v", err) 1129 } 1130 switch c { 1131 case 'S': 1132 c = '$' 1133 case '|': 1134 // nothing to do 1135 default: 1136 Fatalf("importer: unexpected escape sequence in export data") 1137 } 1138 } 1139 return c 1140 }