Ejemplo n.º 1
0
        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;
        }