Пример #1
0
        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();
        }
Пример #2
0
        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;
        }
Пример #3
0
        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;
        }