// Name = identifier | "?" | QualifiedName . // // If materializePkg is set, the returned package is guaranteed to be set. // For fully qualified names, the returned package may be a fake package // (without name, scope, and not in the p.imports map), created for the // sole purpose of providing a package path. Fake packages are created // when the package id is not found in the p.imports map; in that case // we cannot create a real package because we don't have a package name. // For non-qualified names, the returned package is the imported package. // func (p *parser) parseName(materializePkg bool) (pkg *types.Package, name string) { switch p.tok { case scanner.Ident: pkg = p.imports[p.id] name = p.lit p.next() case '?': // anonymous pkg = p.imports[p.id] p.next() case '@': // exported name prefixed with package path var id string id, name = p.parseQualifiedName() if materializePkg { // we don't have a package name - if the package // doesn't exist yet, create a fake package instead pkg = p.getPkg(id, "") if pkg == nil { pkg = types.NewPackage(id, "") } } default: p.error("name expected") } return }
func (imp *importer) newPackageInfo(path string) *PackageInfo { pkg := types.NewPackage(path, "") if imp.conf.PackageCreated != nil { imp.conf.PackageCreated(pkg) } info := &PackageInfo{ Pkg: pkg, Info: types.Info{ Types: make(map[ast.Expr]types.TypeAndValue), Defs: make(map[*ast.Ident]types.Object), Uses: make(map[*ast.Ident]types.Object), Implicits: make(map[ast.Node]types.Object), Scopes: make(map[ast.Node]*types.Scope), Selections: make(map[*ast.SelectorExpr]*types.Selection), }, errorFunc: imp.conf.TypeChecker.Error, } // Copy the types.Config so we can vary it across PackageInfos. tc := imp.conf.TypeChecker tc.IgnoreFuncBodies = false if f := imp.conf.TypeCheckFuncBodies; f != nil { tc.IgnoreFuncBodies = !f(path) } tc.Import = func(_ map[string]*types.Package, to string) (*types.Package, error) { return imp.doImport(info, to) } tc.Error = info.appendError // appendError wraps the user's Error function info.checker = types.NewChecker(&tc, imp.conf.fset(), pkg, &info.Info) imp.typecheckerMu.Lock() imp.prog.AllPackages[pkg] = info imp.typecheckerMu.Unlock() return info }
func (p *importer) pkg() *types.Package { // if the package was seen before, i is its index (>= 0) i := p.int() 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() // 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 }
// getPkg returns the package for a given id. If the package is // not found but we have a package name, create the package and // add it to the p.imports map. // func (p *parser) getPkg(id, name string) *types.Package { // package unsafe is not in the imports map - handle explicitly if id == "unsafe" { return types.Unsafe } pkg := p.imports[id] if pkg == nil && name != "" { pkg = types.NewPackage(id, name) p.imports[id] = pkg } return pkg }
// 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), Object: 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.Object.Path()) } sort.Strings(pkgpaths) init.emit(new(Return)) init.finishBody() testmain.init = init testmain.Object.MarkComplete() testmain.Members[init.name] = init // For debugging convenience, define an unexported const // that enumerates the packages. packagesConst := types.NewConst(token.NoPos, testmain.Object, "packages", tString, exact.MakeString(strings.Join(pkgpaths, " "))) memberFromObject(testmain, packagesConst, nil) // Create main *types.Func and *ssa.Function mainFunc := types.NewFunc(token.NoPos, testmain.Object, "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.Object] = testmain return testmain }
func (in *interp) interpretLine(l line) error { pkgname := fmt.Sprintf("input%05d", in.pkgnum) in.pkgnum++ pkg := types.NewPackage(pkgname, pkgname) scope := pkg.Scope() for _, imppkg := range in.imports { obj := types.NewPkgName(token.NoPos, pkg, imppkg.Name(), imppkg) scope.Insert(obj) } in.augmentPackageScope(pkg) var tv types.TypeAndValue if l.declName == "" && !l.isStmt { var err error tv, err = types.Eval(l.line, pkg, scope) if err != nil { return err } } var code bytes.Buffer fmt.Fprintf(&code, "package %s", pkgname) code.WriteString("\n\nimport __fmt__ \"fmt\"\n") code.WriteString("import __os__ \"os\"\n") for _, pkg := range in.imports { fmt.Fprintf(&code, "import %q\n", pkg.Path()) } if l.declName != "" { code.WriteString(l.line) } else if !l.isStmt && tv.IsValue() { var typs []types.Type if tuple, ok := tv.Type.(*types.Tuple); ok { typs = make([]types.Type, tuple.Len()) for i := range typs { typs[i] = tuple.At(i).Type() } } else { typs = []types.Type{tv.Type} } if len(l.assigns) == 2 && tv.HasOk() { typs = append(typs, types.Typ[types.Bool]) } if len(l.assigns) != 0 && len(l.assigns) != len(typs) { return errors.New("return value mismatch") } code.WriteString("var ") for i := range typs { if i != 0 { code.WriteString(", ") } if len(l.assigns) != 0 && l.assigns[i] != "" { if _, ok := in.scope[l.assigns[i]]; ok { fmt.Fprintf(&code, "__llgoiV%d", i) } else { code.WriteString(l.assigns[i]) } } else { fmt.Fprintf(&code, "__llgoiV%d", i) } } fmt.Fprintf(&code, " = %s\n\n", l.line) code.WriteString("func init() {\n\t") for i, t := range typs { var varname, prefix string if len(l.assigns) != 0 && l.assigns[i] != "" { if _, ok := in.scope[l.assigns[i]]; ok { fmt.Fprintf(&code, "\t%s = __llgoiV%d\n", l.assigns[i], i) } varname = l.assigns[i] prefix = l.assigns[i] } else { varname = fmt.Sprintf("__llgoiV%d", i) prefix = fmt.Sprintf("#%d", i) } if _, ok := t.Underlying().(*types.Interface); ok { fmt.Fprintf(&code, "\t__fmt__.Printf(\"%s %s (%%T) = %%+v\\n\", %s, %s)\n", prefix, t.String(), varname, varname) } else { fmt.Fprintf(&code, "\t__fmt__.Printf(\"%s %s = %%+v\\n\", %s)\n", prefix, t.String(), varname) } } code.WriteString("}") } else { if len(l.assigns) != 0 { return errors.New("return value mismatch") } fmt.Fprintf(&code, "func init() {\n\t%s}", l.line) } copts := in.copts copts.PackageCreated = in.augmentPackageScope copts.DisableUnusedImportCheck = true pkg, err := in.loadSourcePackageFromCode(code.String(), pkgname, copts) if err != nil { return err } in.imports = append(in.imports, pkg) for _, assign := range l.assigns { if assign != "" { if _, ok := in.scope[assign]; !ok { in.scope[assign] = pkg.Scope().Lookup(assign) } } } if l.declName != "" { in.scope[l.declName] = pkg.Scope().Lookup(l.declName) } return nil }
"reflect" "unsafe" "llvm.org/llgo/third_party/gotools/go/ssa" "llvm.org/llgo/third_party/gotools/go/types" ) type opaqueType struct { types.Type name string } func (t *opaqueType) String() string { return t.name } // A bogus "reflect" type-checker package. Shared across interpreters. var reflectTypesPackage = types.NewPackage("reflect", "reflect") // rtype is the concrete type the interpreter uses to implement the // reflect.Type interface. // // type rtype <opaque> var rtypeType = makeNamedType("rtype", &opaqueType{nil, "rtype"}) // error is an (interpreted) named type whose underlying type is string. // The interpreter uses it for all implementations of the built-in error // interface that it creates. // We put it in the "reflect" package for expedience. // // type error string var errorType = makeNamedType("error", &opaqueType{nil, "error"})