// 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 }
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) } }
// 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() }
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) } }
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) } }
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) } }
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) } }
// 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] }
// 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") } }
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") } }
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) } }
// 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] }
// 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 }
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) } } } } }
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) } }
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 }