Example #1
0
// Parse parses the ast for this file and returns a ParsedFile
func (w *Weave) ParseAST(fname string) *ast.File {
	var err error

	fset := token.NewFileSet()
	af, err := parser.ParseFile(fset, fname, nil, 0)
	if err != nil {
		w.flog.Println(err)
	}

	loadcfg := loader.Config{}
	loadcfg.CreateFromFilenames(fname)

	info := types.Info{
		Types: make(map[ast.Expr]types.TypeAndValue),
		Defs:  make(map[*ast.Ident]types.Object),
	}

	var conf types.Config
	_, err = conf.Check(af.Name.Name, fset, []*ast.File{af}, &info)
	if err != nil {
		if w.warnAST {
			w.flog.Println(err)
		}
	}

	return af
}
Example #2
0
func TestLoad_ParseError_AllowErrors(t *testing.T) {
	var conf loader.Config
	conf.AllowErrors = true
	conf.CreateFromFilenames("badpkg", "testdata/badpkgdecl.go")

	prog, err := conf.Load()
	if err != nil {
		t.Errorf("Load failed unexpectedly: %v", err)
	}
	if prog == nil {
		t.Fatalf("Load returned a nil Program")
	}
	if got, want := created(prog), "badpkg"; got != want {
		t.Errorf("Created = %s, want %s", got, want)
	}

	badpkg := prog.Created[0]
	if len(badpkg.Files) != 1 {
		t.Errorf("badpkg has %d files, want 1", len(badpkg.Files))
	}
	wantErr := filepath.Join("testdata", "badpkgdecl.go") + ":1:34: expected 'package', found 'EOF'"
	if !hasError(badpkg.Errors, wantErr) {
		t.Errorf("badpkg.Errors = %v, want %s", badpkg.Errors, wantErr)
	}
}
Example #3
0
// createProgram returns a program containing packages specified.
func createProgram(packages ...string) (*loader.Program, error) {
	var conf loader.Config

	for _, name := range packages {
		conf.CreateFromFilenames(name, getFileNames(name)...)
	}
	return conf.Load()
}
Example #4
0
func TestCreateUnnamedPackage(t *testing.T) {
	var conf loader.Config
	conf.CreateFromFilenames("")
	prog, err := conf.Load()
	if err != nil {
		t.Fatalf("Load failed: %v", err)
	}
	if got, want := fmt.Sprint(prog.InitialPackages()), "[(unnamed)]"; got != want {
		t.Errorf("InitialPackages = %s, want %s", got, want)
	}
}
Example #5
0
func TestLoad_MissingFileInCreatedPackage_AllowErrors(t *testing.T) {
	conf := loader.Config{AllowErrors: true}
	conf.CreateFromFilenames("", "missing.go")

	prog, err := conf.Load()
	if err != nil {
		t.Errorf("Load failed: %v", err)
	}
	if got, want := fmt.Sprint(prog.InitialPackages()), "[(unnamed)]"; got != want {
		t.Fatalf("InitialPackages = %s, want %s", got, want)
	}
}
Example #6
0
func TestMultipleQueries(t *testing.T) {
	// Loader
	var buildContext = build.Default
	buildContext.GOPATH = "testdata"
	conf := loader.Config{Build: &buildContext}
	filename := "testdata/src/main/multi.go"
	conf.CreateFromFilenames("", filename)
	iprog, err := conf.Load()
	if err != nil {
		t.Fatalf("Load failed: %s", err)
	}

	// Oracle
	o, err := oracle.New(iprog, nil, true)
	if err != nil {
		t.Fatalf("oracle.New failed: %s", err)
	}

	// QueryPos
	pos := filename + ":#54,#58"
	qpos, err := oracle.ParseQueryPos(iprog, pos, true)
	if err != nil {
		t.Fatalf("oracle.ParseQueryPos(%q) failed: %s", pos, err)
	}
	// SSA is built and we have the QueryPos.
	// Release the other ASTs and type info to the GC.
	iprog = nil

	// Run different query modes on same scope and selection.
	out := new(bytes.Buffer)
	for _, mode := range [...]string{"callers", "describe", "freevars"} {
		res, err := o.Query(mode, qpos)
		if err != nil {
			t.Errorf("(*oracle.Oracle).Query(%q) failed: %s", pos, err)
		}
		WriteResult(out, res)
	}
	want := `multi.f is called from these 1 sites:
	static function call from multi.main

function call (or conversion) of type ()

Free identifiers:
var x int

`
	if got := out.String(); got != want {
		t.Errorf("Query output differs; want <<%s>>, got <<%s>>\n", want, got)
	}
}
Example #7
0
func TestLoad_FromSource_Success(t *testing.T) {
	var conf loader.Config
	conf.CreateFromFilenames("P", "testdata/a.go", "testdata/b.go")

	prog, err := conf.Load()
	if err != nil {
		t.Errorf("Load failed unexpectedly: %v", err)
	}
	if prog == nil {
		t.Fatalf("Load returned a nil Program")
	}
	if got, want := created(prog), "P"; got != want {
		t.Errorf("Created = %s, want %s", got, want)
	}
}
Example #8
0
// This example creates and type-checks a single package (without tests)
// from a list of filenames, and loads all of its dependencies.
func ExampleConfig_CreateFromFilenames() {
	var conf loader.Config
	filename := filepath.Join(runtime.GOROOT(), "src/container/heap/heap.go")
	conf.CreateFromFilenames("container/heap", filename)
	prog, err := conf.Load()
	if err != nil {
		log.Fatal(err)
	}

	printProgram(prog)
	// Output:
	// created: [container/heap]
	// imported: []
	// initial: [container/heap]
	// all: [container/heap sort]
}
Example #9
0
// CreateTestMainPackage should return nil if there were no tests.
func TestNullTestmainPackage(t *testing.T) {
	var conf loader.Config
	conf.CreateFromFilenames("", "testdata/b_test.go")
	iprog, err := conf.Load()
	if err != nil {
		t.Fatalf("CreatePackages failed: %s", err)
	}
	prog := ssautil.CreateProgram(iprog, ssa.SanityCheckFunctions)
	mainPkg := prog.Package(iprog.Created[0].Pkg)
	if mainPkg.Func("main") != nil {
		t.Fatalf("unexpected main function")
	}
	if prog.CreateTestMainPackage(mainPkg) != nil {
		t.Fatalf("CreateTestMainPackage returned non-nil")
	}
}
Example #10
0
func TestLoad_ParseError(t *testing.T) {
	var conf loader.Config
	conf.CreateFromFilenames("badpkg", "testdata/badpkgdecl.go")

	const wantErr = "couldn't load packages due to errors: badpkg"

	prog, err := conf.Load()
	if err == nil {
		t.Errorf("Load succeeded unexpectedly, want %q", wantErr)
	} else if err.Error() != wantErr {
		t.Errorf("Load failed with wrong error %q, want %q", err, wantErr)
	}
	if prog != nil {
		t.Errorf("Load unexpectedly returned a Program")
	}
}
Example #11
0
func TestLoad_MissingFileInCreatedPackage(t *testing.T) {
	var conf loader.Config
	conf.CreateFromFilenames("", "missing.go")

	const wantErr = "couldn't load packages due to errors: (unnamed)"

	prog, err := conf.Load()
	if prog != nil {
		t.Errorf("Load unexpectedly returned a Program")
	}
	if err == nil {
		t.Fatalf("Load succeeded unexpectedly, want %q", wantErr)
	}
	if err.Error() != wantErr {
		t.Fatalf("Load failed with wrong error %q, want %q", err, wantErr)
	}
}
Example #12
0
// This example creates and type-checks a single package (without tests)
// from a list of filenames, and loads all of its dependencies.
// (The input files are actually only a small part of the math/cmplx package.)
func ExampleConfig_CreateFromFilenames() {
	var conf loader.Config
	conf.CreateFromFilenames("math/cmplx",
		filepath.Join(runtime.GOROOT(), "src/math/cmplx/abs.go"),
		filepath.Join(runtime.GOROOT(), "src/math/cmplx/sin.go"))
	prog, err := conf.Load()
	if err != nil {
		log.Fatal(err)
	}

	printProgram(prog)
	// Output:
	// created: [math/cmplx]
	// imported: []
	// initial: [math/cmplx]
	// all: [math math/cmplx unsafe]
}
Example #13
0
File: guru.go Project: tsandall/opa
// importQueryPackage finds the package P containing the
// query position and tells conf to import it.
// It returns the package's path.
func importQueryPackage(pos string, conf *loader.Config) (string, error) {
	fqpos, err := fastQueryPos(conf.Build, pos)
	if err != nil {
		return "", err // bad query
	}
	filename := fqpos.fset.File(fqpos.start).Name()

	_, importPath, err := guessImportPath(filename, conf.Build)
	if err != nil {
		// Can't find GOPATH dir.
		// Treat the query file as its own package.
		importPath = "command-line-arguments"
		conf.CreateFromFilenames(importPath, filename)
	} else {
		// Check that it's possible to load the queried package.
		// (e.g. guru tests contain different 'package' decls in same dir.)
		// Keep consistent with logic in loader/util.go!
		cfg2 := *conf.Build
		cfg2.CgoEnabled = false
		bp, err := cfg2.Import(importPath, "", 0)
		if err != nil {
			return "", err // no files for package
		}

		switch pkgContainsFile(bp, filename) {
		case 'T':
			conf.ImportWithTests(importPath)
		case 'X':
			conf.ImportWithTests(importPath)
			importPath += "_test" // for TypeCheckFuncBodies
		case 'G':
			conf.Import(importPath)
		default:
			// This happens for ad-hoc packages like
			// $GOROOT/src/net/http/triv.go.
			return "", fmt.Errorf("package %q doesn't contain file %s",
				importPath, filename)
		}
	}

	conf.TypeCheckFuncBodies = func(p string) bool { return p == importPath }

	return importPath, nil
}
Example #14
0
func Test(t *testing.T) {
	switch runtime.GOOS {
	case "windows":
		t.Skipf("skipping test on %q (no /usr/bin/diff)", runtime.GOOS)
	}

	conf := loader.Config{
		Fset:       token.NewFileSet(),
		ParserMode: parser.ParseComments,
	}

	// Each entry is a single-file package.
	// (Multi-file packages aren't interesting for this test.)
	// Order matters: each non-template package is processed using
	// the preceding template package.
	for _, filename := range []string{
		"testdata/A.template",
		"testdata/A1.go",
		"testdata/A2.go",

		"testdata/B.template",
		"testdata/B1.go",

		"testdata/C.template",
		"testdata/C1.go",

		"testdata/D.template",
		"testdata/D1.go",

		"testdata/E.template",
		"testdata/E1.go",

		"testdata/F.template",
		"testdata/F1.go",

		"testdata/G.template",
		"testdata/G1.go",

		"testdata/H.template",
		"testdata/H1.go",

		"testdata/bad_type.template",
		"testdata/no_before.template",
		"testdata/no_after_return.template",
		"testdata/type_mismatch.template",
		"testdata/expr_type_mismatch.template",
	} {
		pkgname := strings.TrimSuffix(filepath.Base(filename), ".go")
		conf.CreateFromFilenames(pkgname, filename)
	}
	iprog, err := conf.Load()
	if err != nil {
		t.Fatal(err)
	}

	var xform *eg.Transformer
	for _, info := range iprog.Created {
		file := info.Files[0]
		filename := iprog.Fset.File(file.Pos()).Name() // foo.go

		if strings.HasSuffix(filename, "template") {
			// a new template
			shouldFail, _ := info.Pkg.Scope().Lookup("shouldFail").(*types.Const)
			xform, err = eg.NewTransformer(iprog.Fset, info, *verboseFlag)
			if err != nil {
				if shouldFail == nil {
					t.Errorf("NewTransformer(%s): %s", filename, err)
				} else if want := exact.StringVal(shouldFail.Val()); !strings.Contains(err.Error(), want) {
					t.Errorf("NewTransformer(%s): got error %q, want error %q", filename, err, want)
				}
			} else if shouldFail != nil {
				t.Errorf("NewTransformer(%s) succeeded unexpectedly; want error %q",
					filename, shouldFail.Val())
			}
			continue
		}

		if xform == nil {
			t.Errorf("%s: no previous template", filename)
			continue
		}

		// apply previous template to this package
		n := xform.Transform(&info.Info, info.Pkg, file)
		if n == 0 {
			t.Errorf("%s: no matches", filename)
			continue
		}

		got := filename + "t"       // foo.got
		golden := filename + "lden" // foo.golden

		// Write actual output to foo.got.
		if err := eg.WriteAST(iprog.Fset, got, file); err != nil {
			t.Error(err)
		}
		defer os.Remove(got)

		// Compare foo.got with foo.golden.
		var cmd *exec.Cmd
		switch runtime.GOOS {
		case "plan9":
			cmd = exec.Command("/bin/diff", "-c", golden, got)
		default:
			cmd = exec.Command("/usr/bin/diff", "-u", golden, got)
		}
		buf := new(bytes.Buffer)
		cmd.Stdout = buf
		cmd.Stderr = os.Stderr
		if err := cmd.Run(); err != nil {
			t.Errorf("eg tests for %s failed: %s.\n%s\n", filename, err, buf)

			if *updateFlag {
				t.Logf("Updating %s...", golden)
				if err := exec.Command("/bin/cp", got, golden).Run(); err != nil {
					t.Errorf("Update failed: %s", err)
				}
			}
		}
	}
}
Example #15
0
func main() {
	var ssaDump = flag.Bool("ssa", false, "dump ssa representation")
	var debug = flag.Bool("debug", false, "include debug comments in assembly")
	var trace = flag.Bool("trace", false, "trace of assembly generation to stdout")
	var printSpills = flag.Bool("spills", false, "print each register spill")
	var disableOptimizations = flag.Bool("N", false, "disable optimizations")
	var output = flag.String("o", "", "Go assembly output file")
	var f = flag.String("f", "", "input file with function definitions")
	var flagFn = flag.String("fn", "", "comma separated list of function names")
	var flagOutFn = flag.String("outfn", "", "comma separated list of output function names")
	var goprotofile = flag.String("goprotofile", "", "output file for SIMD function prototype(s)")

	flag.Parse()

	optimize := !*disableOptimizations

	file := os.ExpandEnv("$GOFILE")
	log.SetFlags(log.Lshortfile)
	if *f != "" {
		file = *f
	}
	if *flagFn == "" {
		log.Fatalf("Error no function name(s) provided")
	}
	spills := os.ExpandEnv("$GENSIMDSPILLS")
	if spills != "" {
		*printSpills = spills == "1"
	}
	fnnames := strings.Split(*flagFn, ",")
	outFns := []string{}
	if *flagOutFn == "" {
		for _, fn := range fnnames {
			outFns = append(outFns, "gensimd_"+fn)
		}
	} else {
		outFns = strings.Split(*flagOutFn, ",")

	}
	if len(fnnames) != len(outFns) {
		log.Fatalf("Error # fns (%v) doesn't match # outfns (%v)\n", len(fnnames), len(outFns))
	}
	for i := range fnnames {
		fnnames[i] = strings.TrimSpace(fnnames[i])
		outFns[i] = strings.TrimSpace(outFns[i])
	}

	parsed, err := simd.ParseFile(file)
	if err != nil {
		msg := "Error parsing file \"%v\", error msg \"%v\"\n"
		log.Fatalf(msg, file, err)
	}

	filePkgName := parsed.Pkg.Name()
	filePkgPath := parsed.Pkg.Path()
	conf := loader.Config{Build: &build.Default}

	// Choose types.Sizes from conf.Build.
	var wordSize int64 = 8
	switch conf.Build.GOARCH {
	case "386", "arm":
		panic("SIMD invalid for x86 and arm")
	}
	conf.TypeChecker.Sizes = &types.StdSizes{
		MaxAlign: 8,
		WordSize: wordSize,
	}

	// Use the initial file from the command line/$GOFILE.
	conf.CreateFromFilenames(filePath(file), file)

	// Load, parse and type-check
	iprog, err := conf.Load()
	if err != nil {
		log.Fatalf("conf.Load, error msg \"%v\"", err)
	}

	// Create and build SSA-form program representation.
	builderMode := ssa.SanityCheckFunctions | ssa.GlobalDebug
	if *ssaDump {
		builderMode = ssa.PrintFunctions
	}
	prog := ssautil.CreateProgram(iprog, builderMode)
	if prog == nil {
		log.Fatalf("Couldn't create ssa representation")
	}

	// Build and display only the initial packages (and synthetic wrappers)
	for _, info := range iprog.InitialPackages() {
		prog.Package(info.Pkg).Build()
	}

	assembly := codegen.AssemblyFilePreamble()
	goprotos := ""
	protoPkgName := ""
	protoImports := ""
	foundpkg := false
	for _, pkg := range prog.AllPackages() {
		if pkg.Pkg.Path() == filePkgPath && pkg.Pkg.Name() == filePkgName {
			foundpkg = true
			for i := range fnnames {
				fnname := fnnames[i]
				outfn := outFns[i]
				if fn := pkg.Func(fnname); fn == nil {
					msg := "Func \"%v\" not found in package \"%v\""
					log.Fatalf(msg, fnname, filePkgName)
				} else {
					dbg := *debug
					fn, err := codegen.CreateFunction(fn, outfn, dbg, *trace, optimize)
					fn.PrintSpills = *printSpills
					if err != nil {
						msg := "codegen error msg \"%v\""
						log.Fatalf(msg, err)
					}
					if asm, err := fn.GoAssembly(); err != nil {
						msg := "Error creating fn asm: \"%v\"\n"
						msgp := "Error creating fn asm, %v, \"%v\"\n"
						position := fn.Position(err.Pos)
						if position.IsValid() {
							log.Fatalf(msgp, position, err.Err)
						} else {
							log.Fatalf(msg, err.Err)
						}
					} else {
						if *output == "" {
							fmt.Println(asm)
						} else {
							if *goprotofile != "" {
								pkg, imports, proto := fn.GoProto()
								goprotos += proto
								if protoPkgName == "" {
									protoPkgName = pkg + "\n"
								}
								if protoImports == "" {
									protoImports = imports
								}
							}
							assembly += asm
						}
					}
				}
			}
		}
	}

	if !foundpkg {
		msg := "Error didn't find package, \"%v\"\n"
		panic(fmt.Sprintf(msg, filePkgName))
	}

	writeFile(*output, assembly)
	if *goprotofile != "" {
		writeFile(*goprotofile, protoPkgName+"\n"+protoImports+"\n"+goprotos)
	}
}
Example #16
0
func doMain() error {
	flag.Parse()
	args := flag.Args()

	if *helpFlag {
		fmt.Fprint(os.Stderr, eg.Help)
		os.Exit(2)
	}

	if *templateFlag == "" {
		return fmt.Errorf("no -t template.go file specified")
	}

	conf := loader.Config{
		Fset:          token.NewFileSet(),
		ParserMode:    parser.ParseComments,
		SourceImports: true,
	}

	// The first Created package is the template.
	if err := conf.CreateFromFilenames("template", *templateFlag); err != nil {
		return err //  e.g. "foo.go:1: syntax error"
	}

	if len(args) == 0 {
		fmt.Fprint(os.Stderr, usage)
		os.Exit(1)
	}

	if _, err := conf.FromArgs(args, true); err != nil {
		return err
	}

	// Load, parse and type-check the whole program.
	iprog, err := conf.Load()
	if err != nil {
		return err
	}

	// Analyze the template.
	template := iprog.Created[0]
	xform, err := eg.NewTransformer(iprog.Fset, template, *verboseFlag)
	if err != nil {
		return err
	}

	// Apply it to the input packages.
	var pkgs []*loader.PackageInfo
	if *transitiveFlag {
		for _, info := range iprog.AllPackages {
			pkgs = append(pkgs, info)
		}
	} else {
		pkgs = iprog.InitialPackages()
	}
	var hadErrors bool
	for _, pkg := range pkgs {
		if pkg == template {
			continue
		}
		for _, file := range pkg.Files {
			n := xform.Transform(&pkg.Info, pkg.Pkg, file)
			if n == 0 {
				continue
			}
			filename := iprog.Fset.File(file.Pos()).Name()
			fmt.Fprintf(os.Stderr, "=== %s (%d matches)\n", filename, n)
			if *writeFlag {
				// Run the before-edit command (e.g. "chmod +w",  "checkout") if any.
				if *beforeeditFlag != "" {
					args := strings.Fields(*beforeeditFlag)
					// Replace "{}" with the filename, like find(1).
					for i := range args {
						if i > 0 {
							args[i] = strings.Replace(args[i], "{}", filename, -1)
						}
					}
					cmd := exec.Command(args[0], args[1:]...)
					cmd.Stdout = os.Stdout
					cmd.Stderr = os.Stderr
					if err := cmd.Run(); err != nil {
						fmt.Fprintf(os.Stderr, "Warning: edit hook %q failed (%s)\n",
							args, err)
					}
				}
				if err := eg.WriteAST(iprog.Fset, filename, file); err != nil {
					fmt.Fprintf(os.Stderr, "eg: %s\n", err)
					hadErrors = true
				}
			} else {
				printer.Fprint(os.Stdout, iprog.Fset, file)
			}
		}
	}
	if hadErrors {
		os.Exit(1)
	}
	return nil
}