changeset 144:6e6355fb5f0f

- Parsing nested attributes. - Creating classes and interfaces in AST. - Updated AstPrinter to print attributes, classes and interfaces.
author Anders Johnsen <skabet@gmail.com>
date Mon, 21 Jul 2008 17:41:40 +0200
parents d76cc5cad4fc
children a14ac9e5c858
files ast/Decl.d ast/Module.d basic/Attribute.d parser/Action.d parser/Parser.d sema/AstAction.d sema/DType.d sema/ScopeBuilder.d sema/Visitor.d tests/parser/public_1.d tools/AstPrinter.d
diffstat 11 files changed, 868 insertions(+), 298 deletions(-) [+]
line wrap: on
line diff
--- a/ast/Decl.d	Mon Jul 21 01:05:20 2008 +0200
+++ b/ast/Decl.d	Mon Jul 21 17:41:40 2008 +0200
@@ -20,6 +20,8 @@
     ImportDecl,
     FuncDecl,
     StructDecl,
+    ClassDecl,
+    InterfaceDecl,
 }
 
 class Decl
@@ -220,3 +222,69 @@
     private DType myType;
 }
 
+class ClassDecl : Decl
+{
+    this(Identifier identifier)
+    {
+        super(DeclType.ClassDecl);
+        this.identifier = identifier;
+    }
+
+    void addMember(Decl decl)
+    {
+        decls ~= decl;
+    }
+
+    void addBaseClass(Identifier identifier)
+    {
+        baseClasses ~= identifier;
+    }
+
+    void simplify()
+    {
+    }
+
+    override DType type()
+    {
+        return env.findType(identifier);
+    }
+
+    Identifier identifier;
+    Identifier[] baseClasses;
+    Decl[] decls;
+    private DType myType;
+}
+
+class InterfaceDecl : Decl
+{
+    this(Identifier identifier)
+    {
+        super(DeclType.InterfaceDecl);
+        this.identifier = identifier;
+    }
+
+    void addMember(Decl decl)
+    {
+        decls ~= decl;
+    }
+
+    void addBaseClass(Identifier identifier)
+    {
+        baseClasses ~= identifier;
+    }
+
+    void simplify()
+    {
+    }
+
+    override DType type()
+    {
+        return env.findType(identifier);
+    }
+
+    Identifier identifier;
+    Identifier[] baseClasses;
+    Decl[] decls;
+    private DType myType;
+}
+
--- a/ast/Module.d	Mon Jul 21 01:05:20 2008 +0200
+++ b/ast/Module.d	Mon Jul 21 17:41:40 2008 +0200
@@ -25,15 +25,23 @@
             case DeclType.StructDecl:
                 structs ~= cast(StructDecl)decl;
                 break;
+            case DeclType.ClassDecl:
+                classes ~= cast(ClassDecl)decl;
+                break;
+            case DeclType.InterfaceDecl:
+                interfaces ~= cast(InterfaceDecl)decl;
+                break;
             default:
                 assert(0, "DeclType not implemented");
         }
         decls ~= decl;
     }
 
-    VarDecl[] vars;
-    FuncDecl[] functions;
-    StructDecl[] structs;
+    VarDecl[]       vars;
+    FuncDecl[]      functions;
+    StructDecl[]    structs;
+    ClassDecl[]     classes;
+    InterfaceDecl[] interfaces;
     Decl[] decls;
 
     char[] moduleName;
--- a/basic/Attribute.d	Mon Jul 21 01:05:20 2008 +0200
+++ b/basic/Attribute.d	Mon Jul 21 17:41:40 2008 +0200
@@ -94,13 +94,20 @@
         return e;
     }
 
-    void setStatic()    { att &= ~Static; }
-    void setFinal()     { att &= ~Final; }
-    void setConst()     { att &= ~Const; }
-    void setAbstract()  { att &= ~Abstract; }
-    void setOverride()  { att &= ~Override; }
-    void setDepracted() { att &= ~Depracted; }
-    void setAuto()      { att &= ~Auto; }
+    void setStatic()    { att |= Static; }
+    bool getStatic()    { return att & Static ? true : false; }
+    void setFinal()     { att |= Final; }
+    bool getFinal()     { return att & Final ? true : false; }
+    void setConst()     { att |= Const; }
+    bool getConst()     { return att & Const ? true : false; }
+    void setAbstract()  { att |= Abstract; }
+    bool getAbstract()  { return att & Abstract ? true : false; }
+    void setOverride()  { att |= Override; }
+    bool getOverride()  { return att & Override ? true : false; }
+    void setDepracted() { att |= Depracted; }
+    bool getDepracted() { return att & Depracted ? true : false; }
+    void setAuto()      { att |= Auto; }
+    bool getAuto()      { return att & Auto ? true : false; }
 
     char[] toString()
     {
--- a/parser/Action.d	Mon Jul 21 01:05:20 2008 +0200
+++ b/parser/Action.d	Mon Jul 21 17:41:40 2008 +0200
@@ -171,7 +171,7 @@
     /**
       Add a class member to a struct.
      */
-    void actOnClassMember(DeclT st_decl, DeclT m_decl)
+    void actOnClassMember(DeclT cl_decl, DeclT m_decl)
     {
         return null;
     }
@@ -179,7 +179,23 @@
     /**
       Add a class member to a struct.
      */
-    void actOnClassBaseClass(DeclT st_decl, ref Id name)
+    void actOnClassBaseClass(DeclT cl_decl, ref Id name)
+    {
+        return null;
+    }
+
+    /**
+      Add a class member to a struct.
+     */
+    void actOnInterfaceMember(DeclT if_decl, DeclT m_decl)
+    {
+        return null;
+    }
+
+    /**
+      Add a class member to a struct.
+     */
+    void actOnInterfaceBaseClass(DeclT if_decl, ref Id name)
     {
         return null;
     }
--- a/parser/Parser.d	Mon Jul 21 01:05:20 2008 +0200
+++ b/parser/Parser.d	Mon Jul 21 17:41:40 2008 +0200
@@ -35,163 +35,105 @@
         this.action = act;
 
         Module m;
-        if (lexer.peek.type == Tok.Module)
+        if ( isa(Tok.Module) )
         {
-            Token _module = lexer.next;
+            Token _module = next;
             ModuleName name = parseModuleName();
             m = action.actOnModule(_module, sm.getText(name.asRange()));
             require(Tok.Seperator);
         }
         else
         {
-            SLoc loc = lexer.peek.location;
+            SLoc loc = peek.location;
             m = action.actOnImplicitModule(loc, sm.getFile(loc));
         }
 
-        Attribute att;
-        while (lexer.peek.type != Tok.EOF)
-            foreach (d; parseDeclDef(&att))
+        auto nes = parseAttributeInit;
+        while( !isa(Tok.EOF) )
+        {
+            while ( peek.isAttribute )
+                nes ~= parseAttribute(nes[$-1]);
+
+            foreach (d; parseDeclDef(nes[$-1].a))
                 action.actOnModuleDecl(m, d);
 
+            nes = parseAttributeScope(nes);
+        }
+
         return m;
     }
 
 private:
-    Decl[] parseDeclDef(Attribute* a)
+    Decl[] parseDeclDef(Attribute a)
     {
-        Token t = lexer.peek;
-        if (t.type == Tok.Import)
+        if ( isa (Tok.Import) )
             return parseImports();
-        else
-            return [parseDecl(a)];
+
+        return [parseDecl(a)];
     }
 
-    Decl parseDecl(Attribute* all_res)
+    Decl parseDecl(Attribute att)
     {
-        Token t = lexer.peek;
-
-        Attribute att = *all_res;
-
-        while ( t.isAttribute )
-        {
-            Attribute* a = &att;
-            bool sco;
-            if(lexer.peek(1).type == Tok.Colon)
-                sco = true;
-
-LSwitch:    switch(t.type)
-            {
-                case Tok.Public:
-                    a.setProtection(Protection.Public);
-                    break;
-                case Tok.Private:
-                    a.setProtection(Protection.Private);
-                    break;
-                case Tok.Package:
-                    a.setProtection(Protection.Package);
-                    break;
-                case Tok.Protected:
-                    a.setProtection(Protection.Protected);
-                    break;
-                case Tok.Export:
-                    a.setProtection(Protection.Export);
-                    break;
-                case Tok.Static:
-                    a.setStatic;
-                    break;
-                case Tok.Final:
-                    a.setFinal;
-                    break;
-                case Tok.Const:
-                    a.setConst;
-                    break;
-                case Tok.Abstract:
-                    a.setAbstract;
-                    break;
-                case Tok.Override:
-                    a.setOverride;
-                    break;
-                case Tok.Depracted:
-                    a.setDepracted;
-                    break;
-                case Tok.Auto:
-                    a.setAuto;
-                    break;
-                case Tok.Extern:
-                    Extern e = parseLinkageType;
-                    a.setExtern(e);
-                    break;
-            }
-            if(sco)
-            {
-                sco = false;
-                a = all_res;
-                lexer.next;
-                goto LSwitch;
-            }
-            lexer.next;
-            t = lexer.peek;
-        }
+        Token t = peek;
 
         if (t.isBasicType || t.isIdentifier)
         {
             Id type;
             Id iden;
             int len = peekParseType;
-            if(lexer.peek(len).type == Tok.Identifier && len != 0)
+            if (peek(len).type == Tok.Identifier && len != 0)
             {
                 type = parseType;
 parseDeclAfterInvalidType:
                 iden = Id(require(Tok.Identifier));
-                Token next = lexer.peek();
-                if (next.type == Tok.Seperator)
+                if ( isa(Tok.Seperator) )
                 {
-                    Token sep = lexer.next();
+                    Token sep = next;
                     return action.actOnDeclarator(type, iden, null, att);
                 }
-                else if (next.type == Tok.Assign)
+                else if ( isa(Tok.Assign) )
                 {
-                    Token assign = lexer.next();
+                    Token assign = next();
                     Exp exp = parseExpression();
                     require(Tok.Seperator);
                     return action.actOnDeclarator(type, iden, exp, att);
                 }
-                else if (next.type == Tok.OpenParentheses)
+                else if ( isa(Tok.OpenParentheses) )
                     return parseFunc(type, iden, att);
                 else
                     messages.report(UnexpectedTok, next.location).arg(next.getType);
                 return null;
             }
-            t = lexer.peek(len);
+            t = 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);
+                next;
+            while(peek.type != Tok.Identifier)
+                next;
+            type = Id(peek);
             goto parseDeclAfterInvalidType;
         }
         else if (t.type == Tok.Struct)
         {
-            Id type = Id(lexer.next);
+            Id type = Id(next);
             Id iden = Id(require(Tok.Identifier));
             
             return parseStruct(type, iden, att);
         }
         else if (t.type == Tok.Class)
         {
-            Id type = Id(lexer.next);
+            Id type = Id(next);
             Id iden = Id(require(Tok.Identifier));
             
             return parseClass(type, iden, att);
         }
         else if (t.type == Tok.Interface)
         {
-            Id type = Id(lexer.next);
+            Id type = Id(next);
             Id iden = Id(require(Tok.Identifier));
             
-            return parseClass(type, iden, att);
+            return parseInterface(type, iden, att);
         }
         messages.report(UnexpectedTok, t.location)
             .arg(t.getType)
@@ -202,18 +144,18 @@
     Extern parseLinkageType()
     {
         Extern e = Extern.D;
-        if(lexer.peek(1).type != Tok.OpenParentheses)
+        if(peek(1).type != Tok.OpenParentheses)
             return e;
 
-        lexer.next; lexer.next;
+        next; next;
 
         Token t = require(Tok.Identifier);
 
         switch(sm.getText(t.asRange))
         {
             case "C":
-                if (lexer.peek(0).type == Tok.Plus && 
-                    lexer.peek(1).type == Tok.Plus)
+                if (peek(0).type == Tok.Plus && 
+                    peek(1).type == Tok.Plus)
                     e = Extern.CPlusPlus;
                 else
                     e = Extern.C;
@@ -248,16 +190,16 @@
         void addToRes(Decl d) { res ~= d; }
 
         bool done = false;
-        while (!done && !on_a(Tok.Seperator))
+        while (!done && !isa(Tok.Seperator))
         {
             ModuleName mod = parseModuleName();
-            Token tok = lexer.peek;
+            Token tok = peek;
             switch (tok.type)
             {
                 case Tok.Comma:
                     // import A, B.C;
                     // parse another module-name
-                    lexer.next();
+                    next();
                     res ~= action.actOnImport(_import, mod, null);
                     break;
                 case Tok.Assign:
@@ -271,7 +213,7 @@
                     }
                     //if (isStatic)
                     //    error("Static imports cannot be renamed");
-                    lexer.next();
+                    next();
                     Id name = mod.id;
                     mod = parseModuleName();
                     // create from mod and rename to `name`
@@ -280,7 +222,7 @@
                 case Tok.Colon:
                     // import A : a;
                     // selective imports, potentially import A : print = a
-                    lexer.next();
+                    next();
                     Decl d = action.actOnImport(_import, mod, null);
                     // do-while on a comma:
                     //   add explicit symbol
@@ -313,8 +255,8 @@
         require(Tok.Seperator);
         return res.safe();
 Lerror:
-        while (!on_a (Tok.Seperator))
-            lexer.next();
+        while (!isa (Tok.Seperator))
+            next();
         return res.safe();
     }
 
@@ -325,37 +267,42 @@
     {
         auto decl = action.actOnDeclarator(type, iden, null, att);
 
-        if (lexer.peek.type == Tok.Colon)
+        if (peek.type == Tok.Colon)
             // SuperInterfaces
         {
-            lexer.next; // Remove colon.
+            next; // Remove colon.
 
-            Token identifier;
+            Id identifier;
 
             // The identifier
-            identifier = require(Tok.Identifier);
+            identifier = Id(require(Tok.Identifier));
 
-            // FIXME: Register Interface here
+            action.actOnInterfaceBaseClass(decl, identifier);
 
             // We should now have an optional list of items, each starting ','
-            while (lexer.peek.type == Tok.Comma)
+            while (peek.type == Tok.Comma)
             {
-                lexer.next; // Remove comma
+                next; // Remove comma
 
                 // The identifier
-                identifier = require(Tok.Identifier);
+                identifier = Id(require(Tok.Identifier));
 
-                // FIXME: Register Interface here
+                action.actOnInterfaceBaseClass(decl, identifier);
             }
         }
 
         require(Tok.OpenBrace);
 
-        Attribute a;
-        while(lexer.peek.isBasicType || lexer.peek.isIdentifier || lexer.peek.isAttribute)
+        auto nes = parseAttributeInit;
+        while( !isa(Tok.EOF) && !isa(Tok.CloseBrace) )
         {
-            auto m_decl = parseDecl(&a);
-            action.actOnStructMember(decl, m_decl); 
+            while ( peek.isAttribute )
+                nes ~= parseAttribute(nes[$-1]);
+
+            auto m_decl = parseDecl(nes[$-1].a);
+            action.actOnInterfaceMember(decl, m_decl);
+
+            nes = parseAttributeScope(nes);
         }
 
         require(Tok.CloseBrace);
@@ -370,41 +317,49 @@
     {
         auto decl = action.actOnDeclarator(type, iden, null, att);
 
-        if (lexer.peek.type == Tok.Colon)
+        if (peek.type == Tok.Colon)
             // BaseClassList - Super class and interfaces(in that order)
         {
-            lexer.next; // Remove colon.
+            next; // Remove colon.
 
-            Token protection, identifier;
+            Token protection;
+            Id    identifier;
 
             // First we expect an optional protection level.
-            if (lexer.peek.isBaseClassProtection)
-                protection = lexer.next;
+            if (peek.isBaseClassProtection)
+                protection = next;
             // Then the identifier
-            identifier = require(Tok.Identifier);
+            identifier = Id(require(Tok.Identifier));
 
-            // FIXME: Register Interface here
+            action.actOnClassBaseClass(decl, identifier);
 
             // We should now have an optional list of items, each starting ','
-            while (lexer.peek.type == Tok.Comma)
+            while (peek.type == Tok.Comma)
             {
-                lexer.next; // Remove comma
+                next; // Remove comma
 
                 // First we expect an optional protection level.
-                if (lexer.peek.isBaseClassProtection)
-                    protection = lexer.next;
+                if (peek.isBaseClassProtection)
+                    protection = next;
                 // Then the identifier
-                identifier = require(Tok.Identifier);
+                identifier = Id(require(Tok.Identifier));
+
+                action.actOnClassBaseClass(decl, identifier);
             }
         }
 
         require(Tok.OpenBrace);
 
-        Attribute a;
-        while(lexer.peek.isBasicType || lexer.peek.isIdentifier || lexer.peek.isAttribute)
+        auto nes = parseAttributeInit;
+        while( !isa(Tok.EOF) && !isa(Tok.CloseBrace) )
         {
-            auto m_decl = parseDecl(&a);
-            action.actOnStructMember(decl, m_decl); // FIXME: Should call actOnClassMember
+            while ( peek.isAttribute )
+                nes ~= parseAttribute(nes[$-1]);
+
+            auto m_decl = parseDecl(nes[$-1].a);
+            action.actOnClassMember(decl, m_decl);
+
+            nes = parseAttributeScope(nes);
         }
 
         require(Tok.CloseBrace);
@@ -421,11 +376,16 @@
 
         require(Tok.OpenBrace);
 
-        Attribute a;
-        while(lexer.peek.isBasicType || lexer.peek.isIdentifier || lexer.peek.isAttribute)
+        auto nes = parseAttributeInit;
+        while( !isa(Tok.EOF) && !isa(Tok.CloseBrace) )
         {
-            auto m_decl = parseDecl(&a);
+            while ( peek.isAttribute )
+                nes ~= parseAttribute(nes[$-1]);
+
+            auto m_decl = parseDecl(nes[$-1].a);
             action.actOnStructMember(decl, m_decl); 
+
+            nes = parseAttributeScope(nes);
         }
 
         require(Tok.CloseBrace);
@@ -433,48 +393,162 @@
         return decl;
     }
 
-    /**
-      Parse statements.
+    Att[] parseAttributeInit()
+    {
+        Att[] nes;
+        nes ~= Att();
+        nes[0].nested = Scope;
+        return nes;
+    }
 
-      This is the place to attack!
-     */
-    Stmt parseStatement()
+    Att[] parseAttributeScope(Att[] nes)
     {
-        Token t = lexer.peek;
+        while ( nes[$-1].nested == Single )
+            nes.length = nes.length - 1;
 
-        if (t.isReturn)
+        while ( isa(Tok.CloseBrace) && nes.length > 1)
         {
-            Token ret = lexer.next;
-            Exp exp;
-            if (lexer.peek.type != Tok.Seperator)
-                exp = parseExpression();
-            require(Tok.Seperator);
-            return action.actOnReturnStmt(ret, exp);
+            while ( nes.length > 1 )
+            {
+                if( nes[$-1].nested == Scope )
+                {
+                    nes.length = nes.length - 1;
+                    next;
+                    break;
+                }
+                nes.length = nes.length - 1;
+            }
+        }
+
+        return nes;
+    }
+
+    Att parseAttribute(Att last)
+    {
+        Att _parseAttribute(Att last)
+        {
+            Att a = last;
+            a.nested = Single;
 
-            /*
-               if (cond)
-               single statement | compound statement
-               [else
-               single statement | compound statement]
-             */
+            switch(peek.type)
+            {
+                case Tok.Public:
+                    a.a.setProtection(Protection.Public);
+                    break;
+                case Tok.Private:
+                    a.a.setProtection(Protection.Private);
+                    break;
+                case Tok.Package:
+                    a.a.setProtection(Protection.Package);
+                    break;
+                case Tok.Protected:
+                    a.a.setProtection(Protection.Protected);
+                    break;
+                case Tok.Export:
+                    a.a.setProtection(Protection.Export);
+                    break;
+                case Tok.Static:
+                    a.a.setStatic;
+                    break;
+                case Tok.Final:
+                    a.a.setFinal;
+                    break;
+                case Tok.Const:
+                    a.a.setConst;
+                    break;
+                case Tok.Abstract:
+                    a.a.setAbstract;
+                    break;
+                case Tok.Override:
+                    a.a.setOverride;
+                    break;
+                case Tok.Depracted:
+                    a.a.setDepracted;
+                    break;
+                case Tok.Auto:
+                    a.a.setAuto;
+                    break;
+                case Tok.Extern:
+                    Extern e = parseLinkageType;
+                    a.a.setExtern(e);
+                    break;
+            }
+            next;
+
+            return a;
         }
-        else if (t.isIf)
+
+        Att a = _parseAttribute(last);
+
+        while (peek.isAttribute)
         {
-            Token _if = lexer.next();
+            a = parseAttribute(a);
+        }
 
-            require(Tok.OpenParentheses);
-            Exp cond = parseExpression();
-            require(Tok.CloseParentheses);
+        if (peek.type == Tok.Colon)
+        {
+            a.nested = All;
+            next;
+        }
+        else if  (peek.type == Tok.OpenBrace)
+        {
+            a.nested = Scope;
+            next;
+        }
+
+        return a;
+    }
 
-            Stmt thenB = parseSingleOrCompoundStatement();
+enum : uint { Single, Scope, All }
+
+       struct Att
+       {
+           Attribute a;
+           uint nested;
+       }
+
+       /**
+         Parse statements.
+
+         This is the place to attack!
+        */
+       Stmt parseStatement()
+       {
+           Token t = peek;
 
-            // if there is no else part we use the if as token, to have
-            // something than can be passed along
-            Token _else = _if;
-            Stmt elseB;
-            if (lexer.peek.type == Tok.Else)
+           if (t.isReturn)
+           {
+               Token ret = next;
+               Exp exp;
+               if (peek.type != Tok.Seperator)
+                   exp = parseExpression();
+               require(Tok.Seperator);
+               return action.actOnReturnStmt(ret, exp);
+
+               /*
+                  if (cond)
+                  single statement | compound statement
+                  [else
+                  single statement | compound statement]
+                */
+           }
+           else if (t.isIf)
+           {
+               Token _if = next();
+
+               require(Tok.OpenParentheses);
+               Exp cond = parseExpression();
+               require(Tok.CloseParentheses);
+
+               Stmt thenB = parseSingleOrCompoundStatement();
+
+               // if there is no else part we use the if as token, to have
+               // something than can be passed along
+               Token _else = _if;
+               Stmt elseB;
+            if (peek.type == Tok.Else)
             {
-                _else = lexer.next;
+                _else = next;
                 elseB = parseSingleOrCompoundStatement();
             }
 
@@ -487,7 +561,7 @@
         }
         else if (t.isWhile)
         {
-            Token _while = lexer.next;
+            Token _while = next;
             require(Tok.OpenParentheses);
             Exp cond = parseExpression();
             require(Tok.CloseParentheses);
@@ -506,14 +580,14 @@
         }
         else if (t.isBasicType || t.isIdentifier)
         {
-            Token iden = lexer.peek;
-            Token n = lexer.peek(1);
+            Token iden = peek;
+            Token n = peek(1);
             // Must be an decl, if we start with a basic type, or two
             // identifiers in a row
             if ( n.type == Tok.Star || n.type == Tok.OpenBracket)
             {
                 int len = peekParseType;
-                if(lexer.peek(len).type == Tok.Identifier && len != 0)
+                if(peek(len).type == Tok.Identifier && len != 0)
                     return action.actOnDeclStmt(parseVarDecl());
 
                 Exp exp = parseExpression();
@@ -531,7 +605,7 @@
         }
         else if(t.isSwitch)
         {
-            lexer.next;
+            next;
             require(Tok.OpenParentheses);
             auto target = parseExpression();
             auto res = action.actOnStartOfSwitchStmt(target);
@@ -544,18 +618,18 @@
                 {
                     require(Tok.Colon);
                     statements.length = 0;
-                    while (lexer.peek.type != Tok.Case
-                            && lexer.peek.type != Tok.Default
-                            && lexer.peek.type != Tok.CloseBrace)
+                    while (peek.type != Tok.Case
+                            && peek.type != Tok.Default
+                            && peek.type != Tok.CloseBrace)
                         statements ~= parseStatement();
                     action.actOnDefaultStmt(res, statements);
                     continue;
                 }
 
-                Token _case = lexer.peek;
+                Token _case = peek;
                 if (_case.type != Tok.Case)
                     break;
-                lexer.next();
+                next();
 
                 Exp[] literals;
                 do
@@ -563,21 +637,21 @@
                     Exp e = parseExpression();
 //                    IntegerLit lit = cast(IntegerLit)e;
 //                    if (lit is null)
-//                        messages.report(CaseValueMustBeInt, lexer.peek.location).arg(lexer.next.getType);
+//                        messages.report(CaseValueMustBeInt, peek.location).arg(next.getType);
 //                    else
                     literals ~= e;
                 }
                 while (skip(Tok.Comma));
                 require(Tok.Colon);
 
-                while (lexer.peek.type != Tok.Case
-                        && lexer.peek.type != Tok.Default
-                        && lexer.peek.type != Tok.CloseBrace)
+                while (peek.type != Tok.Case
+                        && peek.type != Tok.Default
+                        && peek.type != Tok.CloseBrace)
                     statements ~= parseStatement();
 
                 action.actOnCaseStmt(res, literals, statements);
 
-                if (lexer.peek.type == Tok.CloseBrace)
+                if (peek.type == Tok.CloseBrace)
                     break;
             }
             require(Tok.CloseBrace);
@@ -591,7 +665,7 @@
                 require(Tok.Seperator);
                 return action.actOnExprStmt(exp);
             }
-            messages.report(UnexpectedBeginStmt, lexer.peek.location).arg(lexer.next.getType);
+            messages.report(UnexpectedBeginStmt, peek.location).arg(next.getType);
             return null;
         }
         messages.report(UnexpectedTok, t.location);
@@ -603,7 +677,7 @@
         // manually hardcoded to only support "type id [= exp];"
         // as that is the only thing the codegen understands
         Id type = parseType;
-        Id id = Id(lexer.next);
+        Id id = Id(next);
         Exp init;
         if (skip(Tok.Assign))
             init = parseExpression();
@@ -621,9 +695,9 @@
         Decl func = action.actOnStartOfFunctionDef(type, name, att);
         parseFuncArgs(func);
 
-        if(lexer.peek.type == Tok.Seperator)
+        if(peek.type == Tok.Seperator)
         {
-            lexer.next;
+            next;
             return func;
         }
         Stmt stmt = parseCompoundStatement();
@@ -640,16 +714,16 @@
     {
         require(Tok.OpenParentheses); // Remove the "(" token.
 
-        while(lexer.peek.type != Tok.CloseParentheses)
+        while(peek.type != Tok.CloseParentheses)
         {
             auto t = parseType();
             Id i;
-            if(lexer.peek.type == Tok.Identifier)
+            if(peek.type == Tok.Identifier)
                 i = parseIdentifier();
             action.addFuncArg(func, t, i);
 
-            if(lexer.peek.type == Tok.Comma)
-                lexer.next;
+            if(peek.type == Tok.Comma)
+                next;
         }
 
         require(Tok.CloseParentheses); // Remove the ")"
@@ -661,7 +735,7 @@
      */
     Stmt parseSingleOrCompoundStatement()
     {
-        if (lexer.peek.type == Tok.OpenBrace)
+        if (peek.type == Tok.OpenBrace)
             return parseCompoundStatement();
         return parseStatement();
     }
@@ -676,7 +750,7 @@
     {
         Token lbrace = require(Tok.OpenBrace);
         SmallArray!(Stmt, 32) stmts; // Try to use the stack only
-        while (lexer.peek.type != Tok.CloseBrace)
+        while (peek.type != Tok.CloseBrace)
             stmts ~= parseStatement();
         Token rbrace = require(Tok.CloseBrace);
         return action.actOnCompoundStmt(lbrace, rbrace, stmts.unsafe());
@@ -684,7 +758,7 @@
 
     Id parseIdentifier()
     {
-        Token tok = lexer.next;
+        Token tok = next;
 
         if (tok.type is Tok.Identifier)
             return Id(tok);
@@ -701,8 +775,8 @@
         while (skip(Tok.Dot))
         {
             mod.packages ~= id;
-            if (lexer.peek.type != Tok.Identifier) {
-                messages.report(ExpectedIdAfterPackage, lexer.peek.location);
+            if (peek.type != Tok.Identifier) {
+                messages.report(ExpectedIdAfterPackage, peek.location);
                 goto Lerror;
             }
             id = parseIdentifier();
@@ -711,7 +785,7 @@
         return mod;
 Lerror:
         while (!skip(Tok.Seperator))
-            lexer.next();
+            next();
         return mod;
     }
 
@@ -721,7 +795,7 @@
      */
     Id parseType()
     {
-        Token type = lexer.next;
+        Token type = next;
 
         Id currentType;
 
@@ -729,19 +803,19 @@
             messages.report(InvalidType, type.location);
 
         currentType = Id(type);
-        type = lexer.peek;
+        type = peek;
 
         while(type.type == Tok.Star || type.type == Tok.OpenBracket)
         {
             if(type.type == Tok.Star)
             {
                 currentType = PointerId(currentType);
-                lexer.next;
+                next;
             }
             else
             {
-                lexer.next;
-                if(lexer.peek.type == Tok.Integer)
+                next;
+                if(peek.type == Tok.Integer)
                     currentType = StaticArrayId(
                             currentType, 
                             action.actOnNumericConstant(
@@ -749,7 +823,7 @@
                 require(Tok.CloseBracket);
                 
             }
-            type = lexer.peek;
+            type = peek;
         }
 
         return currentType;
@@ -758,7 +832,7 @@
     int peekParseType()
     {
         int i;
-        Token type = lexer.peek(i);
+        Token type = peek(i);
 
         Id currentType;
 
@@ -766,7 +840,7 @@
             return 0;
 
         currentType = Id(type);
-        type = lexer.peek(++i);
+        type = peek(++i);
 
         while(type.type == Tok.Star || type.type == Tok.OpenBracket)
         {
@@ -776,20 +850,20 @@
             }
             else
             {
-                if(lexer.peek(i++).type != Tok.OpenBracket)
+                if(peek(i++).type != Tok.OpenBracket)
                     return 0;
-                if(lexer.peek(i).type == Tok.Integer)
+                if(peek(i).type == Tok.Integer)
                 {
                     i++;
-                    if(lexer.peek(i++).type != Tok.CloseBracket)    
+                    if(peek(i++).type != Tok.CloseBracket)    
                         return 0;
                 }
                 else
-                    if(lexer.peek(i++).type != Tok.CloseBracket)
+                    if(peek(i++).type != Tok.CloseBracket)
                         return 0;
                 
             }
-            type = lexer.peek(i);
+            type = peek(i);
         }
 
         return i;
@@ -799,22 +873,22 @@
     // -- Expression parsing -- //
     Exp parsePostfixExp(Exp target)
     {
-        switch(lexer.peek.type)
+        switch(peek.type)
         {
             case Tok.Dot:
-                switch(lexer.peek(1).type)
+                switch(peek(1).type)
                 {
                     case Tok.Identifier:
-                        Token op = lexer.next;
-                        Id member = Id(lexer.next);
+                        Token op = next;
+                        Id member = Id(next);
                         Exp exp = action.actOnMemberReference(target, op.location, member);
                         return parsePostfixExp(exp);
                     default:
-                        Token t = lexer.peek(1);
+                        Token t = peek(1);
                         messages.report(ExpectedIdAfterDot, t.location);
                 }
             case Tok.OpenBracket:
-                Token open = lexer.next;
+                Token open = next;
                 Exp index = parseExpression();
                 Token close = require(Tok.CloseBracket);
                 return action.actOnIndexEpr(target, open, index, close);
@@ -826,15 +900,15 @@
     Exp parseExpression(int p = 0)
     {
         auto exp = P();
-        Token next = lexer.peek();
+        Token n = peek();
         BinOp* op = null;
-        while ((op = binary(next.type)) != null && op.prec >= p)
+        while ((op = binary(n.type)) != null && op.prec >= p)
         {
-            lexer.next();
+            next();
             int q = op.leftAssoc? 1 + op.prec : op.prec;
             auto exp2 = parseExpression(q);
-            exp = action.actOnBinaryOp(next.location, op.operator, exp, exp2);
-            next = lexer.peek();
+            exp = action.actOnBinaryOp(n.location, op.operator, exp, exp2);
+            n = peek();
         }
 
         return exp;
@@ -842,46 +916,46 @@
 
     Exp P()
     {
-        Token next = lexer.next();
-        if (auto op = unary(next.type))
-            return action.actOnUnaryOp(next, parseExpression(op.prec));
-        else if (next.type == Tok.OpenParentheses)
+        Token n = next();
+        if (auto op = unary(n.type))
+            return action.actOnUnaryOp(n, parseExpression(op.prec));
+        else if (n.type == Tok.OpenParentheses)
         {
             auto e = parseExpression(0);
             require(Tok.CloseParentheses);
             return e;
         }
-        else if (next.type == Tok.Identifier)
+        else if (n.type == Tok.Identifier)
         {
-            Exp value = action.actOnIdentifierExp(Id(next));
+            Exp value = action.actOnIdentifierExp(Id(n));
             Exp iden = parsePostfixExp(value);
-            switch(lexer.peek.type)
+            switch(peek.type)
             {
                 case Tok.OpenParentheses:
-                    Token lp = lexer.next;
+                    Token lp = next;
                     SmallArray!(Exp, 8) args;
-                    while(lexer.peek.type != Tok.CloseParentheses)
+                    while(peek.type != Tok.CloseParentheses)
                     {
-                        if(lexer.peek.type == Tok.Comma)
-                            lexer.next;
+                        if(peek.type == Tok.Comma)
+                            next;
                         args ~= parseExpression();
                     }
 
-                    Token rp = lexer.next();
+                    Token rp = next();
                     return action.actOnCallExpr(iden, lp, args.unsafe(), rp);
 
                 default:
                     return iden;
             }
         }
-        else if (next.type == Tok.Cast)
-            return parseCast(next);
-        else if (next.type == Tok.Integer)
-            return action.actOnNumericConstant(next);
-        else if (next.type == Tok.String)
-            return action.actOnStringExp(next);
+        else if (n.type == Tok.Cast)
+            return parseCast(n);
+        else if (n.type == Tok.Integer)
+            return action.actOnNumericConstant(n);
+        else if (n.type == Tok.String)
+            return action.actOnStringExp(n);
 
-        messages.report(ExpectedExp, next.location)
+        messages.report(ExpectedExp, n.location)
             .fatal(ExitLevel.Parser);
         return null;
     }
@@ -889,13 +963,13 @@
     Exp parseCast(ref Token _cast)
     {
         require(Tok.OpenParentheses);
-        auto next = lexer.next;
-        if(!next.isBasicType && !next.isIdentifier)
-            messages.report(ExpectedCastType, next.location);
+        auto n = next;
+        if(!n.isBasicType && !n.isIdentifier)
+            messages.report(ExpectedCastType, n.location);
         
         require(Tok.CloseParentheses);
         auto exp = P();
-        return action.actOnCastExpr(_cast, Id(next), exp);
+        return action.actOnCastExpr(_cast, Id(n), exp);
     }
 
     struct UnOp
@@ -980,27 +1054,37 @@
 
     Token require(Tok t)
     {
-        if (lexer.peek().type != t)
-            messages.report(UnexpectedTokSingle, lexer.peek.location)
-                .arg(lexer.peek.getType)
+        if (peek().type != t)
+            messages.report(UnexpectedTokSingle, peek.location)
+                .arg(peek.getType)
                 .arg(t);
-        return lexer.next();
+        return next();
     }
 
     bool skip(Tok t)
     {
-        if (lexer.peek().type != t)
+        if (peek().type != t)
             return false;
-        lexer.next();
+        next();
         return true;
     }
 
-    bool on_a(Tok t)
+    bool isa(Tok t)
     {
-        return lexer.peek.type == t;
+        return peek.type == t;
     }
 
-    Lexer lexer;
+    Token next()
+    {
+        return lexer.next;
+    }
+
+    Token peek(int i = 0)
+    {
+        return lexer.peek(i);
+    }
+
+    Lexer lexer;   
     SourceManager sm;
 }
 
--- a/sema/AstAction.d	Mon Jul 21 01:05:20 2008 +0200
+++ b/sema/AstAction.d	Mon Jul 21 17:41:40 2008 +0200
@@ -41,24 +41,25 @@
     {
         return new Identifier(t.location, sm.getText(t.asRange));
     }
-
-    override ModuleT actOnModule(ref Token _module, char[] name)
+override
+{
+    ModuleT actOnModule(ref Token _module, char[] name)
     {
         return new Module(name);
     }
 
-    override ModuleT actOnImplicitModule(SLoc startLoc, char[] name)
+    ModuleT actOnImplicitModule(SLoc startLoc, char[] name)
     {
         return new Module(name);
     }
 
-    override void actOnModuleDecl(ModuleT m, DeclT d)
+    void actOnModuleDecl(ModuleT m, DeclT d)
     {
         (cast(Module)m).addDecl(cast(Decl)d);
     }
 
     // -- Declarations --
-    override DeclT actOnImport(ref Token _, ref ModuleName target, Id* name)
+    DeclT actOnImport(ref Token _, ref ModuleName target, Id* name)
     {
         auto res = new ImportDecl;
         Identifier[] packages = new Identifier[target.packages.length];
@@ -72,7 +73,7 @@
         return res;
     }
 
-    override void addSelectiveImport(DeclT _import, ref Id target, Id* name)
+    void addSelectiveImport(DeclT _import, ref Id target, Id* name)
     {
         auto d = cast(ImportDecl)_import;
         Identifier t = identifierFromTok(target.tok);
@@ -82,12 +83,16 @@
         d.explicitSymbols ~= [t, n];
     }
 
-    override DeclT actOnDeclarator(ref Id type, ref Id id, ExprT init, Attribute att)
+    DeclT actOnDeclarator(ref Id type, ref Id id, ExprT init, Attribute att)
     {
         Decl d;
         Exp exp = cast(Exp)init;
-        if(type.tok.type == Tok.Struct)
+        if (type.tok.type == Tok.Struct)
             d = new StructDecl(identifierFromTok(id.tok));
+        else if (type.tok.type == Tok.Class)
+            d = new ClassDecl(identifierFromTok(id.tok));
+        else if (type.tok.type == Tok.Interface)
+            d = new InterfaceDecl(identifierFromTok(id.tok));
         else
             d = new VarDecl(handleType(type), identifierFromTok(id.tok), exp);
 
@@ -95,27 +100,51 @@
         return d;
     }
     
-    override void actOnStructMember(DeclT st_decl, DeclT m_decl) //ref Id type, ref Id name, ExprT init)
+    void actOnStructMember(DeclT st_decl, DeclT m_decl) //ref Id type, ref Id name, ExprT init)
     {
         StructDecl st = cast(StructDecl)st_decl;
         st.addMember(cast(Decl)m_decl);
     }
 
-    override ExprT actOnMemberReference(ExprT lhs, SLoc op, Id member)
+    void actOnClassMember(DeclT cl_decl, DeclT m_decl) 
+    {
+        ClassDecl cl = cast(ClassDecl)cl_decl;
+        cl.addMember(cast(Decl)m_decl);
+    }
+
+    void actOnClassBaseClass(DeclT cl_decl, ref Id name)
+    {
+        ClassDecl cl = cast(ClassDecl)cl_decl;
+        cl.addBaseClass(identifierFromTok(name.tok));
+    }
+
+    void actOnInterfaceMember(DeclT if_decl, DeclT m_decl)
+    {
+        InterfaceDecl inf = cast(InterfaceDecl)if_decl;
+        inf.addMember(cast(Decl)m_decl);
+    }
+
+    void actOnInterfaceBaseClass(DeclT if_decl, ref Id name)
+    {
+        InterfaceDecl inf = cast(InterfaceDecl)if_decl;
+        inf.addBaseClass(identifierFromTok(name.tok));
+    }
+
+    ExprT actOnMemberReference(ExprT lhs, SLoc op, Id member)
     {
         Exp exp = cast(Exp)lhs;
         Identifier id = identifierFromTok(member.tok);
         return new MemberReference(op, exp, id);
     }
 
-    override DeclT actOnStartOfFunctionDef(ref Id type, ref Id name, Attribute att)
+    DeclT actOnStartOfFunctionDef(ref Id type, ref Id name, Attribute att)
     {
         auto res = new FuncDecl(identifierFromTok(type.tok), identifierFromTok(name.tok));
         res.att = att;
         return res;
     }
 
-    override void addFuncArg(DeclT func, Id type, Id name)
+    void addFuncArg(DeclT func, Id type, Id name)
     {
         FuncDecl fd = cast(FuncDecl)func;
         if(name)
@@ -124,7 +153,7 @@
             fd.addParam(identifierFromTok(type.tok));
     }
 
-    override DeclT actOnEndOfFunction(DeclT func, StmtT stmts)
+    DeclT actOnEndOfFunction(DeclT func, StmtT stmts)
     {
         FuncDecl fd = cast(FuncDecl)func;
         fd.setBody(cast(CompoundStatement)stmts);
@@ -132,18 +161,18 @@
     }
 
     // -- Statements --
-    override StmtT actOnCompoundStmt(ref Token l, ref Token r, StmtT[] stmts)
+    StmtT actOnCompoundStmt(ref Token l, ref Token r, StmtT[] stmts)
     {
         Stmt[] statements = cast(Stmt[])stmts;
         return new CompoundStatement(statements.dup);
     }
 
-    override StmtT actOnExprStmt(ExprT exp)
+    StmtT actOnExprStmt(ExprT exp)
     {
         return new ExpStmt(cast(Exp)exp);
     }
 
-    override StmtT actOnReturnStmt(ref Token loc, ExprT exp)
+    StmtT actOnReturnStmt(ref Token loc, ExprT exp)
     {
         Exp e = cast(Exp)exp;
         auto res = new ReturnStmt;
@@ -151,7 +180,7 @@
         return res;
     }
 
-    override StmtT actOnIfStmt(ref Token ifTok, ExprT cond, StmtT thenBody,
+    StmtT actOnIfStmt(ref Token ifTok, ExprT cond, StmtT thenBody,
                                ref Token elseTok, StmtT elseBody)
     {
         Exp c = cast(Exp)cond;
@@ -160,53 +189,53 @@
         return new IfStmt(c, t, e);
     }
 
-    override StmtT actOnWhileStmt(ref Token tok, ExprT cond, StmtT whileBody)
+    StmtT actOnWhileStmt(ref Token tok, ExprT cond, StmtT whileBody)
     {
         Exp c = cast(Exp)cond;
         Stmt b = cast(Stmt)whileBody;
         return new WhileStmt(c, b);
     }
 
-    override StmtT actOnDeclStmt(DeclT decl)
+    StmtT actOnDeclStmt(DeclT decl)
     {
         Decl d = cast(Decl)decl;
         return new DeclStmt(d);
     }
 
-    override StmtT actOnStartOfSwitchStmt(ExprT exp)
+    StmtT actOnStartOfSwitchStmt(ExprT exp)
     {
         return new SwitchStmt(cast(Exp)exp);
     }
 
-    override void actOnCaseStmt(StmtT stmt, ExprT[] exps, StmtT[] stmts)
+    void actOnCaseStmt(StmtT stmt, ExprT[] exps, StmtT[] stmts)
     {
         auto sw = cast(SwitchStmt)stmt;
         sw.addCase(cast(Exp[])exps, cast(Stmt[])stmts);
     }
 
-    override void actOnDefaultStmt(StmtT stmt, StmtT[] stmts)
+    void actOnDefaultStmt(StmtT stmt, StmtT[] stmts)
     {
         auto sw = cast(SwitchStmt)stmt;
         sw.setDefault(cast(Stmt[])stmts);
     }
 
     // -- Expressions --
-    override ExprT actOnNumericConstant(Token c)
+    ExprT actOnNumericConstant(Token c)
     {
         return new IntegerLit(c.location, sm.getText(c.asRange));
     }
 
-    override ExprT actOnStringExp(Token s)
+    ExprT actOnStringExp(Token s)
     {
         return new StringExp(s.location, sm.getText(s.asRange));
     }
 
-    override ExprT actOnIdentifierExp(Id id)
+    ExprT actOnIdentifierExp(Id id)
     {
         return identifierFromTok(id.tok);
     }
 
-    override ExprT actOnBinaryOp(SLoc op_loc, Operator op, ExprT l, ExprT r)
+    ExprT actOnBinaryOp(SLoc op_loc, Operator op, ExprT l, ExprT r)
     {
         Exp left = cast(Exp)l;
         Exp right = cast(Exp)r;
@@ -225,7 +254,7 @@
         }
     }
 
-    override ExprT actOnUnaryOp(Token op, ExprT operand)
+    ExprT actOnUnaryOp(Token op, ExprT operand)
     {
         Exp target = cast(Exp)operand;
         if (op.type == Tok.Minus)
@@ -235,21 +264,21 @@
         assert(0, "Only valid unary expressions are -x and *x");
     }
 
-    override ExprT actOnCallExpr(ExprT fn, ref Token, ExprT[] args, ref Token)
+    ExprT actOnCallExpr(ExprT fn, ref Token, ExprT[] args, ref Token)
     {
         Exp f = cast(Exp)fn;
         Exp[] arguments = cast(Exp[])args.dup;
         return new CallExp(f, arguments);
     }
 
-    override ExprT actOnCastExpr(ref Token _cast, Id id, ExprT exp)
+    ExprT actOnCastExpr(ref Token _cast, Id id, ExprT exp)
     {
         Exp target = cast(Exp)exp;
         Identifier target_type = identifierFromTok(id.tok);
         return new CastExp(_cast.location, target_type, target);
     }
 
-    override ExprT
+    ExprT
         actOnIndexEpr(ExprT arr, ref Token lb, ExprT index, ref Token rb)
     {
         Exp target = cast(Exp)arr;
@@ -257,4 +286,5 @@
         return new IndexExp(target, lb.location, idx, rb.location);
     }
 }
+}
 
--- a/sema/DType.d	Mon Jul 21 01:05:20 2008 +0200
+++ b/sema/DType.d	Mon Jul 21 17:41:40 2008 +0200
@@ -31,6 +31,16 @@
     /// Return a DStruct if this is one, otherwise return null
     DStruct asStruct() { return null; }
 
+    /// Is this type a DClass
+    bool isClass() { return false; }
+    /// Return a DClass if this is one, otherwise return null
+    DClass asClass() { return null; }
+
+    /// Is this type a DInterface
+    bool isInterface() { return false; }
+    /// Return a DInterface if this is one, otherwise return null
+    DInterface asInterface() { return null; }
+
     /// Is this type a DStaticArray
     bool isStaticArray() { return false; }
     /// Return a DStaticArray if this is one, otherwise return null
@@ -349,6 +359,116 @@
     }
 }
 
+class DClass : DType
+{
+    this(Identifier id, DType actual = null)
+    {
+        super(id, actual);
+    }
+
+    int byteSize() { return bytes_total; }
+
+    override bool isClass() { return true; }
+    override DClass asClass() { return this; }
+
+    void addMember(DType type, char[] name)
+    {
+        auto s = DClassMember(type, members.length);
+        members[name] = s;
+
+        bytes_total += type.byteSize();
+    }
+
+    int indexOf(char[] name)
+    {
+        if(name in members)
+            return members[name].index;
+
+        return -1;
+    }
+
+    DType typeOf(char[] name)
+    {
+        if (auto res = name in members)
+            return res.type;
+        return null;
+    }
+
+    DClassMember[char[]] members;
+    private int bytes_total;
+
+    override char[] mangle()
+    {
+        return "S"~Integer.toString(name.length)~name;
+    }
+
+    struct DClassMember
+    {
+        DType type;
+        int index;
+
+        char[] toString()
+        {
+            return type.toString();
+        }
+    }
+}
+
+class DInterface : DType
+{
+    this(Identifier id, DType actual = null)
+    {
+        super(id, actual);
+    }
+
+    int byteSize() { return bytes_total; }
+
+    override bool isInterface() { return true; }
+    override DInterface asInterface() { return this; }
+
+    void addMember(DType type, char[] name)
+    {
+        auto s = DInterfaceMember(type, members.length);
+        members[name] = s;
+
+        bytes_total += type.byteSize();
+    }
+
+    int indexOf(char[] name)
+    {
+        if(name in members)
+            return members[name].index;
+
+        return -1;
+    }
+
+    DType typeOf(char[] name)
+    {
+        if (auto res = name in members)
+            return res.type;
+        return null;
+    }
+
+    DInterfaceMember[char[]] members;
+    private int bytes_total;
+
+    override char[] mangle()
+    {
+        return "S"~Integer.toString(name.length)~name;
+    }
+
+    struct DInterfaceMember
+    {
+        DType type;
+        int index;
+
+        char[] toString()
+        {
+            return type.toString();
+        }
+    }
+}
+
 class DStaticArray : DType
 {
     this(DType arrayOf, int size, DType actual = null)
--- a/sema/ScopeBuilder.d	Mon Jul 21 01:05:20 2008 +0200
+++ b/sema/ScopeBuilder.d	Mon Jul 21 17:41:40 2008 +0200
@@ -72,6 +72,26 @@
         current.symbol = old;
     }
 
+    override void visitClassDecl(ClassDecl s)
+    {
+        auto old = current.symbol;
+        current.symbol = s.sym;
+        inFunctionBodyStack.push(false);
+        super.visitClassDecl(s);
+        inFunctionBodyStack.pop();
+        current.symbol = old;
+    }
+
+    override void visitInterfaceDecl(InterfaceDecl s)
+    {
+        auto old = current.symbol;
+        current.symbol = s.sym;
+        inFunctionBodyStack.push(false);
+        super.visitInterfaceDecl(s);
+        inFunctionBodyStack.pop();
+        current.symbol = old;
+    }
+
     DType typeOf(Identifier id, Scope sc)
     {
         if(auto i = cast(PointerIdentifier)id)
@@ -124,6 +144,59 @@
         }
     }
 
+    override void visitClassDecl(ClassDecl s)
+    {
+        auto st = s.env.findType(s.identifier).asClass;
+        s.sym = current.symbol.createMember(
+                s.identifier.get, 
+                st,
+                s.env.find(s.identifier));
+
+        foreach (decl; s.decls)
+        {
+            DType type;
+            char[] name;
+            if (auto varDecl = cast(VarDecl)decl)
+            {
+                type = typeOf(varDecl.varType, varDecl.env);
+                name = varDecl.identifier.get;
+            }
+            else if (auto fd = cast(FuncDecl)decl)
+            {
+                type = fd.type;
+                name = fd.identifier.get;
+            }
+            st.addMember(type, name);
+        }
+    }
+
+    override void visitInterfaceDecl(InterfaceDecl s)
+    {
+        auto st = s.env.findType(s.identifier).asInterface;
+        s.sym = current.symbol.createMember(
+                s.identifier.get, 
+                st,
+                s.env.find(s.identifier));
+
+        foreach (decl; s.decls)
+        {
+            DType type;
+            char[] name;
+            if (auto varDecl = cast(VarDecl)decl)
+            {
+                type = typeOf(varDecl.varType, varDecl.env);
+                name = varDecl.identifier.get;
+            }
+            else if (auto fd = cast(FuncDecl)decl)
+            {
+                type = fd.type;
+                name = fd.identifier.get;
+            }
+            st.addMember(type, name);
+        }
+    }
+
+
     DType typeOf(Identifier id, Scope sc)
     {
         if(auto i = cast(PointerIdentifier)id)
@@ -282,11 +355,38 @@
         sc.types[s.identifier.get] = type;
 
         sc = push();
-        Stdout(sc).newline;
         super.visitStructDecl(s);
         pop(sc);
     }
 
+    override void visitClassDecl(ClassDecl s)
+    {
+        auto sc = current();
+        sc.put(s.identifier, s);
+        s.env = sc;
+        auto type = new DClass(s.identifier);
+
+        sc.types[s.identifier.get] = type;
+
+        sc = push();
+        super.visitClassDecl(s);
+        pop(sc);
+    }
+
+    override void visitInterfaceDecl(InterfaceDecl s)
+    {
+        auto sc = current();
+        sc.put(s.identifier, s);
+        s.env = sc;
+        auto type = new DInterface(s.identifier);
+
+        sc.types[s.identifier.get] = type;
+
+        sc = push();
+        super.visitInterfaceDecl(s);
+        pop(sc);
+    }
+
     override void visitDeclStmt(DeclStmt d)
     {
         ++need_push;
--- a/sema/Visitor.d	Mon Jul 21 01:05:20 2008 +0200
+++ b/sema/Visitor.d	Mon Jul 21 17:41:40 2008 +0200
@@ -45,6 +45,10 @@
                 return visitImportDecl(cast(ImportDecl)decl);
             case DeclType.StructDecl:
                 return visitStructDecl(cast(StructDecl)decl);
+            case DeclType.ClassDecl:
+                return visitClassDecl(cast(ClassDecl)decl);
+            case DeclType.InterfaceDecl:
+                return visitInterfaceDecl(cast(InterfaceDecl)decl);
             default:
                 throw new Exception("Unknown declaration type");
         }
@@ -169,6 +173,38 @@
             return DeclT.init;
     }
 
+    DeclT visitClassDecl(ClassDecl s)
+    {
+        visitExp(s.identifier);
+
+        foreach (arg; s.decls)
+            visitDecl(arg);
+
+        foreach (arg; s.baseClasses)
+            visitExp(arg);
+
+        static if (is(DeclT == void))
+            return;
+        else
+            return DeclT.init;
+    }
+
+    DeclT visitInterfaceDecl(InterfaceDecl s)
+    {
+        visitExp(s.identifier);
+
+        foreach (arg; s.decls)
+            visitDecl(arg);
+
+        foreach (arg; s.baseClasses)
+            visitExp(arg);
+
+        static if (is(DeclT == void))
+            return;
+        else
+            return DeclT.init;
+    }
+
     // Statements:
     StmtT visitReturnStmt(ReturnStmt s)
     {
--- a/tests/parser/public_1.d	Mon Jul 21 01:05:20 2008 +0200
+++ b/tests/parser/public_1.d	Mon Jul 21 17:41:40 2008 +0200
@@ -1,16 +1,30 @@
+module tests.parser.public_1;
+
 public struct name
 {
 static:
     public void foo()
     {
     }
-
+public
+{
     private void bar()
     {
     }
+auto:
     final int i;
 }
 
+static:
+    public void food()
+    {
+    }
+    private void bard()
+    {
+    }
+    final int id;
+}
+
 void main()
 {
 }
--- a/tools/AstPrinter.d	Mon Jul 21 01:05:20 2008 +0200
+++ b/tools/AstPrinter.d	Mon Jul 21 17:41:40 2008 +0200
@@ -7,7 +7,8 @@
        ast.Stmt,
        ast.Exp;
 
-import basic.SourceManager;
+import basic.SourceManager,
+       basic.Attribute;
 
 class AstPrinter
 {
@@ -22,7 +23,8 @@
     void print(Module m)
     {
         printBeginLine("module ");
-        printEndLine(m.moduleName);
+        print(m.moduleName);
+        printEndLine(";");
         printEndLine();
         foreach(decl ; m.decls)
         {
@@ -38,6 +40,7 @@
             case DeclType.FuncDecl:
                 auto funcDecl = cast(FuncDecl)decl;
                 printBeginLine();
+                printAttribute(decl.att);
                 printIdentifier(funcDecl.returnType);
                 space;
                 printIdentifier(funcDecl.identifier);
@@ -51,6 +54,7 @@
             case DeclType.VarDecl:
                 auto varDecl = cast(VarDecl)decl;
                 printBeginLine();
+                printAttribute(decl.att);
                 printExp(varDecl.varType);
                 space;
                 printExp(varDecl.identifier);
@@ -64,6 +68,7 @@
 
             case DeclType.StructDecl:
                 auto structDecl = cast(StructDecl)decl;
+                printAttribute(decl.att);
                 printBeginLine("struct ");
                 printIdentifier(structDecl.identifier);
                 printEndLine;
@@ -73,13 +78,48 @@
                 printCloseBrace;
                 break;
 
+            case DeclType.ClassDecl:
+                auto classDecl = cast(ClassDecl)decl;
+                printAttribute(decl.att);
+                printBeginLine("class ");
+                printIdentifier(classDecl.identifier);
+                foreach(i, iden ; classDecl.baseClasses )
+                {
+                    print(i ? " : " : ", ");
+                    printIdentifier(iden);
+                }
+                printEndLine;
+                printOpenBrace;
+                foreach( var ; classDecl.decls)
+                    printDecl(var);
+                printCloseBrace;
+                break;
+
+            case DeclType.InterfaceDecl:
+                auto interfaceDecl = cast(InterfaceDecl)decl;
+                printAttribute(decl.att);
+                printBeginLine("interface ");
+                printIdentifier(interfaceDecl.identifier);
+                foreach(i, iden ; interfaceDecl.baseClasses )
+                {
+                    print(i ? " : " : ", ");
+                    printIdentifier(iden);
+                }
+                printEndLine;
+                printOpenBrace;
+                foreach( var ; interfaceDecl.decls)
+                    printDecl(var);
+                printCloseBrace;
+                break;
+
             case DeclType.ImportDecl:
                 auto i = cast(ImportDecl)decl;
+                printAttribute(decl.att);
                 printBeginLine("import ");
                 printEndLine(i.get);
                 break;
         }
-        printEndLine();
+//        printEndLine();
     }
 
     void printStatement(Stmt stmt)
@@ -218,6 +258,53 @@
         printEndLine(tabIndex~"}");
     }
 
+    void printAttribute(Attribute a)
+    {
+        switch(a.getExtern)
+        {
+            case Extern.C:
+                print("extern(C) ");
+                break;
+            case Extern.CPlusPlus:
+                print("extern(C++) ");
+                break;
+            case Extern.D:
+                break;
+        }
+        switch(a.getProtection)
+        {
+            case Protection.Public:
+                print("public ");
+                break;
+            case Protection.Private:
+                print("private ");
+                break;
+            case Protection.Package:
+                print("package ");
+                break;
+            case Protection.Protected:
+                print("protected ");
+                break;
+            case Protection.Export:
+                print("export ");
+                break;
+        }
+        if ( a.getStatic )
+            print("static ");
+        if ( a.getFinal )
+            print("final ");
+        if ( a.getConst )
+            print("const ");
+        if ( a.getAbstract )
+            print("abstract ");
+        if ( a.getOverride )
+            print("override ");
+        if ( a.getDepracted )
+            print("depracted ");
+        if ( a.getAuto )
+            print("auto ");
+    }
+
     void printBeginLine(char[] line = "")
     {
         Stdout(tabIndex~line);