Beispiel #1
0
// 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
}
Beispiel #2
0
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
}
Beispiel #3
0
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
}
Beispiel #4
0
// 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
}
Beispiel #5
0
// 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
}
Beispiel #6
0
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
}
Beispiel #7
0
	"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"})