func (p *importer) obj(tag int) { switch tag { case constTag: pos := p.pos() pkg, name := p.qualifiedName() typ := p.typ(nil) val := p.value() p.declare(types.NewConst(pos, pkg, name, typ, val)) case typeTag: _ = p.typ(nil) case varTag: pos := p.pos() pkg, name := p.qualifiedName() typ := p.typ(nil) p.declare(types.NewVar(pos, pkg, name, typ)) case funcTag: pos := p.pos() pkg, name := p.qualifiedName() params, isddd := p.paramList() result, _ := p.paramList() sig := types.NewSignature(nil, params, result, isddd) p.declare(types.NewFunc(pos, pkg, name, sig)) default: panic(fmt.Sprintf("unexpected object tag %d", tag)) } }
// Const = Name [Type] "=" ConstValue . func (p *parser) parseConst(pkg *types.Package) *types.Const { name := p.parseName() var typ types.Type if p.tok == '<' { typ = p.parseType(pkg) } p.expect('=') val, vtyp := p.parseConstValue() if typ == nil { typ = vtyp } return types.NewConst(token.NoPos, pkg, name, typ, val) }
func (p *importer) obj(tag int) { switch tag { case constTag: pos := p.pos() pkg, name := p.qualifiedName() typ := p.typ(nil) val := p.value() p.declare(types.NewConst(pos, pkg, name, typ, val)) case typeTag: p.typ(nil) case varTag: pos := p.pos() pkg, name := p.qualifiedName() typ := p.typ(nil) p.declare(types.NewVar(pos, pkg, name, typ)) case funcTag: pos := p.pos() pkg, name := p.qualifiedName() params, isddd := p.paramList() result, _ := p.paramList() sig := types.NewSignature(nil, params, result, isddd) p.declare(types.NewFunc(pos, pkg, name, sig)) case aliasTag: pos := p.pos() name := p.string() var orig types.Object if pkg, name := p.qualifiedName(); pkg != nil { orig = pkg.Scope().Lookup(name) } // Alias-related code. Keep for now. _ = pos _ = name _ = orig // p.declare(types.NewAlias(pos, p.pkgList[0], name, orig)) default: errorf("unexpected object tag %d", tag) } }
func (p *importer) obj(pkg *types.Package) { var obj types.Object switch tag := p.int(); tag { case constTag: obj = types.NewConst(token.NoPos, pkg, p.string(), p.typ(), p.value()) case typeTag: // type object is added to scope via respective named type _ = p.typ().(*types.Named) return case varTag: obj = types.NewVar(token.NoPos, pkg, p.string(), p.typ()) case funcTag: obj = types.NewFunc(token.NoPos, pkg, p.string(), p.typ().(*types.Signature)) default: panic(fmt.Sprintf("unexpected object tag %d", tag)) } if alt := pkg.Scope().Insert(obj); alt != nil { panic(fmt.Sprintf("%s already declared", alt.Name())) } }
// 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) { p := importer{ imports: imports, data: data, } 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: return p.read, nil, fmt.Errorf("invalid encoding format in export data: got %q; want 'c' or 'd'", format) } // --- generic export data --- 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(nil) 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(nil) p.declare(types.NewVar(token.NoPos, pkg, name, typ)) } // read funcs for i := p.int(); i > 0; i-- { name := p.string() sig := p.typ(nil).(*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(nil).(*types.Named) } // ignore compiler-specific import data // 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 }
// ConstDecl = "const" ExportedName [ Type ] "=" Literal . // Literal = bool_lit | int_lit | float_lit | complex_lit | rune_lit | string_lit . // bool_lit = "true" | "false" . // complex_lit = "(" float_lit "+" float_lit "i" ")" . // rune_lit = "(" int_lit "+" int_lit ")" . // string_lit = `"` { unicode_char } `"` . // func (p *parser) parseConstDecl() { p.expectKeyword("const") pkg, name := p.parseExportedName() var typ0 types.Type if p.tok != '=' { // constant types are never structured - no need for parent type typ0 = p.parseType(nil) } p.expect('=') var typ types.Type var val exact.Value switch p.tok { case scanner.Ident: // bool_lit if p.lit != "true" && p.lit != "false" { p.error("expected true or false") } typ = types.Typ[types.UntypedBool] val = exact.MakeBool(p.lit == "true") p.next() case '-', scanner.Int: // int_lit typ, val = p.parseNumber() case '(': // complex_lit or rune_lit p.next() if p.tok == scanner.Char { p.next() p.expect('+') typ = types.Typ[types.UntypedRune] _, val = p.parseNumber() p.expect(')') break } _, re := p.parseNumber() p.expect('+') _, im := p.parseNumber() p.expectKeyword("i") p.expect(')') typ = types.Typ[types.UntypedComplex] val = exact.BinaryOp(re, token.ADD, exact.MakeImag(im)) case scanner.Char: // rune_lit typ = types.Typ[types.UntypedRune] val = exact.MakeFromLiteral(p.lit, token.CHAR, 0) p.next() case scanner.String: // string_lit typ = types.Typ[types.UntypedString] val = exact.MakeFromLiteral(p.lit, token.STRING, 0) p.next() default: p.errorf("expected literal got %s", scanner.TokenString(p.tok)) } if typ0 == nil { typ0 = typ } pkg.Scope().Insert(types.NewConst(token.NoPos, pkg, name, typ0, val)) }
// CreateTestMainPackage creates and returns a synthetic "main" // package that runs all the tests of the supplied packages, similar // to the one that would be created by the 'go test' tool. // // It returns nil if the program contains no tests. // func (prog *Program) CreateTestMainPackage(pkgs ...*Package) *Package { pkgs, tests, benchmarks, examples := FindTests(pkgs) if len(pkgs) == 0 { return nil } testmain := &Package{ Prog: prog, Members: make(map[string]Member), values: make(map[types.Object]Value), Pkg: types.NewPackage("test$main", "main"), } // Build package's init function. init := &Function{ name: "init", Signature: new(types.Signature), Synthetic: "package initializer", Pkg: testmain, Prog: prog, } init.startBody() if testMainStartBodyHook != nil { testMainStartBodyHook(init) } // Initialize packages to test. var pkgpaths []string for _, pkg := range pkgs { var v Call v.Call.Value = pkg.init v.setType(types.NewTuple()) init.emit(&v) pkgpaths = append(pkgpaths, pkg.Pkg.Path()) } sort.Strings(pkgpaths) init.emit(new(Return)) init.finishBody() testmain.init = init testmain.Pkg.MarkComplete() testmain.Members[init.name] = init // For debugging convenience, define an unexported const // that enumerates the packages. packagesConst := types.NewConst(token.NoPos, testmain.Pkg, "packages", tString, exact.MakeString(strings.Join(pkgpaths, " "))) memberFromObject(testmain, packagesConst, nil) // Create main *types.Func and *ssa.Function mainFunc := types.NewFunc(token.NoPos, testmain.Pkg, "main", new(types.Signature)) memberFromObject(testmain, mainFunc, nil) main := testmain.Func("main") main.Synthetic = "test main function" main.startBody() if testMainStartBodyHook != nil { testMainStartBodyHook(main) } if testingPkg := prog.ImportedPackage("testing"); testingPkg != nil { testingMain := testingPkg.Func("Main") testingMainParams := testingMain.Signature.Params() // The generated code is as if compiled from this: // // func main() { // match := func(_, _ string) (bool, error) { return true, nil } // tests := []testing.InternalTest{{"TestFoo", TestFoo}, ...} // benchmarks := []testing.InternalBenchmark{...} // examples := []testing.InternalExample{...} // testing.Main(match, tests, benchmarks, examples) // } matcher := &Function{ name: "matcher", Signature: testingMainParams.At(0).Type().(*types.Signature), Synthetic: "test matcher predicate", parent: main, Pkg: testmain, Prog: prog, } main.AnonFuncs = append(main.AnonFuncs, matcher) matcher.startBody() matcher.emit(&Return{Results: []Value{vTrue, nilConst(types.Universe.Lookup("error").Type())}}) matcher.finishBody() // Emit call: testing.Main(matcher, tests, benchmarks, examples). var c Call c.Call.Value = testingMain c.Call.Args = []Value{ matcher, testMainSlice(main, tests, testingMainParams.At(1).Type()), testMainSlice(main, benchmarks, testingMainParams.At(2).Type()), testMainSlice(main, examples, testingMainParams.At(3).Type()), } emitTailCall(main, &c) } else { // The program does not import "testing", but FindTests // returned non-nil, which must mean there were Examples // but no Tests or Benchmarks. // We'll simply call them from testmain.main; this will // ensure they don't panic, but will not check any // "Output:" comments. for _, eg := range examples { var c Call c.Call.Value = eg c.setType(types.NewTuple()) main.emit(&c) } main.emit(&Return{}) main.currentBlock = nil } main.finishBody() testmain.Members["main"] = main if prog.mode&PrintPackages != 0 { printMu.Lock() testmain.WriteTo(os.Stdout) printMu.Unlock() } if prog.mode&SanityCheckFunctions != 0 { sanityCheckPackage(testmain) } prog.packages[testmain.Pkg] = testmain return testmain }