コード例 #1
0
ファイル: main.go プロジェクト: kiljacken/ark
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)
		}
	}
}
コード例 #2
0
ファイル: name_pass.go プロジェクト: dansawkins/ark
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
}
コード例 #3
0
ファイル: recursive.go プロジェクト: dansawkins/ark
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())
	}

}
コード例 #4
0
ファイル: lexer.go プロジェクト: IanMurray/ark
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)
}
コード例 #5
0
ファイル: resolve.go プロジェクト: IanMurray/ark
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
}
コード例 #6
0
ファイル: constructor.go プロジェクト: gitter-badger/ark
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)
}
コード例 #7
0
ファイル: semantic.go プロジェクト: dansawkins/ark
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
}
コード例 #8
0
ファイル: name_pass.go プロジェクト: dansawkins/ark
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
}
コード例 #9
0
ファイル: constructor.go プロジェクト: kiljacken/ark
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)
}
コード例 #10
0
ファイル: name_pass.go プロジェクト: dansawkins/ark
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
}
コード例 #11
0
ファイル: parser.go プロジェクト: IanMurray/ark
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)
}
コード例 #12
0
ファイル: parser.go プロジェクト: IanMurray/ark
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)
}
コード例 #13
0
ファイル: recursive.go プロジェクト: kiljacken/ark
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())
		}
	}
}
コード例 #14
0
ファイル: main.go プロジェクト: kiljacken/ark
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)
		}
	})
}
コード例 #15
0
ファイル: main.go プロジェクト: vnev/ark
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
}
コード例 #16
0
ファイル: main.go プロジェクト: IanMurray/ark
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
}
コード例 #17
0
ファイル: name_pass.go プロジェクト: dansawkins/ark
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
}