public override AstNode Visit(SwitchStatement node) { // Begin the node. builder.BeginNode(node); // Process the switch expression. Expression switchExpr = node.GetConstant(); switchExpr.Accept(this); // Perform coercion. IChelaType switchType = switchExpr.GetNodeType(); IChelaType coercionType = node.GetCoercionType(); if(switchType != coercionType) Cast(node, switchExpr.GetNodeValue(), switchType, coercionType); // Create the merge block. BasicBlock merge = CreateBasicBlock(); merge.SetName("smerge"); // Store the old break. BasicBlock oldBreak = currentBreak; currentBreak = merge; // Initialize the default block to the merge. BasicBlock defaultBlock = merge; // Get the cases dictionary. IDictionary<ConstantValue, CaseLabel> caseDictionary = node.CaseDictionary; // Create the jump table. int tableSize = caseDictionary.Count + 1; int[] constants = new int[tableSize]; BasicBlock[] blocks = new BasicBlock[tableSize]; // The first element is always the default block. int i = 0; constants[i] = -1; blocks[i] = defaultBlock; ++i; // Add the other elements. BasicBlock caseBlock = null; CaseLabel label = (CaseLabel)node.GetCases(); while(label != null) { // Create the label block. if(caseBlock == null) { caseBlock = CreateBasicBlock(); caseBlock.SetName("caseBlock"); } // Set the label block. label.SetBlock(caseBlock); // Store the default block. if(label.GetConstant() == null) { defaultBlock = caseBlock; blocks[0] = caseBlock; } else { // Append it to the jump table. Expression caseExpr = label.GetConstant(); ConstantValue caseConstant = (ConstantValue)caseExpr.GetNodeValue(); constants[i] = caseConstant.GetIntValue(); blocks[i] = caseBlock; ++i; } // Create a new block if the last case wasn't empty. if(label.GetChildren() != null) caseBlock = null; // Process the next label. label = (CaseLabel)label.GetNext(); } // Perform the switch. BasicBlock switchBlock = builder.GetBlock(); builder.CreateSwitch(constants, blocks); // Generate the cases blocks. VisitList(node.GetCases()); // Continue with the normal flow. currentBreak = oldBreak; // Remove the merge block if its unreachable. if(merge.GetPredsCount() == 0) { builder.SetBlock(switchBlock); merge.Destroy(); if(node.GetNext() != null) Warning(node.GetNext(), "detected unreachable code."); node.SetNext(null); } else { builder.SetBlock(merge); } return builder.EndNode(); }
public override AstNode Visit(SwitchStatement node) { // Store the old switch statement. SwitchStatement oldSwitch = currentSwitch; currentSwitch = node; // Visit the cases. VisitList(node.GetCases()); // Restore the switch statement. currentSwitch = oldSwitch; return node; }
public override AstNode Visit(SwitchStatement node) { // Store the old switch statement. SwitchStatement oldSwitch = currentSwitch; currentSwitch = node; // Get and visit the "constant" expression. Expression constantExpr = node.GetConstant(); constantExpr.Accept(this); // Get the constant type. IChelaType constantType = constantExpr.GetNodeType(); if(constantType.IsReference()) constantType = DeReferenceType(constantType); if(constantType.IsConstant()) constantType = DeConstType(constantType); // Must be an integer. if(!constantType.IsInteger()) { if(constantType.IsStructure()) { Structure enumBuilding = (Structure)constantType; if(!enumBuilding.IsDerivedFrom(currentModule.GetEnumClass())) Error(node, "expected enumeration expression."); // Get the enumeration base type. FieldVariable valueField = (FieldVariable)enumBuilding.FindMember("__value"); if(valueField == null) valueField = (FieldVariable)enumBuilding.FindMember("m_value"); if(valueField == null) Error(node, "invalid enumeration."); // Make sure the enumeration is an integer. IChelaType enumType = valueField.GetVariableType(); if(!enumType.IsInteger()) Error(node, "expected integral enumeration."); constantType = enumType; } else Error(node, "switch expression must be integer."); } // Use always integer types. IChelaType targetType = null; if(constantType.IsUnsigned() && constantType.GetSize() == ChelaType.GetUIntType().GetSize()) targetType = ChelaType.GetUIntType(); else targetType = ChelaType.GetIntType(); // Perform the coercion. if(Coerce(constantType, targetType) != targetType) Error(node, "switch expression type must be int or uint compatible."); node.SetCoercionType(targetType); // A switch statement cannot be empty. AstNode caseNode = node.GetCases(); if(caseNode == null) Error(node, "switch statements cannot be empty."); // Now process the cases. while(caseNode != null) { // Cast the case node. CaseLabel label = (CaseLabel)caseNode; label.SetCoercionType(targetType); // Visit the case node. label.Accept(this); // Check the next case. caseNode = caseNode.GetNext(); } // Restore the old switch statement. currentSwitch = oldSwitch; return node; }