changeset 150:6c5a3c0bb4fb

Make switch work again Also added locations to statements (only filled out for switch) Added a verification pass Removed some comments
author Anders Halager <halager@gmail.com>
date Mon, 21 Jul 2008 20:35:03 +0200
parents 060b6eb16db9
children aeeef0dea14e
files ast/Decl.d ast/Module.d ast/Stmt.d basic/Message.d basic/Messages.d dang/compiler.d parser/Action.d parser/Parser.d sema/AstAction.d sema/Scope.d sema/VC.d tests/code/switch_6.d
diffstat 12 files changed, 143 insertions(+), 89 deletions(-) [+]
line wrap: on
line diff
--- a/ast/Decl.d	Mon Jul 21 19:17:56 2008 +0200
+++ b/ast/Decl.d	Mon Jul 21 20:35:03 2008 +0200
@@ -10,6 +10,7 @@
 import sema.Scope,
        sema.Symbol,
        sema.DType,
+       sema.VC,
        basic.SmallArray,
        basic.Attribute;
 
@@ -35,6 +36,10 @@
     {
     }
 
+    void verify(VC vc)
+    {
+    }
+
     DType type()
     {
         if (sym !is null)
@@ -80,10 +85,6 @@
         this.init = e;
     }
 
-    void simplify()
-    {
-    }
-
     override DType type()
     {
         return env.findType(varType.get);
@@ -171,6 +172,12 @@
             stmt.simplify();
     }
 
+    override void verify(VC vc)
+    {
+        foreach (stmt; statements)
+            stmt.verify(vc);
+    }
+
     override DFunction type()
     {
         if (myType !is null)
@@ -212,6 +219,12 @@
     {
     }
 
+    override void verify(VC vc)
+    {
+        foreach (decl; decls)
+            decl.verify(vc);
+    }
+
     override DType type()
     {
         return env.findType(identifier.get);
--- a/ast/Module.d	Mon Jul 21 19:17:56 2008 +0200
+++ b/ast/Module.d	Mon Jul 21 20:35:03 2008 +0200
@@ -1,6 +1,7 @@
 module ast.Module;
 
 import sema.Scope,
+       sema.VC,
        sema.Symbol;
 
 import ast.Decl;
@@ -37,6 +38,12 @@
         decls ~= decl;
     }
 
+    void verify(VC vc)
+    {
+        foreach (decl; decls)
+            decl.verify(vc);
+    }
+
     VarDecl[]       vars;
     FuncDecl[]      functions;
     StructDecl[]    structs;
--- a/ast/Stmt.d	Mon Jul 21 19:17:56 2008 +0200
+++ b/ast/Stmt.d	Mon Jul 21 20:35:03 2008 +0200
@@ -8,6 +8,8 @@
        ast.Decl;
 
 import sema.Scope,
+       sema.VC,
+       basic.Message,
        basic.SourceLocation;
 
 enum StmtType
@@ -22,7 +24,7 @@
     Switch,
 }
 
-class Stmt
+abstract class Stmt
 {
     this(StmtType stmtType = StmtType.Stmt)
     {
@@ -33,6 +35,17 @@
     {
     }
 
+    void verify(VC vc) {}
+
+    /// The "main" location of the expression.
+    SourceLocation loc;
+
+    /// Return the starting location of this statement
+    SourceLocation startLoc() { return loc; }
+
+    /// Get the full extents of the expression
+    SourceRange sourceRange() { return SourceRange(loc, loc + 1); }
+
     StmtType stmtType;
     Scope env;
     int stmtIndex;
@@ -169,60 +182,25 @@
 
 class SwitchStmt : Stmt
 {
-    this(Exp target)
+    this(SourceLocation loc, Exp target)
     {
         super(StmtType.Switch);
         cond = target;
+        this.loc = loc;
+    }
+
+    void addCase(SourceLocation _case, Exp[] values, Stmt[] stmts)
+    {
+        cases ~= Case(_case, values, stmts);
     }
 
-    void addCase(Exp[] values, Stmt[] stmts)
+    void setDefault(SourceLocation _default, Stmt[] stmts)
     {
-//        long[] new_values;
-//        foreach (lit; values)
-//            new_values ~= Integer.parse(lit.get);
-//        cases ~= Case(values, stmts, new_values);
-        cases ~= Case(values, stmts);
-
-        // Make sure there is no two cases with the same value
-        // Does it belong here?
-/+        new_values = new_values.dup;
-        Array.sort(new_values);
-        long[] all_values = Array.unionOf(old_values, new_values);
-        if (all_values.length != old_values.length + new_values.length)
-        {
-            // overlap!
-            // TODO: Move this to another sema file where it can be enforced.
-         /+   auto e = new Error(
-                    "Can't have multiple cases with the same value."
-                    " Values appearing in multiple cases: %0");
-                    
-            //e.loc(values[0].token.location);
+        if (defaultBlock !is null)
+            extraDefaultBlocks = true;
 
-            all_values = Array.intersectionOf(old_values, new_values);
-            char[][] vals;
-            foreach (val; all_values)
-                vals ~= Integer.toString(val);
-            e.arg(vals);
-            /*
-            foreach (c; cases)
-                foreach (i, v; c.values_converted)
-                    if (Array.bsearch(all_values, v))
-                        e.tok(c.values[i].token);
-            */
-            throw e;+/
-        }
-        old_values = all_values;
-        +/
-    }
-
-    void setDefault(Stmt[] stmts)
-    {
-        // TODO: Move this to another sema file where it can be enforced.
-        /*
-        if (defaultBlock.length != 0)
-            throw new Error("Switch statements can't have multiple defaults");
-            */
         defaultBlock = stmts;
+        defaultLoc = _default;
         if (cases.length > 0)
             cases[$ - 1].followedByDefault = true;
     }
@@ -237,18 +215,55 @@
                 stmt.simplify();
     }
 
+    override void verify(VC vc)
+    {
+        if (extraDefaultBlocks)
+            vc.msg.report(MultipleDefaults, defaultLoc);
+
+        if (cases.length == 0)
+            return;
+
+        scope long[] all_values;
+        foreach (ref Case; cases)
+        {
+            long[] new_values;
+            foreach (exp; Case.values)
+                if (auto lit = cast(IntegerLit)exp)
+                    new_values ~= Integer.parse(lit.get);
+                else
+                    // We flag all non-literals and ignore them
+                    vc.msg.report(InvalidCaseValue, exp.loc);
+            Case.values_converted = new_values;
+            all_values ~= new_values;
+        }
+
+        Array.sort(all_values);
+        char[][] overlapping;
+        size_t i = 0;
+        while ((i = Array.findAdj(all_values)) < all_values.length
+                && all_values.length > 0)
+        {
+            overlapping ~= Integer.toString(all_values[i]);
+            auto similar = Array.count(all_values, all_values[i]);
+            all_values = all_values[i + similar .. $];
+        }
+        if (overlapping.length > 0)
+            vc.msg.report(OverlappingCases, loc).arg(overlapping);
+    }
+
     Exp cond;
     Case[] cases;
     Stmt[] defaultBlock;
+    private bool extraDefaultBlocks = false;
+    private SourceLocation defaultLoc;
 
     struct Case
     {
+        SourceLocation caseLoc;
         Exp[] values;
         Stmt[] stmts;
         long[] values_converted;
         bool followedByDefault = false;
     }
-
-    private long[] old_values;
 }
 
--- a/basic/Message.d	Mon Jul 21 19:17:56 2008 +0200
+++ b/basic/Message.d	Mon Jul 21 20:35:03 2008 +0200
@@ -146,7 +146,7 @@
 
     Message arg(char[] s)
     {
-        if (args.length == 11)
+        if (args.length > 10)
             throw new Exception("Sorry, errors only support up to 10 args");
         args ~= s;
         return this;
--- a/basic/Messages.d	Mon Jul 21 19:17:56 2008 +0200
+++ b/basic/Messages.d	Mon Jul 21 20:35:03 2008 +0200
@@ -34,6 +34,10 @@
     UndefinedType,
     MissingMember,
     CannotRedeclare,
+    //   - switch
+    MultipleDefaults,
+    OverlappingCases,
+    InvalidCaseValue,
 
     // Strings
     InvalidStrPrefix,
@@ -103,6 +107,13 @@
         UndefinedType       : E(Err, "Undefined type '%0'"),
         MissingMember       : E(Err, "%0 %1 has no member %2"),
         CannotRedeclare     : E(Err, "Cannot redeclare '%0'"),
+        //   - switch
+        MultipleDefaults
+            : E(Err, "Switch statements can't have multiple defaults"),
+        OverlappingCases
+            : E(Err, "Can't have multiple cases with the same value."
+                     " Values appearing in multiple cases: %0"),
+        InvalidCaseValue    : E(Err, "Case values must be integers"),
 
         // literals
         InvalidStrPrefix    : E(Err, "Invalid string literal prefix"),
--- a/dang/compiler.d	Mon Jul 21 19:17:56 2008 +0200
+++ b/dang/compiler.d	Mon Jul 21 20:35:03 2008 +0200
@@ -28,6 +28,7 @@
        sema.ScopeBuilder,
        sema.LiteralInterpreter,
        sema.ScopeCheck,
+       sema.VC,
        sema.TypeCheck;
 
 import tango.stdc.posix.unistd;
@@ -185,7 +186,7 @@
                     gcc.stdin.copy(llc.stdout);
                     gcc.stdin.detach;
                     gcc.wait();
-                    timings ~= Measurement("Generating assemble bytecode", w.stop);
+                    timings ~= Measurement("Generating ASM", w.stop);
                 }
 
             });
@@ -310,13 +311,21 @@
     watch.start;
     watch2.start;
     (new ScopeCheck(messages)).visit(modules);
+    messages.checkErrors;
     auto scope_check = watch2.stop;
+
     watch2.start;
-    messages.checkErrors;
     (new TypeCheck(messages)).visit(modules);
+    messages.checkErrors;
     auto type_check = watch2.stop;
+
     watch2.start;
+    auto vc = new VC;
+    vc.msg = messages;
+    foreach (m; modules)
+        m.verify(vc);
     messages.checkErrors;
+    auto ast_verify = watch2.stop;
 
     foreach (m; modules)
         foreach (decl; m.decls)
--- a/parser/Action.d	Mon Jul 21 19:17:56 2008 +0200
+++ b/parser/Action.d	Mon Jul 21 20:35:03 2008 +0200
@@ -300,16 +300,16 @@
         return null;
     }
 
-    StmtT actOnStartOfSwitchStmt(ExprT exp)
+    StmtT actOnStartOfSwitchStmt(Token _switch, ExprT exp)
     {
         return null;
     }
 
-    void actOnCaseStmt(StmtT stmt, ExprT[] exps, StmtT[] stmts)
+    void actOnCaseStmt(StmtT stmt, Token _case, ExprT[] exps, StmtT[] stmts)
     {
     }
 
-    void actOnDefaultStmt(StmtT stmt, StmtT[] stmts)
+    void actOnDefaultStmt(StmtT stmt, Token _default, StmtT[] stmts)
     {
     }
 
--- a/parser/Parser.d	Mon Jul 21 19:17:56 2008 +0200
+++ b/parser/Parser.d	Mon Jul 21 20:35:03 2008 +0200
@@ -632,26 +632,27 @@
             require(Tok.Seperator);
             return action.actOnExprStmt(exp);
         }
-        else if(t.isSwitch)
+        else if (t.isSwitch)
         {
-            next;
+            next();
             require(Tok.OpenParentheses);
             auto target = parseExpression();
-            auto res = action.actOnStartOfSwitchStmt(target);
+            auto res = action.actOnStartOfSwitchStmt(t, target);
             require(Tok.CloseParentheses);
             require(Tok.OpenBrace);
             while (true)
             {
                 Stmt[] statements;
-                if (skip(Tok.Default))
+                if (isa(Tok.Default))
                 {
+                    Token _default = next();
                     require(Tok.Colon);
                     statements.length = 0;
                     while (peek.type != Tok.Case
                             && peek.type != Tok.Default
                             && peek.type != Tok.CloseBrace)
                         statements ~= parseStatement();
-                    action.actOnDefaultStmt(res, statements);
+                    action.actOnDefaultStmt(res, _default, statements);
                     continue;
                 }
 
@@ -664,10 +665,6 @@
                 do
                 {
                     Exp e = parseExpression();
-//                    IntegerLit lit = cast(IntegerLit)e;
-//                    if (lit is null)
-//                        messages.report(CaseValueMustBeInt, peek.location).arg(next.getType);
-//                    else
                     literals ~= e;
                 }
                 while (skip(Tok.Comma));
@@ -678,7 +675,7 @@
                         && peek.type != Tok.CloseBrace)
                     statements ~= parseStatement();
 
-                action.actOnCaseStmt(res, literals, statements);
+                action.actOnCaseStmt(res, _case, literals, statements);
 
                 if (peek.type == Tok.CloseBrace)
                     break;
--- a/sema/AstAction.d	Mon Jul 21 19:17:56 2008 +0200
+++ b/sema/AstAction.d	Mon Jul 21 20:35:03 2008 +0200
@@ -202,21 +202,21 @@
         return new DeclStmt(d);
     }
 
-    StmtT actOnStartOfSwitchStmt(ExprT exp)
+    StmtT actOnStartOfSwitchStmt(Token _switch, ExprT exp)
     {
-        return new SwitchStmt(cast(Exp)exp);
+        return new SwitchStmt(_switch.location, cast(Exp)exp);
     }
 
-    void actOnCaseStmt(StmtT stmt, ExprT[] exps, StmtT[] stmts)
+    void actOnCaseStmt(StmtT stmt, Token _case, ExprT[] exps, StmtT[] stmts)
     {
         auto sw = cast(SwitchStmt)stmt;
-        sw.addCase(cast(Exp[])exps, cast(Stmt[])stmts);
+        sw.addCase(_case.location, cast(Exp[])exps, cast(Stmt[])stmts);
     }
 
-    void actOnDefaultStmt(StmtT stmt, StmtT[] stmts)
+    void actOnDefaultStmt(StmtT stmt, Token _default, StmtT[] stmts)
     {
         auto sw = cast(SwitchStmt)stmt;
-        sw.setDefault(cast(Stmt[])stmts);
+        sw.setDefault(_default.location, cast(Stmt[])stmts);
     }
 
     // -- Expressions --
--- a/sema/Scope.d	Mon Jul 21 19:17:56 2008 +0200
+++ b/sema/Scope.d	Mon Jul 21 20:35:03 2008 +0200
@@ -70,20 +70,6 @@
         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.name ~ " : " ~ (sym.type is null? "?" : sym.type.name);
-        return res;
-    }
-    */
-
     FuncDecl parentFunction()
     {
         if (func !is null)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sema/VC.d	Mon Jul 21 20:35:03 2008 +0200
@@ -0,0 +1,14 @@
+module sema.VC;
+
+import basic.Message;
+
+/**
+    VC is short for verification context.
+
+    This class holds various things that are neccesary to verify validity
+    of the AST.
+**/
+class VC
+{
+    MessageHandler msg;
+}
--- a/tests/code/switch_6.d	Mon Jul 21 19:17:56 2008 +0200
+++ b/tests/code/switch_6.d	Mon Jul 21 20:35:03 2008 +0200
@@ -7,6 +7,8 @@
             return 0;
         case 2, 3:
             return 1;
+        case 1, 3:
+            return 1;
     }
 }