public Value evaluate()

in modules/asc/src/java/macromedia/asc/semantics/FlowAnalyzer.java [2182:2514]


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

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

        PackageDefinitionNode pkgdef = node.def != null ? node.def.pkgdef : null;
        if( pkgdef != null && cx.getScopes().size() == 1 )
        {
            public_namespaces.push_back(pkgdef.publicNamespace);
            default_namespaces.push_back(pkgdef.internalNamespace);
            usednamespaces_sets.push_back(pkgdef.used_namespaces);
            used_def_namespaces_sets.push_back(pkgdef.used_def_namespaces);
            importednames_sets.push_back(pkgdef.imported_names);
        }

        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);
        }

        // First time through, initialize the compile-time constant function value.

        if (node.fun == null)
        {
        	if(node.used_namespaces == null) node.used_namespaces = new Namespaces(usednamespaces_sets.back().size());
            node.used_namespaces.addAll(usednamespaces_sets.back());  // makes a copy
        	if(node.imported_names == null) node.imported_names = new Multinames();
            node.imported_names.putAll(importednames_sets.back());  // makes a copy
            node.private_namespace = (private_namespaces.size() != 0) ? private_namespaces.back() : null;
            node.default_namespace = default_namespaces.back();
            node.public_namespace  = cx.publicNamespace(); //public_namespaces.back();

            node.fun = new ObjectValue(cx,new FunctionBuilder(),cx.functionType());
            
            boolean is_named_anon = false; 
            if( !node.isFunctionDefinition() && node.identifier != null && !"anonymous".equals(node.identifier.name) && node.isUserDefinedBody() )
            {
            	is_named_anon = true;
                node.setNamedInnerFunc(true);

            	// Create a slot in the FunctionBuilder to represent this function so that it can recursively
            	// call itself.
            	Namespaces temp_ns = new Namespaces(cx.publicNamespace());
                int method_id = node.fun.builder.Method(cx,node.fun,node.identifier.name,temp_ns,false);
                node.fun.builder.ExplicitCall(cx,node.fun,node.identifier.name,temp_ns,cx.noType(),false,false,-1,method_id,-1);
                
                cx.pushScope(node.fun);
            }

            // Save the with depth, if there is one, since the FunctionCommonNode is going to get hoisted
            // and there won't be a WithStatementNode above it anymore after hoisting.
            if( cx.statics.withDepth != -1 )
                node.with_depth = cx.statics.withDepth;

            ObjectList<ObjectValue> scope_chain = cx.getScopes();
            for(int s = scope_chain.size(); s > 0; --s  )
            {
                ObjectValue scope = scope_chain.get(s-1);
                if( scope.builder instanceof CatchBuilder ||
                    scope.builder instanceof WithBuilder ||
                    scope.builder instanceof ActivationBuilder)
                {
                    node.scope_chain = new ObjectList<ObjectValue>(scope_chain); // copy the scope chain, since the func will be hoisted
                    break;
                }
            }
            
            if( is_named_anon )
            {
            	// We can pop the scope now since it's been saved by the function.  
            	cx.popScope();
            }
            
            // fexpr_sets is a stack of sets of function expressions.
            // Each set contains the functions at a particular scope level.

            ObjectValue scope = cx.scope();
            Builder b = scope.builder;
            if (b instanceof ClassBuilder)
            {
                int size = staticfexprs_sets.last().size();
                int i;

                // Look for the current node in the set for the current scope.

                for (i = 0; i < size && staticfexprs_sets.last().get(i) != node; ++i);

                // If it is not in the set, then add it.

                if (i >= size)
                {
                    staticfexprs_sets.last().add(node);
                }
            }
            else
            {
                int size = fexprs_sets.last().size();
                int i;

                // Look for the current node in the set for the current scope.

                for (i = 0; i < size && fexprs_sets.last().get(i) != node; ++i);

                // If it is not in the set, then add it.

                if (i >= size)
                {
                    fexprs_sets.last().add(node);
                }

            }
        }
        else
        if( doingMethod() )
        {
        }
        else
        if (node.ref == null)
        {
        	if(node.used_namespaces != null)
        		usednamespaces_sets.push_back(node.used_namespaces);
        	if(node.imported_names != null)
        		importednames_sets.push_back(node.imported_names);

            // Start processing a new function. Add an empty function set to the
            // function sets.

            fexprs_sets.add(new ObjectList<FunctionCommonNode>());
            staticfexprs_sets.push_back(new ObjectList<FunctionCommonNode>());
            instanceinits_sets.push_back(new ObjectList<Node>());

            // Create a reference to the name.

            Value val = node.identifier.evaluate(cx, this);
            node.ref = ((val instanceof ReferenceValue) ? (ReferenceValue)val : null);
            node.fun.name = node.internal_name;   // ISSUE: don't know if this is necessary.

            region_name_stack.push_back(cx.debugName(region_name_stack.back(),node.ref.name,node.namespace_ids,node.kind));

            // The activation object is the compile-time model of the
            // function activation. It is different than the function
            // object, which represents the function constructor.

            node.fun.activation = new ObjectValue(cx, new ActivationBuilder(),cx.noType());

            {
                ObjectValue obj = cx.scope(cx.getScopes().size()-1);
                node.fun.activation.builder.classname = obj.builder.classname;
                node.fun.activation.name = node.internal_name;
            }

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

            // The following stacks are not actually used. They are
            // left here for their side effects.

            // ISSUE: remove references to these stacks.

            fun_name_stack.add(node.internal_name);
            max_params_stack.add(node.signature.size());
            max_locals_stack.add(node.body != null ? node.var_count : 0);
            max_temps_stack.add(node.body != null ? node.temp_count : 0);
            with_used_stack.add(0);
            exceptions_used_stack.add(0);

            if( node.use_stmts != null )
            {
                node.use_stmts.evaluate(cx,this);
            }

            rt_unresolved_sets.last().addAll(unresolved);
            unresolved.clear();

            node.signature.evaluate(cx, this);

            ce_unresolved_sets.last().addAll(unresolved);
            unresolved.clear();

            int scope_index = cx.getScopes().size()-1;
            ObjectValue obj = cx.scope(scope_index);
            if( (node.needsArguments&METHOD_Arguments) != 0 )
            {
            	ObjectValue namespace = node.default_namespace;
                if( !obj.hasName(cx,GET_TOKEN,"arguments",namespace) )
                {
                    Builder bui = obj.builder;
                    int var_id = bui.Variable(cx,obj);
                    bui.ExplicitVar(cx,obj,"arguments",namespace,cx.arrayType(),-1,-1,var_id);
                }
                else
                {
                    node.needsArguments ^= METHOD_Arguments; // don't actually need 'arguments' since there is a parameter or var with the same name
                }
            }

            boolean is_constructor = "$construct".equals(node.ref.name);

            if (is_constructor)
            {
                if (node.signature.result != null)
                {
                    cx.error(node.pos(), kError_CtorWithReturnType);
                }
            }

            if (node.body != null)
            {
                if( !node.isFunctionDefinition() )
                {
                    this_contexts.add(global_this);
                }

                int state = super_error;
                if (is_constructor)
                {
                    state = super_statement;
                }
                super_context.add(state);
                
                if (node.signature.inits != null)
                {
                    int scope_depth = cx.getScopeDepth();
                    ObjectValue iframe = cx.scope(scope_depth-2);
                    
                    // Make get & method slots invisible, only set slots will be visible.
                    if( iframe.builder instanceof InstanceBuilder )
                    	iframe.setInitOnly(true);	

                    this_contexts.push_back(init_this);
                	node.signature.inits.evaluate(cx, this);
                	this_contexts.pop_back();

                    if( iframe.builder instanceof InstanceBuilder )
                    	iframe.setInitOnly(false);	
                }

                if (is_constructor && cx.dialect(11))
                {
                	super_context.set(super_context.size()-1, super_error_es4);
                }
                
                node.body.evaluate(cx, this);

                node.temp_count = getTempCount();
                node.var_count = fun.activation.var_count-node.signature.size();

                super_context.pop_back();
                if( !node.isFunctionDefinition() )
                {
                    this_contexts.pop_back();
                }
            }
            else
            {
                StartMethod(fun_name_stack.last(), max_params_stack.last(), 0 /* no locals */);
            }

            TypeInfo type = null;
            ObjectList<TypeInfo> types = null;
            FinishMethod(cx,fun_name_stack.back(),type,types,node.fun.activation,node.needsArguments,cx.getScopes().size(),node.debug_name,node.isNative(),false, null);

            if (with_used_stack.last() != 0)
            {
                    node.setWithUsed(true);
            }
            with_used_stack.removeLast();

            if (exceptions_used_stack.last() != 0)
            {
                    node.setExceptionsUsed(true);
            }
            exceptions_used_stack.removeLast();

            fun_name_stack.removeLast();

            // Store the accumulated fexprs in this node for CodeGeneration
            node.fexprs = fexprs_sets.back();

            // Now evaluate each function expression
            this_contexts.add(global_this);
            for (Node fexpr : node.fexprs)
            {
                fexpr.evaluate(cx, this);
            }
            this_contexts.pop_back();

            instanceinits_sets.pop_back();
            staticfexprs_sets.pop_back();
            fexprs_sets.pop_back();
            cx.popScope(); // activation

            region_name_stack.pop_back();
            usednamespaces_sets.pop_back();
            importednames_sets.pop_back();
        }

        // Restore the scope chain if it was changed
        if( saved_scopes != null )
        {
            cx.swapScopeChain(saved_scopes);
        }
        // Reset the withDepth to whatever it was
        cx.statics.withDepth = savedWithDepth;

        if( pkgdef != null && cx.getScopes().size() == 1 )
        {
            public_namespaces.pop_back();
            default_namespaces.pop_back();
            usednamespaces_sets.pop_back();
            used_def_namespaces_sets.pop_back();
            importednames_sets.pop_back();
        }

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

    }