public Value evaluate()

in modules/asc/src/java/macromedia/asc/semantics/FlowAnalyzer.java [1115:1394]


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

        NodeFactory nodeFactory = cx.getNodeFactory();

        if (node.has_pragma) {
        	NumberUsage blockUsage = new NumberUsage(number_usage_stack.back());
        	number_usage_stack.push_back(blockUsage);
        }
        ObjectValue obj = cx.scope();
        boolean inside_class = false;
        if (obj.builder instanceof InstanceBuilder ||
            obj.builder instanceof ClassBuilder)
        {
            inside_class = true;
        }

        boolean inside_cinit = ( this_contexts.last() == cinit_this );

        ObjectList<DefinitionNode> hoisted_defs = new ObjectList<DefinitionNode>();
        ObjectList<Node> instance_inits = instanceinits_sets.back();

        {
            // iterate through the statements backwards to find the end point dominator

            for (int i = node.items.size() - 1; i >= 0; i--)
            {
                Node n = node.items.get(i);
                if (n != null)
                {
                    // While we are iterating backwards set aside any definitions we find,
                    // to be processed before the other statements. Handle the initializers
                    // according to their type (e.g. functions get moved to the start of
                    // statements, var initializers stay put

                    // cn: a definition might live in a labelled node
                    LabeledStatementNode label = null;
                    if (n instanceof LabeledStatementNode)
                    {
                        label = (LabeledStatementNode)n;
                        n = label.statement;
                    }
                    if (n.isDefinition())
                    {
                        DefinitionNode def = ((n instanceof DefinitionNode) ? (DefinitionNode)n : null);

                        // Eval the definition. At this point we are iterating backward
                        // (to find the end point dominator) so definitions are ordered
                        // last to first. This is weird, but should not be a problem
                        // since their initializers are evaluated in the right order.

                        if(def instanceof IncludeDirectiveNode || def instanceof ImportDirectiveNode)
                        {
                            // TODO: Remove eventually
                            /* SPECIAL CASE (for bug 124494)
                             * So all statements in an included file have IncludeDirectives
                             * wrapped around them (e.g. evaluated with the correct [sub-]context):
                             *
                             * Hoist a copy of the ID node, leave the original ID node where it is.
                             * Both hoisted definitions and left behind (non-def) statements
                             * are correctly bracketed.
                             *
                             * This is assuming that, semantically, we want non-defs in an
                             * included file (the include statement being within a classdef)
                             * to work, and not throw an error. */

                            hoisted_defs.push_back(def);
                            // node.items.set(i, nodeFactory.emptyStatement(node.pos())); // don't do this
                        }
                        else if( n.isConst() || inside_class )
                        {
                            // If definition is const, then put it and its initializer
                            // at the beginning of the block and replace current item
                            // with an empty statement.

                            hoisted_defs.push_back(def);  // C B A
//                            hoisted_defs.insert(hoisted_defs.begin(),def);
                            if (label == null)
                                node.items.set(i, nodeFactory.emptyStatement());
                            else
                                label.statement = nodeFactory.emptyStatement();
                        }
                        else
                        {
                            // Otherwise, leave the initializer at the location of the
                            // original definition and initalize the variable to its default
                            // value at the beginning of the block.

                            hoisted_defs.push_back(def);
                            if( def.attrs != null && def.attrs.hasAttribute(INTRINSIC) )
                            {
                                if (label == null)
                                    node.items.set(i, nodeFactory.emptyStatement());
                                else
                                    label.statement = nodeFactory.emptyStatement();
                            }
                            else
                            {
                                Node init = n.initializerStatement(cx);
                                if (init != null)
                                {
                                    // Put initializer(if there is one) at position
                                    // of original definition.
                                    if (label == null)
                                        node.items.set(i, init);
                                    else
                                        label.statement = init;
                                }
                                else
                                {
                                    if (label == null)
                                        node.items.set(i, nodeFactory.emptyStatement());
                                    else
                                        label.statement = nodeFactory.emptyStatement();
                                }
                            }
                        }
                    }
                    else if (!endpoint_dominator_is_set &&
                        loop_index == 0 && n.isExpressionStatement() &&
                        cx.getScopes().size() == 1 )
                    {
                        // The end point dominator is the statement that leaves
                        // the continuation value on the stack. All other results,
                        // don't need to be pushed onto the stack.

                        endpoint_dominator = n;
                        endpoint_dominator_is_set = true;
                    }
                }
            }
        }

        ObjectList<Node> inits = new ObjectList<Node>();

        {
            // Insert initializers for constants and functions at the
            // beginning of the block.

            for (int i = hoisted_defs.size() - 1; i >=0; i--) // A B C
            {
                DefinitionNode def = hoisted_defs.get(i);
                {
                    // pre-process namespace definitions and attributes

                    boolean is_static = false;
                    boolean is_intrinsic = false;

                    boolean is_include   = def instanceof IncludeDirectiveNode;
                    boolean is_namespace = def instanceof NamespaceDefinitionNode;
                    boolean is_use       = def instanceof UseDirectiveNode || def instanceof ImportDirectiveNode;
                    boolean is_const     = false;  // tbd

                    if ( is_namespace || is_const || is_use || is_include )
                    {
                        if (def.attrs != null)
                        {
                            def.attrs.evaluate(cx, this);
                            is_static = def.attrs.hasStatic;
                            is_intrinsic = def.attrs.hasIntrinsic;
                        }
                        def.evaluate(cx,this);
                    }
                    else
                    if( def.attrs != null)
                    {
                        def.attrs.evaluate(cx,this);
                        is_static = def.attrs.hasStatic;
                        is_intrinsic = def.attrs.hasIntrinsic;
                    }

                    boolean needs_init = (!is_use && !is_namespace && !is_intrinsic && def.isConst()) || inside_class;

                    if( inside_cinit && !is_static )
                    {
                        instance_inits.push_back(def);
                        if( needs_init )
                        {
                            instance_inits.push_back(def.initializerStatement(cx));
                        }
                    }
                    else
                    {
                        if( !is_use && !(def instanceof ClassDefinitionNode && needs_init)  ) // ISSUE: remove this special case check
                        {
                            inits.push_back(def);
                        }

                        if( needs_init )
                        {
                            inits.push_back(def.initializerStatement(cx));   // A B C
                        }   // otherwise, there is already a initializer at the orginal point of definition
                    }
                }
            }
        }

        {   // add the non-static inits to the beginning of the statements list

            for (int i = inits.size() - 1; i>= 0;i--)  // C B A
            {
                node.items.add(0, inits.get(i));  // A B C
            }
        }

        {
            // Now rip through the statements

            for (Node n : node.items)
            {
                if (n == endpoint_dominator)
                {
                    // This statement is the end point dominator, therefore
                    // set the define_cv flag so the evaluator will know that
                    // this is an implicit assignment to _cv and will create
                    // a new definition for it.

                    define_cv = true;
                }
                else if (!endpoint_dominator_is_set)
                {
                    // This happens when there is no statement that leaves a
                    // continuation value on the stack. In this case, an
                    // empty value is pushed onto the stack at start of the
                    // program.

                    define_cv = true;
                    endpoint_dominator_is_set = true;
                }
                else
                {
                    // This statement is not the end point dominator, and
                    // The end point dominator has been set, then do nothing
                }

                if (n != null)
                {
                    if (!doingMethod() && !n.isDefinition())
                    {
                        // We are done with definitions, which means we are doing
                        // program statements.
                        StartMethod(fun_name_stack.last(), max_params_stack.last(),
                        max_locals_stack.last(), max_temps_stack.last(),
                        false, 0);
                    }

                    n.evaluate(cx, this);
                }
            }

            if (!doingMethod() )  // If still not doing method, then start doing it now.
                                 // This happens when you have a block with only definitions
            {
                StartMethod(fun_name_stack.last(), max_params_stack.last(),
                    max_locals_stack.last(), max_temps_stack.last(), false, 0);
                // Now we are doing a method
            }

        }
/*
        if( node.is_block )
        {
            usednamespaces_sets.back().pop_back();
            default_namespaces.pop_back();
        }
*/
        if (node.has_pragma) {
        	node.numberUsage = number_usage_stack.back();
        	number_usage_stack.pop_back();
        }
        if (debug)
        {
            System.out.print("\n// -StatementListNode");
        }
        return null;
    }