Mercurial > projects > dang
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; }