# HG changeset patch # User Anders Halager # Date 1216665303 -7200 # Node ID 6c5a3c0bb4fb70b4ba48a95b273ffdb781dc8cb3 # Parent 060b6eb16db9a975d5aa2afb3a66b4982f26bb3f Make switch work again Also added locations to statements (only filled out for switch) Added a verification pass Removed some comments diff -r 060b6eb16db9 -r 6c5a3c0bb4fb ast/Decl.d --- 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); diff -r 060b6eb16db9 -r 6c5a3c0bb4fb ast/Module.d --- 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; diff -r 060b6eb16db9 -r 6c5a3c0bb4fb ast/Stmt.d --- 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; } diff -r 060b6eb16db9 -r 6c5a3c0bb4fb basic/Message.d --- 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; diff -r 060b6eb16db9 -r 6c5a3c0bb4fb basic/Messages.d --- 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"), diff -r 060b6eb16db9 -r 6c5a3c0bb4fb dang/compiler.d --- 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) diff -r 060b6eb16db9 -r 6c5a3c0bb4fb parser/Action.d --- 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) { } diff -r 060b6eb16db9 -r 6c5a3c0bb4fb parser/Parser.d --- 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; diff -r 060b6eb16db9 -r 6c5a3c0bb4fb sema/AstAction.d --- 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 -- diff -r 060b6eb16db9 -r 6c5a3c0bb4fb sema/Scope.d --- 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) diff -r 060b6eb16db9 -r 6c5a3c0bb4fb sema/VC.d --- /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; +} diff -r 060b6eb16db9 -r 6c5a3c0bb4fb tests/code/switch_6.d --- 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; } }