view dang/compiler.d @ 97:198ad05f3ace new_gen

"-c" as argument now generates out.o (only works on linux now)
author Anders Johnsen <skabet@gmail.com>
date Tue, 06 May 2008 21:28:05 +0200
parents 48bb2287c035
children 5f258eaf9517
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.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.ScopeCheck,
       sema.TypeCheck;

import tango.stdc.posix.unistd;

import Opt = dang.OptParse;

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 ~= file;
    }

    *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;

    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(["--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(
            ["-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")
        postParse.attach(
            (Module m, SourceManager sm) {
                StopWatch w; w.start;
                auto llvmGen = new CodeGen();
                auto file = new FileConduit("out.bc", FileConduit.WriteCreate);
                llvmGen.gen(m, file.fileHandle, optimize, inline);
                timings ~= Measurement("Generating LLVM bytecode", w.stop);
            });
    else if (what == "compile")
        postParse.attach(
            (Module m, SourceManager sm) {
                StopWatch w; w.start;
                auto llvmGen = new CodeGen();
                auto llc = new Process("llc","-o=-");
                auto gcc = new Process("gcc","-c","-o","out.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 assemble bytecode", w.stop);
            });
    else if (what == "dot")
        postParse.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")
        postParse.attach(
            (Module m, SourceManager sm) {
                StopWatch w; w.start;
                auto print = new AstPrinter(sm);
                print.print(m);
                timings ~= Measurement("Converting AST to text", w.stop);
            });
    StopWatch total;
    total.start;
    foreach (file; filesToHandle)
    {
        preLex(file);

        auto start = src_mgr.addFile(file);
        auto lexer = new Lexer(start, src_mgr, messages);
        postLex(lexer);

        preParse(lexer);

        StopWatch watch;
        watch.start;
        auto parser = new Parser(messages);
        auto action = new AstAction(src_mgr);
        auto m = cast(Module)parser.parse(src_mgr, lexer, action);
        timings ~= Measurement("Lex + Parse", watch.stop);
        messages.checkErrors(ExitLevel.Parser);

        StopWatch watch2;
        watch.start;
        watch2.start;
        (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);
    }
    timings ~= Measurement("Total", total.stop);

    if (options.flag("time"))
        foreach (m; timings)
            Stderr.formatln("{,-45} {}ms", m.label, m.time*1e3);
}