public Value evaluate()

in modules/asc/src/java/macromedia/asc/semantics/ConstantEvaluator.java [841:1033]


    public Value evaluate(Context cx, SetExpressionNode node)
    {
        // Without a type annotation, the expected type of the definition
        // is the union of types of all uses of this definition, except if
        // this is an indexed put, then it is Object because we can't be
        // sure we have seen all assignments.

        if (node.base == null && !node.expr.isLValue())
        {
            cx.error(node.pos(),kError_AssignmentToNonRefVar);
        }
        else
        {
            if (node.ref != null)
            {
                if(node.is_initializer)
            	{
	                node.ref.calcUseDefinitions(cx, rch_bits);
	                if (!node.ref.usedBeforeInitialized())
	                {
	                	// If the slot is set before it is declared/initialized we need to init
	                	// it at the top of the method to get the types to agree at branch targets
	                	// This happens with code like:
	                	//
	                	//   if( something() )
	                	//     x = "blah";
	                	//   var x : String = "hi";
	                	//
	                	// We need to init this at the top of the method, otherwise the types for
	                	// x at the end of the if block would be * and String, which wouldn't match
	                	// and would cause a verify error.
	                    Slot s = node.ref.getSlot(cx,GET_TOKEN);
	                    if (s != null)
	                        s.setNeedsInit(true);
	                }
            	}
            	
                Slot slot = node.ref.getSlot(cx,SET_TOKEN);

                node.ref.getType(cx,SET_TOKEN);

                if( slot != null )
                {
                    // need to check var_index to see if this is a setter.  In the case of slots inherited during abc import,
                    //  this will only be accurate for the original slot
                    Slot origSlot = slot;

                    if( origSlot.getVarIndex() < 0 && size(slot.getTypes()) == 1 )
                    {
                        node.args.addType(slot.getTypes().get(0)); // setter, expected type is param type
                    }
                    else
                    {
                        node.args.addType(slot.getType());
                    }
                }
                else
                {
                    node.args.addType(cx.noType().getDefaultTypeInfo());
                }

               
            }
            else if( node.base != null && node.getMode()==LEFTBRACKET_TOKEN )
            {
                node.expr.evaluate(cx, this);
                TypeInfo t = cx.noType().getDefaultTypeInfo();
                if( node.base.type != null )
                {
                    TypeValue tv = node.base.type.getTypeValue();
                    t = tv.indexed_type != null ? tv.indexed_type.getDefaultTypeInfo() : cx.noType().getDefaultTypeInfo();
                }
                node.args.addType(t);
            }
            else
            {
                node.expr.evaluate(cx, this); // Only do this if there is no ref.
                node.args.addType(cx.noType().getDefaultTypeInfo());
            }
        }

//        rch_bits = rch_bits & ~ node.gen_bits;   // temporarily turn off the current gen bits

        Value val = node.args.evaluate(cx, this);
        TypeInfo type = val != null ? val.getType(cx) : cx.noType().getDefaultTypeInfo();

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

            int rchkill_bits_count = BitSet.and_count(rch_bits, node.getKillBits());  // number of kill bits that reach this definition, should be zero
            int scope_index = node.ref.getScopeIndex(GET_TOKEN);
            int base_index = cx.getScopes().size()-1;

            if (slot != null && slot.isConst() && slot.getType().getTypeValue() == cx.typeType())
            {
                Node firstArg = node.args.items.get(0);
                // check if its the synthetic assignment invented for a CDN.  Authors can't assing a var directly to a CDN
                if (!(firstArg instanceof ClassDefinitionNode))
                {
                    if (slot.getObjectValue() != null) // slot will only have a value if this is a class slot
                    {
                        cx.error(node.pos(), kError_AssignmentToDefinedClass, node.ref.name);
                    }
                }
            }
            else if (slot != null && slot.isConst() && slot.getType().getTypeValue() == cx.functionType())
            {
                Node firstArg = node.args.items.get(0);

                // check if its the synthetic assignment invented for a FDN.
                if (!(firstArg instanceof FunctionCommonNode && ((FunctionCommonNode)firstArg).def != null) )
                {
                    // if the base type is XML or XMLList, ignore.  The prop may actually evaluate to a non-function at runtime (for instance, .name)
                    boolean isXMLProp = false;
                    ObjectValue base = node.ref.getBase();
                    if (base != null &&
                       (base.getType(cx).getTypeValue() == cx.xmlType() ||
                        base.getType(cx).getTypeValue() == cx.xmlListType()))
                    {
                            isXMLProp = true;
                    }
                    if (!isXMLProp && slot.getObjectValue() != null)
                    {
                        cx.error(node.pos(), kError_AssignmentToDefinedFunction, node.ref.name);
                    }
                }
            }
            else if( slot != null && slot.isConst() && (slot.isImported() || scope_index != base_index || val.hasValue() || rchkill_bits_count > 0) )
            {
                cx.error(node.pos(), kError_AssignmentToConstVar);
            }
            else if( cx.useStaticSemantics() && slot == null )
            {
                // If there is no set but there is a get, then the property is read only. Post an error.
                slot = node.ref.getSlot(cx,GET_TOKEN);
                if ( slot != null )
                {
                    // slot will only have a value if this is a slot for a non-anonymous function
                    if( slot.getType() != null && slot.getType().getTypeValue() == cx.functionType() && slot.getObjectValue() != null )
                    {
                        Node firstArg = node.args.items.get(0);
                        CoerceNode cn = (firstArg instanceof CoerceNode) ? (CoerceNode)firstArg : null;
                        if ( !firstArg.isSynthetic() || (cn != null && !(cn.expr instanceof FunctionCommonNode) ) ) // its not the synthetic assignment invented for a FDN.  Authors can't assing a var directly to a FCN
                        {
                            boolean isXMLProp = false;
                            ObjectValue base = node.ref.getBase();
                            if (base != null &&
                               (base.getType(cx).getTypeValue() == cx.xmlType() ||
                                base.getType(cx).getTypeValue() == cx.xmlListType()))
                            {
                                isXMLProp = true;
                            }
                            if (!isXMLProp)
                            {
                                int pos = node.pos() == 0 ? node.expr.pos() : node.pos();
                                cx.error(pos, kError_AssignmentToDefinedFunction, node.ref.name);
                            }
                        }
                    }
                    else
                    {
                        cx.error(node.pos(), kError_PropertyIsReadOnly);
                    }
                }
                else
                {
                    ObjectValue base = node.ref.getBase();
                    //  Note: only global Functions are dynamic, but methods of a class are MethodClosures, a non-dynamic subclass of Function.
                    if( base != null && (!base.isDynamic() || (base.getType(cx).getTypeValue() == cx.functionType() && !(base.builder instanceof GlobalBuilder)) ) )
                    {
                        if (base.hasNameUnqualified(cx, node.ref.name, GET_TOKEN))
                            cx.error(node.expr.pos(), kError_InaccessiblePropertyReference, node.ref.name, base.getType(cx).getName(cx).toString());
                        else
                            cx.error(node.expr.pos(), kError_UndefinedProperty,node.ref.name,base.getType(cx).getName(cx).toString());
                    }
                }
            }
        }

        cx.setDefType(node.gen_bits, type);

        rch_bits = reset_set(rch_bits, node.getKillBits(), node.getGenBits());

        if (node.ref != null)
        {
            node.ref.calcUseDefinitions(cx, rch_bits);
        }

        node.value_type = type;   // for use at code gen time.

        return val;
    }