예제 #1
0
 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);
            }
        }