Пример #1
0
        public override AstNode Visit(NewArrayExpression node)
        {
            // Visit the type expression.
            Expression typeExpression = node.GetTypeExpression();
            typeExpression.SetHints(Expression.TypeHint);
            typeExpression.Accept(this);

            // Get the size expression.
            Expression sizeExpression = node.GetSize();
            int dimensions = node.GetDimensions();

            // Count the dimensions-
            if(sizeExpression != null)
            {
                dimensions = 0;
                AstNode currentSize = sizeExpression;
                while(currentSize != null)
                {
                    ++dimensions;
                    currentSize = currentSize.GetNext();
                }
                node.SetDimensions(dimensions);
            }

            // Get the type.
            IChelaType objectType = typeExpression.GetNodeType();
            objectType = ExtractActualType(typeExpression, objectType);

            // Check the object type.
            if(objectType.IsConstant())
                Error(node, "cannot create array of constants.");

            // Compute the init coercion type.
            IChelaType initCoercionType = objectType;
            if(initCoercionType.IsPassedByReference())
                initCoercionType = ReferenceType.Create(initCoercionType);
            node.SetInitCoercionType(initCoercionType);

            // Create the array type.
            ArrayType arrayType = ArrayType.Create(objectType, dimensions, false);
            node.SetArrayType(arrayType);
            node.SetObjectType(objectType);
            node.SetNodeType(ReferenceType.Create(arrayType));

            // Read or guess the sizes
            int[] arraySizes = new int[dimensions];
            bool canInit = true;
            IChelaType sizeCoercionType = null;
            if(sizeExpression != null)
            {
                // Load the sizes.
                int currentSizeIndex = 0;
                while(sizeExpression != null)
                {
                    // Visit the size expression.
                    sizeExpression.Accept(this);

                    // Get the size type.
                    IChelaType sizeType = sizeExpression.GetNodeType();
                    if(sizeType.IsConstant() && canInit)
                    {
                        sizeType = DeConstType(sizeType);
                        if(sizeType.IsInteger() && sizeType.IsPrimitive())
                        {
                            // Read the size constant.
                            ConstantValue sizeConst = sizeExpression.GetNodeValue() as ConstantValue;
                            if(sizeConst != null)
                            {
                                sizeConst = sizeConst.Cast(ConstantValue.ValueType.Int);
                                arraySizes[currentSizeIndex] = sizeConst.GetIntValue();

                            }
                            else
                            {
                                // Cannot initialize here.
                                canInit = false;
                            }
                        }
                        else
                        {
                            // Cannot initialize here.
                            canInit = false;
                        }
                    }
                    else
                    {
                        // Cannot initialize here.
                        canInit = false;
                    }

                    // Coerce the size type.
                    if(sizeCoercionType == null)
                    {
                        if(sizeType.IsReference())
                            sizeType = DeReferenceType(sizeType);
                        if(sizeType.IsConstant())
                            sizeType = DeReferenceType(sizeType);
                        if(sizeType.IsStructure())
                        {
                            IChelaType assoc = currentModule.GetAssociatedClassPrimitive((Structure)sizeType);
                            if(assoc != null)
                                sizeType = assoc;
                        }
                        if(!sizeType.IsInteger() || !sizeType.IsPrimitive())
                            Error(sizeExpression, "expected a size of integer type instead of '{0}'.", sizeType);
                        sizeCoercionType = sizeType;
                    }
                    else if(sizeType != sizeCoercionType)
                    {
                        // Try to get a common coercion type.
                        IChelaType newSizeCoercion = Coerce(sizeExpression, sizeCoercionType, sizeType, sizeExpression.GetNodeValue());
                        if(!newSizeCoercion.IsInteger() || !newSizeCoercion.IsPrimitive())
                            Error(sizeExpression, "expected a size of integer type instead of '{0}'.", sizeType);
                        sizeCoercionType = newSizeCoercion;
                    }

                    // Process the next size.
                    ++currentSizeIndex;
                    sizeExpression = (Expression)sizeExpression.GetNext();
                }
            }
            else
            {
                // Guess the sizes.
                for(int i = 0; i < dimensions; ++i)
                    arraySizes[i] = -1;
            }

            // Use a coercion type.
            if(sizeCoercionType == null) // For implicit sizes.
                sizeCoercionType = ChelaType.GetIntType();
            node.SetCoercionType(sizeCoercionType);

            // Check the initializer.
            AstNode init = node.GetInitializers();
            if(init != null)
            {
                if(!canInit)
                    Error(node, "cannot have variable size arrays with initializers.");

                CheckArrayInitializers(init, arraySizes, 0, initCoercionType, init);
            }

            // Create implicit size expressions.
            sizeExpression = node.GetSize();
            if(sizeExpression == null)
            {
                Expression lastSize = null;
                for(int i = 0; i < dimensions; ++i)
                {
                    Expression nextSize = new IntegerConstant(arraySizes[i], node.GetPosition());
                    if(i == 0)
                        node.SetSize(nextSize);
                    else
                        lastSize.SetNext(nextSize);
                    lastSize = nextSize;
                }
            }

            return node;
        }