public override void TraverseChildren(ISwitchStatement switchStatement) { var eTraverser = this.factory.MakeExpressionTraverser(this.sink, this, this.contractContext); eTraverser.Traverse(switchStatement.Expression); var conditionExpr = eTraverser.TranslatedExpressions.Pop(); // Can't depend on default case existing or its index in the collection. var switchCases = new List <ISwitchCase>(); ISwitchCase defaultCase = null; foreach (var switchCase in switchStatement.Cases) { if (switchCase.IsDefault) { defaultCase = switchCase; } else { switchCases.Add(switchCase); } } Bpl.StmtList defaultStmts = null; if (defaultCase != null) { var defaultBodyTraverser = this.factory.MakeStatementTraverser(this.sink, this.PdbReader, this.contractContext); defaultBodyTraverser.Traverse(defaultCase.Body); defaultStmts = defaultBodyTraverser.StmtBuilder.Collect(defaultCase.Token()); } Bpl.IfCmd ifCmd = null; for (int i = switchCases.Count - 1; 0 <= i; i--) { var switchCase = switchCases[i]; var scTraverser = this.factory.MakeExpressionTraverser(this.sink, this, this.contractContext); scTraverser.Traverse(switchCase.Expression); var scConditionExpr = scTraverser.TranslatedExpressions.Pop(); var condition = Bpl.Expr.Eq(conditionExpr, scConditionExpr); var scBodyTraverser = this.factory.MakeStatementTraverser(this.sink, this.PdbReader, this.contractContext); scBodyTraverser.Traverse(switchCase.Body); ifCmd = new Bpl.IfCmd(switchCase.Token(), condition, scBodyTraverser.StmtBuilder.Collect(switchCase.Token()), ifCmd, defaultStmts); defaultStmts = null; // default body goes only into the innermost if-then-else } StmtBuilder.Add(ifCmd); }
void StmtList(out StmtList/*!*/ stmtList) { Contract.Ensures(Contract.ValueAtReturn(out stmtList) != null); List<BigBlock/*!*/> bigblocks = new List<BigBlock/*!*/>(); /* built-up state for the current BigBlock: */ IToken startToken = null; string currentLabel = null; List<Cmd> cs = null; /* invariant: startToken != null ==> cs != null */ /* temporary variables: */ IToken label; Cmd c; BigBlock b; StructuredCmd ec = null; StructuredCmd/*!*/ ecn; TransferCmd tc = null; TransferCmd/*!*/ tcn; while (StartOf(7)) { if (StartOf(8)) { LabelOrCmd(out c, out label); if (c != null) { // LabelOrCmd read a Cmd Contract.Assert(label == null); if (startToken == null) { startToken = c.tok; cs = new List<Cmd>(); } Contract.Assert(cs != null); cs.Add(c); } else { // LabelOrCmd read a label Contract.Assert(label != null); if (startToken != null) { Contract.Assert(cs != null); // dump the built-up state into a BigBlock b = new BigBlock(startToken, currentLabel, cs, null, null); bigblocks.Add(b); cs = null; } startToken = label; currentLabel = label.val; cs = new List<Cmd>(); } } else if (la.kind == 41 || la.kind == 43 || la.kind == 46) { StructuredCmd(out ecn); ec = ecn; if (startToken == null) { startToken = ec.tok; cs = new List<Cmd>(); } Contract.Assert(cs != null); b = new BigBlock(startToken, currentLabel, cs, ec, null); bigblocks.Add(b); startToken = null; currentLabel = null; cs = null; } else { TransferCmd(out tcn); tc = tcn; if (startToken == null) { startToken = tc.tok; cs = new List<Cmd>(); } Contract.Assert(cs != null); b = new BigBlock(startToken, currentLabel, cs, null, tc); bigblocks.Add(b); startToken = null; currentLabel = null; cs = null; } } Expect(29); IToken/*!*/ endCurly = t; if (startToken == null && bigblocks.Count == 0) { startToken = t; cs = new List<Cmd>(); } if (startToken != null) { Contract.Assert(cs != null); b = new BigBlock(startToken, currentLabel, cs, null, null); bigblocks.Add(b); } stmtList = new StmtList(bigblocks, endCurly); }
void ImplBody(out List<Variable>/*!*/ locals, out StmtList/*!*/ stmtList) { Contract.Ensures(Contract.ValueAtReturn(out locals) != null); Contract.Ensures(Contract.ValueAtReturn(out stmtList) != null); locals = new List<Variable>(); Expect(28); while (la.kind == 8) { LocalVars(locals); } StmtList(out stmtList); }
private static Bpl.IfCmd BuildIfCmd(Bpl.Expr b, Bpl.Cmd cmd, Bpl.StmtList stmts) { Bpl.StmtListBuilder ifStmtBuilder = new Bpl.StmtListBuilder(); ifStmtBuilder.Add(cmd); return(new Bpl.IfCmd(b.tok, b, ifStmtBuilder.Collect(b.tok), null, stmts)); }
void NameAnonymousBlocks(StmtList stmtList) { Contract.Requires(stmtList != null); foreach (BigBlock b in stmtList.BigBlocks) { if (b.LabelName == null) { b.LabelName = prefix + anon; anon++; } if (b.ec is WhileCmd) { WhileCmd wcmd = (WhileCmd)b.ec; NameAnonymousBlocks(wcmd.Body); } else { for (IfCmd ifcmd = b.ec as IfCmd; ifcmd != null; ifcmd = ifcmd.elseIf) { NameAnonymousBlocks(ifcmd.thn); if (ifcmd.elseBlock != null) { NameAnonymousBlocks(ifcmd.elseBlock); } } } } }
void RecordSuccessors(StmtList stmtList, BigBlock successor) { Contract.Requires(stmtList != null); for (int i = stmtList.BigBlocks.Count; 0 <= --i; ) { BigBlock big = stmtList.BigBlocks[i]; big.successorBigBlock = successor; if (big.ec is WhileCmd) { WhileCmd wcmd = (WhileCmd)big.ec; RecordSuccessors(wcmd.Body, successor); } else { for (IfCmd ifcmd = big.ec as IfCmd; ifcmd != null; ifcmd = ifcmd.elseIf) { RecordSuccessors(ifcmd.thn, successor); if (ifcmd.elseBlock != null) { RecordSuccessors(ifcmd.elseBlock, successor); } } } successor = big; } }
private void ComputeAllLabels(StmtList stmts) { if (stmts == null) return; foreach (BigBlock bb in stmts.BigBlocks) { if (bb.LabelName != null) { allLabels.Add(bb.LabelName); } ComputeAllLabels(bb.ec); } }
// If the enclosing context is a loop, then "runOffTheEndLabel" is the loop head label; // otherwise, it is null. void CreateBlocks(StmtList stmtList, string runOffTheEndLabel) { Contract.Requires(stmtList != null); Contract.Requires(blocks != null); List<Cmd> cmdPrefixToApply = stmtList.PrefixCommands; int n = stmtList.BigBlocks.Count; foreach (BigBlock b in stmtList.BigBlocks) { n--; Contract.Assert(b.LabelName != null); List<Cmd> theSimpleCmds; if (cmdPrefixToApply == null) { theSimpleCmds = b.simpleCmds; } else { theSimpleCmds = new List<Cmd>(); theSimpleCmds.AddRange(cmdPrefixToApply); theSimpleCmds.AddRange(b.simpleCmds); cmdPrefixToApply = null; // now, we've used 'em up } if (b.tc != null) { // this BigBlock has the very same components as a Block Contract.Assert(b.ec == null); Block block = new Block(b.tok, b.LabelName, theSimpleCmds, b.tc); blocks.Add(block); } else if (b.ec == null) { TransferCmd trCmd; if (n == 0 && runOffTheEndLabel != null) { // goto the given label instead of the textual successor block trCmd = new GotoCmd(stmtList.EndCurly, new List<String> { runOffTheEndLabel }); } else { trCmd = GotoSuccessor(stmtList.EndCurly, b); } Block block = new Block(b.tok, b.LabelName, theSimpleCmds, trCmd); blocks.Add(block); } else if (b.ec is BreakCmd) { BreakCmd bcmd = (BreakCmd)b.ec; Contract.Assert(bcmd.BreakEnclosure != null); Block block = new Block(b.tok, b.LabelName, theSimpleCmds, GotoSuccessor(b.ec.tok, bcmd.BreakEnclosure)); blocks.Add(block); } else if (b.ec is WhileCmd) { WhileCmd wcmd = (WhileCmd)b.ec; string loopHeadLabel = prefix + anon + "_LoopHead"; string/*!*/ loopBodyLabel = prefix + anon + "_LoopBody"; string loopDoneLabel = prefix + anon + "_LoopDone"; anon++; List<Cmd> ssBody = new List<Cmd>(); List<Cmd> ssDone = new List<Cmd>(); if (wcmd.Guard != null) { var ac = new AssumeCmd(wcmd.tok, wcmd.Guard); ac.Attributes = new QKeyValue(wcmd.tok, "partition", new List<object>(), null); ssBody.Add(ac); ac = new AssumeCmd(wcmd.tok, Expr.Not(wcmd.Guard)); ac.Attributes = new QKeyValue(wcmd.tok, "partition", new List<object>(), null); ssDone.Add(ac); } // Try to squeeze in ssBody into the first block of wcmd.Body bool bodyGuardTakenCareOf = wcmd.Body.PrefixFirstBlock(ssBody, ref loopBodyLabel); // ... goto LoopHead; Block block = new Block(b.tok, b.LabelName, theSimpleCmds, new GotoCmd(wcmd.tok, new List<String> { loopHeadLabel })); blocks.Add(block); // LoopHead: assert/assume loop_invariant; goto LoopDone, LoopBody; List<Cmd> ssHead = new List<Cmd>(); foreach (PredicateCmd inv in wcmd.Invariants) { ssHead.Add(inv); } block = new Block(wcmd.tok, loopHeadLabel, ssHead, new GotoCmd(wcmd.tok, new List<String> { loopDoneLabel, loopBodyLabel })); blocks.Add(block); if (!bodyGuardTakenCareOf) { // LoopBody: assume guard; goto firstLoopBlock; block = new Block(wcmd.tok, loopBodyLabel, ssBody, new GotoCmd(wcmd.tok, new List<String> { wcmd.Body.BigBlocks[0].LabelName })); blocks.Add(block); } // recurse to create the blocks for the loop body CreateBlocks(wcmd.Body, loopHeadLabel); // LoopDone: assume !guard; goto loopSuccessor; TransferCmd trCmd; if (n == 0 && runOffTheEndLabel != null) { // goto the given label instead of the textual successor block trCmd = new GotoCmd(wcmd.tok, new List<String> { runOffTheEndLabel }); } else { trCmd = GotoSuccessor(wcmd.tok, b); } block = new Block(wcmd.tok, loopDoneLabel, ssDone, trCmd); blocks.Add(block); } else { IfCmd ifcmd = (IfCmd)b.ec; string predLabel = b.LabelName; List<Cmd> predCmds = theSimpleCmds; for (; ifcmd != null; ifcmd = ifcmd.elseIf) { string thenLabel = prefix + anon + "_Then"; Contract.Assert(thenLabel != null); string elseLabel = prefix + anon + "_Else"; Contract.Assert(elseLabel != null); anon++; List<Cmd> ssThen = new List<Cmd>(); List<Cmd> ssElse = new List<Cmd>(); if (ifcmd.Guard != null) { var ac = new AssumeCmd(ifcmd.tok, ifcmd.Guard); ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List<object>(), null); ssThen.Add(ac); ac = new AssumeCmd(ifcmd.tok, Expr.Not(ifcmd.Guard)); ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List<object>(), null); ssElse.Add(ac); } // Try to squeeze in ssThen/ssElse into the first block of ifcmd.thn/ifcmd.elseBlock bool thenGuardTakenCareOf = ifcmd.thn.PrefixFirstBlock(ssThen, ref thenLabel); bool elseGuardTakenCareOf = false; if (ifcmd.elseBlock != null) { elseGuardTakenCareOf = ifcmd.elseBlock.PrefixFirstBlock(ssElse, ref elseLabel); } // ... goto Then, Else; Block block = new Block(b.tok, predLabel, predCmds, new GotoCmd(ifcmd.tok, new List<String> { thenLabel, elseLabel })); blocks.Add(block); if (!thenGuardTakenCareOf) { // Then: assume guard; goto firstThenBlock; block = new Block(ifcmd.tok, thenLabel, ssThen, new GotoCmd(ifcmd.tok, new List<String> { ifcmd.thn.BigBlocks[0].LabelName })); blocks.Add(block); } // recurse to create the blocks for the then branch CreateBlocks(ifcmd.thn, n == 0 ? runOffTheEndLabel : null); if (ifcmd.elseBlock != null) { Contract.Assert(ifcmd.elseIf == null); if (!elseGuardTakenCareOf) { // Else: assume !guard; goto firstElseBlock; block = new Block(ifcmd.tok, elseLabel, ssElse, new GotoCmd(ifcmd.tok, new List<String> { ifcmd.elseBlock.BigBlocks[0].LabelName })); blocks.Add(block); } // recurse to create the blocks for the else branch CreateBlocks(ifcmd.elseBlock, n == 0 ? runOffTheEndLabel : null); } else if (ifcmd.elseIf != null) { // this is an "else if" predLabel = elseLabel; predCmds = new List<Cmd>(); if (ifcmd.Guard != null) { var ac = new AssumeCmd(ifcmd.tok, Expr.Not(ifcmd.Guard)); ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List<object>(), null); predCmds.Add(ac); } } else { // no else alternative is specified, so else branch is just "skip" // Else: assume !guard; goto ifSuccessor; TransferCmd trCmd; if (n == 0 && runOffTheEndLabel != null) { // goto the given label instead of the textual successor block trCmd = new GotoCmd(ifcmd.tok, new List<String> { runOffTheEndLabel }); } else { trCmd = GotoSuccessor(ifcmd.tok, b); } block = new Block(ifcmd.tok, elseLabel, ssElse, trCmd); blocks.Add(block); } } } } }
void CheckLegalLabels(StmtList stmtList, StmtList parentContext, BigBlock parentBigBlock) { Contract.Requires(stmtList != null); Contract.Requires((parentContext == null) == (parentBigBlock == null)); Contract.Requires(stmtList.ParentContext == null); // it hasn't been set yet //modifies stmtList.*; Contract.Ensures(stmtList.ParentContext == parentContext); stmtList.ParentContext = parentContext; stmtList.ParentBigBlock = parentBigBlock; // record the labels declared in this StmtList foreach (BigBlock b in stmtList.BigBlocks) { if (b.LabelName != null) { string n = b.LabelName; if (n.StartsWith(prefix)) { if (prefix.Length < n.Length && n[prefix.Length] == '0') { prefix += "1"; } else { prefix += "0"; } } stmtList.Labels.Add(b.LabelName); } } // check that labels in this and nested StmtList's are legal foreach (BigBlock b in stmtList.BigBlocks) { // goto's must reference blocks in enclosing blocks if (b.tc is GotoCmd) { GotoCmd g = (GotoCmd)b.tc; foreach (string/*!*/ lbl in cce.NonNull(g.labelNames)) { Contract.Assert(lbl != null); /* bool found = false; for (StmtList sl = stmtList; sl != null; sl = sl.ParentContext) { if (sl.Labels.Contains(lbl)) { found = true; break; } } if (!found) { this.errorHandler.SemErr(g.tok, "Error: goto label '" + lbl + "' is undefined or out of reach"); } */ if (!allLabels.Contains(lbl)) { this.errorHandler.SemErr(g.tok, "Error: goto label '" + lbl + "' is undefined"); } } } // break labels must refer to an enclosing while statement else if (b.ec is BreakCmd) { BreakCmd bcmd = (BreakCmd)b.ec; Contract.Assert(bcmd.BreakEnclosure == null); // it hasn't been initialized yet bool found = false; for (StmtList sl = stmtList; sl.ParentBigBlock != null; sl = sl.ParentContext) { cce.LoopInvariant(sl != null); BigBlock bb = sl.ParentBigBlock; if (bcmd.Label == null) { // a label-less break statement breaks out of the innermost enclosing while statement if (bb.ec is WhileCmd) { bcmd.BreakEnclosure = bb; found = true; break; } } else if (bcmd.Label == bb.LabelName) { // a break statement with a label can break out of both if statements and while statements if (bb.simpleCmds.Count == 0) { // this is a good target: the label refers to the if/while statement bcmd.BreakEnclosure = bb; } else { // the label of bb refers to the first statement of bb, which in which case is a simple statement, not an if/while statement this.errorHandler.SemErr(bcmd.tok, "Error: break label '" + bcmd.Label + "' must designate an enclosing statement"); } found = true; // don't look any further, since we've found a matching label break; } } if (!found) { if (bcmd.Label == null) { this.errorHandler.SemErr(bcmd.tok, "Error: break statement is not inside a loop"); } else { this.errorHandler.SemErr(bcmd.tok, "Error: break label '" + bcmd.Label + "' must designate an enclosing statement"); } } } // recurse else if (b.ec is WhileCmd) { WhileCmd wcmd = (WhileCmd)b.ec; CheckLegalLabels(wcmd.Body, stmtList, b); } else { for (IfCmd ifcmd = b.ec as IfCmd; ifcmd != null; ifcmd = ifcmd.elseIf) { CheckLegalLabels(ifcmd.thn, stmtList, b); if (ifcmd.elseBlock != null) { CheckLegalLabels(ifcmd.elseBlock, stmtList, b); } } } } }
public BigBlocksResolutionContext(StmtList stmtList, Errors errorHandler) { Contract.Requires(errorHandler != null); Contract.Requires(stmtList != null); this.stmtList = stmtList; this.errorHandler = errorHandler; ComputeAllLabels(stmtList); }
public WhileCmd(IToken tok, [Captured] Expr guard, List<PredicateCmd/*!*/>/*!*/ invariants, StmtList/*!*/ body) : base(tok) { Contract.Requires(cce.NonNullElements(invariants)); Contract.Requires(body != null); Contract.Requires(tok != null); this.Guard = guard; this.Invariants = invariants; this.Body = body; }
public IfCmd(IToken/*!*/ tok, Expr guard, StmtList/*!*/ thn, IfCmd elseIf, StmtList elseBlock) : base(tok) { Contract.Requires(tok != null); Contract.Requires(thn != null); Contract.Requires(elseIf == null || elseBlock == null); this.Guard = guard; this.thn = thn; this.elseIf = elseIf; this.elseBlock = elseBlock; }
public Implementation(IToken/*!*/ tok, string/*!*/ name, List<TypeVariable>/*!*/ typeParams, List<Variable>/*!*/ inParams, List<Variable>/*!*/ outParams, List<Variable>/*!*/ localVariables, [Captured] StmtList/*!*/ structuredStmts, QKeyValue kv, Errors/*!*/ errorHandler) : base(tok, name, typeParams, inParams, outParams) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(typeParams != null); Contract.Requires(inParams != null); Contract.Requires(outParams != null); Contract.Requires(localVariables != null); Contract.Requires(structuredStmts != null); Contract.Requires(errorHandler != null); LocVars = localVariables; StructuredStmts = structuredStmts; BigBlocksResolutionContext ctx = new BigBlocksResolutionContext(structuredStmts, errorHandler); Blocks = ctx.Blocks; BlockPredecessorsComputed = false; scc = null; Attributes = kv; }