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