Mercurial > projects > dang
view dang/compiler.d @ 188:b3e0729c8524
Extra test
author | Anders Halager <halager@gmail.com> |
---|---|
date | Fri, 25 Jul 2008 12:55:38 +0200 |
parents | dc9bf56b7ace |
children | 08f68d684047 |
line wrap: on
line source
module dang.compiler; import tango.io.Stdout, tango.core.Signal, tango.core.Memory, tango.sys.Process, tango.time.StopWatch, tango.text.Util, tango.io.FileConduit, tango.io.FilePath; import lexer.Lexer, parser.Parser; import basic.SourceManager; import basic.Message; import ast.Module; import tools.AstPrinter, tools.DotPrinter; import gen.CodeGen; import sema.Visitor, sema.AstAction, sema.ScopeBuilder, sema.LiteralInterpreter, sema.ScopeCheck, sema.VC, sema.ObjectOriented, sema.TypeCheck; import tango.stdc.posix.unistd; import tango.stdc.stdlib; import Opt = dang.OptParse; class NullAction : Action { } void checkFiles(char[][] *files) { // GC.disable(); bool non_existant_files = false; bool duplicate_files = false; char[][] validFiles; foreach (file; *files) { scope path = new FilePath(file); if (!path.exists) { Stderr.formatln("'{}' does not exist", file).newline; non_existant_files = true; continue; } bool fileInStack = false; foreach (vFile; validFiles) if (vFile == file) { fileInStack = true; duplicate_files = true; } if (fileInStack) continue; validFiles ~= path.toString(); } *files = validFiles; if (non_existant_files) throw new Exception("All files given must exist"); if (duplicate_files) Stderr("warning: duplicate files ignored").newline; } void main(char[][] args) { char[][] filesToHandle; Signal!(char[][]*) preStart; Signal!(char[]) preLex; Signal!(Lexer) postLex; Signal!(Lexer) preParse; Signal!(Module[], SourceManager) postParse; Signal!(Module[], SourceManager) postSema; preStart.attach(&checkFiles); auto argParse = new Opt.OptionParser(`Dang "D" compiler v0.0`); bool optimize = false; bool inline = false; SourceManager src_mgr = new SourceManager; MessageHandler messages = new MessageHandler(src_mgr); argParse.addOption(["-h", "--help"], Opt.Action.Help) .help("Show this help message"); argParse.addOption(["--ast-dump-dot"], "what-to-do", Opt.Action.StoreConst, "dot") .help("Output the AST in the dot format"); argParse.addOption(["--ast-dump-code"], "what-to-do", Opt.Action.StoreConst, "code") .help("Output the AST as code"); argParse.addOption(["--semantic-only"], "what-to-do", Opt.Action.StoreConst, "exit") .help("Exit after semantics and before codegen"); argParse.addOption(["--gen-llvm"], "what-to-do", Opt.Action.StoreConst, "gen-llvm") .help("Compile to LLVM code (default)"); argParse.addOption(["-c"], "what-to-do", Opt.Action.StoreConst, "compile") .help("Compile to .o or executeable"); argParse.addOption(["--syntax-only"], "what-to-do", Opt.Action.StoreConst, "parse") .help("Only parse the file(s) and output parseing errors."); argParse.addOption( ["-O","--optimize"], { optimize = true; } ).help("Tell LLVM to do its standard optimizations"); argParse.addOption( ["--inline"], { inline = true; } ).help("Tell LLVM that its allowed to inline functions"); argParse .addOption(["--time"], Opt.Action.SetTrue, "time") .help("Time the various operations performed."); auto options = argParse.parse(args); filesToHandle ~= options.args; // Will throw exception if some files don't exist preStart(&filesToHandle); struct Measurement { char[] label; double time; } Measurement[] timings; auto what = options["what-to-do"]; if (what == "" || what == "gen-llvm") postSema.attach( (Module[] modules, SourceManager sm) { foreach(m ; modules) { if (!m.outputModule) continue; StopWatch w; w.start; auto llvmGen = new CodeGen(); auto file = new FileConduit(m.moduleName~".bc", FileConduit.WriteCreate); llvmGen.gen(m, file.fileHandle, optimize, inline); timings ~= Measurement("Generating LLVM bytecode", w.stop); } }); else if (what == "compile") postSema.attach( (Module[] modules, SourceManager sm) { foreach(m ; modules) { if (!m.outputModule) continue; StopWatch w; w.start; auto llvmGen = new CodeGen(); auto llc = new Process("llc","-o=-"); auto gcc = new Process("gcc","-c","-o",m.moduleName~".o","-x","assembler","-"); llc.execute(); int i = dup(llc.stdin.fileHandle); llc.stdin.detach; llvmGen.gen(m, i, optimize, inline); llc.wait(); gcc.execute(); gcc.stdin.copy(llc.stdout); gcc.stdin.detach; gcc.wait(); timings ~= Measurement("Generating ASM", w.stop); } }); else if (what == "parse") preParse.attach( (Lexer lexer) { auto parser = new Parser(messages); auto action = new NullAction(); parser.parse(src_mgr, lexer, action); messages.checkErrors(ExitLevel.Parser); exit(0); }); else if (what == "dot") postSema.attach( (Module[] m, SourceManager sm) { StopWatch w; w.start; // auto print = new DotPrinter(); // print.print(m); timings ~= Measurement("Generating dot output", w.stop); }); else if (what == "code") postSema.attach( (Module[] modules, SourceManager sm) { StopWatch w; w.start; auto print = new AstPrinter(sm); foreach ( m ; modules ) if (m.outputModule) print.print(m); timings ~= Measurement("Converting AST to text", w.stop); }); else if (what == "exit") postSema.attach( (Module[] modules, SourceManager sm) { }); StopWatch total; total.start; Module[] modules; StopWatch watch; watch.start; foreach (file; filesToHandle) { preLex(file); auto start = src_mgr.addFile(file); auto lexer = new Lexer(start, src_mgr, messages); postLex(lexer); preParse(lexer); auto parser = new Parser(messages); auto action = new AstAction(src_mgr); modules ~= cast(Module)parser.parse(src_mgr, lexer, action); timings ~= Measurement("Lex + Parse of '"~file~"'", watch.stop); messages.checkErrors(ExitLevel.Parser); /* StopWatch watch2; watch.start; watch2.start; Module[] mods = (new LoadModule).visit(m, src_mgr, messages); (new ScopeBuilder).visit(m); auto scope_builder = watch2.stop; watch2.start; (new ScopeCheck).visit(m); auto scope_check = watch2.stop; watch2.start; (new TypeCheck).visit(m); auto type_check = watch2.stop; watch2.start; foreach (decl; m.decls) decl.simplify(); auto simplify = watch2.stop; auto extra_stuff = watch.stop; timings ~= Measurement("Extra stuff", watch.stop); timings ~= Measurement(" - Building scopes", scope_builder); timings ~= Measurement(" - Checking scopes", scope_check); timings ~= Measurement(" - Checking types", type_check); postParse(m, src_mgr);*/ } (new LiteralInterpreter(messages)).visit(modules); messages.checkErrors; postParse(modules, src_mgr); class ModuleLoader : Visitor!(void) { Module[] visit(Module[] modules, MessageHandler messages, SourceManager src_mgr) { this.modules = modules; this.messages = messages; this.src_mgr = src_mgr; super.visit(modules); return this.modules; } override void visitImportDecl(ImportDecl decl) { char[] path = replace!(char)(decl.get,'.','/')~".d"; auto start = src_mgr.addFile(path); auto lexer = new Lexer(start, src_mgr, messages); auto parser = new Parser(messages); auto action = new AstAction(src_mgr); Module m = cast(Module)parser.parse(src_mgr, lexer, action); modules ~= m; m.outputModule = false; // decl.env.mHandle.add(m); messages.checkErrors(ExitLevel.Parser); } Module[] modules; SourceManager src_mgr; MessageHandler messages; } modules = (new ModuleLoader()).visit(modules, messages, src_mgr); messages.checkErrors; (new ScopeBuilder).visit(modules); StopWatch watch2; watch.start; watch2.start; (new ScopeCheck(messages)).visit(modules); messages.checkErrors; auto scope_check = watch2.stop; watch2.start; (new TypeCheck(messages)).visit(modules); messages.checkErrors; auto type_check = watch2.stop; watch2.start; (new ObjectOriented(messages)).visit(modules); messages.checkErrors; auto object_check = watch2.stop; watch2.start; auto vc = new VC; vc.msg = messages; foreach (m; modules) m.verify(vc); messages.checkErrors; auto ast_verify = watch2.stop; foreach (m; modules) foreach (decl; m.decls) decl.simplify(); timings ~= Measurement("Total", total.stop); postSema(modules, src_mgr); if (options.flag("time")) foreach (m; timings) Stderr.formatln("{,-45} {}ms", m.label, m.time*1e3); }