diff ast/Stmt.d @ 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 d76cc5cad4fc
children ee202c72cd30
line wrap: on
line diff
--- 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;
 }