changeset 24:2d28b21faad6 new_gen

New codegen! Rewritten codegen to use the llvm bindings Everything except struct are back to normal, and there a a few additions. 1. Correct code in more cases, return at the end of a while/if wont generate a "ret" followed by a "br". 2. Better scope, "int x = x" now illegal 3. Probably more
author Anders Halager <halager@gmail.com>
date Sat, 19 Apr 2008 18:29:42 +0200
parents dd18654b5131 (current diff) e331e4e816e4 (diff)
children 14c1abba773f
files gen/LLVMGen.d misc/Error.d misc/Location.d sema/Declarations.d sema/SymbolTable.d sema/SymbolTableBuilder.d test.td tests/code/basic_2.d tests/code/if_4.d tests/code/math_1.d tests/code/math_2.d tests/code/math_3.d
diffstat 18 files changed, 366 insertions(+), 406 deletions(-) [+]
line wrap: on
line diff
--- a/ast/Decl.d	Sat Apr 19 11:40:20 2008 +0200
+++ b/ast/Decl.d	Sat Apr 19 18:29:42 2008 +0200
@@ -11,6 +11,7 @@
 {
     VarDecl,
     FuncDecl,
+    StructDecl,
 }
 
 class Decl
@@ -56,3 +57,17 @@
     Stmt[] statements;
 }
 
+class StructDecl : Decl
+{
+    this(Identifier identifier, 
+            VarDecl[] vars)
+    {
+        super(DeclType.StructDecl);
+        this.identifier = identifier;
+        this.vars = vars;
+    }
+
+    Identifier identifier;
+    VarDecl[] vars;
+}
+
--- a/dang/compiler.d	Sat Apr 19 11:40:20 2008 +0200
+++ b/dang/compiler.d	Sat Apr 19 18:29:42 2008 +0200
@@ -139,7 +139,15 @@
 
         auto src = DataSource(file);
         auto lexer = new Lexer(src);
-
+/*
+        auto t = lexer.next;
+        while(t.getType != "EOF")
+        {
+            Stdout(t.getType)(" : ")(t.get).newline;
+            t = lexer.next;
+        }
+        lexer = new Lexer(src);
+*/
         postLex(lexer);
 
         preParse(lexer);
--- a/gen/LLVMGen.d	Sat Apr 19 11:40:20 2008 +0200
+++ b/gen/LLVMGen.d	Sat Apr 19 18:29:42 2008 +0200
@@ -12,7 +12,17 @@
 
 import lexer.Token;
 
-import sema.SymbolTableBuilder;
+import sema.SymbolTableBuilder,
+       sema.Visitor;
+
+private char[] genBuildCmp(char[] p)
+{
+    return `
+        (Value l, Value r, char[] n)
+        {
+            return b.buildICmp(IntPredicate.`~p~`, l, r, n);
+        }`;
+}
 
 class LLVMGen
 {
@@ -31,34 +41,52 @@
             "void"   : Type.Void
         ];
         alias BinaryExp.Operator op;
+        b = new Builder;
+        
         opToLLVM = [
-            op.Add      : "add"[],
-            op.Sub      : "sub",
-            op.Mul      : "mul",
-            op.Div      : "div",
-            op.Eq       : "icmp eq",
-            op.Ne       : "icmp ne",
-            op.Lt       : "icmp slt",
-            op.Le       : "icmp sle",
-            op.Gt       : "icmp sgt",
-            op.Ge       : "icmp sge"
+            op.Add      : &b.buildAdd,
+            op.Sub      : &b.buildSub,
+            op.Mul      : &b.buildMul,
+            op.Div      : &b.buildSDiv,
+            op.Eq       : mixin(genBuildCmp("EQ")),
+            op.Ne       : mixin(genBuildCmp("NE")),
+            op.Lt       : mixin(genBuildCmp("SLT")),
+            op.Le       : mixin(genBuildCmp("SLE")),
+            op.Gt       : mixin(genBuildCmp("SGT")),
+            op.Ge       : mixin(genBuildCmp("SGE"))
         ];
         table = new SimpleSymbolTable();
     }
 
+    ~this()
+    {
+        b.dispose();
+    }
+
     void gen(Decl[] decls)
     {
         // create module
         m = new Module("main_module");
         scope(exit) m.dispose();
 
-        b = new Builder;
-        scope(exit) b.dispose();
 
         table.enterScope;
 
-        foreach(decl ; decls)
-                genRootDecl(decl);
+        auto registerFunc =
+            (FuncDecl funcDecl)
+            {
+                Type[] param_types;
+                foreach (param; funcDecl.funcArgs)
+                    param_types ~= typeToLLVM[param.type.get];
+                auto ret_t = typeToLLVM[funcDecl.type.get];
+                auto func_t = FunctionType.Get(ret_t, param_types);
+                auto llfunc = m.addFunction(func_t, funcDecl.identifier.get);
+            };
+        auto visitor = new VisitFuncDecls(registerFunc);
+        visitor.visit(decls);
+
+        foreach (decl; decls)
+            genRootDecl(decl);
 
         table.leaveScope;
 
@@ -66,6 +94,8 @@
         m.verify(err);
         Stderr(err).newline;
 
+        //m.optimize(false);
+
         m.writeBitcodeToFile("test.bc");
     }
 
@@ -76,97 +106,42 @@
             case DeclType.FuncDecl:
                 FuncDecl funcDecl = cast(FuncDecl)decl;
 
-                Type[] param_types;
-                foreach (param; funcDecl.funcArgs)
-                    param_types ~= typeToLLVM[param.type.get];
+                auto llfunc = m.getNamedFunction(funcDecl.identifier.get);
                 auto ret_t = typeToLLVM[funcDecl.type.get];
-                auto func_t = FunctionType.Get(ret_t, param_types);
-                auto llfunc = m.addFunction(func_t, funcDecl.identifier.get);
-
-                foreach (i, v; funcDecl.funcArgs)
-                    llfunc.getParam(i).name = v.identifier.get;
 
                 auto bb = llfunc.appendBasicBlock("entry");
                 b.positionAtEnd(bb);
 
-                if (ret_t is Type.Void)
-                    b.buildRetVoid();
-                else
-                    b.buildRet(ConstantInt.GetS(ret_t, 0));
-
-                /*
-                auto return_type = typeToLLVM[funcDecl.type.token.get];
-
-                printBeginLine("define ");
-                print(return_type);
-                print(" @");
-                genIdentifier(funcDecl.identifier);
-                print("(");
-
                 table.enterScope;
-                Identifier[] args;
-                foreach(i, funcArg ; funcDecl.funcArgs)
+                foreach (i, v; 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(", ");
+                    llfunc.getParam(i).name = v.identifier.get;
+                    auto name = v.identifier.get;
+                    auto AI = b.buildAlloca(llfunc.getParam(i).type, name);
+                    b.buildStore(llfunc.getParam(i), AI);
+                    table[name] = AI;
                 }
-                
-                printEndLine(") {");
-                
-                indent;
-
-                foreach(i, arg ; args)
-                {
-                    auto sym = arg.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);
-                if (return_type == "void")
-                {
-                    printBeginLine("ret void");
-                    printEndLine();
-                }
+
+                // if the function didn't end with a return, we automatically
+                // add one (return 0 as default)
+                if (b.getInsertBlock().terminated() is false)
+                    if (ret_t is Type.Void)
+                        b.buildRetVoid();
+                    else
+                        b.buildRet(ConstantInt.GetS(ret_t, 0));
+
                 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();
-                */
+                Type t = typeToLLVM[varDecl.type.get];
+                GlobalVariable g = m.addGlobal(t, varDecl.identifier.get);
+                g.initializer = ConstantInt.GetS(t, 0);
+                table[varDecl.identifier.get] = g;
                 break;
         
             default:
@@ -180,52 +155,40 @@
         {
             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);
-                }
-                */
+                Type t = typeToLLVM[varDecl.type.get];
+                auto name = varDecl.identifier.get;
+                auto AI = b.buildAlloca(t, name);
+                table[name] = AI;
+                Stderr("env", varDecl.env.names).newline;
+                if (varDecl.init)
+                    buildAssign(varDecl.env.find(varDecl.identifier), varDecl.init);
                 break;
         
             default:
         }
     }
 
-    void unify(Ref* a, Ref* b)
+    void sextSmallerToLarger(ref Value left, ref Value right)
     {
-        if (a.type != b.type)
+        if (left.type != right.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;
-            }
+            // try to find a convertion - only works for iX
+            IntegerType l = cast(IntegerType) left.type;
+            IntegerType r = cast(IntegerType) right.type;
+            if (l is null || r is null)
+                throw new Exception(
+                        "Can't find a valid convertion between "
+                        "a " ~ left.type.toString ~ " and a "
+                        ~ right.type.toString);
 
-            auto res = table.find("%.cast");
-            printBeginLine(res);
-            printCastFromTo(b, a);
-            print(*b);
-            print(" to ");
-            printEndLine(a.type);
-
-            b.type = a.type;
-            b.name = res;
+            if (l.numBits() < r.numBits())
+                left = b.buildSExt(left, r, ".cast");
+            else
+                right = b.buildSExt(right, l, ".cast");
         }
     }
 
-    Ref genExpression(Exp exp)
+    Value genExpression(Exp exp)
     {
         switch(exp.expType)
         {
@@ -235,112 +198,38 @@
                 auto left = genExpression(binaryExp.left);
                 auto right = genExpression(binaryExp.right);
 
-                unify(&left, &right);
-
+                sextSmallerToLarger(left, right);
 
-                auto res = Ref(left.type, table.find);
-                /*
-                printBeginLine(res.name);
-                print(" = "~opToLLVM[binaryExp.op]~" ");
-                print(left);
-                print(", ");
-                printEndLine(right.name);
+                OpBuilder op = opToLLVM[binaryExp.op];
 
-                // exp always returns known type (== returns bool no matter
-                // what the params are)
-                if (binaryExp.resultType)
-                    res.type = typeToLLVM[binaryExp.resultType];
+                return op(left, right, ".");
 
-                */
-                return res;
             case ExpType.IntegerLit:
                 auto integetLit = cast(IntegerLit)exp;
-                auto t = integetLit.token;
-                return Ref("int", t.get, true);
+                auto val = integetLit.token.get;
+                return ConstantInt.GetS(Type.Int32, Integer.parse(val));
             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);
+                return b.buildNeg(target, "neg");
             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;
+                buildAssign(exp.env.find(assignExp.identifier), assignExp.exp);
+                return null;
             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)
+                Value[] args;
+                foreach (arg; callExp.args)
                     args ~= genExpression(arg);
-
-                char[] res = "";
-                if (func_type != "void")
-                {
-                    res = table.find;
-                    printBeginLine(res);
-                    print(" = call ");
-                }
-                else
-                    printBeginLine("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, "");
+                return b.buildCall(m.getNamedFunction(func_sym.id.get), args, ".call");
             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 b.buildLoad(table.find(sym.id.get), sym.id.get);
         }
-        return Ref();
+        assert(0, "Reached end of switch in genExpression");
+        return null;
     }
 
     void genStmt(Stmt stmt)
@@ -350,25 +239,22 @@
             case StmtType.Return:
                 auto ret = cast(ReturnStmt)stmt;
                 auto sym = stmt.env.parentFunction();
-                /*
-                auto type = typeToLLVM[sym.type.get];
-
-                Ref res = genExpression(ret.exp);
-
-                if (type != res.type)
+                Type t = typeToLLVM[sym.type.get];
+                Value v = genExpression(ret.exp);
+                if (v.type != t)
                 {
-                    auto cast_res = table.find("%.cast");
-                    printBeginLine(cast_res);
-                    printCastFromTo(res.type, type);
-                    print(res);
-                    print(" to ");
-                    printEndLine(type);
-                    res.name = cast_res;
-                    res.type = type;
+                    IntegerType v_t = cast(IntegerType) v.type;
+                    IntegerType i_t = cast(IntegerType) t;
+                    if (v_t is null || i_t is null)
+                        throw new Exception(
+                                "Inappropriate assignment"
+                                ", types dont match");
+                    if (v_t.numBits() < i_t.numBits())
+                        v = b.buildSExt(v, t, ".cast");
+                    else
+                        v = b.buildTrunc(v, t, ".cast");
                 }
-                printBeginLine("ret ");
-                printEndLine(res);
-                */
+                b.buildRet(v);
                 break;
             case StmtType.Decl:
                 auto declStmt = cast(DeclStmt)stmt;
@@ -380,163 +266,89 @@
                 break;
             case StmtType.If:
                 auto ifStmt = cast(IfStmt)stmt;
-                Ref val = genExpression(ifStmt.cond);
-                /*
-                auto cond = table.find("%.cond");
-                printBeginLine(cond);
-                print(" = icmp ne ");
-                print(val);
-                printEndLine(", 0");
+                Value cond = genExpression(ifStmt.cond);
+                if (cond.type !is Type.Int1)
+                {
+                    Value False = ConstantInt.GetS(cond.type, 0);
+                    cond = b.buildICmp(IntPredicate.NE, cond, False, ".cond");
+                }
+                auto func_name = stmt.env.parentFunction().id.get;
+                Function func = m.getNamedFunction(func_name);
+                bool has_else = ifStmt.else_body.length > 0;
 
-                auto then_branch = table.find("then");
-                auto else_branch = table.find("else");
-                auto done_label  = table.find("done");
-                printBeginLine("br i1 ");
-                print(cond);
-                print(", label %");
-                print(then_branch);
-                print(", label %");
-                printEndLine(ifStmt.else_body? else_branch : done_label);
+                auto thenBB = func.appendBasicBlock("then");
+                auto elseBB = has_else? func.appendBasicBlock("else") : null;
+                auto mergeBB = func.appendBasicBlock("merge");
 
-                printBeginLine(then_branch);
-                printEndLine(":");
-
-                indent();
+                b.buildCondBr(cond, thenBB, has_else? elseBB : mergeBB);
+                b.positionAtEnd(thenBB);
                 foreach (s; ifStmt.then_body)
                     genStmt(s);
-                printBeginLine("br label %");
-                printEndLine(done_label);
-                dedent();
+                if (b.getInsertBlock().terminated() is false)
+                    b.buildBr(mergeBB);
+                thenBB = b.getInsertBlock();
 
-                if (ifStmt.else_body)
+                if (has_else)
                 {
-                    printBeginLine(else_branch);
-                    printEndLine(":");
-
-                    indent();
+                    b.positionAtEnd(elseBB);
                     foreach (s; ifStmt.else_body)
                         genStmt(s);
-                    printBeginLine("br label %");
-                    printEndLine(done_label);
-                    dedent();
+                    b.buildBr(mergeBB);
+                    elseBB = b.getInsertBlock();
                 }
 
-                printBeginLine(done_label);
-                printEndLine(":");
-                */
-
+                b.positionAtEnd(mergeBB);
                 break;
             case StmtType.While:
                 auto wStmt = cast(WhileStmt)stmt;
-
-                /*
-                auto body_label = table.find("while_body");
-                auto cond_label = table.find("while_cond");
-                auto done_label  = table.find("while_done");
+                auto func_name = stmt.env.parentFunction().id.get;
+                Function func = m.getNamedFunction(func_name);
 
-                printBeginLine("br label %");
-                printEndLine(cond_label);
-
-                printBeginLine(cond_label);
-                printEndLine(":");
-
-                indent();
-
-                Ref val = genExpression(wStmt.cond);
-                auto cond = table.find("%.cond");
+                auto condBB = func.appendBasicBlock("cond");
+                auto bodyBB = func.appendBasicBlock("body");
+                auto doneBB = func.appendBasicBlock("done");
 
-                printBeginLine(cond);
-                print(" = icmp ne ");
-                print(val);
-                printEndLine(", 0");
+                b.buildBr(condBB);
+                b.positionAtEnd(condBB);
+                Value cond = genExpression(wStmt.cond);
+                if (cond.type !is Type.Int1)
+                {
+                    Value False = ConstantInt.GetS(cond.type, 0);
+                    cond = b.buildICmp(IntPredicate.NE, cond, False, ".cond");
+                }
+                b.buildCondBr(cond, bodyBB, doneBB);
 
-                printBeginLine("br i1 ");
-                print(cond);
-                print(", label %");
-                print(body_label);
-                print(", label %");
-                printEndLine(done_label);
-
-                dedent();
-
-                printBeginLine(body_label);
-                printEndLine(":");
-
-                indent();
+                b.positionAtEnd(bodyBB);
                 foreach (s; wStmt.stmts)
                     genStmt(s);
-                printBeginLine("br label %");
-                printEndLine(cond_label);
-                dedent();
+                if (b.getInsertBlock().terminated() is false)
+                    b.buildBr(condBB);
 
-                printBeginLine(done_label);
-                printEndLine(":");
-
-                */
+                b.positionAtEnd(doneBB);
                 break;
         }
     }
 
-    void genIdentifier(Identifier identifier)
-    {
-        print(identifier.get);
-    }
-
-    void indent()
-    {
-        tabIndex ~= tabType;
-    }
-
-    void dedent()
+    private void buildAssign(Symbol sym, Exp exp)
     {
-        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;
-    }
+        Type t = typeToLLVM[sym.type.get];
+        auto name = sym.id.get;
+        auto AI = table.find(name);
+        Value v = genExpression(exp);
+        if (v.type != t)
+        {
+            IntegerType v_t = cast(IntegerType) v.type;
+            IntegerType i_t = cast(IntegerType) t;
+            if (v_t is null || i_t is null)
+                throw new Exception(
+                        "Inappropriate assignment, types don't match");
 
-    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));
+            if (v_t.numBits() < i_t.numBits())
+                v = b.buildSExt(v, t, ".cast");
+            else
+                v = b.buildTrunc(v, t, ".cast");
+        }
+        b.buildStore(v, AI);
     }
 
 private:
@@ -545,59 +357,59 @@
     Module m;
     Builder b;
 
-    char[] tabIndex;
-    const char[] tabType = "    "; // 4 spaces
     FuncDecl[char[]] functions;
 
     SimpleSymbolTable table;
-    SymbolTable symbolTable;
     static Type[char[]] typeToLLVM;
-    static char[][BinaryExp.Operator] opToLLVM;
-
-    static char[][] intTypes = [ "i1", "i8", "i16", "i32", "i64" ];
+    alias Value delegate(Value, Value, char[]) OpBuilder;
+    static OpBuilder[BinaryExp.Operator] opToLLVM;
 }
 
-struct Ref
+private class VisitFuncDecls : Visitor!(void)
 {
-    char[] type;
-    char[] name;
-    bool atomic = false;
-    static Ref opCall(char[] type = "void", char[] name = "", bool atomic = false)
+    void delegate(FuncDecl) dg;
+    this(void delegate(FuncDecl funcDecl) dg)
     {
-        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;
+        this.dg = dg;
+    }
+
+    override void visit(Decl[] decls)
+    {
+        foreach (decl; decls)
+            if (auto f = cast(FuncDecl)decl)
+                dg(f);
     }
 }
 
-class SimpleSymbolTable
+private class SimpleSymbolTable
 {
-    int[char[]][] variables;
+    Value[char[]][] namedValues;
 
     void enterScope()
     {
-        variables ~= cast(int[char[]])["__dollar":-1];
+        namedValues ~= cast(Value[char[]])["__dollar":null];
     }
 
     void leaveScope()
     {
-        variables.length = variables.length - 1;
+        namedValues.length = namedValues.length - 1;
+    }
+
+    Value put(Value val, char[] key)
+    {
+        namedValues[$ - 1][key] = val;
+        return val;
     }
 
-    char[] find(char[] v = "%.tmp")
+    Value find(char[] key)
     {
-        foreach_reverse(map ; variables)
-        {
-            if(v in map)
-                return v~"."~Integer.toString(++map[v]);
-        }
-        variables[$-1][v] = 0;
-        return v;
+        foreach_reverse (map; namedValues)
+            if(auto val_ptr = key in map)
+                return *val_ptr;
+        return null;
     }
+
+    alias find opIndex;
+    alias put opIndexAssign;
 }
 
--- a/lexer/Keyword.d	Sat Apr 19 11:40:20 2008 +0200
+++ b/lexer/Keyword.d	Sat Apr 19 18:29:42 2008 +0200
@@ -25,6 +25,7 @@
         "if"        : Tok.If,
         "else"      : Tok.Else,
         "while"     : Tok.While,
-        "return"    : Tok.Return
+        "return"    : Tok.Return,
+        "struct"    : Tok.Struct
     ];
 }
--- a/lexer/Token.d	Sat Apr 19 11:40:20 2008 +0200
+++ b/lexer/Token.d	Sat Apr 19 18:29:42 2008 +0200
@@ -76,6 +76,8 @@
 
     Bool,
 
+    Struct,
+
     If, Else,
     While,
     Return,
@@ -115,6 +117,7 @@
         Tok.While:"While",
         Tok.Comma:"Comma",
         Tok.Return:"Return",
+        Tok.Struct:"Struct",
         Tok.Seperator:"Seperator"
     ];
 }
--- a/misc/Error.d	Sat Apr 19 11:40:20 2008 +0200
+++ b/misc/Error.d	Sat Apr 19 18:29:42 2008 +0200
@@ -11,7 +11,7 @@
 
     this(char[] message, Location errorLocation)
     {
-        super(message ~ " at line " ~ errorLocation.toString);
+        super(errorLocation.toString ~ " " ~ message);
         this.message = message;
         this.errorLocation = errorLocation;
     }
--- a/misc/Location.d	Sat Apr 19 11:40:20 2008 +0200
+++ b/misc/Location.d	Sat Apr 19 18:29:42 2008 +0200
@@ -13,7 +13,7 @@
     char[] toString ()
     {
         int lineNumber = split(source.get(0, position), "\n").length;
-        return Integer.toString(lineNumber) ~" in "~source.name;
+        return source.name ~ ":" ~ Integer.toString(lineNumber);
     }
 
     char[] get(uint length)
--- a/parser/Parser.d	Sat Apr 19 11:40:20 2008 +0200
+++ b/parser/Parser.d	Sat Apr 19 18:29:42 2008 +0200
@@ -75,7 +75,17 @@
                         error("Unexpexted token "~c~" at line "~Integer.toString(__LINE__));
                 }
                 break;
-
+            case Tok.Struct:
+                Token iden = lexer.next;
+                switch(iden.type)
+                {
+                    case Tok.Identifier:
+                        Identifier identifier = new Identifier(iden);
+                        return new StructDecl (identifier, parseStruct());
+                    default:
+                        throw new Error("Expected struct identifier, but got "~iden.getType, 
+                            iden.location);
+                }
             case Tok.EOF:
                 return null;
             default:
@@ -84,6 +94,19 @@
         }
     }
 
+    VarDecl[] parseStruct()
+    {
+        VarDecl[] varDecls;
+        require(Tok.OpenBrace);
+        while(lexer.peek.type != Tok.CloseBrace)
+        {
+            varDecls ~= cast(VarDecl)parseDecl;
+        }
+
+        require(Tok.CloseBrace);
+        return varDecls;
+    }
+
     Stmt parseStatement()
     {
         Token t = lexer.peek;
@@ -132,6 +155,9 @@
                         require(Tok.Seperator);
                         return stmt;
                         break;
+                    case Tok.Identifier:
+                        auto decl = new DeclStmt(parseDecl());
+                        return decl;
 
                     default:
                         auto e = new ExpStmt(parseExpression());
--- a/sema/Declarations.d	Sat Apr 19 11:40:20 2008 +0200
+++ b/sema/Declarations.d	Sat Apr 19 18:29:42 2008 +0200
@@ -21,7 +21,8 @@
             "uint":5,
             "long":6,
             "ulong":7,
-            "bool":8
+            "bool":8,
+            "void":9
                 ];
     }
 
@@ -36,7 +37,7 @@
 
     override void visitVarDecl(VarDecl d)
     {
-        if(!isType(d.type.get))
+        if(!isType(d.type.get) && d.env.findType(d.identifier))
             throw new Error("Undefined type: '"~d.type.get~"'",d.type.token.location);
 
         visitExp(d.type);
@@ -52,3 +53,4 @@
     }
 
 }
+
--- a/sema/SymbolTable.d	Sat Apr 19 11:40:20 2008 +0200
+++ b/sema/SymbolTable.d	Sat Apr 19 18:29:42 2008 +0200
@@ -38,9 +38,21 @@
         return null;
     }
 
+    Symbol findType(Identifier id)
+    {
+        if (auto sym = id in symbols)
+            if(symbols[id].type == null)
+                return *sym;
+        if (enclosing !is null)
+            return enclosing.find(id);
+        return null;
+    }
+
     char[][] names()
     {
         char[][] res;
+        if (enclosing)
+            res = enclosing.names;
         foreach (id, sym; symbols)
             res ~= sym.id.name ~ " : " ~ sym.type.name;
         return res;
--- a/sema/SymbolTableBuilder.d	Sat Apr 19 11:40:20 2008 +0200
+++ b/sema/SymbolTableBuilder.d	Sat Apr 19 18:29:42 2008 +0200
@@ -56,17 +56,36 @@
 
     override void visitVarDecl(VarDecl d)
     {
+        if (d.init)
+            visitExp(d.init);
+
+        if (need_push > 0) {
+            push();
+            --need_push;
+        }
+
         auto sc = current();
         auto sym = sc.add(d.identifier);
         sym.type = d.type;
-        super.visitVarDecl(d);
+        d.env = sc;
+        visitExp(d.type);
+        visitExp(d.identifier);
+    }
+
+    override void visitStructDecl(StructDecl s)
+    {
+        auto sc = current();
+        auto sym = sc.add(s.identifier);
+//        sym.type = Tok.Struct;
+        super.visitStructDecl(s);
     }
 
     override void visitDeclStmt(DeclStmt d)
     {
+        ++need_push;
         super.visitDeclStmt(d);
-        push();
     }
+    private uint need_push = 0;
 
     override void visitIfStmt(IfStmt s)
     {
--- a/sema/Visitor.d	Sat Apr 19 11:40:20 2008 +0200
+++ b/sema/Visitor.d	Sat Apr 19 18:29:42 2008 +0200
@@ -30,6 +30,8 @@
                 return visitFuncDecl(cast(FuncDecl)decl);
             case DeclType.VarDecl:
                 return visitVarDecl(cast(VarDecl)decl);
+            case DeclType.StructDecl:
+                return visitStructDecl(cast(StructDecl)decl);
             default:
                 throw new Exception("Unknown declaration type");
         }
@@ -104,6 +106,19 @@
             return DeclT.init;
     }
 
+    DeclT visitStructDecl(StructDecl s)
+    {
+        visitExp(s.identifier);
+
+        foreach (arg; s.vars)
+            visitDecl(arg);
+
+        static if (is(DeclT == void))
+            return;
+        else
+            return DeclT.init;
+    }
+
     // Statements:
     StmtT visitReturnStmt(ReturnStmt s)
     {
--- a/test.td	Sat Apr 19 11:40:20 2008 +0200
+++ b/test.td	Sat Apr 19 18:29:42 2008 +0200
@@ -3,21 +3,28 @@
 
 int main()
 {
-    return fib(10);
+    int y = 4;
+    while (y > 0)
+        y = y - 1;
+    return y;
+}
+
+int add(int x, int y)
+{
+    return x + y;
 }
 
 int fib(int n)
 {
     if(n < 2)
         return n;
-    
+
     return fib(n-1) + fib(n-2);
 }
 
-int nice(long s, short t)
+int nice(long s, short t, int p)
 {
-    int y;
-    byte x = 5 + t + y;
+    byte x = 5 + t + 0;
     if (x != 0)
         t = 5 + 1 * 5 * s + t;
     return 2 * (t + -1) - x;
@@ -30,6 +37,7 @@
     {
         res = res * n;
         n = n - 1;
+        return n;
     }
     return res;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/basic_2.d	Sat Apr 19 18:29:42 2008 +0200
@@ -0,0 +1,8 @@
+//test fail
+int main()
+{
+    int x = y;
+    int y = 1;
+    return y;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/if_4.d	Sat Apr 19 18:29:42 2008 +0200
@@ -0,0 +1,13 @@
+int main()
+{
+    int x = 0;
+    int y = 1;
+    if (x)
+        return 1;
+    else if (y == 2)
+        return 1;
+    else
+        y = 0;
+    return y;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/math_1.d	Sat Apr 19 18:29:42 2008 +0200
@@ -0,0 +1,6 @@
+int main()
+{
+    int x = 2;
+    int y = 3;
+    return 2 * (x + y);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/math_2.d	Sat Apr 19 18:29:42 2008 +0200
@@ -0,0 +1,6 @@
+int main()
+{
+    int x = 1 + 2 * 3 + 4 + 5;
+    int y = x - x;
+    return y + x - 15;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/math_3.d	Sat Apr 19 18:29:42 2008 +0200
@@ -0,0 +1,6 @@
+//test fail
+int main()
+{
+    int x = x;
+    return x;
+}