public Value evaluate()

in modules/asc/src/java/macromedia/asc/semantics/CodeGenerator.java [3601:3892]


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

        Context cx = node.cx; // switch to original context

	// getQualifiedErrorOrigin defaults to getErrorOrigin if
	// the qualified_origin isn't set - this is used to prevent
	// naming conflicts in the debug info for authoring (i.e.,
	// multiple scripts with the name "frame1"
        setOrigin(cx.getQualifiedErrorOrigin());

        if (cx.input != null)
        {
            setPosition(cx.input.getLnNum(node.pos()),cx.input.getColPos(node.pos()),node.pos());
        }

        if (doingMethod())
        {
            boolean anon_with_identifier = node.isNamedInnerFunc(); 
            if( anon_with_identifier )
            {
                NewObject(0);
                PushWith();
            }
            NewFunctionObject(node.internal_name);
            
            if( anon_with_identifier )
            {
                if ( !node.isVoidResult() ) {
                    Dup();
                }
                GetBaseObject(cx.getScopeDepth()-frame.firstInnerScope);
                Swap();
                SetProperty(node.identifier.name, new Namespaces(cx.publicNamespace()), true, false, false, false);
                PopScope();
            }
            else
            if ( node.isVoidResult() ) {
                Pop();
            }

            return null;  // defer until the current method is done.
        }

        int savedWithDepth = cx.statics.withDepth;
        if( node.with_depth != -1)
        {
            // FCN was hoisted by an earlier pass
            cx.statics.withDepth = node.with_depth;
        }

        ObjectList<ObjectValue>saved_scopes = null;
        if( node.scope_chain != null )
        {
            saved_scopes = cx.swapScopeChain(node.scope_chain);
        }

        Slot getSlot = node.ref.getSlot(cx, GET_TOKEN);
        Slot setSlot = node.ref.getSlot(cx, SET_TOKEN);
        boolean with_this = getSlot instanceof MethodSlot || setSlot instanceof MethodSlot;

        ObjectValue fun = node.fun;
        cx.pushScope(fun.activation);

        // Do nested functions
        boolean needs_activation = false;

        if( node.fexprs.size() > 0 )
        {
            needs_activation = true;
        }
        if (node.isWithUsed())
        {
                needs_activation = true;
        }
        if (node.isExceptionsUsed())
        {
                needs_activation = true;
        }

/*
        for (int i = (node.fexprs == null) ? -1 : node.fexprs.size() - 1; i >= 0; i--)
        {
            Node fexpr = node.fexprs.get(i);
            fexpr.evaluate(cx, this);
        }
*/

        used_namespaces_sets.push_back(node.used_namespaces);

        for (FunctionCommonNode def : node.fexprs)
        {
            def.evaluate(cx, this);
        }

        // reset debug position.  nested Function evaulation above will have updated it, we need to reset to top of this function.
        if (cx.input != null)
        {
            setPosition(cx.input.getLnNum(node.pos()),cx.input.getColPos(node.pos()),node.pos());
        }

        pushStackFrame();

        frame.functionName = node.internal_name;
        frame.maxParams = node.signature.size();
        frame.maxLocals = node.body != null ? node.var_count : 0;
        frame.maxTemps = node.body != null ? node.temp_count : 0;
        frame.needsArguments = node.needsArguments;

        frame.withThis = with_this;

        frame.firstInnerScope = cx.getScopes().size()-1;
        if (with_this)
        {
            frame.firstInnerScope--;
        }

        // If there are nested functions, this will be true
        frame.activationIsExposed = needs_activation;
        frame.registerScopeIndex = needs_activation ? -1 : (cx.getScopes().size()-1);

        StartMethod(frame.functionName,frame.maxParams,frame.maxLocals,0,needs_activation,node.needsArguments);

        // If this is a constructor, then insert a call to the base constructor,
        // and the instance initializer

        if( "$construct".equals(node.ref.name) && cx.statics.es4_nullability  )
        {
        	// Must run property initializers before this, or activation scope is pushed.  Setting properties
        	// will be handled with getlocal0, setproperty and arguments will use getlocal since there can be no intervening
        	// scopes at this point (even if the method later needs an activation object)
            doCtorSetup(node, cx, needs_activation);
        }
        if (with_this)
        {
            LoadThis();
            PushScope();
        }

        // initialize local variables that are in registers.

        ObjectValue activation = node.fun.activation;
        int firstlocal = node.signature.size();
        if (node.needsArguments != 0)
        {
            firstlocal++;
        }
        int reg_offset = activation.builder.reg_offset;
        int var_offset = activation.builder.var_offset;

        if (needs_activation)
        {
            NewActivation();
            int temp_activation_reg = allocateTemp();
            activation.builder.temp_reg = temp_activation_reg;
            Dup();
            StoreRegister(reg_offset+temp_activation_reg,TYPE_none);
            PushScope();

			// create a 'local' name for the activation object for the debugger to use
			DefineSlotVariable(cx, node.internal_name, node.debug_name, node.pos(), ObjectValue.objectPrototype.type, temp_activation_reg);
        }

        if (activation.slots != null)
        {
            int base_offset = needs_activation ? var_offset : reg_offset;

            for (Slot s: activation.slots)
            {
                int index = base_offset + s.getVarIndex();
                if ( s.needsInit() &&  s.getVarIndex() >= firstlocal)
                {
                    StoreDefaultValue(cx, index, s, needs_activation);
                }
            }
        }

        if (needs_activation)
        {
            // Copy the arguments into the activation object
            int n=frame.maxParams;
            if (node.needsArguments != 0) n++;
            for (int i=0; i<n; i++)
            {
                GetActivationObject(cx.getScopes().size()-1);
                LoadRegister(i+1,TYPE_object);
                StoreVar(i);
            }
        }

        // for debug purposes dump out the list of args
        ParameterListNode parms = node.signature.parameter;
        String[] arg_names = null;
		if (parms != null)
		{
            arg_names = new String[parms.items.size()];
			for(int i = 0; i < parms.items.size(); ++i )
            {
                ParameterNode parm = parms.items.at(i);
				ReferenceValue ref;
				Slot slot;
				if (parm == null)
					; // no good
				else if ((ref = parm.ref) == null)
					; // no good
				else if ((slot = ref.getSlot(cx)) == null)
					; // no good
				else
				{
					TypeInfo expr_type = ref.getType(cx);
					DefineSlotVariable(cx, ref.name, ref.name, pos, expr_type, slot.getVarIndex());
                    arg_names[i] = ref.name;
				}
			}
		}

        if( "$construct".equals(node.ref.name) && !cx.statics.es4_nullability  )
        {
            doCtorSetup(node, cx, needs_activation);
        }

        if( node.body != null)
        {
            if( node.default_dxns != null )
            {
                node.default_dxns.evaluate(cx,this);
            }
            boolean old_in_anonymous_function = this.in_anonymous_function;
            this.in_anonymous_function = (node.isFunctionDefinition() == false); // set flag if we are processing an anonymous function
            node.body.evaluate(cx,this);
            this.in_anonymous_function = old_in_anonymous_function;
        }

        if (cx.input != null)
        {
            setPosition(cx.input.getLnNum(node.signature.pos()),cx.input.getColPos(node.signature.pos()),node.signature.pos());
        }

        // If there is a nested function, then pass the activation object so traits can be emitted
        if (!needs_activation)
            activation = null;
            // ISSUE: this logic can be more subtle. We also might need the activation
            // if there is an embedded eval or with. And we might not need the activation
            // object for all functions with nested functions

		int scope_depth = activation != null ? cx.getScopes().size() : cx.getScopes().size()-1;
		TypeInfo type = node.signature.type;
		ObjectList<TypeInfo> types = node.signature.parameter!=null?node.signature.parameter.types:null;
		node.fun.method_info = FinishMethod(cx,
				frame.functionName,
				type,
				types,
				activation,
				node.needsArguments,
				scope_depth,
				node.debug_name,
				node.isNative(),
				(currentClass instanceof InterfaceDefinitionNode),
                arg_names);

        cx.popScope();
        this.is_ctor = false;
        // We don't need this or the activation builder anymore
        node.fun.activation = null;
        // don't need the FunctionBuilder anymore either
        node.fun.builder = null;
        
        popStackFrame();

        if( saved_scopes != null )
        {
            cx.swapScopeChain(saved_scopes);
        }
        cx.statics.withDepth = savedWithDepth;

        // Call code is compiled as though register 0 is the scope
        // stack, register 1 is the current object, register 2 is the
        // args array, and registers 2 through 2+n-1 (where n is the
        // count of formal parameters) are the formal parameters.

        used_namespaces_sets.pop_back();

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