public override AstNode Visit(MemberAccess node) { // Evaluate the base reference. Expression baseReference = node.GetReference(); baseReference.SetHints(node.Hints); baseReference.Accept(this); // Get the base reference type. IChelaType baseRefType = baseReference.GetNodeType(); if(baseRefType.IsConstant()) baseRefType = DeConstType(baseRefType); // Set a default coercion type. node.SetCoercionType(baseRefType); // Get the scope. Scope scope = null; bool canStatic = true; bool canNoStatic = node.HasHints(Expression.MemberHint); bool suppressVirtual = false; bool implicitThis = false; if(baseRefType.IsMetaType()) { // Read the base reference type. baseRefType = ExtractActualType(node, baseRefType); // Handle incomplete types. if(baseRefType.IsIncompleteType()) { node.SetNodeType(baseRefType); return node; } // Handle built-in types if(!baseRefType.IsStructure() && !baseRefType.IsClass() && !baseRefType.IsInterface()) { baseRefType = currentModule.GetAssociatedClass(baseRefType); if(baseRefType == null) Error(node, "expected a known type."); } scope = (Scope) baseRefType; suppressVirtual = true; // Get the current container scope. Scope contScope = currentScope; while(contScope != null && (contScope.IsPseudoScope() || contScope.IsFunction() || contScope.IsLexicalScope())) contScope = contScope.GetParentScope(); // Check if the base type is a base of me. Structure building = contScope as Structure; if(building != null) { Structure scopeBuilding = (Structure) baseRefType; if(building.IsDerivedFrom(scopeBuilding)) { canNoStatic = true; implicitThis = true; } } } else if(baseRefType.IsNamespace()) { scope = (Namespace) baseReference.GetNodeValue(); } else if(baseRefType.IsReference()) { canStatic = false; canNoStatic = true; // Get the variable referenced type. ReferenceType refType = (ReferenceType)baseRefType; IChelaType objectType = refType.GetReferencedType(); if(objectType.IsReference()) { // Set the variable type as the coercion type. node.SetCoercionType(objectType); // Dereference. refType = (ReferenceType)objectType; objectType = refType.GetReferencedType(); } else if(objectType.IsStructure()) { // Use the structure type as the coercion type. node.SetCoercionType(objectType); } else if(objectType.IsPrimitive() || objectType.IsVector() || objectType.IsPlaceHolderType()) { node.SetCoercionType(objectType); } if(objectType.IsStructure() || objectType.IsClass() || objectType.IsInterface() || objectType.IsTypeInstance()) scope = (Scope)objectType; else if(objectType.IsPlaceHolderType()) scope = new PseudoScope((PlaceHolderType)objectType); else { scope = currentModule.GetAssociatedClass(objectType); if(scope == null) Error(node, "unimplemented primitive type classes."); } } else if(baseRefType.IsStructure()) { canStatic = false; canNoStatic = true; scope = (Scope)baseRefType; } else if(baseRefType.IsPrimitive()) { canStatic = false; canNoStatic = true; scope = currentModule.GetAssociatedClass(baseRefType); if(scope == null) Error(node, "unimplemented primitive type classes."); } else if(baseRefType.IsVector()) { canStatic = false; canNoStatic = true; scope = currentModule.GetAssociatedClass(baseRefType); if(scope == null) Error(node, "unimplemented vector type classes."); } else if(baseRefType.IsPlaceHolderType()) { canStatic = false; canNoStatic = true; scope = new PseudoScope((PlaceHolderType)baseRefType); } else { Error(node, "expected reference, namespace, struct, class, primitive, vector."); } // Check vectorial swizzle. IChelaType coercionType = node.GetCoercionType(); if(coercionType.IsVector()) { VectorType vectorType = (VectorType)coercionType; int minSize = 0; int mask = 0; string fieldName = node.GetName(); if(fieldName.Length <= 4) { // It can be a vectorial swizzle bool isSwizzle = true; for(int i = 0; i < fieldName.Length; ++i) { switch(fieldName[i]) { case 'x': case 'r': case 's': mask |= 0<<(2*i); if(minSize < 1) minSize = 1; break; case 'y': case 'g': case 't': mask |= 1<<(2*i); if(minSize < 2) minSize = 2; break; case 'z': case 'b': case 'p': mask |= 2<<(2*i); if(minSize < 3) minSize = 3; break; case 'w': case 'a': case 'q': mask |= 3<<(2*i); if(minSize < 4) minSize = 4; break; default: i = fieldName.Length + 1; isSwizzle = false; break; } } // Swizzle found. if(isSwizzle) { // Check the validity. if(minSize > vectorType.GetNumComponents()) Error(node, "accessing inexistent elements in the vector."); // Store the base variable. Variable baseVar = baseReference.GetNodeValue() as Variable; // Return the swizzle. IChelaType swizzleType = VectorType.Create(vectorType.GetPrimitiveType(), fieldName.Length); SwizzleVariable swizzleVar = new SwizzleVariable(swizzleType, baseVar, (byte)mask, fieldName.Length); node.SetNodeValue(swizzleVar); node.SetNodeType(ReferenceType.Create(swizzleType)); return node; } } } // Find the scope member. ScopeMember member = scope.FindMemberRecursive(node.GetName()); if(member == null) { // Check attribute name. if(node.IsAttributeName()) member = scope.FindMemberRecursive(node.GetName() + "Attribute"); if(member == null) Error(node, "couldn't find member '" + node.GetName() + "' in '" + scope.GetFullName() + "'."); } // Check the accesiblity. CheckMemberVisibility(node, member); // Return it. IChelaType type = null; if(member.IsNamespace()) { type = ChelaType.GetNamespaceType(); } else if(member.IsType()) { type = MetaType.Create((IChelaType)member); } else if(member.IsTypeName()) { // Read the type name. TypeNameMember typeName = (TypeNameMember)member; type = typeName.GetActualType(); // Create an incomplete type if necessary. if(type == null) type = new IncompleteType(typeName); type = MetaType.Create(type); } else if(member.IsFunctionGroup()) { FunctionGroup fgroup = (FunctionGroup)member; FunctionGroupSelector selector = new FunctionGroupSelector(fgroup); selector.SuppressVirtual = suppressVirtual; selector.ImplicitThis = implicitThis; member = selector; if(canNoStatic && canStatic) type = ChelaType.GetAnyFunctionGroupType(); else if(canStatic) type = ChelaType.GetStaticFunctionGroupType(); else type = ChelaType.GetFunctionGroupType(); } else if(member.IsFunction()) { Function function = (Function)member; type = function.GetFunctionType(); // Check the static flag. if(!canNoStatic && (function.GetFlags() & MemberFlags.InstanceMask) != MemberFlags.Static) { Error(node, "expected a static function."); } else if(function.IsMethod()) { Method method = (Method)function; node.SetSlot(method.GetVSlot()); } } else { Variable variable = (Variable)member; IChelaType variableType = variable.GetVariableType(); if(variableType.IsPassedByReference()) variableType = ReferenceType.Create(variableType); // Required for nested access. type = ReferenceType.Create(variableType); // Check the static flag. if(!canNoStatic && !variable.IsStatic()) { Error(node, "expected a static variable."); } else if(variable.IsField()) { // Use the slot. FieldVariable field = (FieldVariable) variable; node.SetSlot(field.GetSlot()); } else if(variable.IsProperty() && !variable.IsStatic() && suppressVirtual) { // Wrap the property in a direct property slot. member = new DirectPropertySlot((PropertyVariable)variable); } // Store the implicit this property. if(!variable.IsStatic()) node.ImplicitSelf = implicitThis; } // Set the value. node.SetNodeValue(member); // Set the type. node.SetNodeType(type); return node; }
public override AstNode Visit(MemberAccess node) { // Begin the node builder.BeginNode(node); // Get the reference expression. Expression baseRef = node.GetReference(); // Visit it. baseRef.Accept(this); // Get the reference and coercion type. IChelaType refType = baseRef.GetNodeType(); IChelaType coercionType = node.GetCoercionType(); if(refType != coercionType) Cast(node, baseRef.GetNodeValue(), refType, coercionType); // Cast generic place holders into something more appropiate. Scope memberParent = GetMemberParent(node); if(coercionType.IsPlaceHolderType() && memberParent.IsType()) { IChelaType targetType = (IChelaType)memberParent; if(targetType.IsPassedByReference()) targetType = ReferenceType.Create(targetType); // Cast the generic placeholder. builder.CreateGCast(targetType); } // Pop redundant reference. ScopeMember member = (ScopeMember)node.GetNodeValue(); if((coercionType.IsReference() || coercionType.IsStructure()) && member.IsStatic()) builder.CreatePop(); // Load the implicit this. if(node.ImplicitSelf) LoadCurrentSelf(); // Next checks are only for functions. IChelaType nodeType = node.GetNodeType(); if(!nodeType.IsFunctionGroup() && !nodeType.IsFunction()) return builder.EndNode(); // Handle virtual suppression. if(nodeType.IsFunctionGroup() && refType.IsMetaType()) { FunctionGroupSelector selector = (FunctionGroupSelector)node.GetNodeValue(); Function selected = selector.GetSelected(); // Load implicit this. if(!selected.IsStatic() && selector.ImplicitThis) LoadCurrentSelf(); } // Only primitives and structure can be boxed. IChelaType referencedType = DeReferenceType(coercionType); bool firstClass = referencedType.IsFirstClass(); bool structure = referencedType.IsStructure(); if(!firstClass && !structure) return builder.EndNode(); // Box structures when calling virtual methods. Method method = null; if(nodeType.IsFunctionGroup()) { // Set the must box flag. FunctionGroupSelector selector = (FunctionGroupSelector)node.GetNodeValue(); Function selected = selector.GetSelected(); if(selected == null) Error(node, "Trying to get unselected function."); if(selected.IsMethod()) method = (Method)selected; } else //if(nodeType.IsFunction()) { Function function = (Function)node.GetNodeValue(); if(function.IsMethod()) method = (Method)function; } // Only methods may require boxing. if(method != null) { if(!method.GetParentScope().IsStructure()) { // Must box. IChelaType boxType; if(firstClass) boxType = currentModule.GetAssociatedClass(referencedType); else boxType = referencedType; builder.CreateBox(boxType); } else if(firstClass) // Light primitive boxing. { builder.CreatePrimBox(currentModule.GetAssociatedClass(referencedType)); } } return builder.EndNode(); }