func (v *Context) parseFile(path string, module *ast.Module) { // Read sourcefile, err := lexer.NewSourcefile(path) if err != nil { setupErr("%s", err.Error()) } // Lex sourcefile.Tokens = lexer.Lex(sourcefile) // Parse parsedFile, deps := parser.Parse(sourcefile) module.Trees = append(module.Trees, parsedFile) // Add dependencies to parse array for _, dep := range deps { depname := ast.NewModuleName(dep) v.modulesToRead = append(v.modulesToRead, depname) v.depGraph.AddDependency(module.Name, depname) if _, _, err := v.findModuleDir(depname.ToPath()); err != nil { log.Errorln("main", "%s [%s:%d:%d] Couldn't find module `%s`", util.Red("error:"), dep.Where().Filename, dep.Where().StartLine, dep.Where().EndLine, depname.String()) log.Errorln("main", "%s", sourcefile.MarkSpan(dep.Where())) os.Exit(1) } } }
func (v *NameMap) TypeOfNameNode(name *NameNode) NodeType { mod := v typ := NODE_MODULE for _, modName := range name.Modules { if typ == NODE_MODULE { typ = mod.typeOf(modName) if typ == NODE_MODULE { mod = mod.module(modName) if mod == nil { return NODE_UNKOWN } } } else { startPos := modName.Where.Start() log.Errorln("constructor", "[%s:%d:%d] Invalid use of `::`. `%s` is not a module", startPos.Filename, startPos.Line, startPos.Char, modName.Value) log.Error("constructor", v.tree.Source.MarkSpan(modName.Where)) } } if typ == NODE_ENUM { return NODE_ENUM_MEMBER } else if typ == NODE_STRUCT { return NODE_STRUCT_STATIC } typ = mod.typeOf(name.Name) if typ == NODE_UNKOWN { startPos := name.Name.Where.Start() log.Errorln("constructor", "[%s:%d:%d] Undeclared name `%s`", startPos.Filename, startPos.Line, startPos.Char, name.Name.Value) log.Error("constructor", v.tree.Source.MarkSpan(name.Name.Where)) } return typ }
func (v *RecursiveDefinitionCheck) Visit(s *SemanticAnalyzer, n parser.Node) { var typ parser.Type if typeDecl, ok := n.(*parser.TypeDecl); ok { actualType := typeDecl.NamedType.ActualType() switch actualType.(type) { case *parser.EnumType: typ = actualType.(*parser.EnumType) case *parser.StructType: typ = actualType.(*parser.StructType) // TODO: Check tuple types once we add named types for everything default: return } } if ok, path := isTypeRecursive(typ); ok { s.Err(n, "Encountered recursive type definition") log.Errorln("semantic", "Path taken:") for _, typ := range path { log.Error("semantic", typ.TypeName()) log.Error("semantic", " <- ") } log.Error("semantic", "%s\n\n", typ.TypeName()) } }
func (v *lexer) errPos(pos Position, err string, stuff ...interface{}) { log.Errorln("lexer", util.TEXT_RED+util.TEXT_BOLD+"error:"+util.TEXT_RESET+" [%s:%d:%d] %s", pos.Filename, pos.Line, pos.Char, fmt.Sprintf(err, stuff...)) log.Error("lexer", v.input.MarkPos(pos)) os.Exit(1) }
func ExtractTypeVariable(pattern Type, value Type) map[string]Type { /* Pointer($T), Pointer(int) -> {$T: int} Arbitrary depth type => Stack containing breadth first traversal */ res := make(map[string]Type) var ( ps []Type vs []Type ) ps = append(ps, pattern) vs = append(vs, value) for i := 0; i < len(ps); i++ { ppart := ps[i] vpart := vs[i] log.Debugln("resovle", "\nP = `%s`, V = `%s`", ppart.TypeName(), vpart.TypeName()) ps = AddChildren(ppart, ps) vs = AddChildren(vpart, vs) if vari, ok := ppart.(ParameterType); ok { log.Debugln("resolve", "P was variable (Name: %s)", vari.Name) res[vari.Name] = vpart continue } switch ppart.(type) { case PrimitiveType, *NamedType: if !ppart.Equals(vpart) { log.Errorln("resolve", "%s != %s", ppart.TypeName(), vpart.TypeName()) panic("Part of type did not match pattern") } default: if reflect.TypeOf(ppart) != reflect.TypeOf(vpart) { log.Errorln("resolve", "%T != %T", ppart, vpart) panic("Part of type did not match pattern") } } } return res }
func (v *Constructor) errPos(pos lexer.Position, err string, stuff ...interface{}) { log.Errorln("constructor", util.TEXT_RED+util.TEXT_BOLD+"Constructor error:"+util.TEXT_RESET+" [%s:%d:%d] %s", pos.Filename, pos.Line, pos.Char, fmt.Sprintf(err, stuff...)) log.Error("constructor", v.tree.Source.MarkPos(pos)) os.Exit(util.EXIT_FAILURE_CONSTRUCTOR) }
func (v *SemanticAnalyzer) Err(thing parser.Locatable, err string, stuff ...interface{}) { pos := thing.Pos() log.Error("semantic", util.TEXT_RED+util.TEXT_BOLD+"error:"+util.TEXT_RESET+" [%s:%d:%d] %s\n", pos.Filename, pos.Line, pos.Char, fmt.Sprintf(err, stuff...)) log.Errorln("semantic", v.Module.File.MarkPos(pos)) v.shouldExit = true }
func (v *NameMap) TypeOf(name LocatedString) NodeType { typ := v.typeOf(name) if typ == NODE_UNKOWN { startPos := name.Where.Start() log.Errorln("constructor", "[%s:%d:%d] Undeclared name `%s`", startPos.Filename, startPos.Line, startPos.Char, name.Value) log.Error("constructor", v.tree.Source.MarkSpan(name.Where)) } return typ }
func (v *Constructor) errSpan(pos lexer.Span, err string, stuff ...interface{}) { log.Errorln("constructor", util.TEXT_RED+util.TEXT_BOLD+"error:"+util.TEXT_RESET+" [%s:%d:%d] %s", pos.Filename, pos.StartLine, pos.StartChar, fmt.Sprintf(err, stuff...)) log.Error("constructor", v.curTree.Source.MarkSpan(pos)) os.Exit(util.EXIT_FAILURE_CONSTRUCTOR) }
func (v *NameMap) Module(name LocatedString) *NameMap { mod := v.module(name) if mod == nil { startPos := name.Where.Start() log.Errorln("constructor", "[%s:%d:%d] Unknown module `%s`", startPos.Filename, startPos.Line, startPos.Char, name.Value) log.Error("constructor", v.tree.Source.MarkSpan(name.Where)) } return mod }
func (v *parser) errPosSpecific(pos lexer.Position, err string, stuff ...interface{}) { v.dumpRules() log.Errorln("parser", util.TEXT_RED+util.TEXT_BOLD+"error:"+util.TEXT_RESET+" [%s:%d:%d] %s", pos.Filename, pos.Line, pos.Char, fmt.Sprintf(err, stuff...)) log.Error("parser", v.input.MarkPos(pos)) os.Exit(util.EXIT_FAILURE_PARSE) }
func (v *parser) errTokenSpecific(tok *lexer.Token, err string, stuff ...interface{}) { v.dumpRules() log.Errorln("parser", util.TEXT_RED+util.TEXT_BOLD+"error:"+util.TEXT_RESET+" [%s:%d:%d] %s", tok.Where.Filename, tok.Where.StartLine, tok.Where.StartChar, fmt.Sprintf(err, stuff...)) log.Error("parser", v.input.MarkSpan(tok.Where)) os.Exit(util.EXIT_FAILURE_PARSE) }
func (v *RecursiveDefinitionCheck) Visit(s *SemanticAnalyzer, n ast.Node) { if typeDecl, ok := n.(*ast.TypeDecl); ok { typ := typeDecl.NamedType if ok, path := isTypeRecursive(typ); ok { s.Err(n, "Encountered recursive type definition") log.Errorln("semantic", "Path taken:") for _, typ := range path { log.Error("semantic", typ.TypeName()) log.Error("semantic", " <- ") } log.Error("semantic", "%s\n\n", typ.TypeName()) } } }
func (v *Context) parseFiles() { if strings.HasSuffix(v.Input, ".ark") { // Handle the special case of a single .ark file modname := &ast.ModuleName{Parts: []string{"__main"}} module := &ast.Module{ Name: modname, Dirpath: "", } v.moduleLookup.Create(modname).Module = module v.parseFile(v.Input, module) v.modules = append(v.modules, module) } else { if strings.ContainsAny(v.Input, `\/. `) { setupErr("Invalid module name: %s", v.Input) } modname := &ast.ModuleName{Parts: strings.Split(v.Input, "::")} v.modulesToRead = append(v.modulesToRead, modname) } log.Timed("read/lex/parse phase", "", func() { for i := 0; i < len(v.modulesToRead); i++ { modname := v. modulesToRead[i] // Skip already loaded modules if _, err := v.moduleLookup.Get(modname); err == nil { continue } fi, dirpath, err := v.findModuleDir(modname.ToPath()) if err != nil { setupErr("Couldn't find module `%s`: %s", modname, err) } if !fi.IsDir() { setupErr("Expected path `%s` to be directory, was file.", dirpath) } module := &ast.Module{ Name: modname, Dirpath: dirpath, } v.moduleLookup.Create(modname).Module = module // Check module children childFiles, err := ioutil.ReadDir(dirpath) if err != nil { setupErr("%s", err.Error()) } for _, childFile := range childFiles { if strings.HasPrefix(childFile.Name(), ".") || !strings.HasSuffix(childFile.Name(), ".ark") { continue } actualFile := filepath.Join(dirpath, childFile.Name()) v.parseFile(actualFile, module) } v.modules = append(v.modules, module) } }) // Check for cyclic dependencies (in modules) log.Timed("cyclic dependency check", "", func() { errs := v.depGraph.DetectCycles() if len(errs) > 0 { log.Error("main", "%s: Encountered cyclic dependency between: ", util.Bold(util.Red("error"))) for _, cycle := range errs { log.Error("main", "%s", cycle) } log.Errorln("main", "") os.Exit(util.EXIT_FAILURE_SETUP) } }) // construction log.Timed("construction phase", "", func() { for _, module := range v.modules { ast.Construct(module, v.moduleLookup) } }) }
func parseFiles(inputs []string) ([]*parser.Module, *parser.ModuleLookup) { if len(inputs) != 1 { setupErr("Please specify only one file or module to build") } var modulesToRead []*parser.ModuleName var modules []*parser.Module moduleLookup := parser.NewModuleLookup("") depGraph := parser.NewDependencyGraph() input := inputs[0] if strings.HasSuffix(input, ".ark") { // Handle the special case of a single .ark file modname := &parser.ModuleName{Parts: []string{"__main"}} module := &parser.Module{ Name: modname, Dirpath: "", } moduleLookup.Create(modname).Module = module // Read sourcefile, err := lexer.NewSourcefile(input) if err != nil { setupErr("%s", err.Error()) } // Lex sourcefile.Tokens = lexer.Lex(sourcefile) // Parse parsedFile, deps := parser.Parse(sourcefile) module.Trees = append(module.Trees, parsedFile) // Add dependencies to parse array for _, dep := range deps { depname := parser.NewModuleName(dep) modulesToRead = append(modulesToRead, depname) depGraph.AddDependency(modname, depname) } modules = append(modules, module) } else { if strings.ContainsAny(input, `\/. `) { setupErr("Invalid module name: %s", input) } modname := &parser.ModuleName{Parts: strings.Split(input, "::")} modulesToRead = append(modulesToRead, modname) } log.Timed("read/lex/parse phase", "", func() { for i := 0; i < len(modulesToRead); i++ { modname := modulesToRead[i] // Skip already loaded modules if _, err := moduleLookup.Get(modname); err == nil { continue } fi, dirpath := findModuleDir(*buildSearchpaths, modname.ToPath()) if fi == nil { setupErr("Couldn't find module `%s`", modname) } if !fi.IsDir() { setupErr("Expected path `%s` to be directory, was file.", dirpath) } module := &parser.Module{ Name: modname, Dirpath: dirpath, } moduleLookup.Create(modname).Module = module // Check module children childFiles, err := ioutil.ReadDir(dirpath) if err != nil { setupErr("%s", err.Error()) } for _, childFile := range childFiles { if strings.HasPrefix(childFile.Name(), ".") || !strings.HasSuffix(childFile.Name(), ".ark") { continue } actualFile := filepath.Join(dirpath, childFile.Name()) // Read sourcefile, err := lexer.NewSourcefile(actualFile) if err != nil { setupErr("%s", err.Error()) } // Lex sourcefile.Tokens = lexer.Lex(sourcefile) // Parse parsedFile, deps := parser.Parse(sourcefile) module.Trees = append(module.Trees, parsedFile) // Add dependencies to parse array for _, dep := range deps { depname := parser.NewModuleName(dep) modulesToRead = append(modulesToRead, depname) depGraph.AddDependency(modname, depname) } } modules = append(modules, module) } }) // Check for cyclic dependencies (in modules) log.Timed("cyclic dependency check", "", func() { errs := depGraph.DetectCycles() if len(errs) > 0 { log.Errorln("main", "error: Encountered cyclic dependecies:") for _, cycle := range errs { log.Errorln("main", "%s", cycle) } os.Exit(util.EXIT_FAILURE_SETUP) } }) // construction log.Timed("construction phase", "", func() { for _, module := range modules { parser.Construct(module, moduleLookup) } }) return modules, moduleLookup }
func parseFiles(inputs []string) ([]*parser.Module, *parser.ModuleLookup) { var modulesToRead []*parser.ModuleName for _, input := range inputs { if strings.ContainsAny(input, `\/. `) { setupErr("Invalid module name: %s", input) } modname := &parser.ModuleName{Parts: strings.Split(input, "::")} modulesToRead = append(modulesToRead, modname) } var parsedFiles []*parser.ParseTree moduleLookup := parser.NewModuleLookup("") depGraph := parser.NewDependencyGraph() log.Timed("read/lex/parse phase", "", func() { for i := 0; i < len(modulesToRead); i++ { modname := modulesToRead[i] actualFile := filepath.Join(*buildBasedir, modname.ToPath()) fi, err := os.Stat(actualFile + ".ark") shouldBeDir := false if os.IsNotExist(err) { fi, err = os.Stat(actualFile) shouldBeDir = true } if err != nil { setupErr("%s", err.Error()) } if !fi.IsDir() && shouldBeDir { setupErr("Expected file `%s` to be directory, was file.", actualFile) } // Check lookup ll := moduleLookup.Create(modname) if ll.Tree == nil { if shouldBeDir { // Setup dummy parse tree ll.Tree = &parser.ParseTree{} ll.Tree.Name = modname // Setup dummy module ll.Module = &parser.Module{} ll.Module.Path = actualFile ll.Module.Name = modname ll.Module.GlobalScope = parser.NewGlobalScope() // Check module children childFiles, err := ioutil.ReadDir(actualFile) if err != nil { setupErr("%s", err.Error()) } for _, childFile := range childFiles { if strings.HasPrefix(childFile.Name(), ".") { continue } if childFile.IsDir() || strings.HasSuffix(childFile.Name(), ".ark") { childmodname := parser.JoinModuleName(modname, strings.TrimSuffix(childFile.Name(), ".ark")) modulesToRead = append(modulesToRead, childmodname) ll.Module.GlobalScope.UsedModules[childmodname.Last()] = moduleLookup.Create(childmodname) } } } else { // Read sourcefile, err := lexer.NewSourcefile(actualFile + ".ark") if err != nil { setupErr("%s", err.Error()) } // Lex sourcefile.Tokens = lexer.Lex(sourcefile) // Parse parsedFile, deps := parser.Parse(sourcefile) parsedFile.Name = modname parsedFiles = append(parsedFiles, parsedFile) ll.Tree = parsedFile // Add dependencies to parse array for _, dep := range deps { depname := parser.NewModuleName(dep) modulesToRead = append(modulesToRead, depname) depGraph.AddDependency(modname, depname) } } } } }) // Check for cyclic dependencies (in modules) log.Timed("cyclic dependency check", "", func() { errs := depGraph.DetectCycles() if len(errs) > 0 { log.Errorln("main", "error: Encountered cyclic dependecies:") for _, cycle := range errs { log.Errorln("main", "%s", cycle) } os.Exit(util.EXIT_FAILURE_SETUP) } }) hasMainFunc := false // construction var constructedModules []*parser.Module log.Timed("construction phase", "", func() { for _, file := range parsedFiles { mod := parser.Construct(file, moduleLookup) constructedModules = append(constructedModules, mod) // not terribly efficient, but it's best // to catch out earlier on if we have // a main function or not rather than // figuring out at the codegen phase?? // maybe?? // TODO FIXME MAKEPRETTY for _, node := range mod.Nodes { switch node := node.(type) { case *parser.FunctionDecl: if node.Function.Name == "main" { hasMainFunc = true break } default: } } } }) // and here we check if we should // bother continuing any further... if !hasMainFunc { log.Error("main", util.Red("error: ")+"main function not found\n") os.Exit(1) } return constructedModules, moduleLookup }
func MapNames(nodes []ParseNode, tree *ParseTree, modules map[string]*ParseTree, parent *NameMap) *NameMap { nameMap := &NameMap{} nameMap.parent = parent nameMap.tree = tree nameMap.types = make(map[string]NodeType) nameMap.modules = make(map[string]*NameMap) previousLocation := make(map[string]lexer.Span) shouldExit := false var cModule *NameMap if parent == nil { for i := 0; i < len(_PrimitiveType_index); i++ { typ := PrimitiveType(i) name := typ.TypeName() nameMap.types[name] = NODE_PRIMITIVE previousLocation[name] = lexer.Span{Filename: "_builtin"} } cModule = &NameMap{ types: make(map[string]NodeType), modules: make(map[string]*NameMap), } cModule.types["uint"] = NODE_TYPE cModule.types["int"] = NODE_TYPE nameMap.types["C"] = NODE_MODULE nameMap.modules["C"] = cModule } else { cModule = parent.module(LocatedString{Value: "C"}) } for _, node := range nodes { var name LocatedString var typ NodeType switch node.(type) { case *FunctionDeclNode: fdn := node.(*FunctionDeclNode) name, typ = fdn.Header.Name, NODE_FUNCTION if fdn.Header.IsMethod { continue // TODO is this right? } if fdn.Header.Attrs().Contains("c") || fdn.Attrs().Contains("c") { _, occupied := nameMap.modules["C"].types[name.Value] if occupied { startPos := name.Where.Start() log.Errorln("constructor", "[%s:%d:%d] Found duplicate definition of `%s`", tree.Source.Path, startPos.Line, startPos.Char, name.Value) log.Error("constructor", tree.Source.MarkSpan(name.Where)) prevPos := previousLocation[name.Value] log.Errorln("constructor", "[%s:%d:%d] Previous declaration was here", tree.Source.Path, prevPos.StartLine, prevPos.StartChar) log.Error("constructor", tree.Source.MarkSpan(prevPos)) shouldExit = true } cModule.types[name.Value] = typ previousLocation[name.Value] = name.Where continue } case *VarDeclNode: vd := node.(*VarDeclNode) name, typ = vd.Name, NODE_VARIABLE case *TypeDeclNode: vd := node.(*TypeDeclNode) name, typ = vd.Name, NODE_TYPE switch vd.Type.(type) { case *EnumTypeNode: typ = NODE_ENUM case *StructTypeNode: typ = NODE_STRUCT } case *UseDeclNode: udn := node.(*UseDeclNode) baseModuleName := udn.Module.Name if len(udn.Module.Modules) > 0 { baseModuleName = udn.Module.Modules[0] } mod, ok := modules[baseModuleName.Value] if !ok { startPos := baseModuleName.Where.Start() log.Errorln("constructor", "[%s:%d:%d] Unknown module `%s`", tree.Source.Path, startPos.Line, startPos.Char, baseModuleName.Value) log.Error("constructor", tree.Source.MarkSpan(baseModuleName.Where)) shouldExit = true } nameMap.modules[baseModuleName.Value] = MapNames(mod.Nodes, mod, modules, nil) modNameMap := nameMap.modules[baseModuleName.Value] for _, mod := range udn.Module.Modules { nextMap, ok := modNameMap.modules[mod.Value] if !ok { startPos := mod.Where.Start() log.Errorln("constructor", "[%s:%d:%d] Unknown module `%s`", tree.Source.Path, startPos.Line, startPos.Char, mod.Value) log.Error("constructor", tree.Source.MarkSpan(mod.Where)) shouldExit = true break } modNameMap = nextMap } name, typ = udn.Module.Name, NODE_MODULE default: continue } _, occupied := nameMap.types[name.Value] if occupied { startPos := name.Where.Start() log.Errorln("constructor", "[%s:%d:%d] Found duplicate definition of `%s`", tree.Source.Path, startPos.Line, startPos.Char, name.Value) log.Error("constructor", tree.Source.MarkSpan(name.Where)) prevPos := previousLocation[name.Value] log.Errorln("constructor", "[%s:%d:%d] Previous declaration was here", tree.Source.Path, prevPos.StartLine, prevPos.StartChar) log.Error("constructor", tree.Source.MarkSpan(prevPos)) shouldExit = true } nameMap.types[name.Value] = typ previousLocation[name.Value] = name.Where } if shouldExit { os.Exit(util.EXIT_FAILURE_CONSTRUCTOR) } return nameMap }