public override void CaseASwitchStm(ASwitchStm node) { InASwitchStm(node); { Object[] temp = new Object[node.GetCases().Count]; node.GetCases().CopyTo(temp, 0); for (int i = temp.Length - 1; i >= 0; i--) { ((PStm)temp[i]).Apply(this); } } if (node.GetTest() != null) { node.GetTest().Apply(this); } if (node.GetToken() != null) { node.GetToken().Apply(this); } OutASwitchStm(node); }
public override void CaseASwitchStm(ASwitchStm node) { node.GetTest().Apply(this); AALocalDecl fallThroughDecl = new AALocalDecl(new APublicVisibilityModifier(), null, null, null, null, new ANamedType(new TIdentifier("bool"), null), new TIdentifier(MakeUniqueLocalName(node, "switchFallThrough")), new ABooleanConstExp(new AFalseBool())); AALocalDecl continueDecl = new AALocalDecl(new APublicVisibilityModifier(), null, null, null, null, new ANamedType(new TIdentifier("bool"), null), new TIdentifier(MakeUniqueLocalName(node, "switchContinue")), new ABooleanConstExp(new ATrueBool())); AALocalDecl testVar = new AALocalDecl(new APublicVisibilityModifier(), null, null, null, null, Util.MakeClone(data.ExpTypes[node.GetTest()], data), new TIdentifier(MakeUniqueLocalName(node, "switchTestVar")), node.GetTest()); AABlock bigBlock = new AABlock(); //AABlock previousBlock = bigBlock; if (node.GetCases().Count > 0) { List<SwitchCaseData> switchCaseDatas = new List<SwitchCaseData>(); //Join cases without a body for (int i = node.GetCases().Count - 1; i >= 0; i--) { ASwitchCaseStm caseStm = (ASwitchCaseStm) node.GetCases()[i]; SwitchCaseData caseData = new SwitchCaseData(); caseData.Block = (AABlock) caseStm.GetBlock(); if (caseStm.GetType() is ACaseSwitchCaseType) caseData.Tests.Add(((ACaseSwitchCaseType)caseStm.GetType()).GetExp()); else caseData.ContainsDefault = true; caseData.IsLast = switchCaseDatas.Count == 0; if (switchCaseDatas.Count == 0 || caseData.Block.GetStatements().Count > 0) { switchCaseDatas.Insert(0, caseData); continue; } switchCaseDatas[0].Tests.AddRange(caseData.Tests); } for (int i = switchCaseDatas.Count - 1; i >= 0; i--) { switchCaseDatas[i].ContainsFallthrough = CanFallthrough(switchCaseDatas[i].Block, out switchCaseDatas[i].HasBreaks, out switchCaseDatas[i].RequiresWhile); if (i == switchCaseDatas.Count - 1) continue; switchCaseDatas[i + 1].TargetForFallThrough = switchCaseDatas[i].ContainsFallthrough; switchCaseDatas[i].RequiresContinue = !switchCaseDatas[i].ContainsFallthrough && (switchCaseDatas[i + 1].RequiresContinue || switchCaseDatas[i + 1].ContainsFallthrough); } AABlock previousBlock = bigBlock; //Make code for specific case foreach (SwitchCaseData switchCase in switchCaseDatas) { List<PExp> tests = new List<PExp>(); AABlock nextBlock; if (switchCase.TargetForFallThrough) {//Add if (continueSwitch) {} ALocalLvalue lvalue = new ALocalLvalue(new TIdentifier(continueDecl.GetName().Text)); ALvalueExp test = new ALvalueExp(lvalue); nextBlock = new AABlock(); AIfThenStm ifStm = new AIfThenStm(new TLParen("("), test, new ABlockStm(new TLBrace("{"), nextBlock)); previousBlock.GetStatements().Add(ifStm); previousBlock = nextBlock; data.LocalLinks[lvalue] = continueDecl; data.LvalueTypes[lvalue] = data.ExpTypes[test] = continueDecl.GetType(); //First test in next if: if (fallThrough || ... lvalue = new ALocalLvalue(new TIdentifier(fallThroughDecl.GetName().Text)); test = new ALvalueExp(lvalue); tests.Add(test); data.LocalLinks[lvalue] = fallThroughDecl; data.LvalueTypes[lvalue] = data.ExpTypes[test] = fallThroughDecl.GetType(); } //Make code for the test in the if foreach (PExp exp in switchCase.Tests) { ALocalLvalue leftSide = new ALocalLvalue(new TIdentifier(testVar.GetName().Text)); ALvalueExp lvalueExp = new ALvalueExp(leftSide); ABinopExp test = new ABinopExp(lvalueExp, new AEqBinop(new TEq("==")), exp); tests.Add(test); data.LocalLinks[leftSide] = testVar; data.LvalueTypes[leftSide] = data.ExpTypes[lvalueExp] = testVar.GetType(); data.ExpTypes[test] = new ANamedType(new TIdentifier("bool"), null); } if (switchCase.ContainsDefault) { ABooleanConstExp test = new ABooleanConstExp(new ATrueBool()); tests.Add(test); data.ExpTypes[test] = new ANamedType(new TIdentifier("bool"), null); } PExp finalTest = tests[0]; tests.RemoveAt(0); foreach (PExp exp in tests) { finalTest = new ABinopExp(finalTest, new ALazyOrBinop(new TOrOr("||")), exp); data.ExpTypes[finalTest] = new ANamedType(new TIdentifier("bool"), null); } //Transform breaks into assignments //If we can fallthrough, and there are breaks, encase in a while stm AABlock testBlock = switchCase.Block; if (switchCase.RequiresWhile) { AABlock newBlock = new AABlock(); PExp whileTest = new ABooleanConstExp(new ATrueBool()); AWhileStm whileStm = new AWhileStm(new TLParen("("), whileTest, new ABlockStm(new TLBrace("{"), switchCase.Block)); newBlock.GetStatements().Add(whileStm); switchCase.Block = newBlock; } TransformBreaks(testBlock, switchCase, continueDecl, fallThroughDecl); if (switchCase.ContainsFallthrough && !switchCase.TargetForFallThrough) {//Add fallthrough = true; ALocalLvalue lvalue = new ALocalLvalue(new TIdentifier(fallThroughDecl.GetName().Text)); ABooleanConstExp rightSide = new ABooleanConstExp(new ATrueBool()); AAssignmentExp assignment = new AAssignmentExp(new TAssign("="), lvalue, rightSide); testBlock.GetStatements().Add(new AExpStm(new TSemicolon(";"), assignment)); data.LocalLinks[lvalue] = fallThroughDecl; data.LvalueTypes[lvalue] = data.ExpTypes[rightSide] = data.ExpTypes[assignment] = fallThroughDecl.GetType(); } if (switchCase.RequiresWhile) {//Add break at the end of the while testBlock.GetStatements().Add(new ABreakStm(new TBreak("break"))); } //Make if PStm finalIfStm; if (finalTest is ABooleanConstExp) {//Final if is if(true). dont add it. finalIfStm = new ABlockStm(new TLBrace("{"), switchCase.Block); nextBlock = new AABlock(); } else if (switchCase.IsLast || switchCase.ContainsFallthrough) {//One armed if finalIfStm = new AIfThenStm(new TLParen("("), finalTest, new ABlockStm(new TLBrace("{"), switchCase.Block)); nextBlock = bigBlock; } else {//Two armed if nextBlock = new AABlock(); finalIfStm = new AIfThenElseStm(new TLParen("("), finalTest, new ABlockStm(new TLBrace("{"), switchCase.Block), new ABlockStm(new TLBrace("{"), nextBlock)); } previousBlock.GetStatements().Add(finalIfStm); previousBlock = nextBlock; } //If needed, add fallThroughDecl and continueDecl data.Locals.Add(bigBlock, new List<AALocalDecl>()); if (data.LocalLinks.Values.Contains(fallThroughDecl)) { bigBlock.GetStatements().Insert(0, new ALocalDeclStm(new TSemicolon(";"), fallThroughDecl)); data.Locals[bigBlock].Add(fallThroughDecl); } if (data.LocalLinks.Values.Contains(continueDecl)) { bigBlock.GetStatements().Insert(0, new ALocalDeclStm(new TSemicolon(";"), continueDecl)); data.Locals[bigBlock].Add(continueDecl); } bigBlock.GetStatements().Insert(0, new ALocalDeclStm(new TSemicolon(";"), testVar)); data.Locals[bigBlock].Add(testVar); node.ReplaceBy(new ABlockStm(new TLBrace("{"), bigBlock)); bigBlock.Apply(this); } }