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); }