示例#1
0
        SwitchStatement TranslateSwitch(BlockContainer switchContainer, SwitchInstruction inst)
        {
            Debug.Assert(switchContainer.EntryPoint.IncomingEdgeCount == 1);
            var oldBreakTarget = breakTarget;

            breakTarget = switchContainer;             // 'break' within a switch would only leave the switch
            var oldCaseLabelMapping = caseLabelMapping;

            caseLabelMapping = new Dictionary <Block, ConstantResolveResult>();

            TranslatedExpression value;
            var strToInt = inst.Value as StringToInt;

            if (strToInt != null)
            {
                value = exprBuilder.Translate(strToInt.Argument);
            }
            else
            {
                value = exprBuilder.Translate(inst.Value);
            }

            // Pick the section with the most labels as default section.
            IL.SwitchSection defaultSection = inst.Sections.First();
            foreach (var section in inst.Sections)
            {
                if (section.Labels.Count() > defaultSection.Labels.Count())
                {
                    defaultSection = section;
                }
            }

            var stmt = new SwitchStatement()
            {
                Expression = value
            };
            Dictionary <IL.SwitchSection, Syntax.SwitchSection> translationDictionary = new Dictionary <IL.SwitchSection, Syntax.SwitchSection>();

            // initialize C# switch sections.
            foreach (var section in inst.Sections)
            {
                // This is used in the block-label mapping.
                ConstantResolveResult firstValueResolveResult;
                var astSection = new Syntax.SwitchSection();
                // Create case labels:
                if (section == defaultSection)
                {
                    astSection.CaseLabels.Add(new CaseLabel());
                    firstValueResolveResult = null;
                }
                else
                {
                    var values = section.Labels.Values.Select(i => CreateTypedCaseLabel(i, value.Type, strToInt?.Map)).ToArray();
                    if (section.HasNullLabel)
                    {
                        astSection.CaseLabels.Add(new CaseLabel(new NullReferenceExpression()));
                        firstValueResolveResult = new ConstantResolveResult(SpecialType.NullType, null);
                    }
                    else
                    {
                        Debug.Assert(values.Length > 0);
                        firstValueResolveResult = values[0];
                    }
                    astSection.CaseLabels.AddRange(values.Select(label => new CaseLabel(exprBuilder.ConvertConstantValue(label, allowImplicitConversion: true))));
                }
                switch (section.Body)
                {
                case Branch br:
                    // we can only inline the block, if all branches are in the switchContainer.
                    if (br.TargetBlock.Parent == switchContainer && switchContainer.Descendants.OfType <Branch>().Where(b => b.TargetBlock == br.TargetBlock).All(b => BlockContainer.FindClosestSwitchContainer(b) == switchContainer))
                    {
                        caseLabelMapping.Add(br.TargetBlock, firstValueResolveResult);
                    }
                    break;

                default:
                    break;
                }
                translationDictionary.Add(section, astSection);
                stmt.SwitchSections.Add(astSection);
            }
            foreach (var section in inst.Sections)
            {
                var astSection = translationDictionary[section];
                switch (section.Body)
                {
                case Branch br:
                    // we can only inline the block, if all branches are in the switchContainer.
                    if (br.TargetBlock.Parent == switchContainer && switchContainer.Descendants.OfType <Branch>().Where(b => b.TargetBlock == br.TargetBlock).All(b => BlockContainer.FindClosestSwitchContainer(b) == switchContainer))
                    {
                        ConvertSwitchSectionBody(astSection, br.TargetBlock);
                    }
                    else
                    {
                        ConvertSwitchSectionBody(astSection, section.Body);
                    }
                    break;

                case Leave leave:
                    if (astSection.CaseLabels.Count == 1 && astSection.CaseLabels.First().Expression.IsNull&& leave.TargetContainer == switchContainer)
                    {
                        stmt.SwitchSections.Remove(astSection);
                        break;
                    }
                    goto default;

                default:
                    ConvertSwitchSectionBody(astSection, section.Body);
                    break;
                }
            }
            if (switchContainer != null)
            {
                // Translate any remaining blocks:
                var lastSectionStatements = stmt.SwitchSections.Last().Statements;
                foreach (var block in switchContainer.Blocks.Skip(1))
                {
                    if (caseLabelMapping.ContainsKey(block))
                    {
                        continue;
                    }
                    lastSectionStatements.Add(new LabelStatement {
                        Label = block.Label
                    });
                    foreach (var nestedInst in block.Instructions)
                    {
                        var nestedStmt = Convert(nestedInst);
                        if (nestedStmt is BlockStatement b)
                        {
                            foreach (var nested in b.Statements)
                            {
                                lastSectionStatements.Add(nested.Detach());
                            }
                        }
                        else
                        {
                            lastSectionStatements.Add(nestedStmt);
                        }
                    }
                    Debug.Assert(block.FinalInstruction.OpCode == OpCode.Nop);
                }
                if (endContainerLabels.TryGetValue(switchContainer, out string label))
                {
                    lastSectionStatements.Add(new LabelStatement {
                        Label = label
                    });
                    lastSectionStatements.Add(new BreakStatement());
                }
            }

            breakTarget      = oldBreakTarget;
            caseLabelMapping = oldCaseLabelMapping;
            return(stmt);
        }