// loadInclude tries to load the given reference as an include file. // Parses it into the supplied AST and verifies that it contains what // we are looking for. func loadInclude(ast *parser.AST, includes []string, r *parser.Name) (err error) { var file string name := r.Data + ".dasm" walker := func(f string, info os.FileInfo, e error) (err error) { if info.IsDir() { return } parts := strings.Split(f, string(filepath.Separator)) for i := range parts { if len(parts[i]) == 0 { continue } if parts[i][0] == '_' { return nil } } fb := parts[len(parts)-1] if fb == name { file, err = filepath.Abs(f) if err != nil { return } return io.EOF // Signal walker to stop. } return nil } for i := range includes { filepath.Walk(includes[i], walker) if len(file) > 0 { break } } if len(file) == 0 { return parser.NewParseError(ast.Files[r.File()], r.Line(), r.Col(), "Undefined reference: %q", r.Data) } if err = readSource(ast, file); err != nil { return } // Test if the code actually contains the label we are looking for. if !includeHasLabel(ast, file, r.Data) { return parser.NewParseError(ast.Files[r.File()], r.Line(), r.Col(), "Undefined reference: %q. Include file was found, but "+ "it did not define the desired label.", r.Data) } // This new file may hold its own include requirements. return resolveIncludes(ast, includes) }
// resolveIncludes finds references to undefined labels. // It then tries to find the code for these labels in the supplied // include paths. Files should be defined as '<labelname>.dasm'. func resolveIncludes(ast *parser.AST, includes []string) (err error) { var labels []*parser.Label var refs []*parser.Name var consts []*parser.Name var funcs []*parser.Function FindLabels(ast.Root.Children(), &labels) FindReferences(ast.Root.Children(), &refs) FindConstants(ast.Root.Children(), &consts) FindFunctions(ast.Root.Children(), &funcs) refs = findUndefinedRefs(refs, consts, labels, funcs) if len(refs) == 0 { // No undefined references. We're done here. return } if len(includes) == 0 { // We have unresolved references, but no places to look // for their implementation. This constitutes a booboo. return parser.NewParseError(ast.Files[refs[0].File()], refs[0].Line(), refs[0].Col(), "Undefined reference: %q", refs[0].Data) } for i := range refs { if err = loadInclude(ast, includes, refs[i]); err != nil { return } } return }