public Value evaluate()

in modules/asc/src/java/macromedia/asc/embedding/LintEvaluator.java [699:906]


	public Value evaluate( Context cx, SetExpressionNode node )
	{
		if (first_pass)
		{
			return node.args.evaluate(cx,this);
		}

        Slot slot = null;
		if( node.ref != null )
		{
			slot = node.ref.getSlot(cx,GET_TOKEN);

			// 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 (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, SET_TOKEN);
			}
			//TypeValue* dt = node->ref->getType(cx); //  this uses use-definition trees, rather than the slot's def.  Assume slot's def for warnings
			int  base_index           = node.ref.getScopeIndex(SET_TOKEN);
			int  slot_index           = node.ref.getSlotIndex(SET_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 && !(node.expr instanceof QualifiedIdentifierNode))
			{
				//if it's a qualified identifier node, then it's a member/static
				//variable on a class that is being initialized, like this:
				//public var memberVar:String = "hi";
				//this case should not have a warning!
				checkDeprecatedSlot(cx, node.expr, node.ref, slot);
			}
			
			// 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))
			{
			}
            else if (slot != null && slot.getType().getTypeValue() == cx.uintType() &&
                     node.args != null && node.args.items.size() == 1 && node.args.items.get(0) instanceof LiteralNumberNode)
            {
                LiteralNumberNode ln = (LiteralNumberNode)(node.args.items.get(0));
                if (ln.numericValue.doubleValue() < 0)
                    warning(node.getPosition(), cx.input, kWarning_NegativeUintLiteral);
            }
					
			else if ( slot == null && is_unbound_ref)
			{
                int pos = (node.expr != null ? node.expr.getPosition() : node.getPosition());
                boolean unsupported = false;
                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())
                    {
                        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 unsupportedMethodsMap 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 type : search.keySet())
                        {
                            if (type != null && type.includes(cx,searchType))
                            {
                                unsupported = true;
                                warning(pos, cx.input, kWarning_DepricatedPropertyError, node.ref.name,
                                        warningConstantsMap.get(search.get(type)));
                            }
                        }
                    }
                }

                if (unsupported == false && baseType != null ) // check for unsupported event handlers (StyleSheet.onLoad = new function() ... )
                {
                    Map<TypeValue,Integer> search = unsupportedEventsMap.get(node.ref.name);
                    if (search != null && ! search.isEmpty()) // it matches a former auto-registered event handler name
                    {
                        ObjectValue  scope = cx.scope();

                        if (baseType != null) // !!@todo: check that this dynamic var wasn't seen in an addEventListener call during first_pass
                        {
                            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 unsupportedMethodsMap 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 type : search.keySet())
                            {
                                if (type != null && type.includes(cx,searchType))  // it's defining Type matches one of the warning cases
                                {
                                    warning(pos, cx.input, kWarning_DepricatedEventHandlerError, warningConstantsMap.get(search.get(type)));
                                    unsupported = true;
                                }
                            }
                        }
                    }
                }

				ObjectValue base = node.ref.getBase();
				if ((baseType != null && baseType != cx.voidType() && baseType != cx.nullType())
					&& ((base != null && base.isFinal() && !base.isDynamic())
								|| cx.doubleType().includes(cx, baseType)
								|| cx.numberType() == baseType
								|| (cx.statics.es4_numerics && cx.decimalType() == baseType)
								|| cx.stringType() == baseType
								|| cx.booleanType() == baseType
								|| types[kMathType] == baseType))

				{
					warning(node.getPosition(), cx.input, kWarning_ClassIsSealed, getSimpleTypeName(baseType));
				}

			}
			else if (baseType == types[kTextFieldType] && "text".equals(node.ref.name))
			{
				// look for " member.text += "some text" type syntax.  The compiler will have already converted this to
				//  "member.text = member.text + "some text" by now
				Node arg1 = node.args.items.get(0);
				if (arg1 instanceof BinaryExpressionNode)
				{
					MemberExpressionNode membArg = (((BinaryExpressionNode)arg1).lhs instanceof MemberExpressionNode) ?
													(MemberExpressionNode)(((BinaryExpressionNode)arg1).lhs) :
													null;
					if (membArg != null)
					{
						MemberExpressionNode membArgBase = (membArg.base instanceof MemberExpressionNode) ? (MemberExpressionNode)(membArg.base) : null;
						ReferenceValue br = baseRef_context.back();
						if (membArgBase != null && membArgBase.ref != null && br != null && br.slot == membArgBase.ref.slot)
							warning(node.getPosition(), cx.input, kWarning_SlowTextFieldAddition);
					}
				}
			}
		}
		else
		{
			node.expr.evaluate(cx,this);
		}

		Value result = node.args.evaluate(cx,this);
		if (result == cx.nullType() && slot != null)
		{
			TypeValue t = slot.getType().getTypeValue();
			TypeValue rt = (TypeValue)result;
			if ((t != null) && (t.isNumeric(cx) || t == cx.booleanType()))
				warning(node.args.getPosition(), cx.input, kWarning_BadNullAssignment, t.name.toString());
		}
		else if (slot != null && slot.getType().getTypeValue() == cx.booleanType() && result instanceof TypeValue &&
			     result != cx.booleanType() && result != cx.noType() && result != cx.objectType())
		{
			TypeValue rt = (TypeValue)result;
			warning(node.args.getPosition(), cx.input, kWarning_BadBoolAssignment, rt.name.toString());
		}

		return result;
	}