view dang/compiler.d @ 168:7982eb63c0eb

Some changes to get function overloading to work. Also class inherit works now - to some extend. needs vtables and all the complex stuff of it.
author Anders Johnsen <skabet@gmail.com>
date Thu, 24 Jul 2008 12:06:48 +0200
parents 6c5a3c0bb4fb
children dc9bf56b7ace
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(["--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);
            });
    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);
}