public Value evaluate()

in modules/asc/src/java/macromedia/asc/embedding/LintEvaluator.java [520:683]


    public Value evaluate( Context cx, GetExpressionNode node )
	{
		Value  result = null;

		if (first_pass)
		{
			if (node.ref == null)
				node.expr.evaluate(cx,this);

			return result; // doesn't matter what we return during first pass
		}

		if( node.getMode()==LEFTBRACKET_TOKEN )  // no compliance errors possible with bracket access.
		{
			// No reference, then must be dynamic (indexed) access.
			if( node.expr.isLiteralInteger() )
			{
				result = cx.noType();
			}
			else // todo:  add isLiteralString, see if there's a slot for that literal?  if (node.expr.isLiteralString)
			{
				node.expr.evaluate(cx,this);
				result = cx.noType();
			}
		}
		else if( node.ref != null)
		{
			// nothing to evaluate, its an identifier
			Slot slot = node.ref.getSlot(cx,GET_TOKEN);  // check for base object type?

			// special case for looking up a value of a class.  ConstantEvaluator
			//  doesn't recognize direct Class references outside of the global scope, so
			//  it fails to set the ref's base correctly.  It has to do this because when
			//  the function is called, its possible it will be called from a context where
			//  the global class definition has been superceeded by a local definition.
			//  This is pretty unlikely, however, and messes up the undeclared property reference
			//  detection.  If the base of this expression (appears) to be the global definition for
			//  a class, temporarily reset the ref's base and use that definition.
			TypeValue basetype = baseType_context.last();
			if (slot == null && basetype != null && "Class".equals(basetype.name.toString()) )
			{
				ReferenceValue baseRef = baseRef_context.last();

				if (baseRef != null)
				{
					ObjectValue realBase = (ObjectValue)(baseRef.getValue(cx));
					ObjectValue oldBase = node.ref.getBase();
					node.ref.setBase(realBase);
					slot = node.ref.getSlot(cx,GET_TOKEN);
					node.ref.setBase(oldBase);
				}
			}

			// The last ditch, for handling Inteface base types.    If there's a base type, see if its defined in its prototype.
			//  This definition is not good enough for code generation, but its good enough for a warning.  Its pretty unlikely 
			//  that the definition is superceeded at runtime.  
			if (slot == null && basetype != null && basetype.prototype != null && node.ref.name != null)
			{
				slot = getSlot(basetype.prototype, cx, node, GET_TOKEN);
			}

			if (slot != null )
				checkDeprecatedSlot(cx, node, node.ref, slot);
			
			TypeInfo ti = (slot != null) ? slot.getType() : null;
			TypeValue 	type = (ti != null) ? ti.getTypeValue() : null;

			result = type;
			if (result == null)
			{
				result = cx.voidType();
			}
			else if (node.ref.name.compareTo("undefined")==0)
			{
				result = undefinedLiteral;
			}

			//TODO : remove this when these identifiers are declared in playerglobal.as
			Boolean ignoreKeyword = hackIgnoreIdentifierMap.get(node.ref.name);

			int  base_index				 = node.ref.getScopeIndex(GET_TOKEN);
			int  slot_index				 = node.ref.getSlotIndex(GET_TOKEN);
			boolean is_globalref         = base_index == 0;
			boolean is_dotref            = base_index == -2;
			boolean is_unbound_lexref    = base_index == -1;
			boolean is_unbound_dotref    = is_dotref && slot_index < 0;
			boolean is_unbound_globalref = is_globalref && slot_index < 0;
			boolean is_unbound_ref       = is_unbound_dotref || is_unbound_lexref || is_unbound_globalref;

			if ( slot == null && (ignoreKeyword == null || !ignoreKeyword) && is_unbound_ref )
			{
                boolean unsupported = false;
				// special case to avoid warning on access to a Class's prototype property.  This
				//  property can't be expressed in global.as because you can't both declare a class
				//  and declare it to be an instance of the Class class.
				if (basetype != null && "Class".equals(basetype.name.toString()) && "prototype".equals(node.ref.name))
                {
					return node.expr.evaluate(cx,this);
                }
                if (basetype == types[kDateType] || basetype == cx.regExpType() ||
                    (types[kErrorType] != null && types[kErrorType].includes(cx,basetype)))  // these types are dynamic for backwards compatability, so ! doesn't catch this.  Its unlikely anyone is adding dynamic props to them
                {
                    warning(node.pos(), cx.input, kWarning_BadES3TypeProp, node.ref.name, basetype.name.name);
                    unsupported = true;
                }
                else
                {
                    Map<TypeValue,Integer> search = unsupportedPropsMap.get(node.ref.name);

                    if (search != null && !search.isEmpty() ) // && search.second.empty() == false)
                    {
                        TypeValue searchType = baseType_context.last(); // todo: why is this more reliable than node->ref->base

                        // if this is an attempt to access a static member of a class, switch searchType to the class's type
                        //   This is necessary to allow lookup in the unsupportedPropsMap table.
                        if (searchType != null && "Class".equals(searchType.name.toString()))
                        {
                            ReferenceValue br = baseRef_context.back();
                            Slot s = (br != null ? br.getSlot(cx,GET_TOKEN) : null);
                            // c++ variant accesses union member typValue directly, java stores value in objValue
                            TypeValue t = (s != null && s.getObjectValue() instanceof TypeValue) ? (TypeValue)(s.getObjectValue()) : null;
                            searchType = (t != null) ? t : searchType;
                        }

                        for(TypeValue matchType : search.keySet())
                        {
                            if (matchType != null && matchType.includes(cx,searchType))
                            {
                                unsupported = true;
                                warning(node.getPosition(), cx.input, kWarning_DepricatedPropertyError, node.ref.name,
                                            warningConstantsMap.get(search.get(matchType)));
                            }
                        }
                    }

                    if ( !unsupported && node.ref.name.startsWith("_level") && (node.base == null) )
                    {
                        unsupported = true;
                        warning(node.getPosition(), cx.input, kWarning_LevelNotSupported);
                    }

                    // return * for the value type if we are accessing a prop of a dynamic class instance
                    ObjectValue base = node.ref.getBase();
                    return (base != null && base.isDynamic() ? cx.noType() : cx.voidType());
                }
			}
			if (type == cx.functionType())
			{
				slot = node.ref.getSlot(cx,EMPTY_TOKEN);
				if (slot != null && basetype != cx.xmlType() && basetype != cx.xmlListType())
				{
					warning( node.getPosition(), cx.input, kWarning_ScopingChangeInThis, node.ref.name, (node.base != null) ? node.base.name : "" );
				}
			}
		}
		else
		{
			// If there is no reference, then node.expr is a general
			// expression that needs to be evaluated here.            
			result = node.expr.evaluate(cx,this);
		}

		return result;
	}