func run(t *testing.T, dir, input string) bool { fmt.Printf("Input: %s\n", input) var inputs []string for _, i := range strings.Split(input, " ") { inputs = append(inputs, dir+i) } b := ssa.NewBuilder(ssa.SanityCheckFunctions, ssa.GorootLoader, nil) files, err := ssa.ParseFiles(b.Prog.Files, ".", inputs...) if err != nil { t.Errorf("ssa.ParseFiles(%s) failed: %s", inputs, err.Error()) return false } // Print a helpful hint if we don't make it to the end. var hint string defer func() { if hint != "" { fmt.Println(red("FAIL")) fmt.Println(hint) } else { fmt.Println(green("PASS")) } }() hint = fmt.Sprintf("To dump SSA representation, run:\n%% go run exp/ssa/ssadump.go -build=CFP %s\n", input) mainpkg, err := b.CreatePackage("main", files) if err != nil { t.Errorf("ssa.Builder.CreatePackage(%s) failed: %s", inputs, err.Error()) return false } b.BuildPackage(mainpkg) b = nil // discard Builder hint = fmt.Sprintf("To trace execution, run:\n%% go run exp/ssa/ssadump.go -build=C -run --interp=T %s\n", input) if exitCode := interp.Interpret(mainpkg, 0, inputs[0], []string{}); exitCode != 0 { t.Errorf("interp.Interpret(%s) exited with code %d, want zero", inputs, exitCode) return false } hint = "" // call off the hounds return true }
func main() { flag.Parse() args := flag.Args() // TODO(adonovan): perhaps we need a more extensible option // API than a bitset, e.g. a struct with a sane zero value? var mode ssa.BuilderMode for _, c := range *buildFlag { switch c { case 'P': mode |= ssa.LogPackages case 'F': mode |= ssa.LogFunctions case 'S': mode |= ssa.LogSource case 'C': mode |= ssa.SanityCheckFunctions case 'N': mode |= ssa.NaiveForm case 'G': mode |= ssa.UseGCImporter default: log.Fatalf("Unknown -build option: '%c'.", c) } } var interpMode interp.Mode for _, c := range *interpFlag { switch c { case 'T': interpMode |= interp.EnableTracing case 'R': interpMode |= interp.DisableRecover default: log.Fatalf("Unknown -interp option: '%c'.", c) } } if len(args) == 0 { fmt.Fprint(os.Stderr, usage) os.Exit(1) } // Treat all leading consecutive "*.go" arguments as a single package. // // TODO(gri): make it a typechecker error for there to be // duplicate (e.g.) main functions in the same package. var gofiles []string for len(args) > 0 && strings.HasSuffix(args[0], ".go") { gofiles = append(gofiles, args[0]) args = args[1:] } if gofiles == nil { log.Fatal("No *.go source files specified.") } // Profiling support. if *cpuprofile != "" { f, err := os.Create(*cpuprofile) if err != nil { log.Fatal(err) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } // TODO(adonovan): permit naming a package directly instead of // a list of .go files. // TODO(adonovan/gri): the cascade of errors is confusing due // to reentrant control flow. Disable for now and re-think. var errh func(error) // errh = func(err error) { fmt.Println(err.Error()) } b := ssa.NewBuilder(mode, ssa.GorootLoader, errh) files, err := ssa.ParseFiles(b.Prog.Files, ".", gofiles...) if err != nil { log.Fatalf(err.Error()) } mainpkg, err := b.CreatePackage("main", files) if err != nil { log.Fatalf(err.Error()) } b.BuildPackage(mainpkg) b = nil // discard Builder if *runFlag { interp.Interpret(mainpkg, interpMode, gofiles[0], args) } }