Пример #1
0
func build(files []string, outputFile string, cg string, outputType LLVMCodegen.OutputType, optLevel int) {
	constructedModules, _ := parseFiles(files)

	// resolve
	log.Timed("resolve phase", "", func() {
		for _, module := range constructedModules {
			res := &parser.Resolver{Module: module}
			vis := parser.NewASTVisitor(res)
			vis.VisitModule(module)
		}
	})

	// type inference
	log.Timed("inference phase", "", func() {
		for _, module := range constructedModules {
			inf := &parser.TypeInferer{Module: module}
			inf.Infer()

			// Dump AST
			log.Debugln("main", "AST of module `%s`:", module.Name)
			for _, node := range module.Nodes {
				log.Debugln("main", "%s", node.String())
			}
			log.Debugln("main", "")
		}
	})

	// semantic analysis
	log.Timed("semantic analysis phase", "", func() {
		for _, module := range constructedModules {
			sem := semantic.NewSemanticAnalyzer(module, *buildOwnership, *ignoreUnused)
			vis := parser.NewASTVisitor(sem)
			vis.VisitModule(module)
			sem.Finalize()
		}
	})

	// codegen
	if cg != "none" {
		var gen codegen.Codegen

		switch cg {
		case "llvm":
			gen = &LLVMCodegen.Codegen{
				OutputName: outputFile,
				OutputType: outputType,
				OptLevel:   optLevel,
			}
		default:
			log.Error("main", util.Red("error: ")+"Invalid backend choice `"+cg+"`")
			os.Exit(1)
		}

		log.Timed("codegen phase", "", func() {
			gen.Generate(constructedModules)
		})
	}

}
Пример #2
0
Файл: binary.go Проект: vnev/ark
func (v *Codegen) createBinary() {
	if v.OutputType == OUTPUT_LLVM_IR {
		for _, mod := range v.input {
			log.Timed("creating ir", mod.Name.String(), func() {
				v.createIR(mod)
			})
		}
		return
	} else if v.OutputType == OUTPUT_ASSEMBLY {
		for _, mod := range v.input {
			log.Timed("creating assembly", mod.Name.String(), func() {
				v.createObjectOrAssembly(mod, llvm.AssemblyFile)
			})
		}
		return
	}

	linkArgs := append(v.LinkerArgs, "-fno-PIE", "-nodefaultlibs", "-lc", "-lm")

	objFiles := []string{}

	for _, mod := range v.input {
		log.Timed("creating object", mod.Name.String(), func() {
			objName := v.createObjectOrAssembly(mod, llvm.ObjectFile)
			objFiles = append(objFiles, objName)
			linkArgs = append(linkArgs, objName)
			for _, lib := range mod.LinkedLibraries {
				linkArgs = append(linkArgs, fmt.Sprintf("-l%s", lib))
			}
		})
	}

	if v.OutputType == OUTPUT_OBJECT {
		return
	}

	if v.OutputName == "" {
		panic("OutputName is empty")
	}

	linkArgs = append(linkArgs, "-o", v.OutputName)

	if v.Linker == "" {
		v.Linker = "cc"
	}

	log.Timed("linking", "", func() {
		log.Verboseln("codegen", "%s %v", v.Linker, linkArgs)

		cmd := exec.Command(v.Linker, linkArgs...)
		if out, err := cmd.CombinedOutput(); err != nil {
			v.err("failed to link object files: `%s`\n%s", err.Error(), string(out))
		}
	})

	for _, objFile := range objFiles {
		os.Remove(objFile)
	}
}
Пример #3
0
func Construct(module *Module, modules *ModuleLookup) {
	module.Parts = make(map[string]*Submodule)
	con := &Constructor{
		modules: modules,
		module:  module,
	}

	log.Timed("constructing module", module.Name.String(), func() {
		for _, tree := range con.module.Trees {
			log.Timed("constructing submodule", tree.Source.Name, func() {
				con.constructSubmodule(tree)
			})
		}
	})
}
Пример #4
0
func Resolve(mod *Module, mods *ModuleLookup) {
	if mod.resolved {
		return
	}
	mod.resolved = true

	res := &Resolver{
		modules: mods,
		module:  mod,
		cModule: &Module{
			Name:    &ModuleName{Parts: []string{"C"}},
			Parts:   make(map[string]*Submodule),
			Dirpath: "", // not really a path for this module
		},
	}

	res.cModule.ModScope = NewCScope(res.cModule)

	res.curScope = NewGlobalScope(mod)
	mod.ModScope = res.curScope

	// add a C module here which will contain all of the c bindings and what
	// not to keep everything separate
	mod.ModScope.UsedModules["C"] = res.cModule

	res.ResolveUsedModules()
	log.Timed("resolving module", mod.Name.String(), func() {
		res.ResolveTopLevelDecls()
		res.ResolveDescent()
	})
	res.module.ModScope.Dump(0)
}
Пример #5
0
func parseFiles(files []string) ([]*parser.Module, map[string]*parser.Module) {
	// read source files
	var sourcefiles []*lexer.Sourcefile
	log.Timed("reading sourcefiles", func() {
		for _, file := range files {
			sourcefile, err := lexer.NewSourcefile(file)
			if err != nil {
				setupErr("%s", err.Error())
			}
			sourcefiles = append(sourcefiles, sourcefile)
		}
	})

	// lexing
	log.Timed("lexing phase", func() {
		for _, file := range sourcefiles {
			file.Tokens = lexer.Lex(file)
		}
	})

	// parsing
	var parsedFiles []*parser.ParseTree
	parsedFileMap := make(map[string]*parser.ParseTree)
	log.Timed("parsing phase", func() {
		for _, file := range sourcefiles {
			parsedFile := parser.Parse(file)
			parsedFiles = append(parsedFiles, parsedFile)
			parsedFileMap[parsedFile.Source.Name] = parsedFile
		}
	})

	// construction
	var constructedModules []*parser.Module
	modules := make(map[string]*parser.Module)
	log.Timed("construction phase", func() {
		for _, file := range parsedFiles {
			constructedModules = append(constructedModules, parser.Construct(file, parsedFileMap, modules))
		}
	})

	return constructedModules, modules
}
Пример #6
0
func SemCheck(module *ast.Module, ignoreUnused bool) {
	checks := []SemanticCheck{
		&AttributeCheck{},
		&UnreachableCheck{},
		&BreakAndNextCheck{},
		&DeprecatedCheck{},
		&RecursiveDefinitionCheck{},
		&TypeCheck{},
		&ImmutableAssignCheck{},
		&UseBeforeDeclareCheck{},
		&MiscCheck{},
		&ReferenceCheck{},
	}

	if !ignoreUnused {
		checks = append(checks, &UnusedCheck{})
	}

	for _, check := range checks {
		log.Timed("analysis pass", check.Name(), func() {
			for _, submod := range module.Parts {
				log.Timed("checking submodule", module.Name.String()+"/"+submod.File.Name, func() {
					res := &SemanticAnalyzer{}
					res.shouldExit = false
					res.Submodule = submod
					res.Check = check

					res.Init()

					vis := ast.NewASTVisitor(res)
					vis.VisitSubmodule(submod)

					res.Finalize()
				})

			}
		})
	}
}
Пример #7
0
func Parse(input *lexer.Sourcefile) (*ParseTree, []*NameNode) {
	p := &parser{
		input:            input,
		binOpPrecedences: newBinOpPrecedenceMap(),
		tree:             &ParseTree{Source: input},
	}

	log.Timed("parsing", input.Name, func() {
		p.parse()
	})

	return p.tree, p.deps
}
Пример #8
0
func Lex(input *Sourcefile) []*Token {
	v := &lexer{
		input:    input,
		startPos: 0,
		endPos:   0,
		curPos:   Position{Filename: input.Name, Line: 1, Char: 1},
		tokStart: Position{Filename: input.Name, Line: 1, Char: 1},
	}

	log.Timed("lexing", input.Name, func() {
		v.lex()
	})

	return v.input.Tokens
}
Пример #9
0
func Construct(tree *ParseTree, modules *ModuleLookup) *Module {
	c := &Constructor{
		tree: tree,
		module: &Module{
			Nodes: make([]Node, 0),
			File:  tree.Source,
			Path:  tree.Source.Path,
			Name:  tree.Name,
		},
		scope: NewGlobalScope(),
	}
	c.module.GlobalScope = c.scope
	c.modules = modules
	modules.Create(tree.Name).Module = c.module

	// add a C module here which will contain
	// all of the c bindings and what not to
	// keep everything separate
	cModule := &Module{
		Nodes:       make([]Node, 0),
		Path:        "", // not really a path for this module
		Name:        &ModuleName{Parts: []string{"C"}},
		GlobalScope: NewCScope(),
	}
	c.module.GlobalScope.UsedModules["C"] = &ModuleLookup{
		Name:     "C",
		Module:   cModule,
		Children: make(map[string]*ModuleLookup),
	}

	log.Timed("constructing", tree.Source.Name, func() {
		c.construct()
	})

	return c.module
}
Пример #10
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
}
Пример #11
0
Файл: main.go Проект: vnev/ark
func build(files []string, outputFile string, cg string, outputType LLVMCodegen.OutputType, optLevel int) {
	constructedModules, moduleLookup := parseFiles(files)

	// resolve

	hasMainFunc := false
	log.Timed("resolve phase", "", func() {
		for _, module := range constructedModules {
			parser.Resolve(module, moduleLookup)

			// Use module scope to check for main function
			mainIdent := module.ModScope.GetIdent(parser.UnresolvedName{Name: "main"})
			if mainIdent != nil && mainIdent.Type == parser.IDENT_FUNCTION && mainIdent.Public {
				hasMainFunc = true
			}
		}
	})

	// 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)
	}

	// type inference
	log.Timed("inference phase", "", func() {
		for _, module := range constructedModules {
			for _, submod := range module.Parts {
				inf := &parser.TypeInferer{Submodule: submod}
				inf.Infer()

				// Dump AST
				log.Debugln("main", "AST of submodule `%s/%s`:", module.Name, submod.File.Name)
				for _, node := range submod.Nodes {
					log.Debugln("main", "%s", node.String())
				}
				log.Debugln("main", "")
			}
		}
	})

	// semantic analysis
	log.Timed("semantic analysis phase", "", func() {
		for _, module := range constructedModules {
			for _, submod := range module.Parts {
				sem := semantic.NewSemanticAnalyzer(submod, *buildOwnership, *ignoreUnused)
				vis := parser.NewASTVisitor(sem)
				vis.VisitSubmodule(submod)
				sem.Finalize()
			}
		}
	})

	// codegen
	if cg != "none" {
		var gen codegen.Codegen

		switch cg {
		case "llvm":
			gen = &LLVMCodegen.Codegen{
				OutputName: outputFile,
				OutputType: outputType,
				OptLevel:   optLevel,
			}
		default:
			log.Error("main", util.Red("error: ")+"Invalid backend choice `"+cg+"`")
			os.Exit(1)
		}

		log.Timed("codegen phase", "", func() {
			gen.Generate(constructedModules)
		})
	}

}
Пример #12
0
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)
		}
	})
}
Пример #13
0
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
}
Пример #14
0
func (v *Codegen) createBinary() {
	// god this is a long and ugly function

	if v.OutputType == OUTPUT_LLVM_IR {
		for _, file := range v.input {
			log.Timed("create ir "+file.Name, func() {
				v.createIR(file)
			})
		}
		return
	}

	linkArgs := append(v.LinkerArgs, "-fno-PIE", "-nodefaultlibs", "-lc", "-lm")

	bitcodeFiles := []string{}

	for _, file := range v.input {
		log.Timed("create bitcode "+file.Name, func() {
			bitcodeFiles = append(bitcodeFiles, v.createBitcode(file))
		})

	}

	if v.OutputType == OUTPUT_LLVM_BC {
		return
	}

	asmFiles := []string{}

	for _, name := range bitcodeFiles {
		log.Timed("create asm "+name, func() {
			asmName := v.bitcodeToASM(name)
			asmFiles = append(asmFiles, asmName)
		})
	}

	for _, bc := range bitcodeFiles {
		if err := os.Remove(bc); err != nil {
			v.err("Failed to remove "+bc+": `%s`", err.Error())
		}
	}

	if v.OutputType == OUTPUT_ASSEMBLY {
		return
	}

	objFiles := []string{}

	for _, asmFile := range asmFiles {
		log.Timed("create obj "+asmFile, func() {
			objName := v.asmToObject(asmFile)

			objFiles = append(objFiles, objName)
			linkArgs = append(linkArgs, objName)
		})
	}

	for _, asmFile := range asmFiles {
		os.Remove(asmFile)
	}

	if v.OutputType == OUTPUT_OBJECT {
		return
	}

	if v.OutputName == "" {
		panic("OutputName is empty")
	}

	linkArgs = append(linkArgs, "-o", v.OutputName)

	if v.Linker == "" {
		v.Linker = "cc"
	}

	log.Timed("link", func() {
		cmd := exec.Command(v.Linker, linkArgs...)
		if out, err := cmd.CombinedOutput(); err != nil {
			v.err("failed to link object files: `%s`\n%s", err.Error(), string(out))
		}
	})

	for _, objFile := range objFiles {
		os.Remove(objFile)
	}
}
Пример #15
0
func (v *Codegen) Generate(input []*parser.Module) {
	v.builders = make(map[*parser.Function]llvm.Builder)
	v.inBlocks = make(map[*parser.Function][]*parser.Block)
	v.globalBuilder = llvm.NewBuilder()
	defer v.globalBuilder.Dispose()

	v.curLoopExits = make(map[*parser.Function][]llvm.BasicBlock)
	v.curLoopNexts = make(map[*parser.Function][]llvm.BasicBlock)

	v.input = make([]*WrappedModule, len(input))
	for idx, mod := range input {
		v.input[idx] = &WrappedModule{Module: mod}
	}

	v.variableLookup = make(map[*parser.Variable]llvm.Value)
	v.namedTypeLookup = make(map[string]llvm.Type)

	// initialize llvm target
	llvm.InitializeNativeTarget()
	llvm.InitializeNativeAsmPrinter()

	// setup target stuff
	var err error
	v.target, err = llvm.GetTargetFromTriple(llvm.DefaultTargetTriple())
	if err != nil {
		panic(err)
	}
	v.targetMachine = v.target.CreateTargetMachine(llvm.DefaultTargetTriple(), "", "", llvm.CodeGenLevelNone, llvm.RelocDefault, llvm.CodeModelDefault)
	v.targetData = v.targetMachine.TargetData()

	passManager := llvm.NewPassManager()
	passBuilder := llvm.NewPassManagerBuilder()
	if v.OptLevel > 0 {
		passBuilder.SetOptLevel(v.OptLevel)
		passBuilder.Populate(passManager)
	}

	v.blockDeferData = make(map[*parser.Block][]*deferData)

	for _, infile := range v.input {
		log.Timed("codegenning", infile.Name.String(), func() {
			infile.LlvmModule = llvm.NewModule(infile.Name.String())
			v.curFile = infile

			for _, submod := range infile.Parts {
				v.declareDecls(submod.Nodes)

				for _, node := range submod.Nodes {
					v.genNode(node)
				}
			}

			if err := llvm.VerifyModule(infile.LlvmModule, llvm.ReturnStatusAction); err != nil {
				infile.LlvmModule.Dump()
				v.err("%s", err.Error())
			}

			passManager.Run(infile.LlvmModule)

			if log.AtLevel(log.LevelDebug) {
				infile.LlvmModule.Dump()
			}
		})
	}

	passManager.Dispose()

	log.Timed("creating binary", "", func() {
		v.createBinary()
	})

}
Пример #16
0
func (v *Context) Build(output string, outputType codegen.OutputType, usedCodegen string, optLevel int) {
	// Start by loading the runtime
	runtimeModule := LoadRuntime()

	// Parse the passed files
	v.parseFiles()

	// resolve
	hasMainFunc := false
	log.Timed("resolve phase", "", func() {
		for _, module := range v.modules {
			ast.Resolve(module, v.moduleLookup)

			// Use module scope to check for main function
			mainIdent := module.ModScope.GetIdent(ast.UnresolvedName{Name: "main"})
			if mainIdent != nil && mainIdent.Type == ast.IDENT_FUNCTION && mainIdent.Public {
				hasMainFunc = true
			}
		}
	})

	// 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)
	}

	// type inference
	log.Timed("inference phase", "", func() {
		for _, module := range v.modules {
			for _, submod := range module.Parts {
				ast.Infer(submod)

				// Dump AST
				log.Debugln("main", "AST of submodule `%s/%s`:", module.Name, submod.File.Name)
				for _, node := range submod.Nodes {
					log.Debugln("main", "%s", node.String())
				}
				log.Debugln("main", "")
			}
		}
	})

	// semantic analysis
	log.Timed("semantic analysis phase", "", func() {
		for _, module := range v.modules {
			semantic.SemCheck(module, *ignoreUnused)
		}
	})

	// codegen
	if usedCodegen != "none" {
		var gen codegen.Codegen

		switch usedCodegen {
		case "llvm":
			gen = &LLVMCodegen.Codegen{
				OutputName: output,
				OutputType: outputType,
				OptLevel:   optLevel,
			}
		default:
			log.Error("main", util.Red("error: ")+"Invalid backend choice `"+usedCodegen+"`")
			os.Exit(1)
		}

		log.Timed("codegen phase", "", func() {
			mods := v.modules
			if runtimeModule != nil {
				mods = append(mods, runtimeModule)
			}
			gen.Generate(mods)
		})
	}
}
Пример #17
0
func (v *Codegen) Generate(input []*parser.Module, modules map[string]*parser.Module) {
	v.input = input
	v.builder = llvm.NewBuilder()
	v.variableLookup = make(map[*parser.Variable]llvm.Value)
	v.structLookup_UseHelperFunction = make(map[*parser.StructType]llvm.Type)
	v.enumLookup_UseHelperFunction = make(map[*parser.EnumType]llvm.Type)

	// initialize llvm target
	llvm.InitializeNativeTarget()

	// setup target stuff
	var err error
	v.target, err = llvm.GetTargetFromTriple(llvm.DefaultTargetTriple())
	if err != nil {
		panic(err)
	}
	v.targetMachine = v.target.CreateTargetMachine(llvm.DefaultTargetTriple(), "", "", llvm.CodeGenLevelNone, llvm.RelocDefault, llvm.CodeModelDefault)
	v.targetData = v.targetMachine.TargetData()

	passManager := llvm.NewPassManager()
	passBuilder := llvm.NewPassManagerBuilder()
	if v.OptLevel > 0 {
		passBuilder.SetOptLevel(v.OptLevel)
		passBuilder.Populate(passManager)
	}

	v.modules = make(map[string]*parser.Module)
	v.blockDeferData = make(map[*parser.Block][]*deferData)

	for _, infile := range input {
		log.Verboseln("codegen", util.TEXT_BOLD+util.TEXT_GREEN+"Started codegenning "+util.TEXT_RESET+infile.Name)
		t := time.Now()

		infile.Module = llvm.NewModule(infile.Name)
		v.curFile = infile

		v.modules[v.curFile.Name] = v.curFile

		v.declareDecls(infile.Nodes)

		for _, node := range infile.Nodes {
			v.genNode(node)
		}

		if err := llvm.VerifyModule(infile.Module, llvm.ReturnStatusAction); err != nil {
			infile.Module.Dump()
			v.err("%s", err.Error())
		}

		passManager.Run(infile.Module)

		if log.AtLevel(log.LevelVerbose) {
			infile.Module.Dump()
		}

		dur := time.Since(t)
		log.Verbose("codegen", util.TEXT_BOLD+util.TEXT_GREEN+"Finished codegenning "+util.TEXT_RESET+infile.Name+" (%.2fms)\n",
			float32(dur.Nanoseconds())/1000000)
	}

	passManager.Dispose()

	log.Timed("create binary", func() {
		v.createBinary()
	})

}