changeset 92:771ac63898e2 new_gen

A few better parser errors plus renaming most of the sema classes to match that they do now. Some have changes a lot.
author Anders Johnsen <skabet@gmail.com>
date Mon, 05 May 2008 18:44:20 +0200
parents 1a24e61eb104
children 621cedba53ea
files ast/Decl.d ast/Exp.d ast/Stmt.d basic/Message.d basic/Messages.d basic/SourceManager.d dang/compiler.d gen/CodeGen.d lexer/Lexer.d parser/Parser.d sema/Declarations.d sema/ImplicitCast.d sema/Scope.d sema/ScopeBuilder.d sema/ScopeCheck.d sema/SymbolTable.d sema/SymbolTableBuilder.d sema/TypeCheck.d
diffstat 18 files changed, 670 insertions(+), 623 deletions(-) [+]
line wrap: on
line diff
--- a/ast/Decl.d	Mon May 05 17:07:16 2008 +0200
+++ b/ast/Decl.d	Mon May 05 18:44:20 2008 +0200
@@ -7,7 +7,7 @@
 
 import tango.io.Stdout;
 
-import sema.SymbolTable,
+import sema.Scope,
        sema.DType,
        basic.SmallArray;
 
--- a/ast/Exp.d	Mon May 05 17:07:16 2008 +0200
+++ b/ast/Exp.d	Mon May 05 18:44:20 2008 +0200
@@ -8,7 +8,7 @@
 
 import lexer.Token;
 
-import sema.SymbolTable,
+import sema.Scope,
        sema.DType;
 
 enum ExpType
--- a/ast/Stmt.d	Mon May 05 17:07:16 2008 +0200
+++ b/ast/Stmt.d	Mon May 05 18:44:20 2008 +0200
@@ -7,7 +7,7 @@
 import ast.Exp,
        ast.Decl;
 
-import sema.SymbolTable,
+import sema.Scope,
        basic.SourceLocation,
        misc.Error;
 
--- a/basic/Message.d	Mon May 05 17:07:16 2008 +0200
+++ b/basic/Message.d	Mon May 05 18:44:20 2008 +0200
@@ -19,6 +19,13 @@
 
 public import basic.Messages;
 
+enum ExitLevel
+{
+    Normal = 1,
+    Lexer = 2,
+    Parser = 3,
+}
+
 class MessageHandler
 {
 public:
@@ -28,31 +35,36 @@
         this.src_mgr = src_mgr;
     }
 
-    Message report(uint opcode, SLoc location, bool fatal = false)
+    Message report(uint opcode, SLoc location)
     {
-        Message m = new Message(opcode, location, src_mgr);
+        Message m = new Message(opcode, location, src_mgr, this);
         messages ~= m;
-        if(fatal)
-            checkErrors();
         return m;
     }
 
-    void checkErrors()
+    void checkErrors(ExitLevel exitlevel = ExitLevel.Normal)
     {
         if(messages.length == 0)
             return;
 
+        if(warnings)
+            checkWarnings;
         foreach(m ; messages)
             if(m.type == MessageType.Error)
             {
                 Stdout(m).newline;
             }
 
-        exit(1);
+        exit(exitlevel);
     }
 
     void checkWarnings()
     {
+        foreach(m ; messages)
+            if(m.type == MessageType.Warning)
+            {
+                Stdout(m).newline;
+            }
     }
 
     void showWarnings(bool value)
@@ -69,12 +81,13 @@
 class Message
 {
 
-    this(int opcode, SLoc location, SourceManager src_mgr)
+    this(int opcode, SLoc location, SourceManager src_mgr, MessageHandler msg_handler)
     {
         this.src_mgr = src_mgr;
         this.location = location;
         args ~= Messages[opcode].message;
         this.type = Messages[opcode].type;
+        this.msg_handler = msg_handler;
     }
 
     char[] toString()
@@ -95,7 +108,7 @@
         char[] line = src_mgr.getLine(location);
         char[] marks = line.dup;
         marks[] = ' ';
-        size_t p = src_mgr.getOffsetToLine(location);
+        size_t p = src_mgr.getColumn(location);
         marks[p .. p + t.length] = '^';
 
         msg ~= "\n    ";
@@ -141,6 +154,12 @@
         return arg(sym.type.name ~ " " ~ sym.id.get);
     }
 
+    Message fatal(ExitLevel exitlevel = ExitLevel.Normal)
+    {
+        msg_handler.checkErrors(exitlevel);
+        return this;
+    }
+
     /*
     Message loc(SLoc loc)
     {
@@ -154,4 +173,5 @@
     char[][] args;
     SLoc location;
     SourceManager src_mgr;
+    MessageHandler msg_handler;
 }
--- a/basic/Messages.d	Mon May 05 17:07:16 2008 +0200
+++ b/basic/Messages.d	Mon May 05 18:44:20 2008 +0200
@@ -2,7 +2,6 @@
 
 enum : uint
 {
-    InvalidType,
     InvalidSymbol,
     InvalidIlligaleType,
     UnexpectedEOFBlock,
@@ -16,7 +15,9 @@
     UnexpectedTokType,
     ExpectedIdAfterDot,
     ExpectedExp,
-    ExpectedCastType
+    ExpectedCastType,
+    InvalidDeclType,
+    InvalidType,
 }
 
 enum MessageType
@@ -36,7 +37,6 @@
 static this()
 {
     Messages = [
-        InvalidType         : MessageEntry(MessageType.Error, "InvalidType"),
         UnexpectedEOFBlock  : MessageEntry(MessageType.Error, "Unexpected end of file. Unclosed comment block"),
         InvalidSymbol       : MessageEntry(MessageType.Error, "Read invalid symbol: '%0'"),
         OnlyOneDotFloating  : MessageEntry(MessageType.Error, "Only one '.' is allowed in an floating number"),
@@ -49,6 +49,8 @@
         UnexpectedTokType   : MessageEntry(MessageType.Error, "Unexpected token in Type parsing. Got %0"),
         ExpectedIdAfterDot  : MessageEntry(MessageType.Error, "Expected identifier after '.'"),
         ExpectedExp         : MessageEntry(MessageType.Error, "Expected expression"),
-        ExpectedCastType    : MessageEntry(MessageType.Error, "Expected cast type")
+        ExpectedCastType    : MessageEntry(MessageType.Error, "Expected cast type"),
+        InvalidDeclType     : MessageEntry(MessageType.Error, "Invalid declaration type"),
+        InvalidType         : MessageEntry(MessageType.Error, "Invalid type")
     ];
 }
--- a/basic/SourceManager.d	Mon May 05 17:07:16 2008 +0200
+++ b/basic/SourceManager.d	Mon May 05 18:44:20 2008 +0200
@@ -94,13 +94,12 @@
     }
 
     /**
-      Extracts a string containing the entire line loc appears in.
+      Gets the column of where the loc appears.
      **/
-    int getOffsetToLine(SourceLocation loc)
+    int getColumn(SourceLocation loc)
     {
-        // The line is extracted by getting two pointers to the exact location
-        // and decreasing one until the nearest newline while the other ptr is
-        // increased to the nearest newline.
+        // Use same approach as getLine
+
         CP* cp = &checkpoints[loc.fileID];
         char* ptr = cp.data.ptr + loc.fileOffset;
         char* ptr_lo = ptr;
--- a/dang/compiler.d	Mon May 05 17:07:16 2008 +0200
+++ b/dang/compiler.d	Mon May 05 18:44:20 2008 +0200
@@ -24,9 +24,9 @@
 
 import sema.Visitor,
        sema.AstAction,
-       sema.SymbolTableBuilder,
-       sema.ImplicitCast,
-       sema.Declarations;
+       sema.ScopeBuilder,
+       sema.ScopeCheck,
+       sema.TypeCheck;
 
 import Opt = dang.OptParse;
 
@@ -190,19 +190,19 @@
         auto action = new AstAction(src_mgr);
         auto decls = cast(Decl[])parser.parse(src_mgr, lexer, action);
         timings ~= Measurement("Lex + Parse", watch.stop);
-        messages.checkErrors();
+        messages.checkErrors(ExitLevel.Parser);
 
         StopWatch watch2;
         watch.start;
         watch2.start;
-        (new SymbolTableBuilder).visit(decls);
-        auto symbol_table = watch2.stop;
+        (new ScopeBuilder).visit(decls);
+        auto scope_builder = watch2.stop;
         watch2.start;
-        (new Declarations).visit(decls);
-        auto declarations = watch2.stop;
+        (new ScopeCheck).visit(decls);
+        auto scope_check = watch2.stop;
         watch2.start;
-        (new ImplicitCast).visit(decls);
-        auto implicit_casts = watch2.stop;
+        (new TypeCheck).visit(decls);
+        auto type_check = watch2.stop;
         watch2.start;
 
         foreach (decl; decls)
@@ -210,9 +210,9 @@
         auto simplify = watch2.stop;
         auto extra_stuff = watch.stop;
         timings ~= Measurement("Extra stuff", watch.stop);
-        timings ~= Measurement("  - Building scopes", symbol_table);
-        timings ~= Measurement("  - Extracting declarations", declarations);
-        timings ~= Measurement("  - Making casts explicit", implicit_casts);
+        timings ~= Measurement("  - Building scopes", scope_builder);
+        timings ~= Measurement("  - Checking scopes", scope_check);
+        timings ~= Measurement("  - Checking types", type_check);
 
         postParse(decls, src_mgr);
     }
--- a/gen/CodeGen.d	Mon May 05 17:07:16 2008 +0200
+++ b/gen/CodeGen.d	Mon May 05 18:44:20 2008 +0200
@@ -15,7 +15,7 @@
 
 import lexer.Token;
 
-import sema.SymbolTableBuilder,
+import sema.Scope,
        sema.Visitor;
 
 private char[] genBuildCmp(char[] p)
@@ -136,7 +136,7 @@
 
         table.leaveScope;
 
-        debug m.verify();
+//        debug m.verify();
 
         if(optimize)
             m.optimize(inline);
--- a/lexer/Lexer.d	Mon May 05 17:07:16 2008 +0200
+++ b/lexer/Lexer.d	Mon May 05 18:44:20 2008 +0200
@@ -356,7 +356,9 @@
         CharType c = charTable[current];
 
         if(c == CharType.INVALID)
-            messages.report(InvalidSymbol, Loc(), 1).arg(Integer.toString(cast(int)current));
+            messages.report(InvalidSymbol, Loc())
+                .arg(Integer.toString(cast(int)current))
+                .fatal(ExitLevel.Lexer);
 
         return c;
 
--- a/parser/Parser.d	Mon May 05 17:07:16 2008 +0200
+++ b/parser/Parser.d	Mon May 05 18:44:20 2008 +0200
@@ -48,25 +48,41 @@
 
         if (t.isBasicType || t.isIdentifier)
         {
-            Id type = Id(lexer.next);
-            Id iden = Id(require(Tok.Identifier));
-            Token next = lexer.peek();
-            if (next.type == Tok.Seperator)
-            {
-                Token sep = lexer.next();
-                return action.actOnDeclarator(type, iden, null);
-            }
-            else if (next.type == Tok.Assign)
+            Id type;
+            Id iden;
+            int len = peekParseType;
+            if(lexer.peek(len).type == Tok.Identifier && len != 0)
             {
-                Token assign = lexer.next();
-                Exp exp = parseExpression();
-                require(Tok.Seperator);
-                return action.actOnDeclarator(type, iden, exp);
+                type = parseType;
+parseDeclAfterInvalidType:
+                iden = Id(require(Tok.Identifier));
+                Token next = lexer.peek();
+                if (next.type == Tok.Seperator)
+                {
+                    Token sep = lexer.next();
+                    return action.actOnDeclarator(type, iden, null);
+                }
+                else if (next.type == Tok.Assign)
+                {
+                    Token assign = lexer.next();
+                    Exp exp = parseExpression();
+                    require(Tok.Seperator);
+                    return action.actOnDeclarator(type, iden, exp);
+                }
+                else if (next.type == Tok.OpenParentheses)
+                    return parseFunc(type, iden);
+                else
+                    messages.report(UnexpectedTok, next.location).arg(next.getType);
             }
-            else if (next.type == Tok.OpenParentheses)
-                return parseFunc(type, iden);
-            else
-                messages.report(UnexpectedTok, next.location).arg(next.getType);
+            t = lexer.peek(len);
+            messages.report(InvalidDeclType, t.location)
+                .arg(sm.getText(t.asRange));
+            while(len--)
+                lexer.next;
+            while(lexer.peek.type != Tok.Identifier)
+                lexer.next;
+            type = Id(lexer.peek);
+            goto parseDeclAfterInvalidType;
         }
         else if (t.type == Tok.Struct)
         {
@@ -75,7 +91,10 @@
             
             return parseStruct(type, iden);
         }
-        messages.report(UnexpectedTok, t.location).arg(t.getType);
+        messages.report(UnexpectedTok, t.location)
+            .arg(t.getType)
+            .arg(Tok.Identifier)
+            .fatal(ExitLevel.Parser);
     }
 
     /**
@@ -330,8 +349,7 @@
         Id currentType;
 
         if ( !(type.isBasicType || type.type == Tok.Identifier) )
-            messages.report(UnexpectedTokSingle, type.location)
-                .arg(type.getType);
+            messages.report(InvalidType, type.location);
 
         currentType = Id(type);
         type = lexer.peek;
@@ -346,7 +364,8 @@
             else
             {
                 lexer.next;
-                currentType = ArrayId(currentType, action.actOnNumericConstant(require(Tok.Integer)));
+                if(lexer.peek.type == Tok.Integer)
+                    currentType = ArrayId(currentType, action.actOnNumericConstant(require(Tok.Integer)));
                 require(Tok.CloseBracket);
                 
             }
@@ -379,10 +398,15 @@
             {
                 if(lexer.peek(i++).type != Tok.OpenBracket)
                     return 0;
-                if(lexer.peek(i++).type != Tok.Integer)
-                    return 0;
-                if(lexer.peek(i++).type != Tok.CloseBracket)
-                    return 0;
+                if(lexer.peek(i).type == Tok.Integer)
+                {
+                    i++;
+                    if(lexer.peek(i++).type != Tok.CloseBracket)    
+                        return 0;
+                }
+                else
+                    if(lexer.peek(i++).type != Tok.CloseBracket)
+                        return 0;
                 
             }
             type = lexer.peek(i);
@@ -475,8 +499,8 @@
         else if (next.type == Tok.Integer)
             return action.actOnNumericConstant(next);
 
-        messages.report(ExpectedExp, next.location, true);
-//        assert(0, "Should not happen");
+        messages.report(ExpectedExp, next.location)
+            .fatal(ExitLevel.Parser);
         return null;
     }
 
--- a/sema/Declarations.d	Mon May 05 17:07:16 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-module sema.Declarations;
-
-import sema.Visitor,
-       sema.DType;
-
-import tango.io.Stdout;
-
-import misc.Error;
-
-class Declarations : Visitor!(void)
-{
-    int[char[]] types;
-
-    private Error error(uint line, char[] msg)
-    {
-        return new Error(msg);
-    }
-
-    override void visitIdentifier(Identifier i)
-    {
-        auto symbol = i.env.find(i);
-
-        if(symbol is null)
-            throw error(__LINE__, "Undefined identifier: '%0'")
-                .arg(i.get);
-                //.loc(i.token.location);
-    }
-
-    override void visitVarDecl(VarDecl d)
-    {
-        if(!d.env.findType(d.varType))
-            throw error(__LINE__, "Undefined type: '%0'")
-                .arg(d.varType.get);
-                //.loc(d.varType.token.location);
-
-        visitExp(d.identifier);
-        if (d.init)
-            visitExp(d.init);
-    }
-
-    override void visitFuncDecl(FuncDecl f)
-    {
-        visitExp(f.identifier);
-
-        foreach (stmt; f.statements)
-            visitStmt(stmt);
-    }
-
-    override void visitCastExp(CastExp exp)
-    {
-        visitExp(exp.exp);
-    }
-
-    override void visitMemberReference(MemberReference m)
-    {
-        switch(m.target.expType)
-        {
-            case ExpType.Identifier:
-                auto target = cast(Identifier)m.target;
-                auto child = m.child;
-                auto st = cast(DStruct)(target.env.find(target).type);
-                if((child.get in st.members) is null)
-                    throw error(__LINE__, "%0 %1 has no member %2")
-                        .arg(st.name)
-                        .arg(target.get)
-                        .arg(child.get);
-                        //.tok(child.token);
-                break;
-            case ExpType.MemberReference:
-                break;
-        }
-    }
-
-    private bool isType(char[] s)
-    {
-        return (s in types? true : false);
-    }
-}
-
--- a/sema/ImplicitCast.d	Mon May 05 17:07:16 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,146 +0,0 @@
-module sema.ImplicitCast;
-
-import sema.Visitor,
-       sema.DType;
-
-import tango.io.Stdout;
-
-import misc.Error,
-       basic.SourceLocation;
-
-class ImplicitCast : Visitor!(void)
-{
-    private Error error(uint line, char[] msg)
-    {
-        return new Error(msg);
-    }
-
-    override void visitBinaryExp(BinaryExp exp)
-    {
-        super.visitBinaryExp(exp);
-
-        if(exp.left.type.byteSize > exp.right.type.byteSize)
-        {
-            if(!exp.right.type.hasImplicitConversionTo(exp.left.type))
-                throw error(__LINE__, "Cannot make implicit cast");
-
-            auto castExp = new CastExp(
-                    SLoc.Invalid,
-                    new Identifier(exp.left.type.name),
-                    exp.right);
-            castExp.env = exp.env;
-            exp.right = castExp;
-        }
-
-        if(exp.left.type.byteSize < exp.right.type.byteSize)
-        {
-            if(!exp.left.type.hasImplicitConversionTo(exp.right.type))
-                throw error(__LINE__, "Cannot make implicit cast");
-
-            auto castExp = new CastExp(
-                    SLoc.Invalid,
-                    new Identifier(exp.right.type.name),
-                    exp.left);
-            castExp.env = exp.env;
-            exp.left = castExp;
-        }
-
-    }
-
-    override void visitCallExp(CallExp exp)
-    {
-        super.visitCallExp(exp);
-
-        Exp[] newArgs;
-
-        foreach(i, arg; exp.args)
-        {
-            auto argType = (cast(DFunction)exp.exp.type).params[i];
-            auto expType = arg.type;
-            if(argType.byteSize != expType.byteSize)
-            {
-                if(!expType.hasImplicitConversionTo(argType))
-                    throw error(__LINE__, "Cannot make implicit cast");
-
-                auto castExp = new CastExp(
-                        SLoc.Invalid,
-                        new Identifier(argType.name),
-                        arg);
-                castExp.env = exp.exp.env;
-                newArgs ~= castExp;
-            }
-            else
-                newArgs ~= arg;
-        }
-
-        exp.args = newArgs;
-    }
-
-    override void visitAssignExp(AssignExp exp)
-    {
-        super.visitAssignExp(exp);
-
-        auto identifierType = exp.identifier.type;
-        auto expType = exp.exp.type;
-
-        if(identifierType != expType)
-        {
-            if(!expType.hasImplicitConversionTo(identifierType))
-                throw error(__LINE__, "Cannot make implicit cast between");
-
-            auto castExp = new CastExp(
-                    SLoc.Invalid,
-                    new Identifier(expType.name),
-                    exp.exp);
-            castExp.env = exp.exp.env;
-            exp.exp = castExp;
-        }
-    }
-
-    override void visitReturnStmt(ReturnStmt stmt)
-    {
-        super.visitReturnStmt(stmt);
-
-        if(stmt.exp)
-        {
-            auto returnType = stmt.env.parentFunction.type.asFunction.returnType;
-            auto expType = stmt.exp.type;
-            if(returnType != expType)
-            {
-                if(!expType.hasImplicitConversionTo(returnType))
-                    throw error(__LINE__, "Cannot make implicit cast");
-
-                auto castExp = new CastExp(
-                        SLoc.Invalid,
-                        new Identifier(returnType.name),
-                        stmt.exp);
-                castExp.env = stmt.exp.env;
-                stmt.exp = castExp;
-            }
-        }
-    }
-
-    override void visitVarDecl(VarDecl decl)
-    {
-        super.visitVarDecl(decl);
-
-        if(decl.init)
-        {
-            auto varType = decl.type;
-            auto expType = decl.init.type;
-            if(varType.byteSize != expType.byteSize)
-            {
-                if(!expType.hasImplicitConversionTo(varType))
-                    throw error(__LINE__, "Cannot make implicit cast");
-
-                auto castExp = new CastExp(
-                        SLoc.Invalid,
-                        new Identifier(varType.name),
-                        decl.init);
-                castExp.env = decl.init.env;
-                decl.init = castExp;
-            }
-        }
-    }
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sema/Scope.d	Mon May 05 18:44:20 2008 +0200
@@ -0,0 +1,108 @@
+module sema.Scope;
+
+import tango.io.Stdout;
+
+import lexer.Token,
+       ast.Decl,
+       ast.Exp;
+
+import sema.DType;
+
+public
+import sema.Symbol;
+
+class Scope
+{
+    this() {}
+    this(Scope enclosing)
+    {
+        this.enclosing = enclosing;
+        this.func = enclosing.func;
+    }
+
+    Scope enclosing;
+
+    Symbol add(Identifier id)
+    {
+        auto s = new Symbol;
+        s.id = id;
+        symbols[id] = s;
+        return s;
+    }
+
+    Symbol find(Identifier id)
+    {
+        if(!id)
+            return null;
+        if (auto sym = id in symbols)
+            return *sym;
+        if (enclosing !is null)
+            return enclosing.find(id);
+        return null;
+    }
+
+    DType findType(Identifier id)
+    {
+        if (auto type = id.get in types)
+                return *type;
+        if (enclosing !is null)
+            return enclosing.findType(id);
+        return null;
+    }
+
+    char[][] names()
+    {
+        char[][] res;
+        if (parentFunction() !is null)
+            res ~= "pf: " ~ parentFunction().identifier.get;
+        if (enclosing)
+            res = enclosing.names;
+        foreach (id, sym; symbols)
+            res ~= sym.id.name ~ " : " ~ (sym.type is null? "?" : sym.type.name);
+        return res;
+    }
+
+    FuncDecl parentFunction()
+    {
+        if (func !is null)
+            return func;
+        else if (enclosing !is null)
+            return enclosing.parentFunction();
+        else
+            return null;
+    }
+
+    int stmtIndex()
+    {
+        if (currentStmtIndex != -1)
+            return currentStmtIndex;
+        else if (enclosing !is null)
+            return enclosing.stmtIndex();
+        else
+            return -1;
+    }
+
+    int opEquals(Object o)
+    {
+        return this is o;
+    }
+
+    char[] toString()
+    {
+        if (func)
+            return Stdout.layout.convert("{}: {}", func.identifier.get, symbols.length);
+        return Stdout.layout.convert("root: {}", symbols.length);
+    }
+
+    FuncDecl parentFunction(FuncDecl f)
+    {
+        func = f;
+        return f;
+    }
+    DType[char[]] types;
+    int currentStmtIndex = -1;
+private:
+    Symbol[Identifier] symbols;
+    FuncDecl func;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sema/ScopeBuilder.d	Mon May 05 18:44:20 2008 +0200
@@ -0,0 +1,227 @@
+module sema.ScopeBuilder;
+
+import tango.io.Stdout,
+       tango.core.Array : find;
+
+public
+import sema.Scope;
+
+import sema.Visitor,
+       basic.SmallArray;
+
+class ForwardReference : Visitor!(void)
+{
+    override void visit(Decl[] decls)
+    {
+        foreach (decl; decls)
+            visitDecl(decl);
+    }
+
+    override void visitFuncDecl(FuncDecl d)
+    {
+        visitExp(d.returnType);
+        visitExp(d.identifier);
+        foreach (arg; d.funcArgs)
+            visitDecl(arg);
+        foreach (stmt; d.statements)
+            visitStmt(stmt);
+
+        auto sym = d.env.find(d.identifier);
+        sym.type = d.type;
+    }
+
+    override void visitVarDecl(VarDecl d)
+    {
+        visitExp(d.varType);
+        visitExp(d.identifier);
+        
+        if (d.init)
+            visitExp(d.init);
+
+        d.env.find(d.identifier).type = typeOf(d.varType, d.env);
+    }
+
+    override void visitStructDecl(StructDecl s)
+    {
+        DType[char[]] types;
+
+        auto st = s.env.types[s.identifier.get].asStruct;
+        foreach(varDecl ; s.vars)
+            st.addMember(typeOf(varDecl.varType, varDecl.env), varDecl.identifier.get);
+
+        super.visitStructDecl(s);
+    }
+
+    DType typeOf(Identifier id, Scope sc)
+    {
+        if(auto i = cast(PointerIdentifier)id)
+            return (typeOf(i.pointerOf, sc)).getPointerTo();
+        if(auto i = cast(ArrayIdentifier)id)
+            return typeOf(i.arrayOf, sc).getAsArray(i.size);
+        return sc.findType(id);
+    }
+}
+
+class ScopeBuilder : Visitor!(void)
+{
+    this()
+    {
+        table ~= new Scope;
+        table[0].types["void"]    = DType.Void;
+        table[0].types["bool"]    = DType.Bool;
+        table[0].types["byte"]    = DType.Byte;
+        table[0].types["ubyte"]   = DType.UByte;
+        table[0].types["short"]   = DType.Short;
+        table[0].types["ushort"]  = DType.UShort;
+        table[0].types["int"]     = DType.Int;
+        table[0].types["uint"]    = DType.UInt;
+        table[0].types["long"]    = DType.Long;
+        table[0].types["ulong"]   = DType.ULong;
+    }
+
+    override void visit(Decl[] decls)
+    {
+        foreach (decl; decls)
+            visitDecl(decl);
+        auto fr = new ForwardReference();
+        fr.visit(decls);
+    }
+
+    override void visitDecl(Decl d)
+    {
+        d.env = current();
+        super.visitDecl(d);
+    }
+
+    override void visitStmt(Stmt s)
+    {
+        s.env = current();
+        s.stmtIndex = s.env.stmtIndex;
+        super.visitStmt(s);
+    }
+
+    override void visitExp(Exp e)
+    {
+        e.env = current();
+        e.stmtIndex = e.env.stmtIndex;
+        super.visitExp(e);
+    }
+
+    override void visitFuncDecl(FuncDecl d)
+    {
+        auto sym = current().add(d.identifier);
+        auto sc = push();
+
+        visitExp(d.returnType);
+        visitExp(d.identifier);
+        d.env = current();
+        sc.parentFunction = d;
+        foreach (arg; d.funcArgs)
+            visitDecl(arg);
+        foreach (stmt; d.statements)
+        {
+            sc.currentStmtIndex++;
+            visitStmt(stmt);
+        }
+        pop(sc);
+    }
+
+    override void visitVarDecl(VarDecl d)
+    {
+        if (d.init)
+            visitExp(d.init);
+
+        if (need_push > 0 && current().parentFunction !is null) {
+            push();
+            --need_push;
+        }
+
+        auto sc = current();
+        auto sym = sc.add(d.identifier);
+        d.env = sc;
+        visitExp(d.varType);
+        visitExp(d.identifier);
+    }
+
+    override void visitStructDecl(StructDecl s)
+    {
+        auto sc = current();
+        auto sym = sc.add(s.identifier);
+        s.env = sc;
+        auto type = new DStruct(s.identifier);
+        
+        sc.types[s.identifier.get] = type;
+
+        sc = push();
+        super.visitStructDecl(s);
+        pop(sc);
+    }
+
+    override void visitDeclStmt(DeclStmt d)
+    {
+        ++need_push;
+        super.visitDeclStmt(d);
+    }
+    private uint need_push = 0;
+
+    override void visitIfStmt(IfStmt s)
+    {
+        s.env = current();
+        visitExp(s.cond);
+        auto sc = push();
+        visitStmt(s.then_body);
+        pop(sc);
+
+        if (s.else_body !is null)
+        {
+            sc = push();
+            visitStmt(s.else_body);
+            pop(sc);
+        }
+    }
+
+    override void visitWhileStmt(WhileStmt s)
+    {
+        s.env = current();
+        auto sc = push();
+        super.visitWhileStmt(s);
+        pop(sc);
+    }
+
+    override void visitCompoundStmt(CompoundStatement s)
+    {
+        s.env = current();
+        auto sc = push();
+        super.visitCompoundStmt(s);
+        pop(sc);
+    }
+
+private:
+    Scope[] table;
+
+    Scope push()
+    {
+        auto sc = new Scope(current());
+        table ~= sc;
+        return sc;
+    }
+
+    Scope pop(Scope sc = null)
+    {
+        if (sc !is null)
+        {
+            table.length = table.find(sc);
+            return sc;
+        }
+
+        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/ScopeCheck.d	Mon May 05 18:44:20 2008 +0200
@@ -0,0 +1,79 @@
+module sema.ScopeCheck;
+
+import sema.Visitor,
+       sema.DType;
+
+import tango.io.Stdout;
+
+import misc.Error;
+
+class ScopeCheck : Visitor!(void)
+{
+    int[char[]] types;
+
+    private Error error(uint line, char[] msg)
+    {
+        return new Error(msg);
+    }
+
+    override void visitIdentifier(Identifier i)
+    {
+        auto symbol = i.env.find(i);
+
+        if(symbol is null)
+            throw error(__LINE__, "Undefined identifier: '%0'")
+                .arg(i.get);
+                //.loc(i.token.location);
+    }
+
+    override void visitVarDecl(VarDecl d)
+    {
+        if(!d.env.findType(d.varType))
+            throw error(__LINE__, "Undefined type: '%0'")
+                .arg(d.varType.get);
+                //.loc(d.varType.token.location);
+
+        visitExp(d.identifier);
+        if (d.init)
+            visitExp(d.init);
+    }
+
+    override void visitFuncDecl(FuncDecl f)
+    {
+        visitExp(f.identifier);
+
+        foreach (stmt; f.statements)
+            visitStmt(stmt);
+    }
+
+    override void visitCastExp(CastExp exp)
+    {
+        visitExp(exp.exp);
+    }
+
+    override void visitMemberReference(MemberReference m)
+    {
+        switch(m.target.expType)
+        {
+            case ExpType.Identifier:
+                auto target = cast(Identifier)m.target;
+                auto child = m.child;
+                auto st = cast(DStruct)(target.env.find(target).type);
+                if((child.get in st.members) is null)
+                    throw error(__LINE__, "%0 %1 has no member %2")
+                        .arg(st.name)
+                        .arg(target.get)
+                        .arg(child.get);
+                        //.tok(child.token);
+                break;
+            case ExpType.MemberReference:
+                break;
+        }
+    }
+
+    private bool isType(char[] s)
+    {
+        return (s in types? true : false);
+    }
+}
+
--- a/sema/SymbolTable.d	Mon May 05 17:07:16 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,108 +0,0 @@
-module sema.SymbolTable;
-
-import tango.io.Stdout;
-
-import lexer.Token,
-       ast.Decl,
-       ast.Exp;
-
-import sema.DType;
-
-public
-import sema.Symbol;
-
-class Scope
-{
-    this() {}
-    this(Scope enclosing)
-    {
-        this.enclosing = enclosing;
-        this.func = enclosing.func;
-    }
-
-    Scope enclosing;
-
-    Symbol add(Identifier id)
-    {
-        auto s = new Symbol;
-        s.id = id;
-        symbols[id] = s;
-        return s;
-    }
-
-    Symbol find(Identifier id)
-    {
-        if(!id)
-            return null;
-        if (auto sym = id in symbols)
-            return *sym;
-        if (enclosing !is null)
-            return enclosing.find(id);
-        return null;
-    }
-
-    DType findType(Identifier id)
-    {
-        if (auto type = id.get in types)
-                return *type;
-        if (enclosing !is null)
-            return enclosing.findType(id);
-        return null;
-    }
-
-    char[][] names()
-    {
-        char[][] res;
-        if (parentFunction() !is null)
-            res ~= "pf: " ~ parentFunction().identifier.get;
-        if (enclosing)
-            res = enclosing.names;
-        foreach (id, sym; symbols)
-            res ~= sym.id.name ~ " : " ~ (sym.type is null? "?" : sym.type.name);
-        return res;
-    }
-
-    FuncDecl parentFunction()
-    {
-        if (func !is null)
-            return func;
-        else if (enclosing !is null)
-            return enclosing.parentFunction();
-        else
-            return null;
-    }
-
-    int stmtIndex()
-    {
-        if (currentStmtIndex != -1)
-            return currentStmtIndex;
-        else if (enclosing !is null)
-            return enclosing.stmtIndex();
-        else
-            return -1;
-    }
-
-    int opEquals(Object o)
-    {
-        return this is o;
-    }
-
-    char[] toString()
-    {
-        if (func)
-            return Stdout.layout.convert("{}: {}", func.identifier.get, symbols.length);
-        return Stdout.layout.convert("root: {}", symbols.length);
-    }
-
-    FuncDecl parentFunction(FuncDecl f)
-    {
-        func = f;
-        return f;
-    }
-    DType[char[]] types;
-    int currentStmtIndex = -1;
-private:
-    Symbol[Identifier] symbols;
-    FuncDecl func;
-}
-
--- a/sema/SymbolTableBuilder.d	Mon May 05 17:07:16 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,227 +0,0 @@
-module sema.SymbolTableBuilder;
-
-import tango.io.Stdout,
-       tango.core.Array : find;
-
-public
-import sema.SymbolTable;
-
-import sema.Visitor,
-       basic.SmallArray;
-
-class SymbolTableBuilder : Visitor!(void)
-{
-    override void visit(Decl[] decls)
-    {
-        auto sb = new ScopeBuilder();
-        sb.visit(decls);
-        foreach (decl; decls)
-            visitDecl(decl);
-    }
-
-    override void visitFuncDecl(FuncDecl d)
-    {
-        visitExp(d.returnType);
-        visitExp(d.identifier);
-        foreach (arg; d.funcArgs)
-            visitDecl(arg);
-        foreach (stmt; d.statements)
-            visitStmt(stmt);
-
-        auto sym = d.env.find(d.identifier);
-        sym.type = d.type;
-    }
-
-    override void visitVarDecl(VarDecl d)
-    {
-        visitExp(d.varType);
-        visitExp(d.identifier);
-        
-        if (d.init)
-            visitExp(d.init);
-
-        d.env.find(d.identifier).type = typeOf(d.varType, d.env);
-    }
-
-    override void visitStructDecl(StructDecl s)
-    {
-        DType[char[]] types;
-
-        auto st = s.env.types[s.identifier.get].asStruct;
-        foreach(varDecl ; s.vars)
-            st.addMember(typeOf(varDecl.varType, varDecl.env), varDecl.identifier.get);
-
-        super.visitStructDecl(s);
-    }
-
-    DType typeOf(Identifier id, Scope sc)
-    {
-        if(auto i = cast(PointerIdentifier)id)
-            return (typeOf(i.pointerOf, sc)).getPointerTo();
-        if(auto i = cast(ArrayIdentifier)id)
-            return typeOf(i.arrayOf, sc).getAsArray(i.size);
-        return sc.findType(id);
-    }
-}
-
-class ScopeBuilder : Visitor!(void)
-{
-    this()
-    {
-        table ~= new Scope;
-        table[0].types["void"]    = DType.Void;
-        table[0].types["bool"]    = DType.Bool;
-        table[0].types["byte"]    = DType.Byte;
-        table[0].types["ubyte"]   = DType.UByte;
-        table[0].types["short"]   = DType.Short;
-        table[0].types["ushort"]  = DType.UShort;
-        table[0].types["int"]     = DType.Int;
-        table[0].types["uint"]    = DType.UInt;
-        table[0].types["long"]    = DType.Long;
-        table[0].types["ulong"]   = DType.ULong;
-    }
-
-    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();
-        s.stmtIndex = s.env.stmtIndex;
-        super.visitStmt(s);
-    }
-
-    override void visitExp(Exp e)
-    {
-        e.env = current();
-        e.stmtIndex = e.env.stmtIndex;
-        super.visitExp(e);
-    }
-
-    override void visitFuncDecl(FuncDecl d)
-    {
-        auto sym = current().add(d.identifier);
-        auto sc = push();
-
-        visitExp(d.returnType);
-        visitExp(d.identifier);
-        d.env = current();
-        sc.parentFunction = d;
-        foreach (arg; d.funcArgs)
-            visitDecl(arg);
-        foreach (stmt; d.statements)
-        {
-            sc.currentStmtIndex++;
-            visitStmt(stmt);
-        }
-        pop(sc);
-    }
-
-    override void visitVarDecl(VarDecl d)
-    {
-        if (d.init)
-            visitExp(d.init);
-
-        if (need_push > 0 && current().parentFunction !is null) {
-            push();
-            --need_push;
-        }
-
-        auto sc = current();
-        auto sym = sc.add(d.identifier);
-        d.env = sc;
-        visitExp(d.varType);
-        visitExp(d.identifier);
-    }
-
-    override void visitStructDecl(StructDecl s)
-    {
-        auto sc = current();
-        auto sym = sc.add(s.identifier);
-        s.env = sc;
-        auto type = new DStruct(s.identifier);
-        
-        sc.types[s.identifier.get] = type;
-
-        sc = push();
-        super.visitStructDecl(s);
-        pop(sc);
-    }
-
-    override void visitDeclStmt(DeclStmt d)
-    {
-        ++need_push;
-        super.visitDeclStmt(d);
-    }
-    private uint need_push = 0;
-
-    override void visitIfStmt(IfStmt s)
-    {
-        s.env = current();
-        visitExp(s.cond);
-        auto sc = push();
-        visitStmt(s.then_body);
-        pop(sc);
-
-        if (s.else_body !is null)
-        {
-            sc = push();
-            visitStmt(s.else_body);
-            pop(sc);
-        }
-    }
-
-    override void visitWhileStmt(WhileStmt s)
-    {
-        s.env = current();
-        auto sc = push();
-        super.visitWhileStmt(s);
-        pop(sc);
-    }
-
-    override void visitCompoundStmt(CompoundStatement s)
-    {
-        s.env = current();
-        auto sc = push();
-        super.visitCompoundStmt(s);
-        pop(sc);
-    }
-
-private:
-    Scope[] table;
-
-    Scope push()
-    {
-        auto sc = new Scope(current());
-        table ~= sc;
-        return sc;
-    }
-
-    Scope pop(Scope sc = null)
-    {
-        if (sc !is null)
-        {
-            table.length = table.find(sc);
-            return sc;
-        }
-
-        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/TypeCheck.d	Mon May 05 18:44:20 2008 +0200
@@ -0,0 +1,146 @@
+module sema.TypeCheck;
+
+import sema.Visitor,
+       sema.DType;
+
+import tango.io.Stdout;
+
+import misc.Error,
+       basic.SourceLocation;
+
+class TypeCheck : Visitor!(void)
+{
+    private Error error(uint line, char[] msg)
+    {
+        return new Error(msg);
+    }
+
+    override void visitBinaryExp(BinaryExp exp)
+    {
+        super.visitBinaryExp(exp);
+
+        if(exp.left.type.byteSize > exp.right.type.byteSize)
+        {
+            if(!exp.right.type.hasImplicitConversionTo(exp.left.type))
+                throw error(__LINE__, "Cannot make implicit cast");
+
+            auto castExp = new CastExp(
+                    SLoc.Invalid,
+                    new Identifier(exp.left.type.name),
+                    exp.right);
+            castExp.env = exp.env;
+            exp.right = castExp;
+        }
+
+        if(exp.left.type.byteSize < exp.right.type.byteSize)
+        {
+            if(!exp.left.type.hasImplicitConversionTo(exp.right.type))
+                throw error(__LINE__, "Cannot make implicit cast");
+
+            auto castExp = new CastExp(
+                    SLoc.Invalid,
+                    new Identifier(exp.right.type.name),
+                    exp.left);
+            castExp.env = exp.env;
+            exp.left = castExp;
+        }
+
+    }
+
+    override void visitCallExp(CallExp exp)
+    {
+        super.visitCallExp(exp);
+
+        Exp[] newArgs;
+
+        foreach(i, arg; exp.args)
+        {
+            auto argType = (cast(DFunction)exp.exp.type).params[i];
+            auto expType = arg.type;
+            if(argType.byteSize != expType.byteSize)
+            {
+                if(!expType.hasImplicitConversionTo(argType))
+                    throw error(__LINE__, "Cannot make implicit cast");
+
+                auto castExp = new CastExp(
+                        SLoc.Invalid,
+                        new Identifier(argType.name),
+                        arg);
+                castExp.env = exp.exp.env;
+                newArgs ~= castExp;
+            }
+            else
+                newArgs ~= arg;
+        }
+
+        exp.args = newArgs;
+    }
+
+    override void visitAssignExp(AssignExp exp)
+    {
+        super.visitAssignExp(exp);
+
+        auto identifierType = exp.identifier.type;
+        auto expType = exp.exp.type;
+
+        if(identifierType != expType)
+        {
+            if(!expType.hasImplicitConversionTo(identifierType))
+                throw error(__LINE__, "Cannot make implicit cast between");
+
+            auto castExp = new CastExp(
+                    SLoc.Invalid,
+                    new Identifier(expType.name),
+                    exp.exp);
+            castExp.env = exp.exp.env;
+            exp.exp = castExp;
+        }
+    }
+
+    override void visitReturnStmt(ReturnStmt stmt)
+    {
+        super.visitReturnStmt(stmt);
+
+        if(stmt.exp)
+        {
+            auto returnType = stmt.env.parentFunction.type.asFunction.returnType;
+            auto expType = stmt.exp.type;
+            if(returnType != expType)
+            {
+                if(!expType.hasImplicitConversionTo(returnType))
+                    throw error(__LINE__, "Cannot make implicit cast");
+
+                auto castExp = new CastExp(
+                        SLoc.Invalid,
+                        new Identifier(returnType.name),
+                        stmt.exp);
+                castExp.env = stmt.exp.env;
+                stmt.exp = castExp;
+            }
+        }
+    }
+
+    override void visitVarDecl(VarDecl decl)
+    {
+        super.visitVarDecl(decl);
+
+        if(decl.init)
+        {
+            auto varType = decl.type;
+            auto expType = decl.init.type;
+            if(varType.byteSize != expType.byteSize)
+            {
+                if(!expType.hasImplicitConversionTo(varType))
+                    throw error(__LINE__, "Cannot make implicit cast");
+
+                auto castExp = new CastExp(
+                        SLoc.Invalid,
+                        new Identifier(varType.name),
+                        decl.init);
+                castExp.env = decl.init.env;
+                decl.init = castExp;
+            }
+        }
+    }
+}
+