예제 #1
0
        public override AstNode Visit(SubscriptAccess node)
        {
            // Begin the node
            builder.BeginNode(node);

            // Get the array expression.
            Expression array = node.GetArray();

            // Visit it.
            array.Accept(this);

            // Get the array and coercion type.
            IChelaType arrayType = array.GetNodeType();
            IChelaType coercionType = node.GetCoercionType();

            // Perform array coercion.
            if(arrayType != coercionType)
                Cast(node, array.GetNodeValue(), arrayType, coercionType);

            // Visit and coerce each index.
            IChelaType[] indexCoercions = node.GetIndexCoercions();
            Expression index = node.GetIndex();
            int indexId = 0;
            while(index != null)
            {
                // Visit it.
                index.Accept(this);

                // Get the index type.
                IChelaType indexType = index.GetNodeType();

                // Get or compute the index coercion type.
                IChelaType indexCoercion = null;
                if(indexCoercions != null && indexCoercions.Length != 0)
                {
                    indexCoercion = indexCoercions[indexId];
                }
                else
                {
                    // Remove the reference and constant layer.
                    indexCoercion = indexType;
                    if(indexCoercion.IsReference())
                        indexCoercion = DeReferenceType(indexCoercion);
                    if(indexCoercion.IsConstant())
                        indexCoercion = DeConstType(indexCoercion);
                }

                if(indexType != indexCoercion)
                    Cast(index, index.GetNodeValue(), indexType, indexCoercion);

                // Process the next index.
                ++indexId;
                index = (Expression)index.GetNext();
            }

            return builder.EndNode();
        }
예제 #2
0
        public override AstNode Visit(SubscriptAccess node)
        {
            // Evaluate the base reference.
            Expression arrayExpr = node.GetArray();
            arrayExpr.Accept(this);

            // Get the base reference type.
            IChelaType arrayType =  arrayExpr.GetNodeType();
            IChelaType objectType = null;
            if(arrayType.IsReference())
            {
                // Get the referenced type.
                ReferenceType refType = (ReferenceType) arrayType;
                objectType = refType.GetReferencedType();

                // Dereference again (object variable).
                if(objectType.IsReference())
                {
                    refType = (ReferenceType) objectType;
                    arrayType = refType;
                    objectType = refType.GetReferencedType();
                }
                else if(objectType.IsStructure())
                {
                    arrayType = objectType;
                }

                if(objectType.IsPointer())
                {
                    arrayType = objectType;
                }
            }

            // Check the array type.
            if(!arrayType.IsPointer() && !arrayType.IsReference() && !arrayType.IsStructure())
                Error(node, "expected pointer/array/object.");

            // Get the object type.
            IChelaType[] indexCoercionsType = null;
            IChelaType usedArrayType = arrayType;
            int dimensions = 1;
            bool arraySlot = false;
            if(arrayType.IsPointer())
            {
                PointerType pointer = (PointerType) arrayType;
                objectType = pointer.GetPointedType();
                arraySlot = true;
            }
            else if(objectType != null && objectType.IsArray())
            {
                ArrayType array = (ArrayType)objectType;
                dimensions = array.GetDimensions();
                usedArrayType = array;
                objectType = array.GetValueType();
                if(objectType.IsPassedByReference())
                    objectType = ReferenceType.Create(objectType);
                arraySlot = true;
            }
            else if(objectType.IsClass() || objectType.IsStructure() || objectType.IsInterface())
            {
                // Find the indexer.
                Structure building = (Structure)objectType;

                // TODO: support indexer overloading.
                ScopeMember member = building.FindMemberRecursive("Op_Index");
                if(!member.IsProperty())
                    Error(node, "object has invalid indexer.");

                // Check the indices type.
                PropertyVariable indexer = (PropertyVariable)member;
                dimensions = indexer.GetIndexCount();
                if(dimensions == 0)
                    Error(node, "Expected an intexer with at leas one dimension.");

                // Use the indexer as the node value.
                node.SetNodeValue(indexer);

                // Set the index coercion type.
                indexCoercionsType = new IChelaType[dimensions];
                for(int i = 0; i < dimensions; ++i)
                    indexCoercionsType[i] = indexer.GetIndexType(i);
                node.SetIndexCoercions(indexCoercionsType);

                // Use the indexer type.
                objectType = indexer.GetVariableType();
            }
            else
            {
                Error(node, "unexpected object.");
            }

            // Set the coercion type.
            node.SetCoercionType(arrayType);

            // Set the node type.
            node.SetNodeType(ReferenceType.Create(objectType));

            // Create the "variable" for arrays.
            if(arraySlot)
            {
                ArraySlot variable = new ArraySlot(objectType, usedArrayType);
                node.SetNodeValue(variable);
            }

            // Check the index expressions.
            int indexId = 0;
            Expression index = node.GetIndex();
            while(index != null)
            {
                // Don't allow more indices than dimensions.
                if(indexId == dimensions)
                    Error(index, "cannot use more indices than dimensions.");

                // Visit it.
                index.Accept(this);

                // Get the index type.
                IChelaType indexType = index.GetNodeType();
                if(indexCoercionsType != null)
                {
                    // Perform the index coercion.
                    IChelaType coercionType = indexCoercionsType[indexId];
                    if(Coerce(index, coercionType, indexType, index.GetNodeValue()) != coercionType)
                        Error(index, "expected an index of type {0}.", coercionType.GetDisplayName());
                }
                else
                {
                    // Dereference.
                    if(indexType.IsReference())
                    {
                        ReferenceType indexRef = (ReferenceType) indexType;
                        indexType = indexRef.GetReferencedType();
                    }

                    // Deconst.
                    if(indexType.IsConstant())
                        indexType = DeConstType(indexType);

                    if(!indexType.IsInteger())
                        Error(node, "expected integer index.");
                }

                // Check the next index.
                ++indexId;
                index = (Expression)index.GetNext();
            }

            // Don't allow less indices than dimensions.
            if(indexId < dimensions)
                Error(index, "cannot use less indices than dimensions.");

            return node;
        }