public Value evaluate()

in modules/asc/src/java/macromedia/asc/semantics/CodeGenerator.java [1149:1456]


    public Value evaluate(Context cx, SetExpressionNode node)
    {
        if (debug)
        {
            System.out.print("\n// +SetExpression");
        }

        int temp_val_reg = 0;

        boolean is_qualified = node.isQualified();
        boolean is_attribute = node.isAttributeIdentifier();
        boolean is_super = node.isSuper();

        if( node.getMode() == DOUBLEDOT_TOKEN )
        {
            // work in progress
            cx.internalError("Descendant assigment not yet supported");
        }
        else
        if( node.ref == null )
        {
            int reg_offset = -1;
            // Compute the name
            node.expr.evaluate(cx,this);

            boolean is_constinit = is_ctor&&node.isThis();

            if ( node.getIdentifier() == null && (node.getMode() == EMPTY_TOKEN /*synthetic*/ || node.getMode() == LEFTBRACKET_TOKEN) )
            {

                // Push the value on the stack

                node.args.evaluate(cx, this);
                reg_offset = getRegisterOffset(cx);
                if (!node.void_result)
                {
                    temp_val_reg = allocateTemp();
                    Dup();
                    StoreRegister(reg_offset+temp_val_reg,cx.noType().getTypeId());
                }
                SetProperty(is_qualified, is_super, is_attribute, used_namespaces_sets.back(),is_constinit);
            }
            else
            if( node.getIdentifier() != null )
            {
                QualifiedExpressionNode qen = node.getIdentifier() instanceof QualifiedExpressionNode ? (QualifiedExpressionNode) node.getIdentifier() : null;
                if( qen != null )
                {

                    qen.expr.evaluate(cx,this);
                    if( qen.qualifier != null )
                    {
                        ToString();  // must be string
                    }

                    node.args.evaluate(cx,this);
                    reg_offset = getRegisterOffset(cx);
                    if( !node.void_result )
                    {
                        temp_val_reg = allocateTemp();
                        Dup();
                        StoreRegister(reg_offset+temp_val_reg,cx.noType().getTypeId());
                    }

                    if( qen.nss != null )
                    {
                        SetProperty(false/*is_qualified*/, is_super, is_attribute, qen.nss,is_constinit);
                    }
                    else
                    if( qen.qualifier != null )
                    {
                        SetProperty(true/*is_qualified*/, is_super, is_attribute, used_namespaces_sets.back(),is_constinit);
                    }
                    else
                    {
                        SetProperty(false/*is_qualified*/, is_super, is_attribute, used_namespaces_sets.back(),is_constinit);
                    }
                }
                else
                {
                    node.args.evaluate(cx,this);
                    reg_offset = getRegisterOffset(cx);
                    if( !node.void_result )
                    {
                        temp_val_reg = allocateTemp();
                        Dup();
                        StoreRegister(reg_offset+temp_val_reg,cx.noType().getTypeId());
                    }

                    SetProperty(node.getIdentifier().name, is_super, is_attribute);
                }
            }
            else
            {
                cx.internalError(node.pos(),"internal error: lhs is not a reference");
            }

            if (!node.void_result)
            {
                LoadRegister(reg_offset+temp_val_reg,cx.noType().getTypeId());
                freeTemp(temp_val_reg); // temp_val_reg
            }
        }
        else
        {
            Slot slot                = node.ref.getSlot(cx,SET_TOKEN);
            TypeInfo expr_type       = node.ref.getType(cx);
            int  base_index          = node.ref.getScopeIndex(SET_TOKEN);
            int  slot_index          = node.ref.getSlotIndex(SET_TOKEN);
            int  scope_depth         = cx.getScopes().size()-1;
            
            int reg_offset = getRegisterOffset(cx);
            int var_offset = cx.scope(scope_depth).builder.var_offset;

            Builder bui                  = base_index>0?cx.scope(base_index).builder:null; // get the builder from lexical scope, null if object reference

            boolean is_constinit         = node.is_constinit?true:(is_ctor&&node.isThis())?true:(bui instanceof InstanceBuilder)?true:false;
            boolean is_const             = slot!=null?slot.isConst():false;

            boolean is_localref          = isLocalScope(cx, base_index);
            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( is_unbound_ref )
            {
                // If it is a global ref, then the base object is not yet on the
                // stack. Push it now

                if( is_globalref )
                {
                    GetGlobalScope();
                }

                // Push the value on the stack

                node.args.evaluate(cx,this);

                // See if we can tell if the reference is dynamic or not.
                // This is only possible when it is a dot reference, but
                // we don't worry about that here, to simplify

/*  runtime error
                ObjectValue bobj = node.ref.getBase();
                TypeValue btyp = bobj != null ? bobj.getType(cx) : cx.noType();

                if (btyp.isFinal() && !btyp.isDynamic())
                {
                    cx.error(node.pos(), kError_UnknownPropertyInNonDynamicInstance, node.ref.name);
                }
*/
                {
                    if (!node.void_result)
                    {
                        Dup();
                        temp_val_reg = allocateTemp();
                        StoreRegister(reg_offset+temp_val_reg, expr_type.getTypeId());
                    }
                    SetProperty(node.ref.name, node.ref.getImmutableNamespaces(), node.ref.isQualified(), is_super, is_attribute, is_constinit);
                }

                if (!node.void_result)
                {
                    LoadRegister(reg_offset+temp_val_reg, expr_type.getTypeId());
                    freeTemp(temp_val_reg);  // temp_val_reg
                }
            }
            else if (is_globalref)
            {
                // Found, global variable
                int varIndex = slot.getVarIndex();
                if (slot.declaredBy != cx.scope(0))
                {
                    varIndex = -1;
                }

                if (slot.getMethodID() >= 0 || varIndex < 0) // Need to put global on stack
                {
                    FindProperty(node.ref.name,node.ref.getImmutableNamespaces(),node.ref.isQualified(),is_super,is_attribute);
                }
                else
                if( is_const )
                {
                    GetBaseObject(0);
                }

                // Push the value

                node.args.evaluate(cx,this);

                if( !node.void_result )
                {
                    Dup();
                    temp_val_reg = allocateTemp();
                    StoreRegister(reg_offset+temp_val_reg,expr_type.getTypeId());
                }
   
                if( slot.getMethodID() >= 0  && cx.globalScope() == slot.declaredBy) // If it is a setter, invoke it.
                {
                    InvokeMethod(false/*is_virtual*/,GetMethodInfo(slot.getMethodName()), 1);
                    
                    //  callstatic's semantics leave a value on the stack; a void setter 
                    //  doesn't return anything, so pop this pseudo return value to keep
                    //  the stack balanced.
                    if ( node.void_result )
                    	Pop();
                }
                else // If it is a variable and we know the index, then store it
                if( varIndex >= 0 && !is_const)
                {
                    StoreGlobal(varIndex,expr_type.getTypeId());
                }
                else // Otherwise, just do a generic store global by name
                {
                    SetProperty(node.ref.name, node.ref.getImmutableNamespaces(), node.ref.isQualified(), is_super, is_attribute, is_constinit);
                }

                if( !node.void_result )
                {
                    LoadRegister(reg_offset+temp_val_reg,expr_type.getTypeId());
                    freeTemp(temp_val_reg);  // temp_val_reg
                }
            }
            else if (is_localref)
            {
                // Found, local variable

                {
                    if( is_const && !is_constinit )
                    {
                        PushString("Illegal write to local const " + node.ref.name);
                        Throw();
                    }

                    if( slot.getMethodID() >= 0 || frame.registerScopeIndex != base_index)
                    {
                        GetActivationObject(base_index);
                    }
                    node.args.evaluate(cx,this);
                    if (!node.void_result)
                    {
                        Dup();
                        temp_val_reg = allocateTemp();
                        StoreRegister(reg_offset+temp_val_reg, expr_type.getTypeId());
                    }

                    if( slot.getMethodID() >= 0 )
                    {
                        InvokeMethod(true,slot.getMethodID(),1);
                    }
                    else
                    {
                        // issue this CheckType is too conservative
                        // explicit coerce before setting a local, in case VM doesn't know
                        // the type that we know here. (e.g. calling through an interface)
                        CheckType(slot.getType().getName(cx));
                        if (frame.registerScopeIndex != base_index)
                        {
                                StoreVar(var_offset+slot.getVarIndex());
                        }
                        else
                        {
                            //CheckType(slot.getType().name);
                            StoreRegister(reg_offset+slot.getVarIndex(),expr_type.getTypeId(),node.ref.name);
                        }
                    }

                    if (!node.void_result)
                    {
                        LoadRegister(reg_offset+temp_val_reg, expr_type.getTypeId());
                        freeTemp(temp_val_reg);  // temp_val_reg
                    }
                }
            }
            else // is dot ref or lexical ref (not global or local)
            {
                // Found. Push the slot index.

                ObjectValue base = node.ref.getBase();
                base = base != null ? base : cx.scope(node.ref.getScopeIndex());

                node.args.evaluate(cx, this);
                if (!node.void_result)
                {
                    Dup();
                    temp_val_reg = allocateTemp();
                    StoreRegister(reg_offset+temp_val_reg, expr_type.getTypeId());
                }

                SetProperty(node.ref.name, node.ref.getImmutableNamespaces(),node.ref.isQualified(),is_super,is_attribute, is_constinit);

                if (!node.void_result)
                {
                    LoadRegister(reg_offset+temp_val_reg, expr_type.getTypeId());
                    freeTemp(temp_val_reg);  // temp_val_reg
                }
            }
        }

        if (debug)
        {
            System.out.print("\n// -SetExpression");
        }
        return null;
    }