The binary import/export format is significantly more
compact than the existing textual format. It should
also be faster to read and write (to be measured).
Use -newexport to enable, for instance:
export GO_GCFLAGS=-newexport; make.bash
The compiler can import packages using both the old
and the new format ("mixed mode").
Missing: export info for inlined functions bodies
(performance issue, does not affect correctness).
Disabled by default until we have inlined function
bodies and confirmation of no regression and equality
of binaries.
For #6110.
For #1909.
This change depends on:
https://go-review.googlesource.com/16220
https://go-review.googlesource.com/16222
(already submitted) for all.bash to work.
Some initial export data sizes for std lib packages. This data
is without exported functions with inlineable function bodies.
Package old new new/old
archive/tar.................................13875.....3883 28%
archive/zip.................................19464.....5046 26%
bufio....................................... 7733.....2222 29%
bytes.......................................10342.....3347 32%
cmd/addr2line.................................242.......26 11%
cmd/api.....................................39305....10368 26%
cmd/asm/internal/arch.......................27732.....7939 29%
cmd/asm/internal/asm........................35264....10295 29%
cmd/asm/internal/flags........................629......178 28%
cmd/asm/internal/lex........................39248....11128 28%
cmd/asm.......................................306.......26 8%
cmd/cgo.....................................40197....10570 26%
cmd/compile/internal/amd64...................1106......214 19%
cmd/compile/internal/arm....................27891.....7710 28%
cmd/compile/internal/arm64....................891......153 17%
cmd/compile/internal/big....................21637.....8336 39%
cmd/compile/internal/gc....................109845....29727 27%
cmd/compile/internal/mips64...................972......168 17%
cmd/compile/internal/ppc64....................972......168 17%
cmd/compile/internal/x86.....................1104......195 18%
cmd/compile...................................329.......26 8%
cmd/cover...................................12986.....3749 29%
cmd/dist......................................477.......67 14%
cmd/doc.....................................23043.....6793 29%
cmd/expdump...................................167.......26 16%
cmd/fix......................................1190......208 17%
cmd/go......................................26399.....5629 21%
cmd/gofmt.....................................499.......26 5%
cmd/internal/gcprog..........................1342......490 37%
cmd/internal/goobj...........................2690......980 36%
cmd/internal/obj/arm........................32740....10057 31%
cmd/internal/obj/arm64......................46542....15364 33%
cmd/internal/obj/mips.......................42140....13731 33%
cmd/internal/obj/ppc64......................42140....13731 33%
cmd/internal/obj/x86........................52732....19015 36%
cmd/internal/obj............................36729....11690 32%
cmd/internal/objfile........................36365....10287 28%
cmd/link/internal/amd64.....................45893....12220 27%
cmd/link/internal/arm.........................307.......96 31%
cmd/link/internal/arm64.......................345.......98 28%
cmd/link/internal/ld.......................109300....46326 42%
cmd/link/internal/ppc64.......................344.......99 29%
cmd/link/internal/x86.........................334......107 32%
cmd/link......................................314.......26 8%
cmd/newlink..................................8110.....2544 31%
cmd/nm........................................210.......26 12%
cmd/objdump...................................244.......26 11%
cmd/pack....................................14248.....4066 29%
cmd/pprof/internal/commands..................5239.....1285 25%
cmd/pprof/internal/driver...................37967.....8860 23%
cmd/pprof/internal/fetch....................30962.....7337 24%
cmd/pprof/internal/plugin...................47734.....7719 16%
cmd/pprof/internal/profile..................22286.....6922 31%
cmd/pprof/internal/report...................31187.....7838 25%
cmd/pprof/internal/svg.......................4315......965 22%
cmd/pprof/internal/symbolizer...............30051.....7397 25%
cmd/pprof/internal/symbolz..................28545.....6949 24%
cmd/pprof/internal/tempfile.................12550.....3356 27%
cmd/pprof.....................................563.......26 5%
cmd/trace....................................1455......636 44%
cmd/vendor/golang.org/x/arch/arm/armasm....168035....64737 39%
cmd/vendor/golang.org/x/arch/x86/x86asm.....26871.....8578 32%
cmd/vet.....................................38980.....9913 25%
cmd/vet/whitelist.............................102.......49 48%
cmd/yacc.....................................2518......926 37%
compress/bzip2...............................6326......129 2%
compress/flate...............................7069.....2541 36%
compress/gzip...............................20143.....5069 25%
compress/lzw..................................828......295 36%
compress/zlib...............................10676.....2692 25%
container/heap................................523......181 35%
container/list...............................3517......740 21%
container/ring................................881......229 26%
crypto/aes....................................550......187 34%
crypto/cipher................................1966......825 42%
crypto.......................................1836......646 35%
crypto/des....................................632......235 37%
crypto/dsa..................................18718.....5035 27%
crypto/ecdsa................................23131.....6097 26%
crypto/elliptic.............................20790.....5740 28%
crypto/hmac...................................455......186 41%
crypto/md5...................................1375......171 12%
crypto/rand.................................18132.....4748 26%
crypto/rc4....................................561......240 43%
crypto/rsa..................................22094.....6380 29%
crypto/sha1..................................1416......172 12%
crypto/sha256.................................551......238 43%
crypto/sha512.................................839......378 45%
crypto/subtle................................1153......250 22%
crypto/tls..................................58203....17984 31%
crypto/x509/pkix............................29447.....8161 28%
database/sql/driver..........................3318.....1096 33%
database/sql................................11258.....3942 35%
debug/dwarf.................................18416.....7006 38%
debug/elf...................................57530....21014 37%
debug/gosym..................................4992.....2058 41%
debug/macho.................................23037.....6538 28%
debug/pe....................................21063.....6619 31%
debug/plan9obj...............................2467......802 33%
encoding/ascii85.............................1523......360 24%
encoding/asn1................................1718......527 31%
encoding/base32..............................2642......686 26%
encoding/base64..............................3077......800 26%
encoding/binary..............................4727.....1040 22%
encoding/csv................................12223.....2850 23%
encoding......................................383......217 57%
encoding/gob................................37563....10113 27%
encoding/hex.................................1327......390 29%
encoding/json...............................30897.....7804 25%
encoding/pem..................................595......200 34%
encoding/xml................................37798.....9336 25%
errors........................................274.......36 13%
expvar.......................................3155.....1021 32%
flag........................................19860.....2849 14%
fmt..........................................3137.....1263 40%
go/ast......................................44729....13422 30%
go/build....................................16336.....4657 29%
go/constant..................................3703......846 23%
go/doc.......................................9877.....2807 28%
go/format....................................5472.....1575 29%
go/importer..................................4980.....1301 26%
go/internal/gccgoimporter....................5587.....1525 27%
go/internal/gcimporter.......................8979.....2186 24%
go/parser...................................20692.....5304 26%
go/printer...................................7015.....2029 29%
go/scanner...................................9719.....2824 29%
go/token.....................................7933.....2465 31%
go/types....................................64569....19978 31%
hash/adler32.................................1176......176 15%
hash/crc32...................................1663......360 22%
hash/crc64...................................1587......306 19%
hash/fnv.....................................3964......260 7%
hash..........................................591......278 47%
html..........................................217.......74 34%
html/template...............................69623....12588 18%
image/color/palette...........................315.......98 31%
image/color..................................5565.....1036 19%
image/draw...................................6917.....1028 15%
image/gif....................................8894.....1654 19%
image/internal/imageutil.....................9112.....1476 16%
image/jpeg...................................6647.....1026 15%
image/png....................................6906.....1069 15%
image.......................................28992.....6139 21%
index/suffixarray...........................17106.....4773 28%
internal/singleflight........................1614......506 31%
internal/testenv............................12212.....3152 26%
internal/trace...............................2762.....1323 48%
io/ioutil...................................13502.....3682 27%
io...........................................6765.....2482 37%
log.........................................11620.....3317 29%
log/syslog..................................13516.....3821 28%
math/big....................................21819.....8320 38%
math/cmplx...................................2816......438 16%
math/rand....................................2317......929 40%
math.........................................7511.....2444 33%
mime/multipart..............................12679.....3360 27%
mime/quotedprintable.........................5458.....1235 23%
mime.........................................6076.....1628 27%
net/http/cgi................................59796....17173 29%
net/http/cookiejar..........................14781.....3739 25%
net/http/fcgi...............................57861....16426 28%
net/http/httptest...........................84100....24365 29%
net/http/httputil...........................67763....18869 28%
net/http/internal............................6907......637 9%
net/http/pprof..............................57945....16316 28%
net/http....................................95391....30210 32%
net/internal/socktest........................4555.....1453 32%
net/mail....................................14481.....3608 25%
net/rpc/jsonrpc.............................33335......988 3%
net/rpc.....................................79950....23106 29%
net/smtp....................................57790....16468 28%
net/textproto...............................11356.....3248 29%
net/url......................................3123.....1009 32%
os/exec.....................................20738.....5769 28%
os/signal.....................................437......167 38%
os..........................................24875.....6668 27%
path/filepath...............................11340.....2826 25%
path..........................................778......285 37%
reflect.....................................15469.....5198 34%
regexp......................................13627.....4661 34%
regexp/syntax................................5539.....2249 41%
runtime/debug................................9275.....2322 25%
runtime/pprof................................1355......477 35%
runtime/race...................................39.......17 44%
runtime/trace.................................228.......92 40%
runtime.....................................13498.....1821 13%
sort.........................................2848......842 30%
strconv......................................2947.....1252 42%
strings......................................7983.....2456 31%
sync/atomic..................................2666.....1149 43%
sync.........................................2568......845 33%
syscall.....................................81252....38398 47%
testing/iotest...............................2444......302 12%
testing/quick...............................18890.....5076 27%
testing.....................................16502.....4800 29%
text/scanner.................................6849.....2052 30%
text/tabwriter...............................6607.....1863 28%
text/template/parse.........................22978.....6183 27%
text/template...............................64153....11518 18%
time........................................12103.....3546 29%
unicode......................................9706.....3320 34%
unicode/utf16................................1055......148 14%
unicode/utf8.................................1118......513 46%
vendor/golang.org/x/net/http2/hpack..........8905.....2636 30%
All packages
3518505 1017774 29%
Change-Id: Id657334f276383ff1e6fa91472d3d1db5a03349c
Reviewed-on: https://go-review.googlesource.com/13937
Run-TryBot: Robert Griesemer <gri@golang.org>
Reviewed-by: Chris Manghane <cmang@golang.org>
--- /dev/null
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Binary package export.
+// Based loosely on x/tools/go/importer.
+// (see fmt.go, go.y as "documentation" for how to use/setup data structures)
+//
+// Use "-newexport" flag to enable.
+
+// TODO(gri):
+// - inlined functions
+
+/*
+Export data encoding:
+
+The export data is a serialized description of the graph of exported
+objects: constants, types, variables, and functions. Only types can
+be re-exported and so we need to know which package they are coming
+from. Therefore, packages are also part of the export graph.
+
+The roots of the graph are the list of constants, variables, functions,
+and eventually types. Types are written last because most of them will
+be written as part of other objects which will reduce the number of
+types that need to be written separately.
+
+The graph is serialized in in-order fashion, starting with the roots.
+Each object in the graph is serialized by writing its fields sequentially.
+If the field is a pointer to another object, that object is serialized,
+recursively. Otherwise the field is written. Non-pointer fields are all
+encoded as either an integer or string value.
+
+Only packages and types may be referred to more than once. When getting
+to a package or type that was not serialized before, a number (index) is
+assigned to it, starting at 0. In this case, the encoding starts with an
+integer tag with a value < 0. The tag value indicates the kind of object
+(package or type) that follows and that this is the first time that we
+see this object. If the package or tag was already serialized, the encoding
+starts with the respective package or type index >= 0. An importer can
+trivially determine if a package or type needs to be read in for the first
+time (tag < 0) and entered into the respective package or type table, or
+if the package or type was seen already (index >= 0), in which case the
+index is the table index where the respective object can be found.
+
+Before exporting or importing, the type tables are populated with the
+predeclared types (int, string, error, unsafe.Pointer, etc.). This way
+they are automatically encoded with a known and fixed type index.
+
+Encoding format:
+
+The export data starts with a single byte indicating the encoding format
+(compact, or with debugging information), followed by a version string
+(so we can evolve the encoding if need be), the name of the imported
+package, and a string containing platform-specific information for that
+package.
+
+After this header, the lists of objects follow. After the objects, platform-
+specific data may be found which is not used strictly for type checking.
+
+The encoding of objects is straight-forward: Constants, variables, and
+functions start with their name, type, and possibly a value. Named types
+record their name and package so that they can be canonicalized: If the
+same type was imported before via another import, the importer must use
+the previously imported type pointer so that we have exactly one version
+(i.e., one pointer) for each named type (and read but discard the current
+type encoding). Unnamed types simply encode their respective fields.
+
+In the encoding, all lists (of objects, struct fields, methods, parameter
+names, but also the bytes of a string, etc.) start with an integer which
+is the length of the list. This permits an importer to allocate the right
+amount of space to hold the list without the need to grow it later.
+
+All integer values use a variable-length encoding for compact representation.
+
+If debugFormat is set, each integer and string value is preceeded by a marker
+and position information in the encoding. This mechanism permits an importer
+to recognize immediately when it is out of sync. The importer recognizes this
+mode automatically (i.e., it can import export data produced with debugging
+support even if debugFormat is not set at the time of import). Using this mode
+will massively increase the size of the export data (by a factor of 2 to 3)
+and is only recommended for debugging.
+
+The exporter and importer are completely symmetric in implementation: For
+each encoding routine there is the matching and symmetric decoding routine.
+This symmetry makes it very easy to change or extend the format: If a new
+field needs to be encoded, a symmetric change can be made to exporter and
+importer.
+*/
+
+package gc
+
+import (
+ "bytes"
+ "cmd/compile/internal/big"
+ "cmd/internal/obj"
+ "encoding/binary"
+ "fmt"
+ "sort"
+ "strings"
+)
+
+// debugging support
+const (
+ debugFormat = false // use debugging format for export data (emits a lot of additional data)
+)
+
+const exportVersion = "v0"
+
+// Set forceNewExport to force the use of the new export format - for testing on the build dashboard.
+// TODO(gri) remove eventually
+const forceNewExport = false
+
+// Export writes the export data for localpkg to out and returns the number of bytes written.
+func Export(out *obj.Biobuf, trace bool) int {
+ p := exporter{
+ out: out,
+ pkgIndex: make(map[*Pkg]int),
+ typIndex: make(map[*Type]int),
+ trace: trace,
+ }
+
+ // write low-level encoding format
+ var format byte = 'c' // compact
+ if debugFormat {
+ format = 'd'
+ }
+ p.byte(format)
+
+ // --- generic export data ---
+
+ if p.trace {
+ p.tracef("\n--- generic export data ---\n")
+ if p.indent != 0 {
+ Fatalf("incorrect indentation %d", p.indent)
+ }
+ }
+
+ p.string(exportVersion)
+ if p.trace {
+ p.tracef("\n")
+ }
+
+ // populate type map with predeclared "known" types
+ predecl := predeclared()
+ for index, typ := range predecl {
+ p.typIndex[typ] = index
+ }
+ if len(p.typIndex) != len(predecl) {
+ Fatalf("duplicate entries in type map?")
+ }
+
+ // write package data
+ if localpkg.Path != "" {
+ Fatalf("local package path not empty: %q", localpkg.Path)
+ }
+ p.pkg(localpkg)
+
+ // write compiler-specific flags
+ // go.y:import_safety
+ {
+ var flags string
+ if safemode != 0 {
+ flags = "safe"
+ }
+ p.string(flags)
+ }
+
+ if p.trace {
+ p.tracef("\n")
+ }
+
+ // collect objects to export
+ var consts, vars, funcs []*Sym
+ var types []*Type
+ for _, n := range exportlist {
+ sym := n.Sym
+ // TODO(gri) Closures appear marked as exported.
+ // Investigate and determine if we need this.
+ if sym.Flags&SymExported != 0 {
+ continue
+ }
+ sym.Flags |= SymExported
+
+ // TODO(gri) Closures have dots in their names;
+ // e.g., TestFloatZeroValue.func1 in math/big tests.
+ // We may not need this eventually. See also comment
+ // on sym.Flags&SymExported test above.
+ if strings.Contains(sym.Name, ".") {
+ Fatalf("unexpected export symbol: %v", sym)
+ }
+
+ if sym.Flags&SymExport != 0 {
+ if sym.Def == nil {
+ Fatalf("unknown export symbol: %v", sym)
+ }
+ switch n := sym.Def; n.Op {
+ case OLITERAL:
+ // constant
+ typecheck(&n, Erv)
+ if n == nil || n.Op != OLITERAL {
+ Fatalf("dumpexportconst: oconst nil: %v", sym)
+ }
+ consts = append(consts, sym)
+
+ case ONAME:
+ // variable or function
+ typecheck(&n, Erv|Ecall)
+ if n == nil || n.Type == nil {
+ Fatalf("variable/function exported but not defined: %v", sym)
+ }
+ if n.Type.Etype == TFUNC && n.Class == PFUNC {
+ funcs = append(funcs, sym)
+ } else {
+ vars = append(vars, sym)
+ }
+
+ case OTYPE:
+ // named type
+ t := n.Type
+ if t.Etype == TFORW {
+ Fatalf("export of incomplete type %v", sym)
+ }
+ types = append(types, t)
+
+ default:
+ Fatalf("unexpected export symbol: %v %v", Oconv(int(n.Op), 0), sym)
+ }
+ }
+ }
+ exportlist = nil // match export.go use of exportlist
+
+ // for reproducible output
+ sort.Sort(symByName(consts))
+ sort.Sort(symByName(vars))
+ sort.Sort(symByName(funcs))
+ // sort types later when we have fewer types left
+
+ // write consts
+ p.int(len(consts))
+ for _, sym := range consts {
+ n := sym.Def
+ typ := n.Type // may or may not be specified
+ // Untyped (ideal) constants get their own type. This decouples
+ // the constant type from the encoding of the constant value.
+ if typ == nil || isideal(typ) {
+ typ = untype(n.Val().Ctype())
+ }
+
+ p.string(sym.Name)
+ p.typ(typ)
+ p.value(n.Val())
+ }
+
+ // write vars
+ p.int(len(vars))
+ for _, sym := range vars {
+ p.string(sym.Name)
+ p.typ(sym.Def.Type)
+ }
+
+ // write funcs
+ p.int(len(funcs))
+ for _, sym := range funcs {
+ p.string(sym.Name)
+ // The type can only be a signature for functions. However, by always
+ // writing the complete type specification (rather than just a signature)
+ // we keep the option open of sharing common signatures across multiple
+ // functions as a means to further compress the export data.
+ p.typ(sym.Def.Type)
+ p.int(p.collectInlined(sym.Def))
+ }
+
+ // determine which types are still left to write and sort them
+ i := 0
+ for _, t := range types {
+ if _, ok := p.typIndex[t]; !ok {
+ types[i] = t
+ i++
+ }
+ }
+ types = types[:i]
+ sort.Sort(typByName(types))
+
+ // write types
+ p.int(len(types))
+ for _, t := range types {
+ // Writing a type may further reduce the number of types
+ // that are left to be written, but at this point we don't
+ // care.
+ p.typ(t)
+ }
+
+ if p.trace {
+ p.tracef("\n")
+ }
+
+ // --- compiler-specific export data ---
+
+ if p.trace {
+ p.tracef("\n--- compiler specific export data ---\n")
+ if p.indent != 0 {
+ Fatalf("incorrect indentation")
+ }
+ }
+
+ // write inlined function bodies
+ p.int(len(p.inlined))
+ for i, f := range p.inlined {
+ p.body(i, f)
+ }
+
+ if p.trace {
+ p.tracef("\n")
+ }
+
+ // --- end of export data ---
+
+ return p.written
+}
+
+type symByName []*Sym
+
+func (a symByName) Len() int { return len(a) }
+func (a symByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
+func (a symByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+
+type typByName []*Type
+
+func (a typByName) Len() int { return len(a) }
+func (a typByName) Less(i, j int) bool { return a[i].Sym.Name < a[j].Sym.Name }
+func (a typByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+
+type exporter struct {
+ out *obj.Biobuf
+ pkgIndex map[*Pkg]int
+ typIndex map[*Type]int
+ inlined []*Func
+
+ written int // bytes written
+ indent int // for p.trace
+ trace bool
+}
+
+func (p *exporter) pkg(pkg *Pkg) {
+ if pkg == nil {
+ Fatalf("unexpected nil pkg")
+ }
+
+ // if we saw the package before, write its index (>= 0)
+ if i, ok := p.pkgIndex[pkg]; ok {
+ p.index('P', i)
+ return
+ }
+
+ // otherwise, remember the package, write the package tag (< 0) and package data
+ if p.trace {
+ p.tracef("P%d = { ", len(p.pkgIndex))
+ defer p.tracef("} ")
+ }
+ p.pkgIndex[pkg] = len(p.pkgIndex)
+
+ p.tag(packageTag)
+ p.string(pkg.Name)
+ p.string(pkg.Path)
+}
+
+func (p *exporter) typ(t *Type) {
+ if t == nil {
+ Fatalf("nil type")
+ }
+
+ // Possible optimization: Anonymous pointer types *T where
+ // T is a named type are common. We could canonicalize all
+ // such types *T to a single type PT = *T. This would lead
+ // to at most one *T entry in typIndex, and all future *T's
+ // would be encoded as the respective index directly. Would
+ // save 1 byte (pointerTag) per *T and reduce the typIndex
+ // size (at the cost of a canonicalization map). We can do
+ // this later, without encoding format change.
+
+ // if we saw the type before, write its index (>= 0)
+ if i, ok := p.typIndex[t]; ok {
+ p.index('T', i)
+ return
+ }
+
+ // otherwise, remember the type, write the type tag (< 0) and type data
+ if p.trace {
+ p.tracef("T%d = {>\n", len(p.typIndex))
+ defer p.tracef("<\n} ")
+ }
+ p.typIndex[t] = len(p.typIndex)
+
+ // pick off named types
+ if sym := t.Sym; sym != nil {
+ // Fields should be exported by p.field().
+ if t.Etype == TFIELD {
+ Fatalf("printing a field/parameter with wrong function")
+ }
+ // Predeclared types should have been found in the type map.
+ if t.Orig == t {
+ Fatalf("predeclared type missing from type map?")
+ }
+ // TODO(gri) The assertion below seems incorrect (crashes during all.bash).
+ // Investigate.
+ /*
+ // we expect the respective definition to point to us
+ if sym.Def.Type != t {
+ Fatalf("type definition doesn't point to us?")
+ }
+ */
+
+ p.tag(namedTag)
+ p.qualifiedName(sym)
+
+ // write underlying type
+ p.typ(t.Orig)
+
+ // interfaces don't have associated methods
+ if t.Orig.Etype == TINTER {
+ return
+ }
+
+ // sort methods for reproducible export format
+ // TODO(gri) Determine if they are already sorted
+ // in which case we can drop this step.
+ var methods []*Type
+ for m := t.Method; m != nil; m = m.Down {
+ methods = append(methods, m)
+ }
+ sort.Sort(methodbyname(methods))
+ p.int(len(methods))
+
+ if p.trace && t.Method != nil {
+ p.tracef("associated methods {>\n")
+ }
+
+ for _, m := range methods {
+ p.string(m.Sym.Name)
+ p.paramList(getthisx(m.Type))
+ p.paramList(getinargx(m.Type))
+ p.paramList(getoutargx(m.Type))
+ p.int(p.collectInlined(m.Type.Nname))
+
+ if p.trace && m.Down != nil {
+ p.tracef("\n")
+ }
+ }
+
+ if p.trace && t.Method != nil {
+ p.tracef("<\n} ")
+ }
+
+ return
+ }
+
+ // otherwise we have a type literal
+ switch t.Etype {
+ case TARRAY:
+ // TODO(gri) define named constant for the -100
+ if t.Bound >= 0 || t.Bound == -100 {
+ p.tag(arrayTag)
+ p.int64(t.Bound)
+ } else {
+ p.tag(sliceTag)
+ }
+ p.typ(t.Type)
+
+ case T_old_DARRAY:
+ // see p.param use of T_old_DARRAY
+ p.tag(dddTag)
+ p.typ(t.Type)
+
+ case TSTRUCT:
+ p.tag(structTag)
+ p.fieldList(t)
+
+ case TPTR32, TPTR64: // could use Tptr but these are constants
+ p.tag(pointerTag)
+ p.typ(t.Type)
+
+ case TFUNC:
+ p.tag(signatureTag)
+ p.paramList(getinargx(t))
+ p.paramList(getoutargx(t))
+
+ case TINTER:
+ p.tag(interfaceTag)
+
+ // gc doesn't separate between embedded interfaces
+ // and methods declared explicitly with an interface
+ p.int(0) // no embedded interfaces
+ p.methodList(t)
+
+ case TMAP:
+ p.tag(mapTag)
+ p.typ(t.Down) // key
+ p.typ(t.Type) // val
+
+ case TCHAN:
+ p.tag(chanTag)
+ p.int(int(t.Chan))
+ p.typ(t.Type)
+
+ default:
+ Fatalf("unexpected type: %s (Etype = %d)", Tconv(t, 0), t.Etype)
+ }
+}
+
+func (p *exporter) qualifiedName(sym *Sym) {
+ p.string(sym.Name)
+ p.pkg(sym.Pkg)
+}
+
+func (p *exporter) fieldList(t *Type) {
+ if p.trace && t.Type != nil {
+ p.tracef("fields {>\n")
+ defer p.tracef("<\n} ")
+ }
+
+ p.int(countfield(t))
+ for f := t.Type; f != nil; f = f.Down {
+ p.field(f)
+ if p.trace && f.Down != nil {
+ p.tracef("\n")
+ }
+ }
+}
+
+func (p *exporter) field(f *Type) {
+ if f.Etype != TFIELD {
+ Fatalf("field expected")
+ }
+
+ p.fieldName(f)
+ p.typ(f.Type)
+ p.note(f.Note)
+}
+
+func (p *exporter) note(n *string) {
+ var s string
+ if n != nil {
+ s = *n
+ }
+ p.string(s)
+}
+
+func (p *exporter) methodList(t *Type) {
+ if p.trace && t.Type != nil {
+ p.tracef("methods {>\n")
+ defer p.tracef("<\n} ")
+ }
+
+ p.int(countfield(t))
+ for m := t.Type; m != nil; m = m.Down {
+ p.method(m)
+ if p.trace && m.Down != nil {
+ p.tracef("\n")
+ }
+ }
+}
+
+func (p *exporter) method(m *Type) {
+ if m.Etype != TFIELD {
+ Fatalf("method expected")
+ }
+
+ p.fieldName(m)
+ // TODO(gri) For functions signatures, we use p.typ() to export
+ // so we could share the same type with multiple functions. Do
+ // the same here, or never try to do this for functions.
+ p.paramList(getinargx(m.Type))
+ p.paramList(getoutargx(m.Type))
+}
+
+// fieldName is like qualifiedName but it doesn't record the package
+// for blank (_) or exported names.
+func (p *exporter) fieldName(t *Type) {
+ sym := t.Sym
+
+ var name string
+ if t.Embedded == 0 {
+ name = sym.Name
+ } else if bname := basetypeName(t); bname != "" && !exportname(bname) {
+ // anonymous field with unexported base type name: use "?" as field name
+ // (bname != "" per spec, but we are conservative in case of errors)
+ name = "?"
+ }
+
+ p.string(name)
+ if name == "?" || name != "_" && name != "" && !exportname(name) {
+ p.pkg(sym.Pkg)
+ }
+}
+
+func basetypeName(t *Type) string {
+ s := t.Sym
+ if s == nil && Isptr[t.Etype] {
+ s = t.Type.Sym // deref
+ }
+ if s != nil {
+ return s.Name
+ }
+ return ""
+}
+
+func (p *exporter) paramList(params *Type) {
+ if params.Etype != TSTRUCT || !params.Funarg {
+ Fatalf("parameter list expected")
+ }
+
+ // use negative length to indicate unnamed parameters
+ // (look at the first parameter only since either all
+ // names are present or all are absent)
+ n := countfield(params)
+ if n > 0 && parName(params.Type) == "" {
+ n = -n
+ }
+ p.int(n)
+ for q := params.Type; q != nil; q = q.Down {
+ p.param(q, n)
+ }
+}
+
+func (p *exporter) param(q *Type, n int) {
+ if q.Etype != TFIELD {
+ Fatalf("parameter expected")
+ }
+ t := q.Type
+ if q.Isddd {
+ // create a fake type to encode ... just for the p.typ call
+ // (T_old_DARRAY is not used anywhere else in the compiler,
+ // we use it here to communicate between p.param and p.typ.)
+ t = &Type{Etype: T_old_DARRAY, Type: t.Type}
+ }
+ p.typ(t)
+ if n > 0 {
+ p.string(parName(q))
+ }
+ // TODO(gri) This is compiler-specific (escape info).
+ // Move into compiler-specific section eventually?
+ // (Not having escape info causes tests to fail, e.g. runtime GCInfoTest)
+ p.note(q.Note)
+}
+
+func parName(q *Type) string {
+ if q.Sym == nil {
+ return ""
+ }
+ name := q.Sym.Name
+ // undo gc-internal name mangling - we just need the source name
+ if len(name) > 0 && name[0] == '~' {
+ // name is ~b%d or ~r%d
+ switch name[1] {
+ case 'b':
+ return "_"
+ case 'r':
+ return ""
+ default:
+ Fatalf("unexpected parameter name: %s", name)
+ }
+ }
+ // undo gc-internal name specialization
+ if i := strings.Index(name, "·"); i > 0 {
+ name = name[:i] // cut off numbering
+ }
+ return name
+}
+
+func (p *exporter) value(x Val) {
+ if p.trace {
+ p.tracef("= ")
+ }
+
+ switch x := x.U.(type) {
+ case bool:
+ tag := falseTag
+ if x {
+ tag = trueTag
+ }
+ p.tag(tag)
+
+ case *Mpint:
+ if Mpcmpfixfix(Minintval[TINT64], x) <= 0 && Mpcmpfixfix(x, Maxintval[TINT64]) <= 0 {
+ // common case: x fits into an int64 - use compact encoding
+ p.tag(int64Tag)
+ p.int64(Mpgetfix(x))
+ return
+ }
+ // uncommon case: large x - use float encoding
+ // (powers of 2 will be encoded efficiently with exponent)
+ p.tag(floatTag)
+ f := newMpflt()
+ Mpmovefixflt(f, x)
+ p.float(f)
+
+ case *Mpflt:
+ p.tag(floatTag)
+ p.float(x)
+
+ case *Mpcplx:
+ p.tag(complexTag)
+ p.float(&x.Real)
+ p.float(&x.Imag)
+
+ case string:
+ p.tag(stringTag)
+ p.string(x)
+
+ default:
+ Fatalf("unexpected value %v (%T)", x, x)
+ }
+}
+
+func (p *exporter) float(x *Mpflt) {
+ // extract sign, treat -0 as < 0
+ f := &x.Val
+ sign := f.Sign()
+ if sign == 0 {
+ // ±0
+ // TODO(gri) remove 'if' below if #12577 gets accepted
+ if f.Signbit() {
+ // -0 (uncommon)
+ p.int(-1)
+ p.int(0)
+ p.string("")
+ return
+ }
+ // +0
+ p.int(0)
+ return
+ }
+ // x != 0
+
+ // extract exponent such that 0.5 <= m < 1.0
+ var m big.Float
+ exp := f.MantExp(&m)
+
+ // extract mantissa as *big.Int
+ // - set exponent large enough so mant satisfies mant.IsInt()
+ // - get *big.Int from mant
+ m.SetMantExp(&m, int(m.MinPrec()))
+ mant, acc := m.Int(nil)
+ if acc != big.Exact {
+ Fatalf("internal error")
+ }
+
+ p.int(sign)
+ p.int(exp)
+ p.string(string(mant.Bytes()))
+}
+
+// ----------------------------------------------------------------------------
+// Inlined function bodies
+
+// TODO(gri) This section is incomplete. At the moment nothing meaningful
+// is written out for exported functions with inlined function bodies.
+
+func (p *exporter) collectInlined(n *Node) int {
+ if n != nil && n.Func != nil && n.Func.Inl != nil {
+ // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
+ // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
+ if Debug['l'] < 2 {
+ typecheckinl(n)
+ }
+ p.inlined = append(p.inlined, n.Func)
+ return len(p.inlined) - 1 // index >= 0 => inlined
+ }
+ return -1 // index < 0 => not inlined
+}
+
+func (p *exporter) body(i int, f *Func) {
+ p.int(i)
+ p.block(f.Inl)
+}
+
+func (p *exporter) block(list *NodeList) {
+ p.int(count(list))
+ for q := list; q != nil; q = q.Next {
+ p.stmt(q.N)
+ }
+}
+
+func (p *exporter) stmt(n *Node) {
+ // TODO(gri) do something sensible here
+ p.string("body")
+}
+
+// ----------------------------------------------------------------------------
+// Low-level encoders
+
+func (p *exporter) index(marker byte, index int) {
+ if index < 0 {
+ Fatalf("invalid index < 0")
+ }
+ if debugFormat {
+ p.marker('t')
+ }
+ if p.trace {
+ p.tracef("%c%d ", marker, index)
+ }
+ p.rawInt64(int64(index))
+}
+
+func (p *exporter) tag(tag int) {
+ if tag >= 0 {
+ Fatalf("invalid tag >= 0")
+ }
+ if debugFormat {
+ p.marker('t')
+ }
+ if p.trace {
+ p.tracef("%s ", tagString[-tag])
+ }
+ p.rawInt64(int64(tag))
+}
+
+func (p *exporter) int(x int) {
+ p.int64(int64(x))
+}
+
+func (p *exporter) int64(x int64) {
+ if debugFormat {
+ p.marker('i')
+ }
+ if p.trace {
+ p.tracef("%d ", x)
+ }
+ p.rawInt64(x)
+}
+
+func (p *exporter) string(s string) {
+ if debugFormat {
+ p.marker('s')
+ }
+ if p.trace {
+ p.tracef("%q ", s)
+ }
+ p.rawInt64(int64(len(s)))
+ w, err := obj.Bwritestring(p.out, s)
+ p.written += w
+ if w != len(s) || err != nil {
+ Fatalf("write error: %v (wrote %d bytes of %d)", err, w, len(s))
+ }
+}
+
+// marker emits a marker byte and position information which makes
+// it easy for a reader to detect if it is "out of sync". Used for
+// debugFormat format only.
+func (p *exporter) marker(m byte) {
+ p.byte(m)
+ p.rawInt64(int64(p.written))
+}
+
+func (p *exporter) byte(b byte) {
+ obj.Bputc(p.out, b)
+ p.written++
+}
+
+// rawInt64 should only be used by low-level encoders
+func (p *exporter) rawInt64(x int64) {
+ var tmp [binary.MaxVarintLen64]byte
+ n := binary.PutVarint(tmp[:], x)
+ w, err := p.out.Write(tmp[:n])
+ p.written += w
+ if err != nil {
+ Fatalf("write error: %v", err)
+ }
+}
+
+// tracef is like fmt.Printf but it rewrites the format string
+// to take care of indentation.
+func (p *exporter) tracef(format string, args ...interface{}) {
+ if strings.IndexAny(format, "<>\n") >= 0 {
+ var buf bytes.Buffer
+ for i := 0; i < len(format); i++ {
+ // no need to deal with runes
+ ch := format[i]
+ switch ch {
+ case '>':
+ p.indent++
+ continue
+ case '<':
+ p.indent--
+ continue
+ }
+ buf.WriteByte(ch)
+ if ch == '\n' {
+ for j := p.indent; j > 0; j-- {
+ buf.WriteString(". ")
+ }
+ }
+ }
+ format = buf.String()
+ }
+ fmt.Printf(format, args...)
+}
+
+// ----------------------------------------------------------------------------
+// Export format
+
+// Tags. Must be < 0.
+const (
+ // Packages
+ packageTag = -(iota + 1)
+
+ // Types
+ namedTag
+ arrayTag
+ sliceTag
+ dddTag
+ structTag
+ pointerTag
+ signatureTag
+ interfaceTag
+ mapTag
+ chanTag
+
+ // Values
+ falseTag
+ trueTag
+ int64Tag
+ floatTag
+ fractionTag // not used by gc
+ complexTag
+ stringTag
+)
+
+// Debugging support.
+// (tagString is only used when tracing is enabled)
+var tagString = [...]string{
+ // Packages:
+ -packageTag: "package",
+
+ // Types:
+ -namedTag: "named type",
+ -arrayTag: "array",
+ -sliceTag: "slice",
+ -dddTag: "ddd",
+ -structTag: "struct",
+ -pointerTag: "pointer",
+ -signatureTag: "signature",
+ -interfaceTag: "interface",
+ -mapTag: "map",
+ -chanTag: "chan",
+
+ // Values:
+ -falseTag: "false",
+ -trueTag: "true",
+ -int64Tag: "int64",
+ -floatTag: "float",
+ -fractionTag: "fraction",
+ -complexTag: "complex",
+ -stringTag: "string",
+}
+
+// untype returns the "pseudo" untyped type for a Ctype (import/export use only).
+// (we can't use an pre-initialized array because we must be sure all types are
+// set up)
+func untype(ctype int) *Type {
+ switch ctype {
+ case CTINT:
+ return idealint
+ case CTRUNE:
+ return idealrune
+ case CTFLT:
+ return idealfloat
+ case CTCPLX:
+ return idealcomplex
+ case CTSTR:
+ return idealstring
+ case CTBOOL:
+ return idealbool
+ case CTNIL:
+ return Types[TNIL]
+ }
+ Fatalf("unknown Ctype")
+ return nil
+}
+
+var (
+ idealint = typ(TIDEAL)
+ idealrune = typ(TIDEAL)
+ idealfloat = typ(TIDEAL)
+ idealcomplex = typ(TIDEAL)
+)
+
+var predecl []*Type // initialized lazily
+
+func predeclared() []*Type {
+ if predecl == nil {
+ // initialize lazily to be sure that all
+ // elements have been initialized before
+ predecl = []*Type{
+ // basic types
+ Types[TBOOL],
+ Types[TINT],
+ Types[TINT8],
+ Types[TINT16],
+ Types[TINT32],
+ Types[TINT64],
+ Types[TUINT],
+ Types[TUINT8],
+ Types[TUINT16],
+ Types[TUINT32],
+ Types[TUINT64],
+ Types[TUINTPTR],
+ Types[TFLOAT32],
+ Types[TFLOAT64],
+ Types[TCOMPLEX64],
+ Types[TCOMPLEX128],
+ Types[TSTRING],
+
+ // aliases
+ bytetype,
+ runetype,
+
+ // error
+ errortype,
+
+ // untyped types
+ untype(CTBOOL),
+ untype(CTINT),
+ untype(CTRUNE),
+ untype(CTFLT),
+ untype(CTCPLX),
+ untype(CTSTR),
+ untype(CTNIL),
+
+ // package unsafe
+ Types[TUNSAFEPTR],
+ }
+ }
+ return predecl
+}
--- /dev/null
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Binary package import.
+// Based loosely on x/tools/go/importer.
+
+package gc
+
+import (
+ "cmd/compile/internal/big"
+ "cmd/internal/obj"
+ "encoding/binary"
+)
+
+// The overall structure of Import is symmetric to Export: For each
+// export method in bexport.go there is a matching and symmetric method
+// in bimport.go. Changing the export format requires making symmetric
+// changes to bimport.go and bexport.go.
+
+// Import populates importpkg from the serialized package data.
+func Import(in *obj.Biobuf) {
+ p := importer{in: in}
+ p.buf = p.bufarray[:]
+
+ // read low-level encoding format
+ switch format := p.byte(); format {
+ case 'c':
+ // compact format - nothing to do
+ case 'd':
+ p.debugFormat = true
+ default:
+ Fatalf("invalid encoding format in export data: got %q; want 'c' or 'd'", format)
+ }
+
+ // --- generic export data ---
+
+ if v := p.string(); v != exportVersion {
+ Fatalf("unknown export data version: %s", v)
+ }
+
+ // populate typList with predeclared "known" types
+ p.typList = append(p.typList, predeclared()...)
+
+ // read package data
+ p.pkg()
+ if p.pkgList[0] != importpkg {
+ Fatalf("imported package not found in pkgList[0]")
+ }
+
+ // read compiler-specific flags
+ importpkg.Safe = p.string() == "safe"
+
+ // defer some type-checking until all types are read in completely
+ // (go.y:import_there)
+ tcok := typecheckok
+ typecheckok = true
+ defercheckwidth()
+
+ // read consts
+ for i := p.int(); i > 0; i-- {
+ sym := p.localname()
+ typ := p.typ()
+ val := p.value(typ)
+ if isideal(typ) {
+ // canonicalize ideal types
+ typ = Types[TIDEAL]
+ }
+ importconst(sym, typ, nodlit(val))
+ }
+
+ // read vars
+ for i := p.int(); i > 0; i-- {
+ sym := p.localname()
+ typ := p.typ()
+ importvar(sym, typ)
+ }
+
+ // read funcs
+ for i := p.int(); i > 0; i-- {
+ // go.y:hidden_fndcl
+ sym := p.localname()
+ typ := p.typ()
+ // TODO(gri) fix this
+ p.int() // read and discard index of inlined function body for now
+
+ importsym(sym, ONAME)
+ if sym.Def != nil && sym.Def.Op == ONAME && !Eqtype(typ, sym.Def.Type) {
+ Fatalf("inconsistent definition for func %v during import\n\t%v\n\t%v", sym, sym.Def.Type, typ)
+ }
+
+ n := newfuncname(sym)
+ n.Type = typ
+ declare(n, PFUNC)
+ funchdr(n)
+
+ // go.y:hidden_import
+ n.Func.Inl = nil
+ funcbody(n)
+ importlist = append(importlist, n) // TODO(gri) do this only if body is inlineable?
+ }
+
+ // read types
+ for i := p.int(); i > 0; i-- {
+ // name is parsed as part of named type
+ p.typ()
+ }
+
+ // --- compiler-specific export data ---
+
+ for i := p.int(); i > 0; i-- {
+ p.body()
+ }
+
+ // --- end of export data ---
+
+ typecheckok = tcok
+ resumecheckwidth()
+
+ testdclstack() // debugging only
+}
+
+type importer struct {
+ in *obj.Biobuf
+ buf []byte // for reading strings
+ bufarray [64]byte // initial underlying array for buf, large enough to avoid allocation when compiling std lib
+ pkgList []*Pkg
+ typList []*Type
+
+ debugFormat bool
+ read int // bytes read
+}
+
+func (p *importer) pkg() *Pkg {
+ // if the package was seen before, i is its index (>= 0)
+ i := p.tagOrIndex()
+ if i >= 0 {
+ return p.pkgList[i]
+ }
+
+ // otherwise, i is the package tag (< 0)
+ if i != packageTag {
+ Fatalf("expected package tag, found tag = %d", i)
+ }
+
+ // read package data
+ name := p.string()
+ path := p.string()
+
+ // we should never see an empty package name
+ if name == "" {
+ Fatalf("empty package name in import")
+ }
+
+ // we should never see a bad import path
+ if isbadimport(path) {
+ Fatalf("bad path in import: %q", path)
+ }
+
+ // an empty path denotes the package we are currently importing
+ pkg := importpkg
+ if path != "" {
+ pkg = mkpkg(path)
+ }
+ if pkg.Name == "" {
+ pkg.Name = name
+ } else if pkg.Name != name {
+ Fatalf("inconsistent package names: got %s; want %s (path = %s)", pkg.Name, name, path)
+ }
+ p.pkgList = append(p.pkgList, pkg)
+
+ return pkg
+}
+
+func (p *importer) localname() *Sym {
+ // go.y:hidden_importsym
+ name := p.string()
+ if name == "" {
+ Fatalf("unexpected anonymous name")
+ }
+ structpkg = importpkg // go.y:hidden_pkg_importsym
+ return importpkg.Lookup(name)
+}
+
+func (p *importer) newtyp(etype int) *Type {
+ t := typ(etype)
+ p.typList = append(p.typList, t)
+ return t
+}
+
+func (p *importer) typ() *Type {
+ // if the type was seen before, i is its index (>= 0)
+ i := p.tagOrIndex()
+ if i >= 0 {
+ return p.typList[i]
+ }
+
+ // otherwise, i is the type tag (< 0)
+ var t *Type
+ switch i {
+ case namedTag:
+ // go.y:hidden_importsym
+ tsym := p.qualifiedName()
+
+ // go.y:hidden_pkgtype
+ t = pkgtype(tsym)
+ importsym(tsym, OTYPE)
+ p.typList = append(p.typList, t)
+
+ // read underlying type
+ // go.y:hidden_type
+ t0 := p.typ()
+ importtype(t, t0) // go.y:hidden_import
+
+ // interfaces don't have associated methods
+ if t0.Etype == TINTER {
+ break
+ }
+
+ // read associated methods
+ for i := p.int(); i > 0; i-- {
+ // go.y:hidden_fndcl
+ name := p.string()
+ recv := p.paramList() // TODO(gri) do we need a full param list for the receiver?
+ params := p.paramList()
+ result := p.paramList()
+ // TODO(gri) fix this
+ p.int() // read and discard index of inlined function body for now
+
+ pkg := localpkg
+ if !exportname(name) {
+ pkg = tsym.Pkg
+ }
+ sym := pkg.Lookup(name)
+
+ n := methodname1(newname(sym), recv.N.Right)
+ n.Type = functype(recv.N, params, result)
+ checkwidth(n.Type)
+ // addmethod uses the global variable structpkg to verify consistency
+ {
+ saved := structpkg
+ structpkg = tsym.Pkg
+ addmethod(sym, n.Type, false, nointerface)
+ structpkg = saved
+ }
+ nointerface = false
+ funchdr(n)
+
+ // (comment from go.y)
+ // inl.C's inlnode in on a dotmeth node expects to find the inlineable body as
+ // (dotmeth's type).Nname.Inl, and dotmeth's type has been pulled
+ // out by typecheck's lookdot as this $$.ttype. So by providing
+ // this back link here we avoid special casing there.
+ n.Type.Nname = n
+
+ // go.y:hidden_import
+ n.Func.Inl = nil
+ funcbody(n)
+ importlist = append(importlist, n) // TODO(gri) do this only if body is inlineable?
+ }
+
+ case arrayTag, sliceTag:
+ t = p.newtyp(TARRAY)
+ t.Bound = -1
+ if i == arrayTag {
+ t.Bound = p.int64()
+ }
+ t.Type = p.typ()
+
+ case dddTag:
+ t = p.newtyp(T_old_DARRAY)
+ t.Bound = -1
+ t.Type = p.typ()
+
+ case structTag:
+ t = p.newtyp(TSTRUCT)
+ tostruct0(t, p.fieldList())
+
+ case pointerTag:
+ t = p.newtyp(Tptr)
+ t.Type = p.typ()
+
+ case signatureTag:
+ t = p.newtyp(TFUNC)
+ params := p.paramList()
+ result := p.paramList()
+ functype0(t, nil, params, result)
+
+ case interfaceTag:
+ t = p.newtyp(TINTER)
+ if p.int() != 0 {
+ Fatalf("unexpected embedded interface")
+ }
+ tointerface0(t, p.methodList())
+
+ case mapTag:
+ t = p.newtyp(TMAP)
+ t.Down = p.typ() // key
+ t.Type = p.typ() // val
+
+ case chanTag:
+ t = p.newtyp(TCHAN)
+ t.Chan = uint8(p.int())
+ t.Type = p.typ()
+
+ default:
+ Fatalf("unexpected type (tag = %d)", i)
+ }
+
+ if t == nil {
+ Fatalf("nil type (type tag = %d)", i)
+ }
+
+ return t
+}
+
+func (p *importer) qualifiedName() *Sym {
+ name := p.string()
+ pkg := p.pkg()
+ return pkg.Lookup(name)
+}
+
+// go.y:hidden_structdcl_list
+func (p *importer) fieldList() *NodeList {
+ i := p.int()
+ if i == 0 {
+ return nil
+ }
+ n := list1(p.field())
+ for i--; i > 0; i-- {
+ n = list(n, p.field())
+ }
+ return n
+}
+
+// go.y:hidden_structdcl
+func (p *importer) field() *Node {
+ sym := p.fieldName()
+ typ := p.typ()
+ note := p.note()
+
+ var n *Node
+ if sym.Name != "" {
+ n = Nod(ODCLFIELD, newname(sym), typenod(typ))
+ } else {
+ // anonymous field - typ must be T or *T and T must be a type name
+ s := typ.Sym
+ if s == nil && Isptr[typ.Etype] {
+ s = typ.Type.Sym // deref
+ }
+ pkg := importpkg
+ if sym != nil {
+ pkg = sym.Pkg
+ }
+ n = embedded(s, pkg)
+ n.Right = typenod(typ)
+ }
+ n.SetVal(note)
+
+ return n
+}
+
+func (p *importer) note() (v Val) {
+ if s := p.string(); s != "" {
+ v.U = s
+ }
+ return
+}
+
+// go.y:hidden_interfacedcl_list
+func (p *importer) methodList() *NodeList {
+ i := p.int()
+ if i == 0 {
+ return nil
+ }
+ n := list1(p.method())
+ for i--; i > 0; i-- {
+ n = list(n, p.method())
+ }
+ return n
+}
+
+// go.y:hidden_interfacedcl
+func (p *importer) method() *Node {
+ sym := p.fieldName()
+ params := p.paramList()
+ result := p.paramList()
+ return Nod(ODCLFIELD, newname(sym), typenod(functype(fakethis(), params, result)))
+}
+
+// go.y:sym,hidden_importsym
+func (p *importer) fieldName() *Sym {
+ name := p.string()
+ pkg := localpkg
+ if name == "_" {
+ // During imports, unqualified non-exported identifiers are from builtinpkg
+ // (see go.y:sym). The binary exporter only exports blank as a non-exported
+ // identifier without qualification.
+ pkg = builtinpkg
+ } else if name == "?" || name != "" && !exportname(name) {
+ if name == "?" {
+ name = ""
+ }
+ pkg = p.pkg()
+ }
+ return pkg.Lookup(name)
+}
+
+// go.y:ohidden_funarg_list
+func (p *importer) paramList() *NodeList {
+ i := p.int()
+ if i == 0 {
+ return nil
+ }
+ // negative length indicates unnamed parameters
+ named := true
+ if i < 0 {
+ i = -i
+ named = false
+ }
+ // i > 0
+ n := list1(p.param(named))
+ i--
+ for ; i > 0; i-- {
+ n = list(n, p.param(named))
+ }
+ return n
+}
+
+// go.y:hidden_funarg
+func (p *importer) param(named bool) *Node {
+ typ := p.typ()
+
+ isddd := false
+ if typ.Etype == T_old_DARRAY {
+ // T_old_DARRAY indicates ... type
+ typ.Etype = TARRAY
+ isddd = true
+ }
+
+ n := Nod(ODCLFIELD, nil, typenod(typ))
+ n.Isddd = isddd
+
+ if named {
+ name := p.string()
+ if name == "" {
+ Fatalf("expected named parameter")
+ }
+ // The parameter package doesn't matter; it's never consulted.
+ // We use the builtinpkg per go.y:sym (line 1181).
+ n.Left = newname(builtinpkg.Lookup(name))
+ }
+
+ // TODO(gri) This is compiler-specific (escape info).
+ // Move into compiler-specific section eventually?
+ n.SetVal(p.note())
+
+ return n
+}
+
+func (p *importer) value(typ *Type) (x Val) {
+ switch tag := p.tagOrIndex(); tag {
+ case falseTag:
+ x.U = false
+ case trueTag:
+ x.U = true
+ case int64Tag:
+ u := new(Mpint)
+ Mpmovecfix(u, p.int64())
+ u.Rune = typ == idealrune
+ x.U = u
+ case floatTag:
+ f := newMpflt()
+ p.float(f)
+ if typ == idealint || Isint[typ.Etype] {
+ // uncommon case: large int encoded as float
+ u := new(Mpint)
+ mpmovefltfix(u, f)
+ x.U = u
+ break
+ }
+ x.U = f
+ case complexTag:
+ u := new(Mpcplx)
+ p.float(&u.Real)
+ p.float(&u.Imag)
+ x.U = u
+ case stringTag:
+ x.U = p.string()
+ default:
+ Fatalf("unexpected value tag %d", tag)
+ }
+
+ // verify ideal type
+ if isideal(typ) && untype(x.Ctype()) != typ {
+ Fatalf("value %v and type %v don't match", x, typ)
+ }
+
+ return
+}
+
+func (p *importer) float(x *Mpflt) {
+ sign := p.int()
+ if sign == 0 {
+ Mpmovecflt(x, 0)
+ return
+ }
+
+ exp := p.int()
+ mant := new(big.Int).SetBytes([]byte(p.string()))
+
+ m := x.Val.SetInt(mant)
+ m.SetMantExp(m, exp-mant.BitLen())
+ if sign < 0 {
+ m.Neg(m)
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Inlined function bodies
+
+func (p *importer) body() {
+ p.int()
+ p.block()
+}
+
+func (p *importer) block() {
+ for i := p.int(); i > 0; i-- {
+ p.stmt()
+ }
+}
+
+func (p *importer) stmt() {
+ // TODO(gri) do something sensible here
+ p.string()
+}
+
+// ----------------------------------------------------------------------------
+// Low-level decoders
+
+func (p *importer) tagOrIndex() int {
+ if p.debugFormat {
+ p.marker('t')
+ }
+
+ return int(p.rawInt64())
+}
+
+func (p *importer) int() int {
+ x := p.int64()
+ if int64(int(x)) != x {
+ Fatalf("exported integer too large")
+ }
+ return int(x)
+}
+
+func (p *importer) int64() int64 {
+ if p.debugFormat {
+ p.marker('i')
+ }
+
+ return p.rawInt64()
+}
+
+func (p *importer) string() string {
+ if p.debugFormat {
+ p.marker('s')
+ }
+
+ if n := int(p.rawInt64()); n > 0 {
+ if cap(p.buf) < n {
+ p.buf = make([]byte, n)
+ } else {
+ p.buf = p.buf[:n]
+ }
+ r := obj.Bread(p.in, p.buf)
+ p.read += r
+ if r != n {
+ Fatalf("read error: read %d bytes of %d", r, n)
+ }
+ return string(p.buf)
+ }
+
+ return ""
+}
+
+func (p *importer) marker(want byte) {
+ if got := p.byte(); got != want {
+ Fatalf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read)
+ }
+
+ pos := p.read
+ if n := int(p.rawInt64()); n != pos {
+ Fatalf("incorrect position: got %d; want %d", n, pos)
+ }
+}
+
+func (p *importer) byte() byte {
+ if c := obj.Bgetc(p.in); c >= 0 {
+ p.read++
+ return byte(c)
+ }
+ Fatalf("read error")
+ return 0
+}
+
+// rawInt64 should only be used by low-level decoders
+func (p *importer) rawInt64() int64 {
+ i, err := binary.ReadVarint(p)
+ if err != nil {
+ Fatalf("read error: %v", err)
+ }
+ return i
+}
+
+// needed for binary.ReadVarint in rawInt64
+func (p *importer) ReadByte() (byte, error) {
+ return p.byte(), nil
+}
* a type for struct/interface/arglist
*/
func tostruct(l *NodeList) *Type {
- var f *Type
t := typ(TSTRUCT)
+ tostruct0(t, l)
+ return t
+}
+
+func tostruct0(t *Type, l *NodeList) {
+ if t == nil || t.Etype != TSTRUCT {
+ Fatalf("struct expected")
+ }
for tp := &t.Type; l != nil; l = l.Next {
- f = structfield(l.N)
+ f := structfield(l.N)
*tp = f
tp = &f.Down
if !t.Broke {
checkwidth(t)
}
-
- return t
}
func tofunargs(l *NodeList) *Type {
}
func tointerface(l *NodeList) *Type {
- var f *Type
- var t1 *Type
-
t := typ(TINTER)
+ tointerface0(t, l)
+ return t
+}
+
+func tointerface0(t *Type, l *NodeList) *Type {
+ if t == nil || t.Etype != TINTER {
+ Fatalf("interface expected")
+ }
tp := &t.Type
for ; l != nil; l = l.Next {
- f = interfacefield(l.N)
+ f := interfacefield(l.N)
if l.N.Left == nil && f.Type.Etype == TINTER {
// embedded interface, inline methods
- for t1 = f.Type.Type; t1 != nil; t1 = t1.Down {
+ for t1 := f.Type.Type; t1 != nil; t1 = t1.Down {
f = typ(TFIELD)
f.Type = t1.Type
f.Broke = t1.Broke
*/
func functype(this *Node, in *NodeList, out *NodeList) *Type {
t := typ(TFUNC)
+ functype0(t, this, in, out)
+ return t
+}
+
+func functype0(t *Type, this *Node, in *NodeList, out *NodeList) {
+ if t == nil || t.Etype != TFUNC {
+ Fatalf("function type expected")
+ }
var rcvr *NodeList
if this != nil {
t.Outnamed = true
}
}
-
- return t
}
var methodsym_toppkg *Pkg
package gc
import (
+ "bytes"
"cmd/internal/obj"
"fmt"
"sort"
"unicode/utf8"
)
+var (
+ newexport int // if set, use new export format
+ Debug_export int // if set, print debugging information about export data
+ exportsize int
+)
+
+func exportf(format string, args ...interface{}) {
+ n, _ := fmt.Fprintf(bout, format, args...)
+ exportsize += n
+ if Debug_export != 0 {
+ fmt.Printf(format, args...)
+ }
+}
+
var asmlist *NodeList
// Mark n's symbol as exported
}
func exportname(s string) bool {
- if s[0] < utf8.RuneSelf {
- return 'A' <= s[0] && s[0] <= 'Z'
+ if r := s[0]; r < utf8.RuneSelf {
+ return 'A' <= r && r <= 'Z'
}
r, _ := utf8.DecodeRuneInString(s)
return unicode.IsUpper(r)
if !p.Direct {
suffix = " // indirect"
}
- fmt.Fprintf(bout, "\timport %s %q%s\n", p.Name, p.Path, suffix)
+ exportf("\timport %s %q%s\n", p.Name, p.Path, suffix)
}
// Look for anything we need for the inline body
}
}
- // Local variables in the bodies need their type.
+ // Local variables in the bodies need their type.
case ODCL:
t := n.Left.Type
exportlist = append(exportlist, n)
}
- // for operations that need a type when rendered, put the type on the export list.
+ // for operations that need a type when rendered, put the type on the export list.
case OCONV,
OCONVIFACE,
OCONVNOP,
dumpexporttype(t)
if t != nil && !isideal(t) {
- fmt.Fprintf(bout, "\tconst %v %v = %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtSharp), Vconv(n.Val(), obj.FmtSharp))
+ exportf("\tconst %v %v = %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtSharp), Vconv(n.Val(), obj.FmtSharp))
} else {
- fmt.Fprintf(bout, "\tconst %v = %v\n", Sconv(s, obj.FmtSharp), Vconv(n.Val(), obj.FmtSharp))
+ exportf("\tconst %v = %v\n", Sconv(s, obj.FmtSharp), Vconv(n.Val(), obj.FmtSharp))
}
}
}
// NOTE: The space after %#S here is necessary for ld's export data parser.
- fmt.Fprintf(bout, "\tfunc %v %v { %v }\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp), Hconv(n.Func.Inl, obj.FmtSharp))
+ exportf("\tfunc %v %v { %v }\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp), Hconv(n.Func.Inl, obj.FmtSharp))
reexportdeplist(n.Func.Inl)
} else {
- fmt.Fprintf(bout, "\tfunc %v %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp))
+ exportf("\tfunc %v %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp))
}
} else {
- fmt.Fprintf(bout, "\tvar %v %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtSharp))
+ exportf("\tvar %v %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtSharp))
}
}
}
sort.Sort(methodbyname(m))
- fmt.Fprintf(bout, "\ttype %v %v\n", Sconv(t.Sym, obj.FmtSharp), Tconv(t, obj.FmtSharp|obj.FmtLong))
+ exportf("\ttype %v %v\n", Sconv(t.Sym, obj.FmtSharp), Tconv(t, obj.FmtSharp|obj.FmtLong))
for _, f := range m {
if f.Nointerface {
- fmt.Fprintf(bout, "\t//go:nointerface\n")
+ exportf("\t//go:nointerface\n")
}
if f.Type.Nname != nil && f.Type.Nname.Func.Inl != nil { // nname was set by caninl
if Debug['l'] < 2 {
typecheckinl(f.Type.Nname)
}
- fmt.Fprintf(bout, "\tfunc (%v) %v %v { %v }\n", Tconv(getthisx(f.Type).Type, obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp), Hconv(f.Type.Nname.Func.Inl, obj.FmtSharp))
+ exportf("\tfunc (%v) %v %v { %v }\n", Tconv(getthisx(f.Type).Type, obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp), Hconv(f.Type.Nname.Func.Inl, obj.FmtSharp))
reexportdeplist(f.Type.Nname.Func.Inl)
} else {
- fmt.Fprintf(bout, "\tfunc (%v) %v %v\n", Tconv(getthisx(f.Type).Type, obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp))
+ exportf("\tfunc (%v) %v %v\n", Tconv(getthisx(f.Type).Type, obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp))
}
}
}
}
func dumpexport() {
- lno := lineno
-
if buildid != "" {
- fmt.Fprintf(bout, "build id %q\n", buildid)
- }
- fmt.Fprintf(bout, "\n$$\npackage %s", localpkg.Name)
- if safemode != 0 {
- fmt.Fprintf(bout, " safe")
- }
- fmt.Fprintf(bout, "\n")
+ exportf("build id %q\n", buildid)
+ }
+
+ size := 0 // size of export section without enclosing markers
+ if forceNewExport || newexport != 0 {
+ // binary export
+ // The linker also looks for the $$ marker - use char after $$ to distinguish format.
+ exportf("\n$$B\n") // indicate binary format
+ const verifyExport = true // enable to check format changes
+ if verifyExport {
+ // save a copy of the export data
+ var copy bytes.Buffer
+ bcopy := obj.Binitw(©)
+ size = Export(bcopy, Debug_export != 0)
+ bcopy.Flush() // flushing to bytes.Buffer cannot fail
+ if n, err := bout.Write(copy.Bytes()); n != size || err != nil {
+ Fatalf("error writing export data: got %d bytes, want %d bytes, err = %v", n, size, err)
+ }
+
+ // verify there's no "\n$$\n" inside the export data
+ // TODO(gri) fragile - the end marker needs to be fixed
+ // TODO(gri) investigate if exporting a string containing "\n$$\n"
+ // causes problems (old and new format)
+ if bytes.Index(copy.Bytes(), []byte("\n$$\n")) >= 0 {
+ Fatalf("export data contains end marker in its midst")
+ }
- for _, p := range pkgs {
- if p.Direct {
- dumppkg(p)
+ // verify that we can read the copied export data back in
+ // (use empty package map to avoid collisions)
+ savedPkgMap := pkgMap
+ savedPkgs := pkgs
+ pkgMap = make(map[string]*Pkg)
+ pkgs = nil
+ importpkg = mkpkg("")
+ Import(obj.Binitr(©)) // must not die
+ importpkg = nil
+ pkgs = savedPkgs
+ pkgMap = savedPkgMap
+ } else {
+ size = Export(bout, Debug_export != 0)
+ }
+ exportf("\n$$\n")
+ } else {
+ // textual export
+ lno := lineno
+
+ exportf("\n$$\n") // indicate textual format
+ exportsize = 0
+ exportf("package %s", localpkg.Name)
+ if safemode != 0 {
+ exportf(" safe")
+ }
+ exportf("\n")
+
+ for _, p := range pkgs {
+ if p.Direct {
+ dumppkg(p)
+ }
}
- }
- // exportlist grows during iteration - cannot use range
- for len(exportlist) > 0 {
- n := exportlist[0]
- exportlist = exportlist[1:]
- lineno = n.Lineno
- dumpsym(n.Sym)
+ // exportlist grows during iteration - cannot use range
+ for len(exportlist) > 0 {
+ n := exportlist[0]
+ exportlist = exportlist[1:]
+ lineno = n.Lineno
+ dumpsym(n.Sym)
+ }
+
+ size = exportsize
+ exportf("\n$$\n")
+ lineno = lno
}
- fmt.Fprintf(bout, "\n$$\n")
- lineno = lno
+ if Debug_export != 0 {
+ fmt.Printf("export data size = %d bytes\n", size)
+ }
}
/*
TFUNC
TARRAY
- T_old_DARRAY
+ T_old_DARRAY // Doesn't seem to be used in existing code. Used now for Isddd export (see bexport.go). TODO(gri) rename.
TSTRUCT
TCHAN
TMAP
break;
}
if my.Name == "init" {
+ lineno = int32($1)
Yyerror("cannot import package as init - init must be a func");
break;
}
{"slice", &Debug_slice}, // print information about slice compilation
{"typeassert", &Debug_typeassert}, // print information about type assertion inlining
{"wb", &Debug_wb}, // print information about write barriers
+ {"export", &Debug_export}, // print export data
}
const (
obj.Flagcount("live", "debug liveness analysis", &debuglive)
obj.Flagcount("m", "print optimization decisions", &Debug['m'])
obj.Flagcount("msan", "build code compatible with C/C++ memory sanitizer", &flag_msan)
+ obj.Flagcount("newexport", "use new export format", &newexport) // TODO remove eventually
obj.Flagcount("nolocalimports", "reject local (relative) imports", &nolocalimports)
obj.Flagstr("o", "write output to `file`", &outfile)
obj.Flagstr("p", "set expected package import `path`", &myimportpath)
cannedimports("fake.o", "$$\n")
}
+// TODO(gri) line argument doesn't appear to be used
func importfile(f *Val, line int) {
if _, ok := f.U.(string); !ok {
Yyerror("import statement not a string")
// so don't record the full path.
linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib
- /*
- * position the input right
- * after $$ and return
- */
- pushedio = curio
-
- curio.bin = imp
- curio.peekc = 0
- curio.peekc1 = 0
- curio.infile = file
- curio.nlsemi = false
- typecheckok = true
+ // In the importfile, if we find:
+ // $$\n (old format): position the input right after $$\n and return
+ // $$B\n (new format): import directly, then feed the lexer a dummy statement
+ // look for $$
+ var c int
for {
- c := getc()
- if c == EOF {
- break
- }
- if c != '$' {
- continue
- }
- c = getc()
- if c == EOF {
+ c = obj.Bgetc(imp)
+ if c < 0 {
break
}
- if c != '$' {
- continue
+ if c == '$' {
+ c = obj.Bgetc(imp)
+ if c == '$' || c < 0 {
+ break
+ }
}
- return
}
- Yyerror("no import in %q", f.U.(string))
- unimportfile()
+ // get character after $$
+ if c >= 0 {
+ c = obj.Bgetc(imp)
+ }
+
+ switch c {
+ case '\n':
+ // old export format
+ pushedio = curio
+
+ curio.bin = imp
+ curio.peekc = 0
+ curio.peekc1 = 0
+ curio.infile = file
+ curio.nlsemi = false
+ typecheckok = true
+
+ case 'B':
+ // new export format
+ obj.Bgetc(imp) // skip \n after $$B
+ Import(imp)
+
+ // continue as if the package was imported before (see above)
+ tag := ""
+ if importpkg.Safe {
+ tag = "safe"
+ }
+ p := fmt.Sprintf("package %s %s\n$$\n", importpkg.Name, tag)
+ cannedimports(file, p)
+
+ default:
+ Yyerror("no import in %q", f.U.(string))
+ }
}
func unimportfile() {
return false
}
+// downcount is the same as countfield
+// TODO decide if we want both (for semantic reasons)
func downcount(t *Type) int {
n := 0
for tl := t.Type; tl != nil; tl = tl.Down {
const yyErrCode = 2
const yyMaxDepth = 200
-//line go.y:2308
+//line go.y:2309
func fixlbrace(lbr int) {
// If the opening brace was an LBODY,
// set up for another one now that we're done.
break
}
if my.Name == "init" {
+ lineno = int32(yyDollar[1].i)
Yyerror("cannot import package as init - init must be a func")
break
}
}
case 12:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:272
+ //line go.y:273
{
// When an invalid import path is passed to importfile,
// it calls Yyerror and then sets up a fake import with
}
case 15:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:288
+ //line go.y:289
{
// import with original name
yyVAL.i = parserline()
}
case 16:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:295
+ //line go.y:296
{
// import with given name
yyVAL.i = parserline()
}
case 17:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:302
+ //line go.y:303
{
// import into my name space
yyVAL.i = parserline()
}
case 18:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:311
+ //line go.y:312
{
if importpkg.Name == "" {
importpkg.Name = yyDollar[2].sym.Name
}
case 20:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:328
+ //line go.y:329
{
if yyDollar[1].sym.Name == "safe" {
curio.importsafe = true
}
case 21:
yyDollar = yyS[yypt-0 : yypt+1]
- //line go.y:335
+ //line go.y:336
{
defercheckwidth()
}
case 22:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:339
+ //line go.y:340
{
resumecheckwidth()
unimportfile()
}
case 23:
yyDollar = yyS[yypt-0 : yypt+1]
- //line go.y:348
+ //line go.y:349
{
Yyerror("empty top-level declaration")
yyVAL.list = nil
}
case 25:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:354
+ //line go.y:355
{
yyVAL.list = list1(yyDollar[1].node)
}
case 26:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:358
+ //line go.y:359
{
Yyerror("non-declaration statement outside function body")
yyVAL.list = nil
}
case 27:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:363
+ //line go.y:364
{
yyVAL.list = nil
}
case 28:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:369
+ //line go.y:370
{
yyVAL.list = yyDollar[2].list
}
case 29:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:373
+ //line go.y:374
{
yyVAL.list = yyDollar[3].list
}
case 30:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:377
+ //line go.y:378
{
yyVAL.list = nil
}
case 31:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:381
+ //line go.y:382
{
yyVAL.list = yyDollar[2].list
iota_ = -100000
}
case 32:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:387
+ //line go.y:388
{
yyVAL.list = yyDollar[3].list
iota_ = -100000
}
case 33:
yyDollar = yyS[yypt-7 : yypt+1]
- //line go.y:393
+ //line go.y:394
{
yyVAL.list = concat(yyDollar[3].list, yyDollar[5].list)
iota_ = -100000
}
case 34:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:399
+ //line go.y:400
{
yyVAL.list = nil
iota_ = -100000
}
case 35:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:404
+ //line go.y:405
{
yyVAL.list = list1(yyDollar[2].node)
}
case 36:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:408
+ //line go.y:409
{
yyVAL.list = yyDollar[3].list
}
case 37:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:412
+ //line go.y:413
{
yyVAL.list = nil
}
case 38:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:418
+ //line go.y:419
{
iota_ = 0
}
case 39:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:424
+ //line go.y:425
{
yyVAL.list = variter(yyDollar[1].list, yyDollar[2].node, nil)
}
case 40:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:428
+ //line go.y:429
{
yyVAL.list = variter(yyDollar[1].list, yyDollar[2].node, yyDollar[4].list)
}
case 41:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:432
+ //line go.y:433
{
yyVAL.list = variter(yyDollar[1].list, nil, yyDollar[3].list)
}
case 42:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:438
+ //line go.y:439
{
yyVAL.list = constiter(yyDollar[1].list, yyDollar[2].node, yyDollar[4].list)
}
case 43:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:442
+ //line go.y:443
{
yyVAL.list = constiter(yyDollar[1].list, nil, yyDollar[3].list)
}
case 45:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:449
+ //line go.y:450
{
yyVAL.list = constiter(yyDollar[1].list, yyDollar[2].node, nil)
}
case 46:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:453
+ //line go.y:454
{
yyVAL.list = constiter(yyDollar[1].list, nil, nil)
}
case 47:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:459
+ //line go.y:460
{
// different from dclname because the name
// becomes visible right here, not at the end
}
case 48:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:468
+ //line go.y:469
{
yyVAL.node = typedcl1(yyDollar[1].node, yyDollar[2].node, true)
}
case 49:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:474
+ //line go.y:475
{
yyVAL.node = yyDollar[1].node
}
case 50:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:488
+ //line go.y:489
{
yyVAL.node = Nod(OASOP, yyDollar[1].node, yyDollar[3].node)
yyVAL.node.Etype = uint8(yyDollar[2].i) // rathole to pass opcode
}
case 51:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:493
+ //line go.y:494
{
if yyDollar[1].list.Next == nil && yyDollar[3].list.Next == nil {
// simple
}
case 52:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:505
+ //line go.y:506
{
if yyDollar[3].list.N.Op == OTYPESW {
yyVAL.node = Nod(OTYPESW, nil, yyDollar[3].list.N.Right)
}
case 53:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:523
+ //line go.y:524
{
yyVAL.node = Nod(OASOP, yyDollar[1].node, Nodintconst(1))
yyVAL.node.Implicit = true
}
case 54:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:529
+ //line go.y:530
{
yyVAL.node = Nod(OASOP, yyDollar[1].node, Nodintconst(1))
yyVAL.node.Implicit = true
}
case 55:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:537
+ //line go.y:538
{
var n, nn *Node
}
case 56:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:560
+ //line go.y:561
{
var n *Node
}
case 57:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:578
+ //line go.y:579
{
// will be converted to OCASE
// right will point to next case
}
case 58:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:587
+ //line go.y:588
{
var n, nn *Node
}
case 59:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:608
+ //line go.y:609
{
markdcl()
}
case 60:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:612
+ //line go.y:613
{
if yyDollar[3].list == nil {
yyVAL.node = Nod(OEMPTY, nil, nil)
}
case 61:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:623
+ //line go.y:624
{
// If the last token read by the lexer was consumed
// as part of the case, clear it (parser has cleared yychar).
}
case 62:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:634
+ //line go.y:635
{
// This is the only place in the language where a statement
// list is not allowed to drop the final semicolon, because
}
case 63:
yyDollar = yyS[yypt-0 : yypt+1]
- //line go.y:653
+ //line go.y:654
{
yyVAL.list = nil
}
case 64:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:657
+ //line go.y:658
{
yyVAL.list = list(yyDollar[1].list, yyDollar[2].node)
}
case 65:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:663
+ //line go.y:664
{
markdcl()
}
case 66:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:667
+ //line go.y:668
{
yyVAL.list = yyDollar[3].list
popdcl()
}
case 67:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:674
+ //line go.y:675
{
yyVAL.node = Nod(ORANGE, nil, yyDollar[4].node)
yyVAL.node.List = yyDollar[1].list
}
case 68:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:680
+ //line go.y:681
{
yyVAL.node = Nod(ORANGE, nil, yyDollar[4].node)
yyVAL.node.List = yyDollar[1].list
}
case 69:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:687
+ //line go.y:688
{
yyVAL.node = Nod(ORANGE, nil, yyDollar[2].node)
yyVAL.node.Etype = 0 // := flag
}
case 70:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:694
+ //line go.y:695
{
// init ; test ; incr
if yyDollar[5].node != nil && yyDollar[5].node.Colas {
}
case 71:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:707
+ //line go.y:708
{
// normal test
yyVAL.node = Nod(OFOR, nil, nil)
}
case 73:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:716
+ //line go.y:717
{
yyVAL.node = yyDollar[1].node
yyVAL.node.Nbody = concat(yyVAL.node.Nbody, yyDollar[2].list)
}
case 74:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:723
+ //line go.y:724
{
markdcl()
}
case 75:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:727
+ //line go.y:728
{
yyVAL.node = yyDollar[3].node
popdcl()
}
case 76:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:734
+ //line go.y:735
{
// test
yyVAL.node = Nod(OIF, nil, nil)
}
case 77:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:740
+ //line go.y:741
{
// init ; test
yyVAL.node = Nod(OIF, nil, nil)
}
case 78:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:752
+ //line go.y:753
{
markdcl()
}
case 79:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:756
+ //line go.y:757
{
if yyDollar[3].node.Left == nil {
Yyerror("missing condition in if statement")
}
case 80:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:762
+ //line go.y:763
{
yyDollar[3].node.Nbody = yyDollar[5].list
}
case 81:
yyDollar = yyS[yypt-8 : yypt+1]
- //line go.y:766
+ //line go.y:767
{
var n *Node
var nn *NodeList
}
case 82:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:784
+ //line go.y:785
{
markdcl()
}
case 83:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:788
+ //line go.y:789
{
if yyDollar[4].node.Left == nil {
Yyerror("missing condition in if statement")
}
case 84:
yyDollar = yyS[yypt-0 : yypt+1]
- //line go.y:797
+ //line go.y:798
{
yyVAL.list = nil
}
case 85:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:801
+ //line go.y:802
{
yyVAL.list = concat(yyDollar[1].list, yyDollar[2].list)
}
case 86:
yyDollar = yyS[yypt-0 : yypt+1]
- //line go.y:806
+ //line go.y:807
{
yyVAL.list = nil
}
case 87:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:810
+ //line go.y:811
{
l := &NodeList{N: yyDollar[2].node}
l.End = l
}
case 88:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:818
+ //line go.y:819
{
markdcl()
}
case 89:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:822
+ //line go.y:823
{
var n *Node
n = yyDollar[3].node.Left
}
case 90:
yyDollar = yyS[yypt-7 : yypt+1]
- //line go.y:831
+ //line go.y:832
{
yyVAL.node = yyDollar[3].node
yyVAL.node.Op = OSWITCH
}
case 91:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:841
+ //line go.y:842
{
typesw = Nod(OXXX, typesw, nil)
}
case 92:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:845
+ //line go.y:846
{
yyVAL.node = Nod(OSELECT, nil, nil)
yyVAL.node.Lineno = typesw.Lineno
}
case 94:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:858
+ //line go.y:859
{
yyVAL.node = Nod(OOROR, yyDollar[1].node, yyDollar[3].node)
}
case 95:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:862
+ //line go.y:863
{
yyVAL.node = Nod(OANDAND, yyDollar[1].node, yyDollar[3].node)
}
case 96:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:866
+ //line go.y:867
{
yyVAL.node = Nod(OEQ, yyDollar[1].node, yyDollar[3].node)
}
case 97:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:870
+ //line go.y:871
{
yyVAL.node = Nod(ONE, yyDollar[1].node, yyDollar[3].node)
}
case 98:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:874
+ //line go.y:875
{
yyVAL.node = Nod(OLT, yyDollar[1].node, yyDollar[3].node)
}
case 99:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:878
+ //line go.y:879
{
yyVAL.node = Nod(OLE, yyDollar[1].node, yyDollar[3].node)
}
case 100:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:882
+ //line go.y:883
{
yyVAL.node = Nod(OGE, yyDollar[1].node, yyDollar[3].node)
}
case 101:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:886
+ //line go.y:887
{
yyVAL.node = Nod(OGT, yyDollar[1].node, yyDollar[3].node)
}
case 102:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:890
+ //line go.y:891
{
yyVAL.node = Nod(OADD, yyDollar[1].node, yyDollar[3].node)
}
case 103:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:894
+ //line go.y:895
{
yyVAL.node = Nod(OSUB, yyDollar[1].node, yyDollar[3].node)
}
case 104:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:898
+ //line go.y:899
{
yyVAL.node = Nod(OOR, yyDollar[1].node, yyDollar[3].node)
}
case 105:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:902
+ //line go.y:903
{
yyVAL.node = Nod(OXOR, yyDollar[1].node, yyDollar[3].node)
}
case 106:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:906
+ //line go.y:907
{
yyVAL.node = Nod(OMUL, yyDollar[1].node, yyDollar[3].node)
}
case 107:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:910
+ //line go.y:911
{
yyVAL.node = Nod(ODIV, yyDollar[1].node, yyDollar[3].node)
}
case 108:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:914
+ //line go.y:915
{
yyVAL.node = Nod(OMOD, yyDollar[1].node, yyDollar[3].node)
}
case 109:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:918
+ //line go.y:919
{
yyVAL.node = Nod(OAND, yyDollar[1].node, yyDollar[3].node)
}
case 110:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:922
+ //line go.y:923
{
yyVAL.node = Nod(OANDNOT, yyDollar[1].node, yyDollar[3].node)
}
case 111:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:926
+ //line go.y:927
{
yyVAL.node = Nod(OLSH, yyDollar[1].node, yyDollar[3].node)
}
case 112:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:930
+ //line go.y:931
{
yyVAL.node = Nod(ORSH, yyDollar[1].node, yyDollar[3].node)
}
case 113:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:935
+ //line go.y:936
{
yyVAL.node = Nod(OSEND, yyDollar[1].node, yyDollar[3].node)
}
case 115:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:942
+ //line go.y:943
{
yyVAL.node = Nod(OIND, yyDollar[2].node, nil)
}
case 116:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:946
+ //line go.y:947
{
if yyDollar[2].node.Op == OCOMPLIT {
// Special case for &T{...}: turn into (*T){...}.
}
case 117:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:957
+ //line go.y:958
{
yyVAL.node = Nod(OPLUS, yyDollar[2].node, nil)
}
case 118:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:961
+ //line go.y:962
{
yyVAL.node = Nod(OMINUS, yyDollar[2].node, nil)
}
case 119:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:965
+ //line go.y:966
{
yyVAL.node = Nod(ONOT, yyDollar[2].node, nil)
}
case 120:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:969
+ //line go.y:970
{
Yyerror("the bitwise complement operator is ^")
yyVAL.node = Nod(OCOM, yyDollar[2].node, nil)
}
case 121:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:974
+ //line go.y:975
{
yyVAL.node = Nod(OCOM, yyDollar[2].node, nil)
}
case 122:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:978
+ //line go.y:979
{
yyVAL.node = Nod(ORECV, yyDollar[2].node, nil)
}
case 123:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:988
+ //line go.y:989
{
yyVAL.node = Nod(OCALL, yyDollar[1].node, nil)
}
case 124:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:992
+ //line go.y:993
{
yyVAL.node = Nod(OCALL, yyDollar[1].node, nil)
yyVAL.node.List = yyDollar[3].list
}
case 125:
yyDollar = yyS[yypt-6 : yypt+1]
- //line go.y:997
+ //line go.y:998
{
yyVAL.node = Nod(OCALL, yyDollar[1].node, nil)
yyVAL.node.List = yyDollar[3].list
}
case 126:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1005
+ //line go.y:1006
{
yyVAL.node = nodlit(yyDollar[1].val)
}
case 128:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1010
+ //line go.y:1011
{
if yyDollar[1].node.Op == OPACK {
var s *Sym
}
case 129:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:1021
+ //line go.y:1022
{
yyVAL.node = Nod(ODOTTYPE, yyDollar[1].node, yyDollar[4].node)
}
case 130:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:1025
+ //line go.y:1026
{
yyVAL.node = Nod(OTYPESW, nil, yyDollar[1].node)
}
case 131:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:1029
+ //line go.y:1030
{
yyVAL.node = Nod(OINDEX, yyDollar[1].node, yyDollar[3].node)
}
case 132:
yyDollar = yyS[yypt-6 : yypt+1]
- //line go.y:1033
+ //line go.y:1034
{
yyVAL.node = Nod(OSLICE, yyDollar[1].node, Nod(OKEY, yyDollar[3].node, yyDollar[5].node))
}
case 133:
yyDollar = yyS[yypt-8 : yypt+1]
- //line go.y:1037
+ //line go.y:1038
{
if yyDollar[5].node == nil {
Yyerror("middle index required in 3-index slice")
}
case 135:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:1048
+ //line go.y:1049
{
// conversion
yyVAL.node = Nod(OCALL, yyDollar[1].node, nil)
}
case 136:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:1054
+ //line go.y:1055
{
yyVAL.node = yyDollar[3].node
yyVAL.node.Right = yyDollar[1].node
}
case 137:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:1061
+ //line go.y:1062
{
yyVAL.node = yyDollar[3].node
yyVAL.node.Right = yyDollar[1].node
}
case 138:
yyDollar = yyS[yypt-7 : yypt+1]
- //line go.y:1067
+ //line go.y:1068
{
Yyerror("cannot parenthesize type in composite literal")
yyVAL.node = yyDollar[5].node
}
case 140:
yyDollar = yyS[yypt-0 : yypt+1]
- //line go.y:1076
+ //line go.y:1077
{
// composite expression.
// make node early so we get the right line number.
}
case 141:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1084
+ //line go.y:1085
{
yyVAL.node = Nod(OKEY, yyDollar[1].node, yyDollar[3].node)
}
case 142:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1090
+ //line go.y:1091
{
// These nodes do not carry line numbers.
// Since a composite literal commonly spans several lines,
}
case 143:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:1103
+ //line go.y:1104
{
yyVAL.node = yyDollar[2].node
yyVAL.node.List = yyDollar[3].list
}
case 145:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:1111
+ //line go.y:1112
{
yyVAL.node = yyDollar[2].node
yyVAL.node.List = yyDollar[3].list
}
case 147:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1119
+ //line go.y:1120
{
yyVAL.node = yyDollar[2].node
}
case 151:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1140
+ //line go.y:1141
{
yyVAL.i = LBODY
}
case 152:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1144
+ //line go.y:1145
{
yyVAL.i = '{'
}
case 153:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1155
+ //line go.y:1156
{
if yyDollar[1].sym == nil {
yyVAL.node = nil
}
case 154:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1165
+ //line go.y:1166
{
yyVAL.node = dclname(yyDollar[1].sym)
}
case 155:
yyDollar = yyS[yypt-0 : yypt+1]
- //line go.y:1170
+ //line go.y:1171
{
yyVAL.node = nil
}
case 157:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1177
+ //line go.y:1178
{
yyVAL.sym = yyDollar[1].sym
// during imports, unqualified non-exported identifiers are from builtinpkg
}
case 159:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1186
+ //line go.y:1187
{
yyVAL.sym = nil
}
case 160:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:1192
+ //line go.y:1193
{
var p *Pkg
}
case 161:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:1206
+ //line go.y:1207
{
var p *Pkg
}
case 162:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1222
+ //line go.y:1223
{
yyVAL.node = oldname(yyDollar[1].sym)
if yyVAL.node.Name != nil && yyVAL.node.Name.Pack != nil {
}
case 164:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1243
+ //line go.y:1244
{
Yyerror("final argument in variadic function missing type")
yyVAL.node = Nod(ODDD, typenod(typ(TINTER)), nil)
}
case 165:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:1248
+ //line go.y:1249
{
yyVAL.node = Nod(ODDD, yyDollar[2].node, nil)
}
case 171:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1259
+ //line go.y:1260
{
yyVAL.node = yyDollar[2].node
}
case 175:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:1268
+ //line go.y:1269
{
yyVAL.node = Nod(OIND, yyDollar[2].node, nil)
}
case 180:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1278
+ //line go.y:1279
{
yyVAL.node = yyDollar[2].node
}
case 190:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1299
+ //line go.y:1300
{
if yyDollar[1].node.Op == OPACK {
var s *Sym
}
case 191:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:1312
+ //line go.y:1313
{
yyVAL.node = Nod(OTARRAY, yyDollar[2].node, yyDollar[4].node)
}
case 192:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:1316
+ //line go.y:1317
{
// array literal of nelem
yyVAL.node = Nod(OTARRAY, Nod(ODDD, nil, nil), yyDollar[4].node)
}
case 193:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:1321
+ //line go.y:1322
{
yyVAL.node = Nod(OTCHAN, yyDollar[2].node, nil)
yyVAL.node.Etype = Cboth
}
case 194:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1326
+ //line go.y:1327
{
yyVAL.node = Nod(OTCHAN, yyDollar[3].node, nil)
yyVAL.node.Etype = Csend
}
case 195:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:1331
+ //line go.y:1332
{
yyVAL.node = Nod(OTMAP, yyDollar[3].node, yyDollar[5].node)
}
case 198:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:1339
+ //line go.y:1340
{
yyVAL.node = Nod(OIND, yyDollar[2].node, nil)
}
case 199:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1345
+ //line go.y:1346
{
yyVAL.node = Nod(OTCHAN, yyDollar[3].node, nil)
yyVAL.node.Etype = Crecv
}
case 200:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:1352
+ //line go.y:1353
{
yyVAL.node = Nod(OTSTRUCT, nil, nil)
yyVAL.node.List = yyDollar[3].list
}
case 201:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1358
+ //line go.y:1359
{
yyVAL.node = Nod(OTSTRUCT, nil, nil)
fixlbrace(yyDollar[2].i)
}
case 202:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:1365
+ //line go.y:1366
{
yyVAL.node = Nod(OTINTER, nil, nil)
yyVAL.node.List = yyDollar[3].list
}
case 203:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1371
+ //line go.y:1372
{
yyVAL.node = Nod(OTINTER, nil, nil)
fixlbrace(yyDollar[2].i)
}
case 204:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1382
+ //line go.y:1383
{
yyVAL.node = yyDollar[2].node
if yyVAL.node == nil {
}
case 205:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:1402
+ //line go.y:1403
{
var t *Node
}
case 206:
yyDollar = yyS[yypt-8 : yypt+1]
- //line go.y:1433
+ //line go.y:1434
{
var rcvr, t *Node
}
case 207:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:1471
+ //line go.y:1472
{
var s *Sym
var t *Type
}
case 208:
yyDollar = yyS[yypt-8 : yypt+1]
- //line go.y:1496
+ //line go.y:1497
{
yyVAL.node = methodname1(newname(yyDollar[4].sym), yyDollar[2].list.N.Right)
yyVAL.node.Type = functype(yyDollar[2].list.N, yyDollar[6].list, yyDollar[8].list)
}
case 209:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:1514
+ //line go.y:1515
{
yyDollar[3].list = checkarglist(yyDollar[3].list, 1)
yyVAL.node = Nod(OTFUNC, nil, nil)
}
case 210:
yyDollar = yyS[yypt-0 : yypt+1]
- //line go.y:1522
+ //line go.y:1523
{
yyVAL.list = nil
}
case 211:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1526
+ //line go.y:1527
{
yyVAL.list = yyDollar[2].list
if yyVAL.list == nil {
}
case 212:
yyDollar = yyS[yypt-0 : yypt+1]
- //line go.y:1535
+ //line go.y:1536
{
yyVAL.list = nil
}
case 213:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1539
+ //line go.y:1540
{
yyVAL.list = list1(Nod(ODCLFIELD, nil, yyDollar[1].node))
}
case 214:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1543
+ //line go.y:1544
{
yyDollar[2].list = checkarglist(yyDollar[2].list, 0)
yyVAL.list = yyDollar[2].list
}
case 215:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1550
+ //line go.y:1551
{
closurehdr(yyDollar[1].node)
}
case 216:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:1556
+ //line go.y:1557
{
yyVAL.node = closurebody(yyDollar[3].list)
fixlbrace(yyDollar[2].i)
}
case 217:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:1561
+ //line go.y:1562
{
yyVAL.node = closurebody(nil)
}
case 218:
yyDollar = yyS[yypt-0 : yypt+1]
- //line go.y:1572
+ //line go.y:1573
{
yyVAL.list = nil
}
case 219:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1576
+ //line go.y:1577
{
yyVAL.list = concat(yyDollar[1].list, yyDollar[2].list)
if nsyntaxerrors == 0 {
}
case 221:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1592
+ //line go.y:1593
{
yyVAL.list = concat(yyDollar[1].list, yyDollar[3].list)
}
case 223:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1599
+ //line go.y:1600
{
yyVAL.list = concat(yyDollar[1].list, yyDollar[3].list)
}
case 224:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1605
+ //line go.y:1606
{
yyVAL.list = list1(yyDollar[1].node)
}
case 225:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1609
+ //line go.y:1610
{
yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
}
case 227:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1616
+ //line go.y:1617
{
yyVAL.list = concat(yyDollar[1].list, yyDollar[3].list)
}
case 228:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1622
+ //line go.y:1623
{
yyVAL.list = list1(yyDollar[1].node)
}
case 229:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1626
+ //line go.y:1627
{
yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
}
case 230:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1632
+ //line go.y:1633
{
var l *NodeList
}
case 231:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:1656
+ //line go.y:1657
{
yyDollar[1].node.SetVal(yyDollar[2].val)
yyVAL.list = list1(yyDollar[1].node)
}
case 232:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:1661
+ //line go.y:1662
{
yyDollar[2].node.SetVal(yyDollar[4].val)
yyVAL.list = list1(yyDollar[2].node)
}
case 233:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1667
+ //line go.y:1668
{
yyDollar[2].node.Right = Nod(OIND, yyDollar[2].node.Right, nil)
yyDollar[2].node.SetVal(yyDollar[3].val)
}
case 234:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:1673
+ //line go.y:1674
{
yyDollar[3].node.Right = Nod(OIND, yyDollar[3].node.Right, nil)
yyDollar[3].node.SetVal(yyDollar[5].val)
}
case 235:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:1680
+ //line go.y:1681
{
yyDollar[3].node.Right = Nod(OIND, yyDollar[3].node.Right, nil)
yyDollar[3].node.SetVal(yyDollar[5].val)
}
case 236:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1689
+ //line go.y:1690
{
var n *Node
}
case 237:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1699
+ //line go.y:1700
{
var pkg *Pkg
}
case 238:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1714
+ //line go.y:1715
{
yyVAL.node = embedded(yyDollar[1].sym, localpkg)
}
case 239:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:1720
+ //line go.y:1721
{
yyVAL.node = Nod(ODCLFIELD, yyDollar[1].node, yyDollar[2].node)
ifacedcl(yyVAL.node)
}
case 240:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1725
+ //line go.y:1726
{
yyVAL.node = Nod(ODCLFIELD, nil, oldname(yyDollar[1].sym))
}
case 241:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1729
+ //line go.y:1730
{
yyVAL.node = Nod(ODCLFIELD, nil, oldname(yyDollar[2].sym))
Yyerror("cannot parenthesize embedded type")
}
case 242:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:1736
+ //line go.y:1737
{
// without func keyword
yyDollar[2].list = checkarglist(yyDollar[2].list, 1)
}
case 244:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:1750
+ //line go.y:1751
{
yyVAL.node = Nod(ONONAME, nil, nil)
yyVAL.node.Sym = yyDollar[1].sym
}
case 245:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:1756
+ //line go.y:1757
{
yyVAL.node = Nod(ONONAME, nil, nil)
yyVAL.node.Sym = yyDollar[1].sym
}
case 247:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1765
+ //line go.y:1766
{
yyVAL.list = list1(yyDollar[1].node)
}
case 248:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1769
+ //line go.y:1770
{
yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
}
case 249:
yyDollar = yyS[yypt-0 : yypt+1]
- //line go.y:1774
+ //line go.y:1775
{
yyVAL.list = nil
}
case 250:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:1778
+ //line go.y:1779
{
yyVAL.list = yyDollar[1].list
}
case 251:
yyDollar = yyS[yypt-0 : yypt+1]
- //line go.y:1786
+ //line go.y:1787
{
yyVAL.node = nil
}
case 253:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1791
+ //line go.y:1792
{
yyVAL.node = liststmt(yyDollar[1].list)
}
case 255:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1796
+ //line go.y:1797
{
yyVAL.node = nil
}
case 261:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:1807
+ //line go.y:1808
{
yyDollar[1].node = Nod(OLABEL, yyDollar[1].node, nil)
yyDollar[1].node.Sym = dclstack // context, for goto restrictions
}
case 262:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:1812
+ //line go.y:1813
{
var l *NodeList
}
case 263:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1823
+ //line go.y:1824
{
// will be converted to OFALL
yyVAL.node = Nod(OXFALL, nil, nil)
}
case 264:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:1829
+ //line go.y:1830
{
yyVAL.node = Nod(OBREAK, yyDollar[2].node, nil)
}
case 265:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:1833
+ //line go.y:1834
{
yyVAL.node = Nod(OCONTINUE, yyDollar[2].node, nil)
}
case 266:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:1837
+ //line go.y:1838
{
yyVAL.node = Nod(OPROC, yyDollar[2].node, nil)
}
case 267:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:1841
+ //line go.y:1842
{
yyVAL.node = Nod(ODEFER, yyDollar[2].node, nil)
}
case 268:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:1845
+ //line go.y:1846
{
yyVAL.node = Nod(OGOTO, yyDollar[2].node, nil)
yyVAL.node.Sym = dclstack // context, for goto restrictions
}
case 269:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:1850
+ //line go.y:1851
{
yyVAL.node = Nod(ORETURN, nil, nil)
yyVAL.node.List = yyDollar[2].list
}
case 270:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1872
+ //line go.y:1873
{
yyVAL.list = nil
if yyDollar[1].node != nil {
}
case 271:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1879
+ //line go.y:1880
{
yyVAL.list = yyDollar[1].list
if yyDollar[3].node != nil {
}
case 272:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1888
+ //line go.y:1889
{
yyVAL.list = list1(yyDollar[1].node)
}
case 273:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1892
+ //line go.y:1893
{
yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
}
case 274:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1898
+ //line go.y:1899
{
yyVAL.list = list1(yyDollar[1].node)
}
case 275:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1902
+ //line go.y:1903
{
yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
}
case 276:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1908
+ //line go.y:1909
{
yyVAL.list = list1(yyDollar[1].node)
}
case 277:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1912
+ //line go.y:1913
{
yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
}
case 278:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1918
+ //line go.y:1919
{
yyVAL.list = list1(yyDollar[1].node)
}
case 279:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1922
+ //line go.y:1923
{
yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
}
case 280:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1931
+ //line go.y:1932
{
yyVAL.list = list1(yyDollar[1].node)
}
case 281:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:1935
+ //line go.y:1936
{
yyVAL.list = list1(yyDollar[1].node)
}
case 282:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1939
+ //line go.y:1940
{
yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
}
case 283:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:1943
+ //line go.y:1944
{
yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
}
case 284:
yyDollar = yyS[yypt-0 : yypt+1]
- //line go.y:1948
+ //line go.y:1949
{
yyVAL.list = nil
}
case 285:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:1952
+ //line go.y:1953
{
yyVAL.list = yyDollar[1].list
}
case 290:
yyDollar = yyS[yypt-0 : yypt+1]
- //line go.y:1966
+ //line go.y:1967
{
yyVAL.node = nil
}
case 292:
yyDollar = yyS[yypt-0 : yypt+1]
- //line go.y:1972
+ //line go.y:1973
{
yyVAL.list = nil
}
case 294:
yyDollar = yyS[yypt-0 : yypt+1]
- //line go.y:1978
+ //line go.y:1979
{
yyVAL.node = nil
}
case 296:
yyDollar = yyS[yypt-0 : yypt+1]
- //line go.y:1984
+ //line go.y:1985
{
yyVAL.list = nil
}
case 298:
yyDollar = yyS[yypt-0 : yypt+1]
- //line go.y:1990
+ //line go.y:1991
{
yyVAL.list = nil
}
case 300:
yyDollar = yyS[yypt-0 : yypt+1]
- //line go.y:1996
+ //line go.y:1997
{
yyVAL.list = nil
}
case 302:
yyDollar = yyS[yypt-0 : yypt+1]
- //line go.y:2002
+ //line go.y:2003
{
yyVAL.val.U = nil
}
case 304:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:2012
+ //line go.y:2013
{
importimport(yyDollar[2].sym, yyDollar[3].val.U.(string))
}
case 305:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:2016
+ //line go.y:2017
{
importvar(yyDollar[2].sym, yyDollar[3].typ)
}
case 306:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:2020
+ //line go.y:2021
{
importconst(yyDollar[2].sym, Types[TIDEAL], yyDollar[4].node)
}
case 307:
yyDollar = yyS[yypt-6 : yypt+1]
- //line go.y:2024
+ //line go.y:2025
{
importconst(yyDollar[2].sym, yyDollar[3].typ, yyDollar[5].node)
}
case 308:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:2028
+ //line go.y:2029
{
importtype(yyDollar[2].typ, yyDollar[3].typ)
}
case 309:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:2032
+ //line go.y:2033
{
if yyDollar[2].node == nil {
dclcontext = PEXTERN // since we skip the funcbody below
}
case 310:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:2053
+ //line go.y:2054
{
yyVAL.sym = yyDollar[1].sym
structpkg = yyVAL.sym.Pkg
}
case 311:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:2060
+ //line go.y:2061
{
yyVAL.typ = pkgtype(yyDollar[1].sym)
importsym(yyDollar[1].sym, OTYPE)
}
case 317:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:2080
+ //line go.y:2081
{
yyVAL.typ = pkgtype(yyDollar[1].sym)
}
case 318:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:2084
+ //line go.y:2085
{
// predefined name like uint8
yyDollar[1].sym = Pkglookup(yyDollar[1].sym.Name, builtinpkg)
}
case 319:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:2095
+ //line go.y:2096
{
yyVAL.typ = aindex(nil, yyDollar[3].typ)
}
case 320:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:2099
+ //line go.y:2100
{
yyVAL.typ = aindex(nodlit(yyDollar[2].val), yyDollar[4].typ)
}
case 321:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:2103
+ //line go.y:2104
{
yyVAL.typ = maptype(yyDollar[3].typ, yyDollar[5].typ)
}
case 322:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:2107
+ //line go.y:2108
{
yyVAL.typ = tostruct(yyDollar[3].list)
}
case 323:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:2111
+ //line go.y:2112
{
yyVAL.typ = tointerface(yyDollar[3].list)
}
case 324:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:2115
+ //line go.y:2116
{
yyVAL.typ = Ptrto(yyDollar[2].typ)
}
case 325:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:2119
+ //line go.y:2120
{
yyVAL.typ = typ(TCHAN)
yyVAL.typ.Type = yyDollar[2].typ
}
case 326:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:2125
+ //line go.y:2126
{
yyVAL.typ = typ(TCHAN)
yyVAL.typ.Type = yyDollar[3].typ
}
case 327:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:2131
+ //line go.y:2132
{
yyVAL.typ = typ(TCHAN)
yyVAL.typ.Type = yyDollar[3].typ
}
case 328:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:2139
+ //line go.y:2140
{
yyVAL.typ = typ(TCHAN)
yyVAL.typ.Type = yyDollar[3].typ
}
case 329:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:2147
+ //line go.y:2148
{
yyVAL.typ = functype(nil, yyDollar[3].list, yyDollar[5].list)
}
case 330:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:2153
+ //line go.y:2154
{
yyVAL.node = Nod(ODCLFIELD, nil, typenod(yyDollar[2].typ))
if yyDollar[1].sym != nil {
}
case 331:
yyDollar = yyS[yypt-4 : yypt+1]
- //line go.y:2161
+ //line go.y:2162
{
var t *Type
}
case 332:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:2178
+ //line go.y:2179
{
var s *Sym
var p *Pkg
}
case 333:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:2202
+ //line go.y:2203
{
yyVAL.node = Nod(ODCLFIELD, newname(yyDollar[1].sym), typenod(functype(fakethis(), yyDollar[3].list, yyDollar[5].list)))
}
case 334:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:2206
+ //line go.y:2207
{
yyVAL.node = Nod(ODCLFIELD, nil, typenod(yyDollar[1].typ))
}
case 335:
yyDollar = yyS[yypt-0 : yypt+1]
- //line go.y:2211
+ //line go.y:2212
{
yyVAL.list = nil
}
case 337:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:2218
+ //line go.y:2219
{
yyVAL.list = yyDollar[2].list
}
case 338:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:2222
+ //line go.y:2223
{
yyVAL.list = list1(Nod(ODCLFIELD, nil, typenod(yyDollar[1].typ)))
}
case 339:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:2232
+ //line go.y:2233
{
yyVAL.node = nodlit(yyDollar[1].val)
}
case 340:
yyDollar = yyS[yypt-2 : yypt+1]
- //line go.y:2236
+ //line go.y:2237
{
yyVAL.node = nodlit(yyDollar[2].val)
switch yyVAL.node.Val().Ctype() {
}
case 341:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:2254
+ //line go.y:2255
{
yyVAL.node = oldname(Pkglookup(yyDollar[1].sym.Name, builtinpkg))
if yyVAL.node.Op != OLITERAL {
}
case 343:
yyDollar = yyS[yypt-5 : yypt+1]
- //line go.y:2264
+ //line go.y:2265
{
if yyDollar[2].node.Val().Ctype() == CTRUNE && yyDollar[4].node.Val().Ctype() == CTINT {
yyVAL.node = yyDollar[2].node
}
case 346:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:2280
+ //line go.y:2281
{
yyVAL.list = list1(yyDollar[1].node)
}
case 347:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:2284
+ //line go.y:2285
{
yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
}
case 348:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:2290
+ //line go.y:2291
{
yyVAL.list = list1(yyDollar[1].node)
}
case 349:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:2294
+ //line go.y:2295
{
yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
}
case 350:
yyDollar = yyS[yypt-1 : yypt+1]
- //line go.y:2300
+ //line go.y:2301
{
yyVAL.list = list1(yyDollar[1].node)
}
case 351:
yyDollar = yyS[yypt-3 : yypt+1]
- //line go.y:2304
+ //line go.y:2305
{
yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
}
return &Biobuf{w: bufio.NewWriter(w)}
}
+func Binitr(r io.Reader) *Biobuf {
+ return &Biobuf{r: bufio.NewReader(r)}
+}
+
func (b *Biobuf) Write(p []byte) (int, error) {
return b.w.Write(p)
}
--- /dev/null
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gcimporter
+
+import (
+ "encoding/binary"
+ "fmt"
+ "go/constant"
+ "go/token"
+ "go/types"
+ "sort"
+ "unicode"
+ "unicode/utf8"
+)
+
+// BImportData imports a package from the serialized package data
+// and returns the number of bytes consumed and a reference to the package.
+// If data is obviously malformed, an error is returned but in
+// general it is not recommended to call BImportData on untrusted data.
+func BImportData(imports map[string]*types.Package, data []byte, path string) (int, *types.Package, error) {
+ // determine low-level encoding format
+ read := 0
+ var format byte = 'm' // missing format
+ if len(data) > 0 {
+ format = data[0]
+ data = data[1:]
+ read++
+ }
+ if format != 'c' && format != 'd' {
+ return read, nil, fmt.Errorf("invalid encoding format in export data: got %q; want 'c' or 'd'", format)
+ }
+
+ // --- generic export data ---
+
+ p := importer{
+ imports: imports,
+ data: data,
+ debugFormat: format == 'd',
+ read: read,
+ }
+
+ if v := p.string(); v != "v0" {
+ return p.read, nil, fmt.Errorf("unknown version: %s", v)
+ }
+
+ // populate typList with predeclared "known" types
+ p.typList = append(p.typList, predeclared...)
+
+ // read package data
+ // TODO(gri) clean this up
+ i := p.tagOrIndex()
+ if i != packageTag {
+ panic(fmt.Sprintf("package tag expected, got %d", i))
+ }
+ name := p.string()
+ if s := p.string(); s != "" {
+ panic(fmt.Sprintf("empty path expected, got %s", s))
+ }
+ pkg := p.imports[path]
+ if pkg == nil {
+ pkg = types.NewPackage(path, name)
+ p.imports[path] = pkg
+ }
+ p.pkgList = append(p.pkgList, pkg)
+
+ if debug && p.pkgList[0] != pkg {
+ panic("imported packaged not found in pkgList[0]")
+ }
+
+ // read compiler-specific flags
+ p.string() // discard
+
+ // read consts
+ for i := p.int(); i > 0; i-- {
+ name := p.string()
+ typ := p.typ()
+ val := p.value()
+ p.declare(types.NewConst(token.NoPos, pkg, name, typ, val))
+ }
+
+ // read vars
+ for i := p.int(); i > 0; i-- {
+ name := p.string()
+ typ := p.typ()
+ p.declare(types.NewVar(token.NoPos, pkg, name, typ))
+ }
+
+ // read funcs
+ for i := p.int(); i > 0; i-- {
+ name := p.string()
+ sig := p.typ().(*types.Signature)
+ p.int() // read and discard index of inlined function body
+ p.declare(types.NewFunc(token.NoPos, pkg, name, sig))
+ }
+
+ // read types
+ for i := p.int(); i > 0; i-- {
+ // name is parsed as part of named type and the
+ // type object is added to scope via respective
+ // named type
+ _ = p.typ().(*types.Named)
+ }
+
+ // complete interfaces
+ for _, typ := range p.typList {
+ if it, ok := typ.(*types.Interface); ok {
+ it.Complete()
+ }
+ }
+
+ // record all referenced packages as imports
+ list := append(([]*types.Package)(nil), p.pkgList[1:]...)
+ sort.Sort(byPath(list))
+ pkg.SetImports(list)
+
+ // package was imported completely and without errors
+ pkg.MarkComplete()
+
+ return p.read, pkg, nil
+}
+
+type importer struct {
+ imports map[string]*types.Package
+ data []byte
+ pkgList []*types.Package
+ typList []types.Type
+
+ debugFormat bool
+ read int // bytes read
+}
+
+func (p *importer) declare(obj types.Object) {
+ if alt := p.pkgList[0].Scope().Insert(obj); alt != nil {
+ // This can only happen if we import a package a second time.
+ panic(fmt.Sprintf("%s already declared", alt.Name()))
+ }
+}
+
+func (p *importer) pkg() *types.Package {
+ // if the package was seen before, i is its index (>= 0)
+ i := p.tagOrIndex()
+ if i >= 0 {
+ return p.pkgList[i]
+ }
+
+ // otherwise, i is the package tag (< 0)
+ if i != packageTag {
+ panic(fmt.Sprintf("unexpected package tag %d", i))
+ }
+
+ // read package data
+ name := p.string()
+ path := p.string()
+
+ // we should never see an empty package name
+ if name == "" {
+ panic("empty package name in import")
+ }
+
+ // we should never see an empty import path
+ if path == "" {
+ panic("empty import path")
+ }
+
+ // if the package was imported before, use that one; otherwise create a new one
+ pkg := p.imports[path]
+ if pkg == nil {
+ pkg = types.NewPackage(path, name)
+ p.imports[path] = pkg
+ }
+ p.pkgList = append(p.pkgList, pkg)
+
+ return pkg
+}
+
+func (p *importer) record(t types.Type) {
+ p.typList = append(p.typList, t)
+}
+
+// A dddSlice is a types.Type representing ...T parameters.
+// It only appears for parameter types and does not escape
+// the importer.
+type dddSlice struct {
+ elem types.Type
+}
+
+func (t *dddSlice) Underlying() types.Type { return t }
+func (t *dddSlice) String() string { return "..." + t.elem.String() }
+
+func (p *importer) typ() types.Type {
+ // if the type was seen before, i is its index (>= 0)
+ i := p.tagOrIndex()
+ if i >= 0 {
+ return p.typList[i]
+ }
+
+ // otherwise, i is the type tag (< 0)
+ switch i {
+ case namedTag:
+ // read type object
+ name := p.string()
+ tpkg := p.pkg()
+ scope := tpkg.Scope()
+ obj := scope.Lookup(name)
+
+ // if the object doesn't exist yet, create and insert it
+ if obj == nil {
+ obj = types.NewTypeName(token.NoPos, tpkg, name, nil)
+ scope.Insert(obj)
+ }
+
+ if _, ok := obj.(*types.TypeName); !ok {
+ panic(fmt.Sprintf("pkg = %s, name = %s => %s", tpkg, name, obj))
+ }
+
+ // associate new named type with obj if it doesn't exist yet
+ t0 := types.NewNamed(obj.(*types.TypeName), nil, nil)
+
+ // but record the existing type, if any
+ t := obj.Type().(*types.Named)
+ p.record(t)
+
+ // read underlying type
+ t0.SetUnderlying(p.typ())
+
+ // interfaces don't have associated methods
+ if _, ok := t0.Underlying().(*types.Interface); ok {
+ return t
+ }
+
+ // read associated methods
+ for i := p.int(); i > 0; i-- {
+ name := p.string()
+ recv, _ := p.paramList() // TODO(gri) do we need a full param list for the receiver?
+ params, isddd := p.paramList()
+ result, _ := p.paramList()
+ p.int() // read and discard index of inlined function body
+ sig := types.NewSignature(recv.At(0), params, result, isddd)
+ t0.AddMethod(types.NewFunc(token.NoPos, tpkg, name, sig))
+ }
+
+ return t
+
+ case arrayTag:
+ t := new(types.Array)
+ p.record(t)
+
+ n := p.int64()
+ *t = *types.NewArray(p.typ(), n)
+ return t
+
+ case sliceTag:
+ t := new(types.Slice)
+ p.record(t)
+
+ *t = *types.NewSlice(p.typ())
+ return t
+
+ case dddTag:
+ t := new(dddSlice)
+ p.record(t)
+
+ t.elem = p.typ()
+ return t
+
+ case structTag:
+ t := new(types.Struct)
+ p.record(t)
+
+ n := p.int()
+ fields := make([]*types.Var, n)
+ tags := make([]string, n)
+ for i := range fields {
+ fields[i] = p.field()
+ tags[i] = p.string()
+ }
+ *t = *types.NewStruct(fields, tags)
+ return t
+
+ case pointerTag:
+ t := new(types.Pointer)
+ p.record(t)
+
+ *t = *types.NewPointer(p.typ())
+ return t
+
+ case signatureTag:
+ t := new(types.Signature)
+ p.record(t)
+
+ params, isddd := p.paramList()
+ result, _ := p.paramList()
+ *t = *types.NewSignature(nil, params, result, isddd)
+ return t
+
+ case interfaceTag:
+ // Create a dummy entry in the type list. This is safe because we
+ // cannot expect the interface type to appear in a cycle, as any
+ // such cycle must contain a named type which would have been
+ // first defined earlier.
+ n := len(p.typList)
+ p.record(nil)
+
+ // no embedded interfaces with gc compiler
+ if p.int() != 0 {
+ panic("unexpected embedded interface")
+ }
+
+ // read methods
+ methods := make([]*types.Func, p.int())
+ for i := range methods {
+ pkg, name := p.fieldName()
+ params, isddd := p.paramList()
+ result, _ := p.paramList()
+ sig := types.NewSignature(nil, params, result, isddd)
+ methods[i] = types.NewFunc(token.NoPos, pkg, name, sig)
+ }
+
+ t := types.NewInterface(methods, nil)
+ p.typList[n] = t
+ return t
+
+ case mapTag:
+ t := new(types.Map)
+ p.record(t)
+
+ key := p.typ()
+ val := p.typ()
+ *t = *types.NewMap(key, val)
+ return t
+
+ case chanTag:
+ t := new(types.Chan)
+ p.record(t)
+
+ var dir types.ChanDir
+ // tag values must match the constants in cmd/compile/internal/gc/go.go
+ switch d := p.int(); d {
+ case 1 /* Crecv */ :
+ dir = types.RecvOnly
+ case 2 /* Csend */ :
+ dir = types.SendOnly
+ case 3 /* Cboth */ :
+ dir = types.SendRecv
+ default:
+ panic(fmt.Sprintf("unexpected channel dir %d", d))
+ }
+ val := p.typ()
+ *t = *types.NewChan(dir, val)
+ return t
+
+ default:
+ panic(fmt.Sprintf("unexpected type tag %d", i))
+ }
+}
+
+func (p *importer) field() *types.Var {
+ pkg, name := p.fieldName()
+ typ := p.typ()
+
+ anonymous := false
+ if name == "" {
+ // anonymous field - typ must be T or *T and T must be a type name
+ switch typ := deref(typ).(type) {
+ case *types.Basic: // basic types are named types
+ name = typ.Name()
+ case *types.Named:
+ pkg = p.pkgList[0]
+ name = typ.Obj().Name()
+ default:
+ panic("anonymous field expected")
+ }
+ anonymous = true
+ }
+
+ return types.NewField(token.NoPos, pkg, name, typ, anonymous)
+}
+
+func (p *importer) fieldName() (*types.Package, string) {
+ name := p.string()
+ if name == "" {
+ return nil, "" // anonymous field
+ }
+ pkg := p.pkgList[0]
+ if name == "?" || name != "_" && !exported(name) {
+ if name == "?" {
+ name = ""
+ }
+ pkg = p.pkg()
+ }
+ return pkg, name
+}
+
+func (p *importer) paramList() (*types.Tuple, bool) {
+ n := p.int()
+ if n == 0 {
+ return nil, false
+ }
+ // negative length indicates unnamed parameters
+ named := true
+ if n < 0 {
+ n = -n
+ named = false
+ }
+ // n > 0
+ params := make([]*types.Var, n)
+ isddd := false
+ for i := range params {
+ params[i], isddd = p.param(named)
+ }
+ return types.NewTuple(params...), isddd
+}
+
+func (p *importer) param(named bool) (*types.Var, bool) {
+ t := p.typ()
+ td, isddd := t.(*dddSlice)
+ if isddd {
+ t = types.NewSlice(td.elem)
+ }
+
+ var name string
+ if named {
+ name = p.string()
+ if name == "" {
+ panic("expected named parameter")
+ }
+ }
+
+ // read and discard compiler-specific info
+ p.string()
+
+ return types.NewVar(token.NoPos, nil, name, t), isddd
+}
+
+func exported(name string) bool {
+ ch, _ := utf8.DecodeRuneInString(name)
+ return unicode.IsUpper(ch)
+}
+
+func (p *importer) value() constant.Value {
+ switch kind := constant.Kind(p.int()); kind {
+ case falseTag:
+ return constant.MakeBool(false)
+ case trueTag:
+ return constant.MakeBool(true)
+ case int64Tag:
+ return constant.MakeInt64(p.int64())
+ case floatTag:
+ return p.float()
+ case complexTag:
+ re := p.float()
+ im := p.float()
+ return constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
+ case stringTag:
+ return constant.MakeString(p.string())
+ default:
+ panic(fmt.Sprintf("unexpected value kind %d", kind))
+ }
+}
+
+func (p *importer) float() constant.Value {
+ sign := p.int()
+ if sign == 0 {
+ return constant.MakeInt64(0)
+ }
+
+ exp := p.int()
+ mant := []byte(p.string()) // big endian
+
+ // remove leading 0's if any
+ for len(mant) > 0 && mant[0] == 0 {
+ mant = mant[1:]
+ }
+
+ // convert to little endian
+ // TODO(gri) go/constant should have a more direct conversion function
+ // (e.g., once it supports a big.Float based implementation)
+ for i, j := 0, len(mant)-1; i < j; i, j = i+1, j-1 {
+ mant[i], mant[j] = mant[j], mant[i]
+ }
+
+ // adjust exponent (constant.MakeFromBytes creates an integer value,
+ // but mant represents the mantissa bits such that 0.5 <= mant < 1.0)
+ exp -= len(mant) << 3
+ if len(mant) > 0 {
+ for msd := mant[len(mant)-1]; msd&0x80 == 0; msd <<= 1 {
+ exp++
+ }
+ }
+
+ x := constant.MakeFromBytes(mant)
+ switch {
+ case exp < 0:
+ d := constant.Shift(constant.MakeInt64(1), token.SHL, uint(-exp))
+ x = constant.BinaryOp(x, token.QUO, d)
+ case exp > 0:
+ x = constant.Shift(x, token.SHL, uint(exp))
+ }
+
+ if sign < 0 {
+ x = constant.UnaryOp(token.SUB, x, 0)
+ }
+ return x
+}
+
+// ----------------------------------------------------------------------------
+// Low-level decoders
+
+func (p *importer) tagOrIndex() int {
+ if p.debugFormat {
+ p.marker('t')
+ }
+
+ return int(p.rawInt64())
+}
+
+func (p *importer) int() int {
+ return int(p.int64())
+}
+
+func (p *importer) int64() int64 {
+ if p.debugFormat {
+ p.marker('i')
+ }
+
+ return p.rawInt64()
+}
+
+func (p *importer) string() string {
+ if p.debugFormat {
+ p.marker('s')
+ }
+
+ var b []byte
+ if n := int(p.rawInt64()); n > 0 {
+ b = p.data[:n]
+ p.data = p.data[n:]
+ p.read += n
+ }
+ return string(b)
+}
+
+func (p *importer) marker(want byte) {
+ if got := p.data[0]; got != want {
+ panic(fmt.Sprintf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read))
+ }
+ p.data = p.data[1:]
+ p.read++
+
+ pos := p.read
+ if n := int(p.rawInt64()); n != pos {
+ panic(fmt.Sprintf("incorrect position: got %d; want %d", n, pos))
+ }
+}
+
+// rawInt64 should only be used by low-level decoders
+func (p *importer) rawInt64() int64 {
+ i, n := binary.Varint(p.data)
+ p.data = p.data[n:]
+ p.read += n
+ return i
+}
+
+// ----------------------------------------------------------------------------
+// Export format
+
+// Tags. Must be < 0.
+const (
+ // Packages
+ packageTag = -(iota + 1)
+
+ // Types
+ namedTag
+ arrayTag
+ sliceTag
+ dddTag
+ structTag
+ pointerTag
+ signatureTag
+ interfaceTag
+ mapTag
+ chanTag
+
+ // Values
+ falseTag
+ trueTag
+ int64Tag
+ floatTag
+ fractionTag // not used by gc
+ complexTag
+ stringTag
+)
+
+var predeclared = []types.Type{
+ // basic types
+ types.Typ[types.Bool],
+ types.Typ[types.Int],
+ types.Typ[types.Int8],
+ types.Typ[types.Int16],
+ types.Typ[types.Int32],
+ types.Typ[types.Int64],
+ types.Typ[types.Uint],
+ types.Typ[types.Uint8],
+ types.Typ[types.Uint16],
+ types.Typ[types.Uint32],
+ types.Typ[types.Uint64],
+ types.Typ[types.Uintptr],
+ types.Typ[types.Float32],
+ types.Typ[types.Float64],
+ types.Typ[types.Complex64],
+ types.Typ[types.Complex128],
+ types.Typ[types.String],
+
+ // aliases
+ types.Universe.Lookup("byte").Type(),
+ types.Universe.Lookup("rune").Type(),
+
+ // error
+ types.Universe.Lookup("error").Type(),
+
+ // untyped types
+ types.Typ[types.UntypedBool],
+ types.Typ[types.UntypedInt],
+ types.Typ[types.UntypedRune],
+ types.Typ[types.UntypedFloat],
+ types.Typ[types.UntypedComplex],
+ types.Typ[types.UntypedString],
+ types.Typ[types.UntypedNil],
+
+ // package unsafe
+ types.Typ[types.UnsafePointer],
+}
// FindExportData positions the reader r at the beginning of the
// export data section of an underlying GC-created object/archive
// file by reading from it. The reader must be positioned at the
-// start of the file before calling this function.
+// start of the file before calling this function. The hdr result
+// is the string before the export data, either "$$" or "$$B".
//
-func FindExportData(r *bufio.Reader) (err error) {
+func FindExportData(r *bufio.Reader) (hdr string, err error) {
// Read first line to make sure this is an object file.
line, err := r.ReadSlice('\n')
if err != nil {
return
}
+
if string(line) == "!<arch>\n" {
// Archive file. Scan to __.PKGDEF.
var name string
}
// Skip over object header to export data.
- // Begins after first line with $$.
+ // Begins after first line starting with $$.
for line[0] != '$' {
if line, err = r.ReadSlice('\n'); err != nil {
return
}
}
+ hdr = string(line)
return
}
"go/build"
"go/token"
"io"
+ "io/ioutil"
"os"
"path/filepath"
"sort"
}
}()
+ var hdr string
buf := bufio.NewReader(f)
- if err = FindExportData(buf); err != nil {
+ if hdr, err = FindExportData(buf); err != nil {
return
}
- pkg, err = ImportData(packages, filename, id, buf)
+ switch hdr {
+ case "$$\n":
+ return ImportData(packages, filename, id, buf)
+ case "$$B\n":
+ var data []byte
+ data, err = ioutil.ReadAll(buf)
+ if err == nil {
+ _, pkg, err = BImportData(packages, data, path)
+ return
+ }
+ default:
+ err = fmt.Errorf("unknown export data header: %q", hdr)
+ }
return
}
return filepath.Join(dirname, filename[:len(filename)-2]+"o")
}
-// Use the same global imports map for all tests. The effect is
-// as if all tested packages were imported into a single package.
-var imports = make(map[string]*types.Package)
+// TODO(gri) Remove this function once we switched to new export format by default.
+func compileNewExport(t *testing.T, dirname, filename string) string {
+ testenv.MustHaveGoBuild(t)
+ cmd := exec.Command("go", "tool", "compile", "-newexport", filename)
+ cmd.Dir = dirname
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Logf("%s", out)
+ t.Fatalf("go tool compile %s failed: %s", filename, err)
+ }
+ // filename should end with ".go"
+ return filepath.Join(dirname, filename[:len(filename)-2]+"o")
+}
func testPath(t *testing.T, path string) *types.Package {
t0 := time.Now()
- pkg, err := Import(imports, path)
+ pkg, err := Import(make(map[string]*types.Package), path)
if err != nil {
t.Errorf("testPath(%s): %s", path, err)
return nil
return
}
-func TestImport(t *testing.T) {
+func TestImportTestdata(t *testing.T) {
// This package only handles gc export data.
if runtime.Compiler != "gc" {
t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
defer os.Remove(outFn)
}
- nimports := 0
if pkg := testPath(t, "./testdata/exports"); pkg != nil {
- nimports++
- // The package's Imports should include all the types
- // referenced by the exportdata, which may be more than
- // the import statements in the package's source, but
- // fewer than the transitive closure of dependencies.
- want := `[package ast ("go/ast") package token ("go/token") package runtime ("runtime")]`
+ // The package's Imports list must include all packages
+ // explicitly imported by exports.go, plus all packages
+ // referenced indirectly via exported objects in exports.go.
+ // With the textual export format, the list may also include
+ // additional packages that are not strictly required for
+ // import processing alone (they are exported to err "on
+ // the safe side").
+ got := fmt.Sprint(pkg.Imports())
+ for _, want := range []string{"go/ast", "go/token"} {
+ if !strings.Contains(got, want) {
+ t.Errorf(`Package("exports").Imports() = %s, does not contain %s`, got, want)
+ }
+ }
+ }
+}
+
+// TODO(gri) Remove this function once we switched to new export format by default
+// (and update the comment and want list in TestImportTestdata).
+func TestImportTestdataNewExport(t *testing.T) {
+ // This package only handles gc export data.
+ if runtime.Compiler != "gc" {
+ t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+ return
+ }
+
+ if outFn := compileNewExport(t, "testdata", "exports.go"); outFn != "" {
+ defer os.Remove(outFn)
+ }
+
+ if pkg := testPath(t, "./testdata/exports"); pkg != nil {
+ // The package's Imports list must include all packages
+ // explicitly imported by exports.go, plus all packages
+ // referenced indirectly via exported objects in exports.go.
+ want := `[package ast ("go/ast") package token ("go/token")]`
got := fmt.Sprint(pkg.Imports())
if got != want {
t.Errorf(`Package("exports").Imports() = %s, want %s`, got, want)
}
}
- nimports += testDir(t, "", time.Now().Add(maxTime)) // installed packages
+}
+
+func TestImportStdLib(t *testing.T) {
+ skipSpecialPlatforms(t)
+
+ // This package only handles gc export data.
+ if runtime.Compiler != "gc" {
+ t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+ return
+ }
+
+ nimports := testDir(t, "", time.Now().Add(maxTime)) // installed packages
t.Logf("tested %d imports", nimports)
}
importPath := s[0]
objName := s[1]
- pkg, err := Import(imports, importPath)
+ pkg, err := Import(make(map[string]*types.Package), importPath)
if err != nil {
t.Error(err)
continue