changeset 1:2168f4cb73f1

First push
author johnsen@johnsen-desktop
date Fri, 18 Apr 2008 02:01:38 +0200
parents
children ae5bbe4e7fd6
files LICENSE ast/Decl.d ast/Exp.d ast/Stmt.d dang/OptParse.d dang/compiler.d dsss.conf gen/LLVMGen.d gen/LuaGen.d lexer/Keyword.d lexer/Lexer.d lexer/Token.d misc/DataSource.d misc/Error.d misc/Location.d parser/Parser.d sema/SymbolTable.d sema/SymbolTableBuilder.d sema/Visitor.d test.td tests/lexer/Comments.d tests/lexer/Comments1.d tests/run.d tools/AstPrinter.d tools/DotPrinter.d
diffstat 25 files changed, 3347 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,19 @@
+            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+                    Version 2, December 2004
+
+ Copyright (C) 2004 Sam Hocevar
+  14 rue de Plaisance, 75014 Paris, France
+ Everyone is permitted to copy and distribute verbatim or modified
+ copies of this license document, and changing it is allowed as long
+ as the name is changed.
+
+            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. You just DO WHAT THE FUCK YOU WANT TO.
+
+/* This program is free software. It comes without any warranty, to
+ * the extent permitted by applicable law. You can redistribute it
+ * and/or modify it under the terms of the Do What The Fuck You Want
+ * To Public License, Version 2, as published by Sam Hocevar. See
+ * http://sam.zoy.org/wtfpl/COPYING for more details. */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ast/Decl.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,58 @@
+module ast.Decl;
+
+import ast.Exp,
+       ast.Stmt;
+
+import lexer.Token;
+
+import sema.SymbolTable;
+
+enum DeclType
+{
+    VarDecl,
+    FuncDecl,
+}
+
+class Decl
+{
+    this(DeclType declType)
+    {
+        this.declType = declType;
+    }
+
+    DeclType declType;
+    Scope env;
+}
+
+class VarDecl : Decl
+{
+    this(Identifier type, Identifier identifier,
+            Exp e = null)
+    {
+        super(DeclType.VarDecl);
+        this.type = type;
+        this.identifier = identifier;
+        this.init = e;
+    }
+
+    Identifier type, identifier;
+    Exp init;
+}
+
+class FuncDecl : Decl
+{
+    this(Identifier type, Identifier identifier, 
+            VarDecl[] funcArgs, Stmt[] statements)
+    {
+        super(DeclType.FuncDecl);
+        this.type = type;
+        this.identifier = identifier;
+        this.funcArgs = funcArgs;
+        this.statements = statements;
+    }
+
+    Identifier type, identifier;
+    VarDecl[] funcArgs;
+    Stmt[] statements;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ast/Exp.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,135 @@
+module ast.Exp;
+
+import tango.text.Util : jhash;
+
+import lexer.Token;
+
+import sema.SymbolTable;
+
+enum ExpType
+{
+    Binary,
+    Negate,
+    IntegerLit,
+    Identifier,
+    AssignExp,
+    CallExp,
+}
+
+class Exp
+{
+    this(ExpType expType) 
+    {
+        this.expType = expType;
+    }
+
+    ExpType expType;
+    Scope env;
+}
+
+class CallExp : Exp
+{
+    this(Exp exp, Exp[] args)
+    {
+        super(ExpType.CallExp);
+        this.exp = exp;
+        this.args = args;
+    }
+
+    Exp exp;
+    Exp[] args;
+}
+
+class AssignExp : Exp
+{
+    this(Identifier identifier, Exp exp)
+    {
+        super(ExpType.AssignExp);
+        this.identifier = identifier;
+        this.exp = exp;
+    }
+
+    Identifier identifier;
+    Exp exp;
+}
+
+class BinaryExp : Exp
+{
+    public enum Operator : char
+    {
+        Mul = '*', Div = '/',
+        Add = '+', Sub = '-'
+    }
+
+    this(Operator op, Exp left, Exp right)
+    {
+        super(ExpType.Binary);
+        this.op = op;
+        this.left = left;
+        this.right = right;
+    }
+
+    Operator op;
+    Exp left, right;
+}
+
+class NegateExp : Exp
+{
+    this(Exp exp)
+    {
+        super(ExpType.Negate);
+        this.exp = exp;
+    }
+
+    public Exp exp;
+}
+
+class IntegerLit : Exp
+{
+    this(Token t)
+    {
+        super(ExpType.IntegerLit);
+        this.token = t;
+    }
+
+    Token token;
+}
+
+class Identifier : Exp
+{
+    this(Token t)
+    {
+        super(ExpType.Identifier);
+        this.token = t;
+        name = t.get;
+    }
+
+    char[] get()
+    {
+        return name;
+    }
+
+    hash_t toHash()
+    {
+        return jhash(name);
+    }
+
+    int opCmp(Object o)
+    {
+        if (auto id = cast(Identifier)o)
+            return typeid(char[]).compare(&name, &id.name);
+        return 0;
+    }
+
+    int opEquals(Object o)
+    {
+        if (auto id = cast(Identifier)o)
+            return typeid(char[]).equals(&name, &id.name);
+        return 0;
+    }
+
+    Token token;
+    char[] name;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ast/Stmt.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,57 @@
+module ast.Stmt;
+
+import ast.Exp,
+       ast.Decl;
+
+import sema.SymbolTable;
+
+enum StmtType
+{
+    Stmt,
+    Decl,
+    Exp,
+    Return,
+}
+
+class Stmt
+{
+    this(StmtType stmtType = StmtType.Stmt)
+    {
+        this.stmtType = stmtType;
+    }
+
+    StmtType stmtType;
+    Scope env;
+}
+
+class ReturnStmt : Stmt
+{
+    this()
+    {
+        super(StmtType.Return);
+    }
+
+    public Exp exp;
+}
+
+class DeclStmt : Stmt
+{
+    this(Decl decl)
+    {
+        super(StmtType.Decl);
+        this.decl = decl;
+    }
+
+    public Decl decl;
+}
+
+class ExpStmt : Stmt
+{
+    this(Exp exp)
+    {
+        super(StmtType.Exp);
+        this.exp = exp;
+    }
+
+    public Exp exp;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dang/OptParse.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,810 @@
+/*
+Copyright (c) 2007 Kirk McDonald
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+/**
+ * Command-line option parsing, in the style of Python's optparse.
+ *
+ * Refer to the complete docs for more information.
+ */
+module dang.OptParse;
+
+import tango.io.Stdout;
+import tango.text.Util : locate, locatePrior;
+import tango.text.Ascii : toUpper;
+import tango.stdc.stdlib : exit, EXIT_FAILURE, EXIT_SUCCESS;
+import tango.text.convert.Integer : parse, toInt, toString = toString;
+import tango.text.convert.Utf : toString, toString32;
+
+/*
+Options may be in two forms: long and short. Short options start with a single
+dash and are one letter long. Long options start with two dashes and may
+consist of any number of characters (so long as they don't start with a dash,
+though they may contain dashes). Options are case-sensitive.
+
+Short options may be combined. The following are equivalent:
+
+$ myapp -a -b -c
+$ myapp -abc
+$ myapp -ab -c
+
+If -f and --file are aliases of the same option, which accepts an argument,
+the following are equivalent:
+
+$ myapp -f somefile.txt
+$ myapp -fsomefile.txt
+$ myapp --file somefile.txt
+$ myapp --file=somefile.txt
+
+The following are also valid:
+
+$ myapp -abcf somefile.txt
+$ myapp -abcfsomefile.txt
+$ myapp -abc --file somefile.txt
+
+If an option occurs multiple times, the last one is the one recorded:
+
+$ myapp -f somefile.txt --file otherfile.txt
+
+Matches 'otherfile.txt'.
+*/
+
+bool startswith(char[] s, char[] start) {
+    if (s.length < start.length) return false;
+    return s[0 .. start.length] == start;
+}
+bool endswith(char[] s, char[] end) {
+    if (s.length < end.length) return false;
+    return s[$ - end.length .. $] == end;
+}
+
+/// Thrown if client code tries to set up an improper option.
+class OptionError : Exception {
+    this(char[] msg) { super(msg); }
+}
+// Thrown if client code tries to extract the wrong type from an option.
+class OptionTypeError : Exception {
+    this(char[] msg) { super(msg); }
+}
+
+/++
+This class represents the results after parsing the command-line.
++/
+class Options {
+    char[][][char[]] opts;
+    int[char[]] counted_opts;
+    /// By default, leftover arguments are placed in this array.
+    char[][] args;
+
+    /// Retrieves the results of the Store and StoreConst actions.
+    char[] opIndex(char[] opt) {
+        char[][]* o = opt in opts;
+        if (o) {
+            return (*o)[0];
+        } else {
+            return "";
+        }
+    }
+    /// Retrieves the results of the Store action, when the type is Integer.
+    int value(char[] opt) {
+        char[][]* o = opt in opts;
+        if (o) {
+            return toInt((*o)[0]);
+        } else {
+            return 0;
+        }
+    }
+    /// Retrieves the results of the Append and AppendConst actions.
+    char[][] list(char[] opt) {
+        char[][]* o = opt in opts;
+        if (o) {
+            return *o;
+        } else {
+            return null;
+        }
+    }
+    /// Retrieves the results of the Append action, when the type is Integer.
+    int[] valueList(char[] opt) {
+        char[][]* o = opt in opts;
+        int[] l;
+        if (o) {
+            l.length = (*o).length;
+            foreach (i, s; *o) {
+                l[i] = toInt(s);
+            }
+        }
+        return l;
+    }
+    /// Retrieves the results of the Count action.
+    int count(char[] opt) {
+        int* c = opt in counted_opts;
+        if (c) {
+            return *c;
+        } else {
+            return 0;
+        }
+    }
+    /// Retrieves the results of the SetTrue and SetFalse actions.
+    bool flag(char[] opt) {
+        char[][]* o = opt in opts;
+        if (o) {
+            return (*o)[0] == "1";
+        } else {
+            return false;
+        }
+    }
+}
+
+// Options, args, this opt's index in args, name[, arg]
+///
+alias void delegate(Options, inout char[][], inout int, char[], char[]) OptionCallbackFancyArg;
+///
+alias void delegate(Options, inout char[][], inout int, char[], int)    OptionCallbackFancyInt;
+///
+alias void delegate(Options, inout char[][], inout int, char[])         OptionCallbackFancy;
+
+///
+alias void delegate(char[]) OptionCallbackArg;
+///
+alias void delegate(int)    OptionCallbackInt;
+///
+alias void delegate()       OptionCallback;
+
+/*
+Actions:
+ * Store:        name
+ * StoreConst:   name, const_value
+ * Append:       name
+ * AppendConst:  name, const_value
+ * Count:        name
+ * CallbackArg:  dga
+ * CallbackVoid: dg
+*/
+///
+enum Action { /+++/Store, /+++/StoreConst, /+++/Append, /+++/AppendConst, /+++/Count, /+++/SetTrue, /+++/SetFalse, /+++/Callback, /+++/CallbackFancy, /+++/Help /+++/}
+///
+enum ArgType { /+++/None, /+++/String, /+++/Integer /+++/}
+
+ArgType defaultType(Action action) {
+    switch (action) {
+        case Action.Store, Action.Append, Action.Callback, Action.CallbackFancy:
+            return ArgType.String;
+            break;
+        default:
+            return ArgType.None;
+            break;
+    }
+}
+
+/++
+This class represents a single command-line option.
++/
+class Option {
+    char[][] shortopts, longopts;
+    Action action;
+    ArgType type;
+    char[] name, argname;
+    char[] const_value;
+
+    char[] default_string;
+    int default_value;
+    bool default_flag, has_default;
+
+    OptionCallbackArg callback;
+    OptionCallbackInt int_callback;
+    OptionCallback void_callback;
+
+    OptionCallbackFancyArg fancy_callback;
+    OptionCallbackFancyInt fancy_int_callback;
+    OptionCallbackFancy fancy_void_callback;
+    char[] helptext;
+    this(
+        char[][] shorts, char[][] longs, ArgType type,
+        Action act, char[] name, char[] const_value,
+        OptionCallbackArg dga, OptionCallback dg,
+        OptionCallbackInt dgi,
+        OptionCallbackFancyArg fdga,
+        OptionCallbackFancyInt fdgi,
+        OptionCallbackFancy fdg
+    ) {
+        this.shortopts = shorts;
+        this.longopts = longs;
+        this.action = act;
+        this.type = type;
+        this.name = name;
+        this.argname = toUpper(name.dup);
+        this.default_string = "";
+        this.default_value = 0;
+        this.default_flag = false;
+
+        // Perform sanity checks.
+        assert (name !is null);
+        switch (act) {
+            case Action.Store, Action.Append:
+                assert(type != ArgType.None);
+                break;
+            case Action.StoreConst, Action.AppendConst:
+                assert(type == ArgType.None);
+                assert(const_value !is null);
+                break;
+            case Action.Callback:
+                //assert(type != ArgType.None);
+                switch (type) {
+                    case ArgType.String:
+                        assert(dga !is null);
+                        break;
+                    case ArgType.Integer:
+                        assert(dgi !is null);
+                        break;
+                    case ArgType.None:
+                        assert(dg !is null);
+                        break;
+                }
+                break;
+            case Action.CallbackFancy:
+                switch (type) {
+                    case ArgType.String:
+                        assert(fdga !is null);
+                        break;
+                    case ArgType.Integer:
+                        assert(fdgi !is null);
+                        break;
+                    case ArgType.None:
+                        assert(fdg !is null);
+                        break;
+                }
+            default:
+                break;
+        }
+        this.const_value = const_value;
+        this.callback = dga;
+        this.int_callback = dgi;
+        this.void_callback = dg;
+        this.fancy_callback = fdga;
+        this.fancy_int_callback = fdgi;
+        this.fancy_void_callback = fdg;
+    }
+    char[] toString() {
+        int optCount = this.shortopts.length + this.longopts.length;
+        char[] result;
+        bool printed_arg = false;
+        foreach(i, opt; this.shortopts ~ this.longopts) {
+            result ~= opt;
+            if (i < optCount-1) {
+                result ~= ", ";
+            } else if (this.hasArg()) {
+                result ~= "=" ~ toUpper(this.argname.dup);
+            }
+        }
+        return result;
+    }
+    //enum Action { Store, StoreConst, Append, AppendConst, Count, SetTrue, SetFalse, Callback, CallbackFancy, Help }
+    void issue_default(Options results) {
+        // Only set the default if the option doesn't already have a value.
+        char[][]* val = this.name in results.opts;
+        switch (this.action) {
+            case Action.Store, Action.Append:
+                if (val !is null) return;
+                if (this.type == ArgType.String) {
+                    results.opts[name] = [default_string];
+                } else {
+                    results.opts[name] = [.toString(default_value)];
+                }
+                break;
+            case Action.StoreConst, Action.AppendConst:
+                if (val !is null) return;
+                results.opts[name] = [default_string];
+                break;
+            case Action.SetTrue, Action.SetFalse:
+                if (val !is null) return;
+                if (default_flag) {
+                    results.opts[name] = ["1"];
+                } else {
+                    results.opts[name] = ["0"];
+                }
+                break;
+            default:
+                return;
+        }
+    }
+    // Does whatever this option is supposed to do.
+    void performAction(OptionParser parser, Options results, inout char[][] args, inout int idx, char[] arg) {
+        int i;
+        if (this.type == ArgType.Integer) {
+            // Verify that it's an int.
+            i = parser.toOptInt(arg);
+        }
+        switch (this.action) {
+            case Action.Store:
+                results.opts[name] = [arg];
+                break;
+            case Action.Append:
+                results.opts[name] ~= arg;
+                break;
+            case Action.StoreConst:
+                assert(arg is null, "Got unexpected argument for '"~name~"' option.");
+                results.opts[name] = [const_value];
+                break;
+            case Action.AppendConst:
+                assert(arg is null, "Got unexpected argument for '"~name~"' option.");
+                results.opts[name] ~= const_value;
+                break;
+            case Action.Count:
+                assert(arg is null, "Got unexpected argument for '"~name~"' option.");
+                ++results.counted_opts[name];
+                break;
+            case Action.SetTrue:
+                results.opts[name] = ["1"];
+                break;
+            case Action.SetFalse:
+                results.opts[name] = ["0"];
+                break;
+            case Action.Callback:
+                switch (type) {
+                    case ArgType.String:
+                        callback(arg);
+                        break;
+                    case ArgType.Integer:
+                        int_callback(i);
+                        break;
+                    case ArgType.None:
+                        void_callback();
+                        break;
+                }
+                break;
+            case Action.CallbackFancy:
+                switch (type) {
+                    case ArgType.String:
+                        fancy_callback(results, args, idx, name, arg);
+                        break;
+                    case ArgType.Integer:
+                        fancy_int_callback(results, args, idx, name, i);
+                        break;
+                    case ArgType.None:
+                        fancy_void_callback(results, args, idx, name);
+                        break;
+                }
+                break;
+            case Action.Help:
+                parser.helpText();
+                exit(EXIT_SUCCESS);
+                break;
+        }
+    }
+    /// Returns whether this option accepts an argument.
+    bool hasArg() {
+        return this.type != ArgType.None;
+    }
+    /// Sets the help text for this option.
+    Option help(char[] help) {
+        this.helptext = help;
+        return this;
+    }
+    /// Sets the name of this option's argument, if it has one.
+    Option argName(char[] argname) {
+        this.argname = argname;
+        return this;
+    }
+    Option def(char[] val) {
+        if (
+            (this.type != ArgType.String || (this.action != Action.Store && this.action != Action.Append)) &&
+            this.action != Action.StoreConst && this.action != Action.AppendConst
+        )
+            throw new OptionError("Cannot specify string default for non-string option '"~this.name~"'");
+        this.has_default = true;
+        this.default_string = val;
+        return this;
+    }
+    Option def(int val) {
+        if (this.type != ArgType.Integer || (this.action != Action.Store && this.action != Action.Append))
+            throw new OptionError("Cannot specify integer default for non-integer option '"~this.name~"'");
+        this.has_default = true;
+        this.default_value = val;
+        return this;
+    }
+    Option def(bool val) {
+        if (this.action != Action.SetTrue && this.action != Action.SetFalse)
+            throw new OptionError("Cannot specify boolean default for non-flag option '"~this.name~"'");
+        this.has_default = true;
+        this.default_flag = val;
+        return this;
+    }
+    // Returns true if the passed option string matches this option.
+    bool matches(char[] _arg) {
+        dchar[] arg = toString32(_arg);
+        if (
+            arg.length < 2 ||
+            arg.length == 2 && (arg[0] != '-' || arg[1] == '-') ||
+            arg.length > 2 && (arg[0 .. 2] != "--" || arg[2] == '-')
+        ) {
+            return false;
+        }
+        if (arg.length == 2) {
+            foreach (opt; shortopts) {
+                if (_arg == opt) {
+                    return true;
+                }
+            }
+        } else {
+            foreach (opt; longopts) {
+                if (_arg == opt) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+}
+
+/++
+This class is used to define a set of options, and parse the command-line
+arguments.
++/
+class OptionParser {
+    OptionCallbackArg leftover_cb;
+    /// An array of all of the options known by this parser.
+    Option[] options;
+    char[] name, desc;
+    /// The description of the programs arguments, as used in the Help action.
+    char[] argdesc;
+    private void delegate(char[]) error_callback;
+
+    this(char[] desc="") {
+        this.name = "";
+        this.desc = desc;
+        this.argdesc = "[options] args...";
+    }
+
+    /// Sets a callback, to override the default error behavior.
+    void setErrorCallback(void delegate(char[]) dg) {
+        error_callback = dg;
+    }
+    void unknownOptError(char[] opt) {
+        error("Unknown argument '"~opt~"'");
+    }
+    void expectedArgError(char[] opt) {
+        error("'"~opt~"' option expects an argument.");
+    }
+    /// Displays an error message and terminates the program.
+    void error(char[] err) {
+        if (error_callback !is null) {
+            error_callback(err);
+        } else {
+            this.helpText();
+            Stdout.formatln(err);
+        }
+        exit(EXIT_FAILURE);
+    }
+    int toOptInt(char[] s) {
+        int i;
+        uint ate;
+        i = .parse(s, 10u, &ate);
+        if (ate != s.length)
+            error("Could not convert '"~s~"' to an integer.");
+        return i;
+    }
+
+    /// Displays useful "help" information about the program's options.
+    void helpText() {
+        int optWidth;
+        char[][] optStrs;
+        typedef char spacechar = ' ';
+        spacechar[] padding;
+        // Calculate the maximum width of the option lists.
+        foreach(i, opt; options) {
+            optStrs ~= opt.toString();
+            if (optStrs[i].length > optWidth) {
+                optWidth = optStrs[i].length;
+            }
+        }
+        Stdout.formatln("Usage: {0} {1}", this.name, this.argdesc);
+        if (this.desc !is null && this.desc != "") Stdout.formatln(this.desc);
+        Stdout.formatln("\nOptions:");
+        foreach(i, opt; options) {
+            padding.length = optWidth - optStrs[i].length;
+            Stdout.formatln("  {0}{1} {2}", optStrs[i], cast(char[])padding, opt.helptext);
+        }
+    }
+    
+    // Checks the passed arg against all the options in the parser.
+    // Returns null if no match is found.
+    Option matches(char[] arg) {
+        foreach(o; options) {
+            if (o.matches(arg)) {
+                return o;
+            }
+        }
+        return null;
+    }
+    char[] getBaseName(char[] path) {
+        version(Windows) {
+            char delimiter = '\\';
+        } else {
+            char delimiter = '/';
+        }
+        uint idx = locatePrior(path, delimiter);
+        if (idx == path.length) return path;
+        return path[idx+1 .. $];
+    }
+    char[] getProgramName(char[] path) {
+        version(Windows) {
+            // (Unicode note: ".exe" only contains 4 code units, so this slice
+            // should Just Work.) (Although it remains to be seen how robust
+            // this code actually is.)
+            //Stdout.formatln(path);
+            //assert(path[$-4 .. $] == ".exe");
+            //path = path[0 .. $-4];
+        }
+        return getBaseName(path);
+    }
+    /// Parses the passed command-line arguments and returns the results.
+    Options parse(char[][] args) {
+        this.name = getProgramName(args[0]);
+        args = args[1 .. $];
+        Options options = new Options;
+        /*
+        The issue is this:
+
+        $ myapp -abc
+
+        This might be three short opts, or one or two opts, the last of which
+        accepts an argument. In the three-opt case, we want to get:
+
+        $ myapp -a -b -c
+
+        In the one-opt case, we want:
+
+        $ myapp -a bc
+
+        In the two-opt case, we want:
+
+        $ myapp -a -b c
+
+        We also want to parse apart "--file=somefile" into "--file somefile"
+        */
+        char[] opt, newopt, arg;
+        dchar[] opt32;
+        int idx;
+        Option match;
+
+        for (int i=0; i<args.length; ++i) {
+            opt = args[i];
+            // -- ends the option list, the remainder is dumped into args
+            if (opt == "--") {
+                if (this.leftover_cb !is null) {
+                    foreach(a; args[i+1 .. $]) {
+                        this.leftover_cb(a);
+                    }
+                } else {
+                    options.args ~= args[i+1 .. $];
+                }
+                i = args.length;
+            } else if (opt.startswith("--")) {
+                idx = locate(opt, '=');
+                if (idx != opt.length) {
+                    newopt = opt[0 .. idx];
+                    // Stitch out the old arg, stitch in the newopt, arg pair.
+                    // (Unicode note: idx+1 works, since we know '=' is a
+                    // single code unit.)
+                    args = args[0 .. i] ~ [newopt, opt[idx+1 .. $]] ~ args[i+1 .. $];
+                } else {
+                    newopt = opt;
+                }
+                match = matches(newopt);
+                if (match is null) {
+                    unknownOptError(newopt);
+                }
+                if (match.hasArg) {
+                    if (i == args.length-1) expectedArgError(match.name);
+                    arg = args[i+1];
+                    ++i;
+                } else {
+                    arg = null;
+                }
+                match.performAction(this, options, args, i, arg);
+            } else if (opt.startswith("-")) {
+                if (opt.length >= 2) {
+                    opt32 = toString32(opt[1 .. $]);
+                    foreach (j, c; opt32) {
+                        newopt = .toString("-" ~ [c]);
+                        match = matches(newopt);
+                        if (match is null) {
+                            unknownOptError(newopt);
+                        }
+                        if (match.hasArg) {
+                            // This is the last char in the group, look to the
+                            // next element of args for the arg.
+                            if (j == opt32.length-1) {
+                                if (i == args.length-1) expectedArgError(match.name);
+                                arg = args[i+1];
+                                ++i;
+                            // Otherwise, consume the rest of this group for
+                            // the arg.
+                            } else {
+                                arg = .toString(opt32[j+1 .. $]);
+                                match.performAction(this, options, args, i, arg);
+                                break;
+                            }
+                        } else {
+                            arg = null;
+                        }
+                        match.performAction(this, options, args, i, arg);
+                    }
+                } else {
+                    unknownOptError(opt);
+                }
+            } else {
+                if (this.leftover_cb is null) {
+                    options.args ~= opt;
+                } else {
+                    this.leftover_cb(opt);
+                }
+            }
+        }
+        foreach (o; this.options) {
+            o.issue_default(options);
+        }
+        return options;
+    }
+
+    /++
+    Overrides the default behavior of leftover arguments, calling this callback
+    with them instead of adding them an array.
+    +/
+    void leftoverCallback(OptionCallbackArg dg) {
+        this.leftover_cb = dg;
+    }
+    ///
+    Option addOption(Option option) {
+        this.options ~= option;
+        return option;
+    }
+    //                    options  action             name  type                       const_value  dga   dgv   dgi   fdga  fdgi  fdg
+    ///
+    Option addOption(char[][] options ...) {
+        return addOption(options, Action.Store,      null, defaultType(Action.Store), null,        null, null, null, null, null, null);
+    }
+    ///
+    Option addOption(char[][] options, char[] name) {
+        return addOption(options, Action.Store,      name, defaultType(Action.Store), null,        null, null, null, null, null, null);
+    }
+    ///
+    Option addOption(char[][] options, Action action) {
+        return addOption(options, action,            null, defaultType(action),       null,        null, null, null, null, null, null);
+    }
+    ///
+    Option addOption(char[][] options, ArgType type) {
+        return addOption(options, Action.Store,      null, type,                      null,        null, null, null, null, null, null);
+    }
+    ///
+    Option addOption(char[][] options, Action action, ArgType type) {
+        return addOption(options, action,            null, type,                      null,        null, null, null, null, null, null);
+    }
+    ///
+    Option addOption(char[][] options, char[] name, Action action) {
+        return addOption(options, action,            name, defaultType(action),       null,        null, null, null, null, null, null);
+    }
+    ///
+    Option addOption(char[][] options, char[] name, Action action, ArgType type) {
+        return addOption(options, action,            name, type,                      null,        null, null, null, null, null, null);
+    }
+    ///
+    Option addOption(char[][] options, Action action, char[] const_value) {
+        return addOption(options, action,            null, defaultType(action),       const_value, null, null, null, null, null, null);
+    }
+    ///
+    Option addOption(char[][] options, char[] name, char[] const_value) {
+        return addOption(options, Action.StoreConst, name, defaultType(Action.Store), const_value, null, null, null, null, null, null);
+    }
+    ///
+    Option addOption(char[][] options, char[] name, Action action, char[] const_value) {
+        return addOption(options, action,            name, defaultType(action),       const_value, null, null, null, null, null, null);
+    }
+    ///
+    Option addOption(char[][] options, OptionCallbackArg dg) {
+        return addOption(options, Action.Callback,   null, ArgType.String,            null,        dg,   null, null, null, null, null);
+    }
+    ///
+    Option addOption(char[][] options, OptionCallback dg) {
+        return addOption(options, Action.Callback,   null, ArgType.None,              null,        null, dg,   null, null, null, null);
+    }
+    ///
+    Option addOption(char[][] options, OptionCallbackInt dg) {
+        return addOption(options, Action.Callback,   null, ArgType.Integer,           null,        null, null, dg,   null, null, null);
+    }
+    ///
+    Option addOption(char[][] options, OptionCallbackFancyArg dg) {
+        return addOption(options, Action.CallbackFancy, null, ArgType.String,         null,        null, null, null, dg,   null, null);
+    }
+    ///
+    Option addOption(char[][] options, OptionCallbackFancy dg) {
+        return addOption(options, Action.CallbackFancy, null, ArgType.None,           null,        null, null, null, null, null, dg);
+    }
+    ///
+    Option addOption(char[][] options, OptionCallbackFancyInt dg) {
+        return addOption(options, Action.CallbackFancy, null, ArgType.Integer,        null,        null, null, null, null, dg,   null);
+    }
+    ///
+    Option addOption(char[][] options, char[] name, OptionCallbackFancyArg dg) {
+        return addOption(options, Action.CallbackFancy, name, ArgType.String,         null,        null, null, null, dg,   null, null);
+    }
+    ///
+    Option addOption(char[][] options, char[] name, OptionCallbackFancy dg) {
+        return addOption(options, Action.CallbackFancy, name, ArgType.None,           null,        null, null, null, null, null, dg);
+    }
+    ///
+    Option addOption(char[][] options, char[] name, OptionCallbackFancyInt dg) {
+        return addOption(options, Action.CallbackFancy, name, ArgType.Integer,        null,        null, null, null, null, dg,   null);
+    }
+    // Although users certainly /can/ call this, all those overloads are there
+    // for a reason.
+    Option addOption(
+        char[][] options, 
+        Action action, char[] name, ArgType type, char[] const_value,
+        OptionCallbackArg callback, OptionCallback vcall,
+        OptionCallbackInt icall,
+        OptionCallbackFancyArg fdga,
+        OptionCallbackFancyInt fdgi,
+        OptionCallbackFancy fdg
+    ) {
+        char[][] shortopts;
+        char[][] longopts;
+        dchar[] opt;
+        Option option;
+        foreach (_opt; options) {
+            // (Unicode note: We convert to dchar[] so the length checks work
+            // out in the event of a short opt with a >127 character.)
+            opt = toString32(_opt);
+            if (opt.length < 2) {
+                throw new OptionError(
+                    "invalid option string '" ~ _opt ~ "': must be at least two characters long"
+                );
+            } else if (opt.length > 2) {
+                if (opt[0 .. 2] != "--" || opt[2] == '-')
+                    throw new OptionError(
+                        "invalid long option string '" ~ _opt ~ "': must start with --, followed by non-dash"
+                    );
+                longopts ~= _opt;
+            } else {
+                if (opt[0] != '-' || opt[1] == '-')
+                    throw new OptionError(
+                        "invalid short option string '" ~ _opt ~ "': must be of the form -x, where x is non-dash"
+                    );
+                shortopts ~= _opt;
+            }
+        }
+        if (name is null) {
+            // (Unicode note: We know '-' is a single code unit, so these
+            // slices are okay.)
+            if (longopts.length > 0)
+                name = longopts[0][2 .. $];
+            else if (shortopts.length > 0)
+                name = shortopts[0][1 .. 2];
+            else
+                throw new OptionError(
+                    "No options provided to addOption!"
+                );
+        }
+        option = new Option(shortopts, longopts, type, action, name, const_value, callback, vcall, icall, fdga, fdgi, fdg);
+        this.options ~= option;
+        return option;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dang/compiler.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,171 @@
+module dang.compiler;
+
+import tango.io.Stdout,
+       tango.core.Signal,
+       tango.io.FilePath;
+
+import lexer.Lexer,
+       parser.Parser;
+
+import misc.DataSource;
+
+import ast.Decl;
+
+import tools.AstPrinter,
+       tools.DotPrinter;
+
+import gen.LuaGen,
+       gen.LLVMGen;
+
+import sema.Visitor;
+
+import dang.OptParse;
+
+void checkFiles(char[][] *files)
+{
+    bool error = false;
+
+    char[][] validFiles;
+
+    foreach(file ; *files)
+    {
+        auto path = new FilePath(file);
+
+        if(!path.exists)
+        {
+            Stdout("File '"~file~"' does not exists").newline;
+            error = true;
+
+            continue;
+        }
+        
+        bool fileInStack = false;
+        foreach(vFile ; validFiles)
+            if(vFile == file)
+                fileInStack = true;
+
+        if(fileInStack)
+            continue;
+
+        validFiles ~= file;
+    }
+
+    *files = validFiles;
+
+    if(error)
+        throw new Exception("Some file(s) did not exist");
+}
+void main(char[][] args)
+{
+    char[][] filesToHandle;
+
+    Signal!(char[][]*) preStart;
+
+    Signal!(char[]) preLex;
+    Signal!(Lexer) postLex;
+
+    Signal!(Lexer) preParse;
+    Signal!(Decl[], DataSource) postParse;
+
+    preStart.attach(&checkFiles);
+
+    auto argParse = new OptionParser;
+
+    argParse.addOption(
+            ["-h", "--help"],{
+                argParse.helpText();
+                return;
+            }
+    ).help("Show this help message");
+
+    argParse.addOption(
+            ["--ast-dump-dot"], {
+                postParse.attach(
+                    (Decl[] decls, DataSource src) {
+                        auto print = new DotPrinter();
+                        print.print(decls);
+                    });
+            }
+    ).help("Output the AST as dot-graphicz");
+
+    argParse.addOption(
+            ["--ast-dump-code"], {
+                postParse.attach(
+                    (Decl[] decls, DataSource src) {
+                        auto print = new AstPrinter(src);
+                        print.print(decls);
+                    });
+            }
+    ).help("Output the AST as dot-graphicz");
+
+    argParse.addOption(
+            ["--gen-lua"], {
+                postParse.attach(
+                    (Decl[] decls, DataSource src) {
+                        auto luaGen = new LuaGen();
+                        luaGen.gen(decls);
+                    });
+            }
+    ).help("Compile to Lua code");
+
+    argParse.addOption(
+            ["--gen-llvm"], {
+                postParse.attach(
+                    (Decl[] decls, DataSource src) {
+                        auto llvmGen = new LLVMGen();
+                        llvmGen.gen(decls);
+                    });
+            }
+    ).help("Compile to LLVM code");
+
+    auto options = argParse.parse(args);
+
+    filesToHandle ~= options.args;
+    
+    try
+    {
+        preStart(&filesToHandle);
+    }
+    catch(Exception e)
+    {
+        return;
+    }
+
+    foreach(file ; filesToHandle)
+    {
+        preLex(file);
+
+        auto src = DataSource(file);
+        auto lexer = new Lexer(src);
+
+        postLex(lexer);
+
+        preParse(lexer);
+
+        auto parser = new Parser;
+        auto decls = parser.parse(lexer);
+
+        postParse(decls, src);
+    }
+
+/*    if (args.length > 1 && args[1] == "lex")
+    {
+        Token t;
+
+        t = lexer.next();
+        while(t.type != Tok.EOF)
+        {
+            Stdout(src.get(t.position, t.length)).newline;
+            t = lexer.next();
+        }
+    }
+    else
+    {
+        auto decl = parser.parse(lexer);
+        if(args.length > 1 && args[1] == "dump-ast")
+        {
+            auto buffer = new AstBuffer(src.data);
+            decl.print(buffer);
+        }
+    }*/
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dsss.conf	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,9 @@
+[lexer]
+[parser]
+[ast]
+
+[dang/compiler.d]
+Target = Dang
+
+[tests/run.d]
+Target = tests/run
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/LLVMGen.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,409 @@
+module gen.LLVMGen;
+
+import tango.io.Stdout,
+       Int = tango.text.convert.Integer;
+import tango.core.Array : find;
+
+import ast.Decl,
+       ast.Stmt,
+       ast.Exp;
+
+import lexer.Token;
+
+import sema.SymbolTableBuilder;
+
+class LLVMGen
+{
+public:
+    this()
+    {
+        typeToLLVM =
+        [
+            "int"[]  : "i32"[],
+            "byte"   : "i8",
+            "short"  : "i16",
+            "long"   : "i64",
+            "float"  : "float",
+            "double" : "double",
+            "void"   : "void",
+            "+"      : "add",
+            "-"      : "sub",
+            "*"      : "mul",
+            "/"      : "div"
+        ];
+        table = new SimpleSymbolTable();
+    }
+
+    void gen(Decl[] decls)
+    {
+        // Fill in scopes
+        (new SymbolTableBuilder).visit(decls);
+
+        table.enterScope;
+
+        foreach(decl ; decls)
+                genRootDecl(decl);
+
+        table.leaveScope;
+    }
+
+    void genRootDecl(Decl decl)
+    {
+        switch(decl.declType)
+        {
+            case DeclType.FuncDecl:
+                FuncDecl funcDecl = cast(FuncDecl)decl;
+
+                printBeginLine("define ");
+                print(typeToLLVM[funcDecl.type.token.get]);
+                print(" @");
+                genIdentifier(funcDecl.identifier);
+                print("(");
+
+                table.enterScope;
+                Identifier[] args;
+                foreach(i, funcArg ; funcDecl.funcArgs)
+                {
+                    print(typeToLLVM[funcArg.type.token.get]);
+                    print(" %");
+                    print("."~Integer.toString(i));
+                    args ~= funcArg.identifier;
+                    table.find(funcArg.identifier.get);
+                    if(i+1 < funcDecl.funcArgs.length)
+                        print(", ");
+                }
+                
+                printEndLine(") {");
+                
+                indent;
+
+                foreach(i, arg ; args)
+                {
+                    auto sym = funcDecl.env.find(arg);
+                    auto type = typeToLLVM[sym.type.get];
+                    printBeginLine("%"~arg.get);
+                    printEndLine(" = alloca " ~ type);
+                    printBeginLine("store " ~ type ~ " %.");
+                    print(Integer.toString(i));
+                    print(", " ~ type ~ "* %");
+                    printEndLine(arg.get);
+                }
+
+                printEndLine();
+
+                foreach(stmt ; funcDecl.statements)
+                {
+                    genStmt(stmt);
+                }
+                table.leaveScope;
+                dedent;
+                printBeginLine("}");
+                printEndLine();
+                
+                break;
+
+            case DeclType.VarDecl:
+                auto varDecl = cast(VarDecl)decl;
+                printBeginLine("@");
+                genIdentifier(varDecl.identifier);
+                
+                print(" = ");
+                if(varDecl.init)
+                {
+                    if(cast(IntegerLit)varDecl.init)
+                        printEndLine("global i32 " ~ (cast(IntegerLit)varDecl.init).token.get);
+                    else
+                        assert(0,"Declaring an variable to an expression is not allowed");
+                }
+                else
+                    printEndLine("i32 0");
+
+                printEndLine();
+        
+            default:
+        }
+    }
+
+    void genDecl(Decl decl)
+    {
+        switch(decl.declType)
+        {
+            case DeclType.VarDecl:
+                auto varDecl = cast(VarDecl)decl;
+                printBeginLine("%");
+                print(table.find(varDecl.identifier.get));
+                print(" = alloca ");
+                printEndLine(typeToLLVM[varDecl.type.get]);
+                if(varDecl.init)
+                {
+                    auto assignExp = new AssignExp(varDecl.identifier, varDecl.init);
+                    assignExp.env = decl.env;
+                    assignExp.identifier.env = decl.env;
+                    genExpression(assignExp);
+                }
+        
+            default:
+        }
+    }
+
+    void unify(Ref* a, Ref* b)
+    {
+        if (a.type != b.type)
+        {
+            auto a_val = intTypes.find(a.type);
+            auto b_val = intTypes.find(b.type);
+            // swap types so a is always the "largest" type 
+            if (a_val < b_val)
+            {
+                Ref* tmp = b;
+                b = a;
+                a = tmp;
+            }
+
+            auto res = table.find("%.cast");
+            printBeginLine(res);
+            printCastFromTo(b, a);
+            print(*b);
+            print(" to ");
+            printEndLine(a.type);
+
+            b.type = a.type;
+            b.name = res;
+        }
+    }
+
+    Ref genExpression(Exp exp)
+    {
+        switch(exp.expType)
+        {
+            case ExpType.Binary:
+                auto binaryExp = cast(BinaryExp)exp;
+
+                auto left = genExpression(binaryExp.left);
+                auto right = genExpression(binaryExp.right);
+
+                unify(&left, &right);
+
+                auto res = Ref(left.type, table.find);
+                printBeginLine(res.name);
+                print(" = "~typeToLLVM[[binaryExp.op]]~" ");
+                print(left);
+                print(", ");
+                printEndLine(right.name);
+                return res;
+            case ExpType.IntegerLit:
+                auto integetLit = cast(IntegerLit)exp;
+                auto t = integetLit.token;
+                return Ref("int", t.get, true);
+            case ExpType.Negate:
+                auto negateExp = cast(NegateExp)exp;
+                auto target = genExpression(negateExp.exp);
+                auto res = table.find;
+                printBeginLine(res);
+                print(" = sub "~target.type~" 0, ");
+                printEndLine(target.name);
+                return Ref(target.type, res);
+            case ExpType.AssignExp:
+                auto assignExp = cast(AssignExp)exp;
+                auto sym = exp.env.find(assignExp.identifier);
+
+                Ref val = genExpression(assignExp.exp);
+                Ref r = Ref(typeToLLVM[sym.type.get], val.name);
+
+                if (val.type != r.type)
+                {
+                    auto res = table.find("%.cast");
+                    printBeginLine(res);
+                    printCastFromTo(val.type, r.type);
+                    print(val);
+                    print(" to ");
+                    printEndLine(r.type);
+                    r.name = res;
+                }
+
+                printBeginLine("store ");
+                print(r);
+                print(", ");
+                print(r.type ~ "* %");
+                printEndLine(assignExp.identifier.get);
+                break;
+            case ExpType.CallExp:
+                auto callExp = cast(CallExp)exp;
+                auto func_sym = exp.env.find(cast(Identifier)callExp.exp);
+                auto func_type = typeToLLVM[func_sym.type.get];
+                Ref[] args;
+                foreach(i, arg ; callExp.args)
+                    args ~= genExpression(arg);
+
+                char[] res = table.find;
+                printBeginLine(res);
+                print(" = call ");
+                print(func_type);
+                print(" @");
+                
+                print(func_sym.id.get);
+
+                print("(");
+                foreach(i, arg ; args)
+                {
+                    print(arg);
+                    if(i+1 < args.length)
+                        print(", ");
+                }
+                printEndLine(")");
+                return Ref(func_sym.type.get, res);
+            case ExpType.Identifier:
+                auto identifier = cast(Identifier)exp;
+                auto sym = exp.env.find(identifier);
+                char[] res = table.find;
+                printBeginLine(res);
+                print(" = load ");
+                print(typeToLLVM[sym.type.get]);
+                print("* %");
+                printEndLine(sym.id.name);
+                return Ref(sym.type.get, res);
+        }
+        return Ref();
+    }
+
+    void genStmt(Stmt stmt)
+    {
+        switch(stmt.stmtType)
+        {
+            case StmtType.Return:
+                auto ret = cast(ReturnStmt)stmt;
+                Ref res = genExpression(ret.exp);
+                printBeginLine("ret ");
+                printEndLine(res);
+                break;
+            case StmtType.Decl:
+                auto declStmt = cast(DeclStmt)stmt;
+                genDecl(declStmt.decl);
+                break;
+            case StmtType.Exp:
+                auto expStmt = cast(ExpStmt)stmt;
+                genExpression(expStmt.exp);
+                break;
+
+        }
+    }
+
+    void genIdentifier(Identifier identifier)
+    {
+        print(identifier.get);
+    }
+
+    void indent()
+    {
+        tabIndex ~= tabType;
+    }
+
+    void dedent()
+    {
+        tabIndex = tabIndex[0 .. $-tabType.length];
+    }
+
+    void printBeginLine(char[] line = "")
+    {
+        Stdout(tabIndex~line);
+    }
+    void printBeginLine(Ref r)
+    {
+        Stdout(tabIndex~r.type~" "~r.name);
+    }
+
+    void printEndLine(char[] line = "")
+    {
+        Stdout(line).newline;
+    }
+
+    void printEndLine(Ref r)
+    {
+        Stdout(r.type~" "~r.name).newline;
+    }
+
+    void print(char[] line)
+    {
+        Stdout(line);
+    }
+
+    void print(Ref r)
+    {
+        Stdout(r.type~" "~r.name);
+    }
+
+    void printCastFromTo(size_t t1, size_t t2)
+    {
+        if (t1 < t2)
+            print(" = zext ");
+        else
+            print(" = trunc ");
+    }
+
+    void printCastFromTo(char[] t1, char[] t2)
+    {
+        printCastFromTo(intTypes.find(t1), intTypes.find(t2));
+    }
+
+    void printCastFromTo(Ref* t1, Ref* t2)
+    {
+        printCastFromTo(intTypes.find(t1.type), intTypes.find(t2.type));
+    }
+
+private:
+
+    char[] tabIndex;
+    const char[] tabType = "    "; // 4 spaces
+    FuncDecl[char[]] functions;
+
+    SimpleSymbolTable table;
+    SymbolTable symbolTable;
+    static char[][char[]] typeToLLVM;
+
+    static char[][] intTypes = [ "i8", "i16", "i32", "i64" ];
+}
+
+struct Ref
+{
+    char[] type;
+    char[] name;
+    bool atomic = false;
+    static Ref opCall(char[] type = "void", char[] name = "", bool atomic = false)
+    {
+        Ref r;
+        if(auto llvm_t = type in LLVMGen.typeToLLVM)
+            r.type = *llvm_t;
+        else
+            r.type = type;
+        r.name = name;
+        r.atomic = atomic;
+        return r;
+    }
+}
+
+class SimpleSymbolTable
+{
+    int[char[]][] variables;
+
+    void enterScope()
+    {
+        variables ~= cast(int[char[]])["__dollar":-1];
+    }
+
+    void leaveScope()
+    {
+        variables.length = variables.length - 1;
+    }
+
+    char[] find(char[] v = "%.tmp")
+    {
+        foreach_reverse(map ; variables)
+        {
+            if(v in map)
+                return v~"."~Integer.toString(++map[v]);
+        }
+        variables[$-1][v] = 0;
+        return v;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/LuaGen.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,180 @@
+module gen.LuaGen;
+
+import tango.io.Stdout,
+       Int = tango.text.convert.Integer;
+
+import ast.Decl,
+       ast.Stmt,
+       ast.Exp;
+
+import lexer.Token;
+
+class LuaGen
+{
+public:
+    this()
+    {
+    }
+    
+    void gen(Decl[] decls)
+    {
+
+        foreach(decl ; decls)
+                genDecl(decl);
+        printBeginLine("main()");
+        printEndLine;
+    }
+
+    void genDecl(Decl decl)
+    {
+        switch(decl.declType)
+        {
+            case DeclType.FuncDecl:
+                FuncDecl funcDecl = cast(FuncDecl)decl;
+
+                printBeginLine("function ");
+                genIdentifier(funcDecl.identifier);
+                print("(");
+                foreach(i, funcArg ; funcDecl.funcArgs)
+                {
+                    genIdentifier(funcArg.identifier);
+                    if(i+1 < funcDecl.funcArgs.length)
+                        print(", ");
+                }
+                printEndLine(")");
+                indent;
+                foreach(stmt ; funcDecl.statements)
+                {
+                    genStmt(stmt);
+                }
+                dedent;
+                printBeginLine("end");
+                printEndLine();
+                break;
+
+            case DeclType.VarDecl:
+                genVarDecl(cast(VarDecl)decl);
+
+            default:
+        }
+    }
+
+    void genStmt(Stmt stmt)
+    {
+        switch(stmt.stmtType)
+        {
+            case StmtType.Return:
+                auto ret = cast(ReturnStmt)stmt;
+                printBeginLine("return ");
+                genExpression(ret.exp);
+                printEndLine();
+                break;
+            case StmtType.Decl:
+                auto declStmt = cast(DeclStmt)stmt;
+                genDecl(declStmt.decl);
+                break;
+            case StmtType.Exp:
+                auto expStmt = cast(ExpStmt)stmt;
+                printBeginLine();
+                genExpression(expStmt.exp);
+                printEndLine();
+                break;
+
+        }
+    }
+
+    void genVarDecl(VarDecl decl)
+    {
+        printBeginLine("local ");
+        genIdentifier(decl.identifier);
+        if(decl.init)
+        {
+            print(" = ");
+            genExpression(decl.init);
+        }
+        printEndLine();
+
+    }
+
+    void genExpression(Exp exp)
+    {
+        switch(exp.expType)
+        {
+            case ExpType.Binary:
+                auto binaryExp = cast(BinaryExp)exp;
+                genExpression(binaryExp.left);
+                print(" " ~ [binaryExp.op] ~ " ");
+                genExpression(binaryExp.right);
+                break;
+            case ExpType.IntegerLit:
+                auto integetLit = cast(IntegerLit)exp;
+                auto t = integetLit.token;
+                print(t.get);
+                break;
+            case ExpType.Negate:
+                auto negateExp = cast(NegateExp)exp;
+                print("-(");
+                genExpression(negateExp.exp);
+                print(")");
+                break;
+            case ExpType.AssignExp:
+                auto assignExp = cast(AssignExp)exp;
+                genIdentifier(assignExp.identifier);
+                print(" = ");
+                genExpression(assignExp.exp);
+                break;
+            case ExpType.CallExp:
+                auto callExp = cast(CallExp)exp;
+                genExpression(callExp.exp);
+                print("(");
+                foreach(i, arg ; callExp.args)
+                {
+                    genExpression(arg);
+                    if(i+1 < callExp.args.length)
+                        print(", ");
+                }
+                print(")");
+                break;
+            case ExpType.Identifier:
+                auto identifier = cast(Identifier)exp;
+                print(identifier.token.get);
+                break;
+        }
+
+    }
+
+    void genIdentifier(Identifier identifier)
+    {
+        print(identifier.token.get);
+    }
+
+    void indent()
+    {
+        tabIndex ~= tabType;
+    }
+
+    void dedent()
+    {
+        tabIndex = tabIndex[0 .. $-tabType.length];
+    }
+
+    void printBeginLine(char[] line = "")
+    {
+        Stdout(tabIndex~line);
+    }
+
+    void printEndLine(char[] line = "")
+    {
+        Stdout(line).newline;
+    }
+
+    void print(char[] line)
+    {
+        Stdout(line);
+    }
+
+private:
+    char[] tabIndex;
+    const char[] tabType = "    "; // 4 spaces
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lexer/Keyword.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,25 @@
+module lexer.Keyword;
+
+import lexer.Token;
+
+Tok[char[]] keywords;
+
+static this ()
+{
+    keywords =
+    [
+        "byte"[]    : Tok.Byte,
+        "ubyte"     : Tok.Ubyte,
+        "short"     : Tok.Short,
+        "ushort"    : Tok.Ushort,
+        "int"       : Tok.Int,
+        "uint"      : Tok.Uint,
+        "long"      : Tok.Long,
+        "ulong"     : Tok.Ulong,
+
+        "float"     : Tok.Float,
+        "double"    : Tok.Double,
+
+        "return"    : Tok.Return
+    ];
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lexer/Lexer.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,224 @@
+module lexer.Lexer;
+
+import misc.Error,
+       misc.DataSource;
+
+import lexer.Token,
+       lexer.Keyword;
+
+import tango.io.Stdout;
+
+class Lexer
+{
+public:
+    this (DataSource source)
+    {
+        this.source = source;
+        this.position = 0;
+    }
+
+    Token next ()
+    {
+        switch (getNextChar)
+        {
+            case CharType.EOF:
+                Location l;
+                return Token (Tok.EOF, l, 0); 
+
+            case CharType.Whitespace:
+                position += 1;
+                return this.next;
+
+            case CharType.Symbol:
+                return lexSymbol;
+
+            case CharType.Letter:
+                return lexLetter;
+
+            case CharType.Number:
+                return lexNumber;
+        }
+    }
+
+    Token peek ( int skip = 0)
+    {
+        int oldPosition = this.position;
+        while(skip-- > 0)
+            this.next;
+        Token t = this.next;
+        this.position = oldPosition;
+        return t;
+    }
+
+    public Error[] getErrors()
+    {
+        return this.errors;
+    }
+private:
+
+    Token lexNumber ()
+    {
+        int i = 0;
+        while(getNextChar(++i) == CharType.Number)
+        {}
+
+        position += i;
+
+        return Token(Tok.Integer, Location(position - i, this.source), i);
+    }
+
+    Token lexSymbol ()
+    {
+        switch(source.data[position++])
+        {
+            case '(':
+                return Token(Tok.OpenParentheses, Location(position - 1, this.source), 1);
+            case ')':
+                return Token(Tok.CloseParentheses, Location(position - 1, this.source), 1);
+            case '{':
+                return Token(Tok.OpenBrace, Location(position - 1, this.source), 1);
+            case '}':
+                return Token(Tok.CloseBrace, Location(position - 1, this.source), 1);
+            case ';':
+                return Token(Tok.Seperator, Location(position - 1, this.source), 1);
+            case ',':
+                return Token(Tok.Comma, Location(position - 1, this.source), 1);
+            case '=':
+                return Token(Tok.Assign, Location(position - 1, this.source), 1);
+            case '+':
+                return Token(Tok.Add, Location(position - 1, this.source), 1);
+            case '-':
+                return Token(Tok.Sub, Location(position - 1, this.source), 1);
+            case '*':
+                return Token(Tok.Mul, Location(position - 1, this.source), 1);
+            case '/':
+                switch(source.data[position])
+                {
+                    case '/':
+                        while(getNextChar != CharType.EOF)
+                        {
+                            if(source.data[position++] == '\n')
+                                return this.next;
+                        }
+                        return Token(Tok.EOF, Location(position, this.source), 0);
+
+                    case '*':
+                        position += 2;
+                        while(getNextChar != CharType.EOF)
+                        {
+                            ++position;
+                            if(source.data[position-2] == '*')
+                                if(source.data[position-1] == '/')
+                                   return this.next;
+                        }
+                        return Token(Tok.EOF, Location(position, this.source), 0);
+
+                    case '+':
+                        position += 2;
+                        int nesting = 1;
+                        while(getNextChar != CharType.EOF)
+                        {
+                            ++position;
+                            if(source.data[position-2] == '+')
+                                if(source.data[position-1] == '/')
+                                {
+                                    position++;
+                                    nesting--;
+                                }
+
+                            if(source.data[position-2] == '/')
+                                if(source.data[position-1] == '+')
+                                {
+                                    nesting++;
+                                    position++;
+                                }
+
+                            if(nesting == 0)
+                                return this.next;
+                        }
+                        return Token(Tok.EOF, Location(position, this.source), 0);
+
+                    default:
+                        return Token(Tok.Div, Location(position - 1, this.source), 1);
+                }
+        }
+    }
+
+    Token lexLetter ()
+    {
+        int i = 0;
+        bool hasNumber = false;
+        while (getNextChar(++i) == CharType.Letter || 
+                getNextChar(i) == CharType.Number)
+        {
+            if (getNextChar(i) == CharType.Number)
+            {
+                hasNumber = true;
+            }
+        }
+
+        Token t = Token(Tok.Identifier, Location(position, source), i);
+
+        if (!hasNumber)
+        {
+            char[] str = source.data[position .. position + i];
+            if(str in keywords)
+                t.type = keywords[str];
+        }
+
+        position += i;
+
+        return t;
+    }
+
+    CharType getNextChar(int offset = 0)
+    {
+        if (position + offset >= this.source.data.length)
+            return CharType.EOF;
+
+        char current = source.data[position + offset];
+
+        if (current >= 'A' && current <= 'Z' ||
+            current >= 'a' && current <= 'z' || current > 127)
+            return CharType.Letter;
+
+        if (current >= '0' && current <= '9')
+            return CharType.Number;
+
+        switch(current)
+        {
+            case ' ':
+            case '\n':
+                return CharType.Whitespace;
+
+            case '(':
+            case ')':
+            case '{':
+            case '}':
+            case ';':
+            case ',':
+            case '=':
+            case '+':
+            case '-':
+            case '*':
+            case '/':
+                return CharType.Symbol;
+
+        }
+
+    }
+
+    DataSource source;
+    int position;
+    Error[] errors;
+}
+
+enum CharType : ubyte
+{
+    Letter,
+    Number,
+    Symbol,
+    Whitespace,
+
+    EOF
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lexer/Token.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,98 @@
+module lexer.Token;
+
+public 
+import misc.Location;
+
+import Integer = tango.text.convert.Integer;
+
+struct Token
+{
+    Tok type;
+    Location location;
+    uint length;
+
+    static Token opCall (Tok type, Location location, uint length)
+    {
+        Token t;
+        t.type = type;
+        t.location = location;
+        t.length = length;
+        return t;
+    }
+
+    char[] getType ()
+    {
+        return typeToString[this.type];
+    }
+
+    char[] toString ()
+    {
+        return this.getType()~": Len: "~Integer.toString(this.length)
+            ~", Loc: "~location.toString;
+    }
+
+    char[] get ()
+    {
+        return location.get(length);
+    }
+}
+
+enum Tok : ushort
+{
+    /* Non-code related tokens */
+    EOF,
+
+    /* Basic types */
+    Identifier,
+    Integer,
+
+    /* Basic operators */
+    Assign,
+    Add, Sub,
+    Mul, Div,
+    Comma,
+
+    /* Symbols */
+    OpenParentheses,
+    CloseParentheses,
+    OpenBrace,
+    CloseBrace,
+    Seperator,
+
+    /* Keywords */
+    Byte, Ubyte,
+    Short, Ushort,
+    Int, Uint,
+    Long, Ulong,
+
+    Float, Double,
+
+    Return,
+
+}
+
+public char[][Tok] typeToString;
+
+static this()
+{
+    typeToString =
+    [
+        Tok.EOF:"EOF"[],
+        Tok.Identifier:"Identifier",
+        Tok.Byte:"Byte",
+        Tok.Short:"Short",
+        Tok.Int:"Int",
+        Tok.Long:"Long",
+        Tok.OpenParentheses:"OpenParentheses",
+        Tok.CloseParentheses:"CloseParentheses",
+        Tok.OpenBrace:"OpenBrace",
+        Tok.CloseBrace:"CloseBrace",
+        Tok.Assign:"Assign",
+        Tok.Add:"Add",
+        Tok.Sub:"Sub",
+        Tok.Mul:"Mul",
+        Tok.Div:"Div",
+        Tok.Integer:"Interger",
+        Tok.Seperator:"Seperator"
+    ];
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/DataSource.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,25 @@
+module misc.DataSource;
+
+import tango.io.UnicodeFile;
+
+struct DataSource
+{
+    char[] name;
+    char[] data;
+
+    static DataSource opCall(char[] name)
+    {
+        DataSource source;
+
+        auto file = new UnicodeFile!(char)(name, Encoding.UTF_8);
+
+        source.name = name;
+        source.data = file.read();
+        return source;
+    }
+
+    char[] get(uint position, ushort len)
+    {
+        return data[position .. position+len];
+    }    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/Error.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,9 @@
+module misc.Error;
+
+import misc.Location;
+
+struct Error
+{
+    char[] messeage;
+    Location errorLocation;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/Location.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,21 @@
+module misc.Location;
+
+import misc.DataSource;
+
+import Integer = tango.text.convert.Integer;
+
+struct Location
+{
+    uint position;
+    DataSource source;
+
+    char[] toString ()
+    {
+        return Integer.toString (position) ~" in "~source.name;
+    }
+
+    char[] get(uint length)
+    {
+        return source.get(position, length);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parser/Parser.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,305 @@
+module parser.Parser;
+
+import lexer.Lexer,
+       lexer.Token;
+
+import ast.Exp,
+       ast.Stmt,
+       ast.Decl;
+
+import tango.io.Stdout,
+       Integer = tango.text.convert.Integer;
+
+class Parser
+{
+
+public:
+    Decl[] parse(Lexer lexer)
+    {
+        this.lexer = lexer;
+
+
+        Decl[] declarations;
+
+        while(lexer.peek.type != Tok.EOF)
+        {
+            declarations ~= parseDecl;
+        }
+
+        return declarations;
+    }
+
+    Decl parseDecl()
+    {
+        Token t = lexer.next;
+
+        switch(t.type)
+        {
+            case Tok.Byte,  Tok.Ubyte,
+                 Tok.Short, Tok.Ushort,
+                 Tok.Int,   Tok.Uint,
+                 Tok.Long,  Tok.Ulong,
+                 Tok.Float, Tok.Double,
+                 Tok.Identifier:
+                Identifier type = new Identifier(t);
+
+                Token iden = lexer.next;
+                switch(iden.type)
+                {
+                    case Tok.Identifier:
+                        Identifier identifier = new Identifier(iden);
+                        Token p = lexer.peek();
+                        switch(p.type)
+                        {
+                            case Tok.OpenParentheses:
+                                return parseFunc(type, identifier);
+                            case Tok.Seperator:
+                                require(Tok.Seperator);
+                                return new VarDecl(type, identifier, null);
+                            case Tok.Assign:
+                                lexer.next();
+                                auto exp = parseExpression();
+                                require(Tok.Seperator);
+                                return new VarDecl(type, identifier, exp);
+                            default:
+                                char[] c = t.getType;
+                                error("Unexpexted token "~c~" at line "~Integer.toString(__LINE__));
+                        }
+                        break;
+                    default:
+                        char[] c = t.getType;
+                        error("Unexpexted token "~c~" at line "~Integer.toString(__LINE__));
+                }
+                break;
+
+            case Tok.EOF:
+                return null;
+            default:
+                char[] c = t.getType;
+                error("Unexpexted token "~c~" at line "~Integer.toString(__LINE__));
+        }
+    }
+
+    Stmt parseStatement()
+    {
+        Token t = lexer.peek;
+
+        switch(t.type)
+        {
+            case Tok.Return:
+                lexer.next;
+                auto ret = new ReturnStmt();
+                ret.exp = parseExpression();
+                require(Tok.Seperator);
+                return ret;
+            case Tok.Identifier:
+                Token n = lexer.peek(1);
+                switch(n.type)
+                {
+                    case Tok.Assign:
+                        lexer.next;
+                        lexer.next;
+                        auto stmt = new ExpStmt(new AssignExp(new Identifier(t), parseExpression()));
+                        require(Tok.Seperator);
+                        return stmt;
+                        break;
+
+                    default:
+                        auto e = new ExpStmt(parseExpression());
+                        require(Tok.Seperator);
+                        return e;
+
+                }
+                break;
+
+            default:
+                auto decl = new DeclStmt(parseDecl());
+                //require(Tok.Seperator);
+                return decl;
+        }
+        return new Stmt();
+    }
+
+    FuncDecl parseFunc(Identifier type, Identifier identifier)
+    {
+        VarDecl[] funcArgs = parseFuncArgs();
+
+        lexer.next; // Remove the "{"
+
+        Stmt[] statements;
+
+        while(lexer.peek.type != Tok.CloseBrace)
+            statements ~= parseStatement();
+
+        lexer.next; // Remove "}"
+
+        return new FuncDecl(type, identifier, funcArgs, statements);
+    }
+
+    VarDecl[] parseFuncArgs()
+    {
+        lexer.next; // Remove the "(" token.
+
+        VarDecl[] funcArgs;
+
+        while(lexer.peek.type != Tok.CloseParentheses)
+        {
+            funcArgs ~= new VarDecl(parseType, parseIdentifier);
+
+            if(lexer.peek.type == Tok.Comma)
+                lexer.next;
+        }
+
+        lexer.next; // Remove the ")"
+
+        return funcArgs;
+    }
+
+    Identifier parseIdentifier()
+    {
+        Token identifier = lexer.next;
+
+        switch(identifier.type)
+        {
+            case Tok.Identifier:
+                return new Identifier(identifier);
+                break;
+            default:
+                error("Unexpexted token in Identifier parsing");
+        }
+    }
+
+    Identifier parseType()
+    {
+        Token type = lexer.next;
+
+        switch(type.type)
+        {
+            case Tok.Byte,  Tok.Ubyte,
+                 Tok.Short, Tok.Ushort,
+                 Tok.Int,   Tok.Uint,
+                 Tok.Long,  Tok.Ulong,
+                 Tok.Float, Tok.Double,
+                 Tok.Identifier:
+                return new Identifier(type);
+                break;
+            default:
+                char[] c = type.getType;
+                error("Unexpexted token in Type parsing. Got "~c);
+        }
+    }
+
+    // -- Expression parsing -- //
+private:
+    Exp parseExpression(int p = 0)
+    {
+        auto exp = P();
+        Token next = lexer.peek();
+        BinOp* op = null;
+        while ((op = binary(next.type)) != null && op.prec >= p)
+        {
+            lexer.next();
+            int q = op.leftAssoc? 1 + op.prec : op.prec;
+            auto exp2 = parseExpression(q);
+            exp = new BinaryExp(op.operator, exp, exp2);
+            next = lexer.peek();
+        }
+
+        return exp;
+    }
+
+    Exp P()
+    {
+        Token next = lexer.next();
+        if (auto op = unary(next.type))
+            return new NegateExp(parseExpression(op.prec));
+        else if (next.type == Tok.OpenParentheses)
+        {
+            auto e = parseExpression(0);
+            require(Tok.CloseParentheses);
+            return e;
+        }
+        else if (next.type == Tok.Identifier)
+        {
+            switch(lexer.peek.type)
+            {
+                case Tok.OpenParentheses:
+                    lexer.next;
+                    Exp[] args;
+                    while(lexer.peek.type != Tok.CloseParentheses)
+                    {
+                        if(lexer.peek.type == Tok.Comma)
+                        {
+                            lexer.next;
+                        }
+                        args ~= parseExpression();
+                    }
+
+                    lexer.next();
+                    return new CallExp(new Identifier(next), args);
+
+                default:
+                    return new Identifier(next);
+            }
+        }
+        else if (next.type == Tok.Integer)
+            return new IntegerLit(next);
+
+        Stdout.formatln("{}", next.getType);
+        assert(0, "Should not happen");
+    }
+
+    struct UnOp
+    {
+        Tok tokenType;
+        int prec;
+    }
+
+    static UnOp[] _unary = [{Tok.Sub, 4}];
+    UnOp* unary(Tok t)
+    {
+        foreach (ref op; _unary)
+            if (op.tokenType == t)
+                return &op;
+        return null;
+    }
+
+    struct BinOp
+    {
+        Tok tokenType;
+        int prec;
+        bool leftAssoc;
+        BinaryExp.Operator operator;
+    }
+
+    static BinOp[] _binary =
+    [
+        {Tok.Add, 3, true, BinaryExp.Operator.Add},
+        {Tok.Sub, 3, true, BinaryExp.Operator.Sub},
+        {Tok.Mul, 5, true, BinaryExp.Operator.Mul},
+        {Tok.Div, 5, true, BinaryExp.Operator.Div}
+    ];
+    BinOp* binary(Tok t)
+    {
+        foreach (ref op; _binary)
+            if (op.tokenType == t)
+                return &op;
+        return null;
+    }
+
+private:
+
+    void require(Tok t)
+    {
+        if (lexer.peek().type != t)
+            error("Unexpexted token: Got '"~lexer.peek.getType~"' Expected '"~typeToString[t]~"'");
+        lexer.next();
+    }
+
+    void error(char[] errMsg)
+    {
+        throw new Exception("Parser error: " ~errMsg);
+    }
+
+    Lexer lexer;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sema/SymbolTable.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,57 @@
+module sema.SymbolTable;
+
+import tango.io.Stdout;
+
+import lexer.Token;
+
+import ast.Exp : Identifier;
+
+class SymbolTable
+{
+}
+
+class Scope
+{
+    this() {}
+    this(Scope enclosing)
+    {
+        this.enclosing = enclosing;
+    }
+
+    Scope enclosing;
+
+    Symbol add(Identifier id)
+    {
+        auto s = new Symbol;
+        s.id = id;
+        symbols[id] = s;
+        return s;
+    }
+
+    Symbol find(Identifier id)
+    {
+        if (auto sym = id in symbols)
+            return *sym;
+        if (enclosing !is null)
+            return enclosing.find(id);
+        return null;
+    }
+
+    char[][] names()
+    {
+        char[][] res;
+        foreach (id, sym; symbols)
+            res ~= sym.id.name ~ " : " ~ sym.type.name;
+        return res;
+    }
+
+private:
+    Symbol[Identifier] symbols;
+}
+
+class Symbol
+{
+    Identifier id;
+    Identifier type;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sema/SymbolTableBuilder.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,78 @@
+module sema.SymbolTableBuilder;
+
+import tango.io.Stdout;
+
+public import sema.SymbolTable;
+
+import sema.Visitor;
+
+class SymbolTableBuilder : Visitor!(void)
+{
+    this()
+    {
+        table ~= new Scope;
+    }
+
+    override void visit(Decl[] decls)
+    {
+        foreach (decl; decls)
+            visitDecl(decl);
+    }
+
+    override void visitDecl(Decl d)
+    {
+        d.env = current();
+        super.visitDecl(d);
+    }
+
+    override void visitStmt(Stmt s)
+    {
+        s.env = current();
+        super.visitStmt(s);
+    }
+
+    override void visitExp(Exp e)
+    {
+        e.env = current();
+        super.visitExp(e);
+    }
+
+    override void visitFuncDecl(FuncDecl d)
+    {
+        auto sym = current().add(d.identifier);
+        sym.type = d.type;
+        push();
+        d.env = current();
+        super.visitFuncDecl(d);
+        pop();
+    }
+
+    override void visitVarDecl(VarDecl d)
+    {
+        auto sc = current();
+        auto sym = sc.add(d.identifier);
+        sym.type = d.type;
+        super.visitVarDecl(d);
+    }
+
+private:
+    Scope[] table;
+
+    void push()
+    {
+        table ~= new Scope(current());
+    }
+
+    Scope pop()
+    {
+        auto res = table[$ - 1];
+        table.length = table.length - 1;
+        return res;
+    }
+
+    Scope current()
+    {
+        return table[$ - 1];
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sema/Visitor.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,188 @@
+module sema.Visitor;
+
+import tango.io.Stdout;
+
+public
+import ast.Decl,
+       ast.Stmt,
+       ast.Exp;
+
+import lexer.Token;
+
+class Visitor(FinalT = int, DeclT = FinalT, StmtT = DeclT, ExpT = StmtT)
+{
+public:
+    FinalT visit(Decl[] decls)
+    {
+        foreach (decl; decls)
+            visitDecl(decl);
+        static if (is(FinalT == void))
+            return;
+        else
+            return FinalT.init;
+    }
+
+    DeclT visitDecl(Decl decl)
+    {
+        switch(decl.declType)
+        {
+            case DeclType.FuncDecl:
+                return visitFuncDecl(cast(FuncDecl)decl);
+            case DeclType.VarDecl:
+                return visitVarDecl(cast(VarDecl)decl);
+            default:
+                throw new Exception("Unknown declaration type");
+        }
+    }
+
+    StmtT visitStmt(Stmt stmt)
+    {
+        switch(stmt.stmtType)
+        {
+            case StmtType.Return:
+                return visitReturnStmt(cast(ReturnStmt)stmt);
+            case StmtType.Decl:
+                return visitDeclStmt(cast(DeclStmt)stmt);
+            case StmtType.Exp:
+                return visitExpStmt(cast(ExpStmt)stmt);
+            default:
+                throw new Exception("Unknown statement type");
+        }
+    }
+
+    ExpT visitExp(Exp exp)
+    {
+        switch(exp.expType)
+        {
+            case ExpType.Binary:
+                return visitBinaryExp(cast(BinaryExp)exp);
+            case ExpType.IntegerLit:
+                return visitIntegerLit(cast(IntegerLit)exp);
+            case ExpType.Negate:
+                return visitNegateExp(cast(NegateExp)exp);
+            case ExpType.AssignExp:
+                return visitAssignExp(cast(AssignExp)exp);
+            case ExpType.CallExp:
+                return visitCallExp(cast(CallExp)exp);
+            case ExpType.Identifier:
+                return visitIdentifier(cast(Identifier)exp);
+            default:
+                throw new Exception("Unknown expression type");
+        }
+    }
+
+    // Declarations:
+    DeclT visitVarDecl(VarDecl d)
+    {
+        visitExp(d.type);
+        visitExp(d.identifier);
+        if (d.init)
+            visitExp(d.init);
+
+        static if (is(DeclT == void))
+            return;
+        else
+            return DeclT.init;
+    }
+
+    DeclT visitFuncDecl(FuncDecl f)
+    {
+        visitExp(f.type);
+        visitExp(f.identifier);
+        foreach (arg; f.funcArgs)
+            visitDecl(arg);
+        foreach (stmt; f.statements)
+            visitStmt(stmt);
+
+        static if (is(DeclT == void))
+            return;
+        else
+            return DeclT.init;
+    }
+
+    // Statements:
+    StmtT visitReturnStmt(ReturnStmt s)
+    {
+        visitExp(s.exp);
+        static if (is(StmtT == void))
+            return;
+        else
+            return StmtT.init;
+    }
+
+    StmtT visitDeclStmt(DeclStmt d)
+    {
+        visitDecl(d.decl);
+        static if (is(StmtT == void))
+            return;
+        else
+            return StmtT.init;
+    }
+
+    StmtT visitExpStmt(ExpStmt s)
+    {
+        visitExp(s.exp);
+        static if (is(StmtT == void))
+            return;
+        else
+            return StmtT.init;
+    }
+
+    // Expressions:
+    ExpT visitAssignExp(AssignExp exp)
+    {
+        visitExp(exp.identifier);
+        visitExp(exp.exp);
+        static if (is(ExpT == void))
+            return;
+        else
+            return ExpT.init;
+    }
+
+    ExpT visitBinaryExp(BinaryExp exp)
+    {
+        visitExp(exp.left);
+        visitExp(exp.right);
+        static if (is(ExpT == void))
+            return;
+        else
+            return ExpT.init;
+    }
+
+    ExpT visitCallExp(CallExp exp)
+    {
+        visitExp(exp.exp);
+        foreach (arg; exp.args)
+            visitExp(arg);
+        static if (is(ExpT == void))
+            return;
+        else
+            return ExpT.init;
+    }
+
+    ExpT visitNegateExp(NegateExp exp)
+    {
+        visitExp(exp.exp);
+        static if (is(ExpT == void))
+            return;
+        else
+            return ExpT.init;
+    }
+
+    ExpT visitIntegerLit(IntegerLit exp)
+    {
+        static if (is(ExpT == void))
+            return;
+        else
+            return ExpT.init;
+    }
+
+    ExpT visitIdentifier(Identifier exp)
+    {
+        static if (is(ExpT == void))
+            return;
+        else
+            return ExpT.init;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test.td	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,19 @@
+
+int x = 4;
+
+byte main()
+{
+    long var1 = 1;
+    short var2 = 2;
+    return nice(var1, var2);
+}
+
+int nice(long s, short t)
+{
+    byte x = 5 + t;
+    // int f(float z) { return -1 * z; }
+    t = 5 + 1 * 5 * s + t;
+    return 2 * (t + -1) - x;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/lexer/Comments.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,33 @@
+/*
+
+
+   /++
+   +++++
+
+
+   /++++
+
+   */
+
+int i = 0;
+ /// lalalala
+
+/****
+  */
+
+/+
+
+/+
+
++/
+
+/+
+
++/
+
++/
+
+/+ /+/
+fdsafasdf
++/ +/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/lexer/Comments1.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,17 @@
+/*
+
+
+*/
+
+/*/
+
+*/
+
+/+
+
++/
+
+
+/+/
+
++/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/run.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,69 @@
+module run.d;
+
+import tango.io.Stdout,
+       tango.io.FilePath,
+       tango.sys.Process;
+
+
+char[] prog = "./Dang";
+
+void main(char[][] args)
+{
+    auto cPath = FilePath("tests");
+
+    int succes, failure;
+
+    foreach( path ; cPath.toList((FilePath path, bool isFolder){return isFolder;}))
+    {
+        Stdout(path.name)(":").newline;
+        foreach( p ; path.toList((FilePath path, bool isFolder)
+                    {
+                        if(path.ext == "d" && path.name[0] != '.')
+                            return true;
+                        return false;
+                    }))
+        {
+            auto test = new Test(p);
+            bool result = test.run();
+            if(result)
+                succes++;
+            else
+                failure++;
+        }
+    }
+
+    Stdout().newline.newline()
+        ("Result:").newline()
+        ("  - Succes:   ")(succes).newline()
+        ("  - Failure:  ")(failure).newline;
+}
+
+class Test
+{
+    FilePath target;
+    public this(FilePath target)
+    {
+        this.target = target;
+    }
+
+    public bool run()
+    {
+        auto process = new Process(prog,target.path~target.file);
+
+        Stdout("  - ")(target.file)(".. ");
+
+        process.execute;
+
+        auto result = process.wait;
+        if(result.status == 0)
+        {
+            Stdout("SUCCES").newline;
+            return true;
+        }
+        else
+        {
+            Stdout("FAILURE").newline;
+            return false;
+        }
+    }    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/AstPrinter.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,164 @@
+module tools.AstPrinter;
+
+import tango.io.Stdout;
+
+import ast.Decl,
+       ast.Stmt,
+       ast.Exp;
+
+import misc.DataSource;
+
+class AstPrinter
+{
+    const char[] tabType = "    "; // 4 spaces
+
+    this(DataSource ds)
+    {
+
+        this.ds = ds;
+    }
+
+    void print(Decl[] decls)
+    {
+        foreach(decl ; decls)
+        {
+            printDecl(decl);
+        }
+    }
+
+    void printDecl(Decl decl)
+    {
+        switch(decl.declType)
+        {
+            case DeclType.FuncDecl:
+                auto funcDecl = cast(FuncDecl)decl;
+                printBeginLine();
+                printIdentifier(funcDecl.type);
+                printIdentifier(funcDecl.identifier);
+                printFuncArgs(funcDecl.funcArgs);
+                printOpenBrace();
+                foreach(stmt ; funcDecl.statements)
+                    printStatement(stmt);
+                printCloseBrace();
+                break;
+
+            case DeclType.VarDecl:
+                auto varDecl = cast(VarDecl)decl;
+                printBeginLine();
+                printIdentifier(varDecl.type);
+                printIdentifier(varDecl.identifier);
+                if(varDecl.init)
+                {
+                    print("= ");
+                    printExp(varDecl.init);
+                }
+                printEndLine(";");
+                break;
+        }
+    }
+
+    void printStatement(Stmt stmt)
+    {
+        switch(stmt.stmtType)
+        {
+            case StmtType.Return:
+                auto ret = cast(ReturnStmt)stmt;
+                printBeginLine("return ");
+                printExp(ret.exp);
+                printEndLine(";");
+                break;
+            case StmtType.Decl:
+                auto declStmt = cast(DeclStmt)stmt;
+                printDecl(declStmt.decl);
+                break;
+            case StmtType.Exp:
+                auto expStmt = cast(ExpStmt)stmt;
+                printBeginLine();
+                printExp(expStmt.exp);
+                printEndLine(";");
+                break;
+
+        }
+    }
+
+    void printExp(Exp exp)
+    {
+        switch(exp.expType)
+        {
+            case ExpType.Binary:
+                auto binaryExp = cast(BinaryExp)exp;
+                printExp(binaryExp.left);
+                print([binaryExp.op] ~ " ");
+                printExp(binaryExp.right);
+                break;
+            case ExpType.IntegerLit:
+                auto integetLit = cast(IntegerLit)exp;
+                auto t = integetLit.token;
+                print(t.get ~ " ");
+                break;
+            case ExpType.Negate:
+                auto negateExp = cast(NegateExp)exp;
+                print("-");
+                printExp(negateExp.exp);
+                break;
+            case ExpType.AssignExp:
+                auto assignExp = cast(AssignExp)exp;
+                printIdentifier(assignExp.identifier);
+                print("= ");
+                printExp(assignExp.exp);
+                break;
+        }
+        
+    }
+
+    void printFuncArgs(VarDecl[] decls)
+    {
+        print("(");
+     
+        foreach(i, decl; decls)
+        {
+            printIdentifier(decl.type);
+            printIdentifier(decl.identifier);
+            if(i+1 < decls.length)
+                print(",");
+        }
+
+        printEndLine(")");
+    }
+
+    void printIdentifier(Identifier identifier)
+    {
+        auto t = identifier.token;
+        print(t.get ~ " ");
+    }
+
+    void printOpenBrace()
+    {
+        printEndLine(tabIndex~"{");
+        tabIndex ~= tabType;
+    }
+
+    void printCloseBrace()
+    {
+        tabIndex = tabIndex[0 .. $-tabType.length];
+        printEndLine(tabIndex~"}");
+    }
+
+    void printBeginLine(char[] line = "")
+    {
+        Stdout(tabIndex~line);
+    }
+
+    void printEndLine(char[] line = "")
+    {
+        Stdout(line).newline;
+    }
+
+    void print(char[] line)
+    {
+        Stdout(line);
+    }
+private:
+    DataSource ds;
+    char[] tabIndex;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/DotPrinter.d	Fri Apr 18 02:01:38 2008 +0200
@@ -0,0 +1,167 @@
+module tools.DotPrinter;
+
+import tango.io.Stdout,
+       Int = tango.text.convert.Integer;
+
+import ast.Decl,
+       ast.Stmt,
+       ast.Exp;
+
+import misc.DataSource,
+       lexer.Token;
+
+class DotPrinter
+{
+    this()
+    {
+    }
+
+    private char[][void*] identifiers;
+    private int current_id = 0;
+
+    void print(Decl[] decls)
+    {
+        Stdout("digraph {").newline;
+        foreach(decl ; decls)
+        {
+            printDecl(decl);
+        }
+        Stdout("}").newline;
+    }
+
+    void printDecl(Decl decl)
+    {
+        switch(decl.declType)
+        {
+            case DeclType.FuncDecl:
+                FuncDecl funcDecl = cast(FuncDecl)decl;
+
+                //printIdentifier(funcDecl.identifier);
+                //printFuncArgs(funcDecl.funcArgs);
+                Stdout(dotId(decl))(` [label="function`);
+                Stdout(`\n name: `)(text(funcDecl.identifier));
+                Stdout(`\n return type: `)(text(funcDecl.type));
+                Stdout(`", shape=box, fillcolor=lightblue, style=filled]`);
+                Stdout.newline;
+                //Stdout(`"`);
+                foreach(stmt ; funcDecl.statements)
+                    printStatement(dotId(decl), stmt);
+                break;
+
+            case DeclType.VarDecl:
+                VarDecl varDecl = cast(VarDecl)decl;
+
+                //printIdentifier(funcDecl.identifier);
+                //printFuncArgs(funcDecl.funcArgs);
+                Stdout(dotId(decl))(` [label="var`);
+                Stdout(`\n name: `)(text(varDecl.identifier));
+                Stdout(`\n type: `)(text(varDecl.type));
+                Stdout(`"]`).newline;
+
+                if (varDecl.init !is null)
+                    printExpression(dotId(decl), varDecl.init);
+                break;
+        }
+    }
+
+    void printStatement(char[] parent, Stmt stmt)
+    {
+        auto id = dotId(stmt);
+        switch (stmt.stmtType)
+        {
+            case StmtType.Stmt:
+                Stdout(id)(` [label="Statement"]`).newline;
+                Stdout(parent)(` -> `)(id).newline;
+                break;
+
+            case StmtType.Decl:
+                Stdout(id)(` [label="Decl"]`).newline;
+                Stdout(parent)(` -> `)(id).newline;
+                auto decl = (cast(DeclStmt)stmt).decl;
+                printDecl(decl);
+                Stdout(id)(` -> `)(dotId(decl)).newline;
+                break;
+
+            case StmtType.Return:
+                Stdout(id)(` [label="Return"]`).newline;
+                Stdout(parent)(` -> `)(id).newline;
+                printExpression(id, (cast(ReturnStmt)stmt).exp);
+                break;
+
+            case StmtType.Exp:
+                Stdout(parent)(` -> `)(id).newline;
+                printExpression(id, (cast(ExpStmt)stmt).exp);
+                break;
+        }
+    }
+
+    void printExpression(char[] parent, Exp exp)
+    {
+        auto id = dotId(exp);
+
+        switch(exp.expType)
+        {
+            case ExpType.Binary:
+                auto bin = cast(BinaryExp)exp;
+                Stdout(id)(` [label="`)(bin.op)(`"]`).newline;
+                printExpression(id, bin.left);
+                printExpression(id, bin.right);
+                break;
+
+            case ExpType.Negate:
+                auto neg = cast(NegateExp)exp;
+                Stdout(id)(` [label="Negate"]`).newline;
+                printExpression(id, neg.exp);
+                break;
+
+            case ExpType.IntegerLit:
+                auto e = cast(IntegerLit)exp;
+                Stdout(id)(` [label="`)(text(e.token))(`"]`).newline;
+                break;
+        
+            case ExpType.Identifier:
+                auto e = cast(Identifier)exp;
+                Stdout(id)(` [label="`)(text(e))(`"]`).newline;
+                break;
+
+            case ExpType.AssignExp:
+                auto ass = cast(AssignExp)exp;
+                Stdout(parent)(` [label="Assign"]`).newline;
+                Stdout(id)(` [label="`)(text(ass.identifier))(`"]`).newline;
+                printExpression(parent, ass.exp);
+                break;
+
+            case ExpType.CallExp:
+                break;
+        }
+        Stdout(parent)(` -> `)(id).newline;
+    }
+
+    char[] dotId(Decl d) { return dotId(cast(void*)d); }
+    char[] dotId(Stmt s) { return dotId(cast(void*)s); }
+    char[] dotId(Exp e)  { return dotId(cast(void*)e); }
+
+    char[] dotId(void* o)
+    {
+        auto id = o in identifiers;
+        if (id is null)
+        {
+            ++current_id;
+            identifiers[o] = Int.toString(current_id);
+            id = o in identifiers;
+        }
+        return *id;
+    }
+
+    char[] text(Identifier identifier)
+    {
+        auto t = identifier.token;
+        return t.get;
+    }
+    char[] text(Token t)
+    {
+        return t.get;
+    }
+private:
+    DataSource ds;
+}