func test(t *testing.T, src string, code []cpu.Word) { var ast parser.AST files, err := path.SourceFiles(src) if err != nil { t.Fatal(err) } for i := range files { err = ast.Parse(files[i], 0) if err != nil { t.Fatal(err) } } ar, err := Assemble(&ast, 0) if err != nil { t.Fatal(err) } if len(code) != len(ar.Code) { t.Fatalf("Code size mismatch. Expected %d, have %d\n%04x\n%04x", len(code), len(ar.Code), code, ar.Code) } for i := range code { if code[i] != cpu.Word(ar.Code[i]) { t.Fatalf("Code mismatch at instruction %d:\nWant: %04x\nHave: %04x", i, code, ar.Code) } } }
// findDeps creates a tree of dependencies (import paths) for // the given package. It parses the package source code for this purpose. func findDeps(importpath string, list *[]string) bool { if containsDep(*list, importpath) { return true } // Find source files for the given package. sources, err := path.SourceFiles(importpath) if err != nil { return false } // Parse sources into a partial AST. // We are only interested in the import statements. var ast parser.AST for _, file := range sources { err = ast.Parse(file, parser.ImportsOnly) if err != nil { return false } } // Create a new dependency entry. *list = append(*list, importpath) for _, imp := range ast.Imports { if !findDeps(imp.Path.Value, list) { return false } } return true }
func doTest(t *testing.T, src string, sbin ...cpu.Word) { var ast parser.AST var dbin []cpu.Word buf := bytes.NewBufferString(src) err := ast.Parse(buf, "") if err != nil { t.Fatal(err) } dbin, _, err = Assemble(&ast) if err != nil { t.Fatal(err) } if len(dbin) != len(sbin) { fmt.Printf("%04x\n", dbin) fmt.Printf("%04x\n", sbin) t.Fatalf("Size mismatch. Expect %d, got %d", len(sbin), len(dbin)) } for i := range sbin { if dbin[i] != sbin[i] { fmt.Printf("%04x\n", dbin) fmt.Printf("%04x\n", sbin) t.Fatalf("Code mismatch at %d. Expect %04x, got %04x", i, sbin[i], dbin[i]) } } }
// readSource reads the given file and parses its contents // into the given AST. func readSource(ast *parser.AST, file string) error { fd, err := os.Open(file) if err != nil { return err } defer fd.Close() return ast.Parse(fd, file) }
// parseFunctions resolves function constants and it injects the // necessary function prolog and epilog code. // // What the latter means, is that we analyze the registers being // used. If any of them are registers that are guaranteed to // be preserved across function calls, then we explicitly inject stack // push/pop instructions to save their state. // // If there are any `return` instructions, we replace them with `set pc, $$`. // Where `$$` is a label we generate which points to the function epilog. func parseFunctions(ast *parser.AST) (err error) { list := ast.Functions() for i := range list { if err = parseFuncConst(ast, list[i]); err != nil { return } fixFunctionReturns(ast, list[i]) injectFunctionCode(ast, list[i]) } return }
func Format(in, out string) (err error) { var fout io.WriteCloser var fin io.ReadCloser var ast parser.AST // Open input stream. if in == Stdin { fin = _stdin } else { fin, err = os.Open(in) if err != nil { return } } // Parse source into AST. err = ast.Parse(fin, in) fin.Close() if err != nil { return } if *strip { StripComments(&ast) } // Open output stream. if out == Stdout { fout = _stdout } else { fout, err = os.Create(out) if err != nil { return } defer fout.Close() } // Write source. sw := util.NewSourceWriter(fout, &ast) sw.Tabs = *tabs sw.TabWidth = *tabwidth sw.Comments = !*strip sw.Write() return }
// build builds the given package and its dependencies. func build(importpath string, flags asm.AsmFlags) (err error) { files, _ := path.SourceFiles(importpath) if len(files) == 0 { return nil // No source files } var ast parser.AST for i := range files { err = ast.Parse(files[i], 0) if err != nil { return } } ar, err := asm.Assemble(&ast, flags) if err != nil { return } return writeArchive(ar, importpath) }