2003/05/12 05:31:48
[org.ibex.core.git] / src / org / mozilla / javascript / NodeTransformer.java
diff --git a/src/org/mozilla/javascript/NodeTransformer.java b/src/org/mozilla/javascript/NodeTransformer.java
deleted file mode 100644 (file)
index e73fdc5..0000000
+++ /dev/null
@@ -1,743 +0,0 @@
-/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
- *\r
- * The contents of this file are subject to the Netscape Public\r
- * License Version 1.1 (the "License"); you may not use this file\r
- * except in compliance with the License. You may obtain a copy of\r
- * the License at http://www.mozilla.org/NPL/\r
- *\r
- * Software distributed under the License is distributed on an "AS\r
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr\r
- * implied. See the License for the specific language governing\r
- * rights and limitations under the License.\r
- *\r
- * The Original Code is Rhino code, released\r
- * May 6, 1999.\r
- *\r
- * The Initial Developer of the Original Code is Netscape\r
- * Communications Corporation.  Portions created by Netscape are\r
- * Copyright (C) 1997-1999 Netscape Communications Corporation. All\r
- * Rights Reserved.\r
- *\r
- * Contributor(s): \r
- * Norris Boyd\r
- * Roger Lawrence\r
- * Mike McCabe\r
- *\r
- * Alternatively, the contents of this file may be used under the\r
- * terms of the GNU Public License (the "GPL"), in which case the\r
- * provisions of the GPL are applicable instead of those above.\r
- * If you wish to allow use of your version of this file only\r
- * under the terms of the GPL and not to allow others to use your\r
- * version of this file under the NPL, indicate your decision by\r
- * deleting the provisions above and replace them with the notice\r
- * and other provisions required by the GPL.  If you do not delete\r
- * the provisions above, a recipient may use your version of this\r
- * file under either the NPL or the GPL.\r
- */\r
-\r
-package org.mozilla.javascript;\r
-\r
-import java.util.Hashtable;\r
-import java.util.Stack;\r
-import java.util.Vector;\r
-\r
-/**\r
- * This class transforms a tree to a lower-level representation for codegen.\r
- *\r
- * @see Node\r
- * @author Norris Boyd\r
- */\r
-\r
-public class NodeTransformer {\r
-    \r
-    /**\r
-     * Return new instance of this class. So that derived classes\r
-     * can override methods of the transformer.\r
-     */\r
-    public NodeTransformer newInstance() {\r
-        return new NodeTransformer();\r
-    }\r
-    \r
-    public IRFactory createIRFactory(TokenStream ts, Scriptable scope) {\r
-        return new IRFactory(ts, scope);\r
-    }\r
-\r
-    public Node transform(Node tree, Node enclosing, TokenStream ts,\r
-                          Scriptable scope) \r
-    {\r
-        loops = new Stack();\r
-        loopEnds = new Stack();\r
-        inFunction = tree.getType() == TokenStream.FUNCTION;\r
-        if (!inFunction) {\r
-            addVariables(tree, getVariableTable(tree));\r
-        }\r
-        irFactory = createIRFactory(ts, scope);\r
-\r
-        // to save against upchecks if no finally blocks are used.\r
-        boolean hasFinally = false;\r
-\r
-        PreorderNodeIterator iterator = tree.getPreorderIterator();\r
-        Node node;\r
-        while ((node = iterator.nextNode()) != null) {\r
-            int type = node.getType();\r
-\r
-          typeswitch:\r
-            switch (type) {\r
-\r
-              case TokenStream.FUNCTION:\r
-                if (node == tree) {\r
-                    // Add the variables to variable table, the\r
-                    // parameters were added earlier.\r
-                    VariableTable vars = getVariableTable(tree);\r
-                    addVariables(tree, vars);\r
-\r
-                    // Add return to end if needed.\r
-                    Node stmts = node.getLastChild();\r
-                    Node lastStmt = stmts.getLastChild();\r
-                    if (lastStmt == null ||\r
-                        lastStmt.getType() != TokenStream.RETURN)\r
-                    {\r
-                        stmts.addChildToBack(new Node(TokenStream.RETURN));\r
-                    }\r
-\r
-                } else {\r
-                    FunctionNode fnNode = (FunctionNode)\r
-                                          node.getProp(Node.FUNCTION_PROP);\r
-                    if (inFunction) {\r
-                        // Functions containing other functions require \r
-                        //  activation objects \r
-                        ((FunctionNode) tree).setRequiresActivation(true);\r
-\r
-                        // Nested functions must check their 'this' value to\r
-                        //  insure it is not an activation object:\r
-                        //  see 10.1.6 Activation Object\r
-                        fnNode.setCheckThis(true);\r
-                    }\r
-                    addParameters(fnNode);\r
-                    NodeTransformer inner = newInstance();\r
-                    fnNode = (FunctionNode) \r
-                            inner.transform(fnNode, tree, ts, scope);\r
-                    node.putProp(Node.FUNCTION_PROP, fnNode);\r
-                    Vector fns = (Vector) tree.getProp(Node.FUNCTION_PROP);\r
-                    if (fns == null) {\r
-                        fns = new Vector(7);\r
-                        tree.putProp(Node.FUNCTION_PROP, fns);\r
-                    }\r
-                    fns.addElement(fnNode);\r
-                }\r
-                break;\r
-\r
-              case TokenStream.LABEL:\r
-              {\r
-                Node child = node.getFirstChild();\r
-                node.removeChild(child);\r
-                String id = child.getString();\r
-\r
-                // check against duplicate labels...\r
-                for (int i=loops.size()-1; i >= 0; i--) {\r
-                    Node n = (Node) loops.elementAt(i);\r
-                    if (n.getType() == TokenStream.LABEL) {\r
-                        String otherId = (String)n.getProp(Node.LABEL_PROP);\r
-                        if (id.equals(otherId)) {\r
-                            String message = Context.getMessage1(\r
-                                "msg.dup.label", id);\r
-                            reportMessage(Context.getContext(), message, node, \r
-                                          tree, true, scope);\r
-                            break typeswitch;\r
-                        }\r
-                    }\r
-                }\r
-\r
-                node.putProp(Node.LABEL_PROP, id);\r
-\r
-                /* Make a target and put it _after_ the following\r
-                 * node.  And in the LABEL node, so breaks get the\r
-                 * right target.\r
-                 */\r
-                Node breakTarget = new Node(TokenStream.TARGET);\r
-                Node parent = iterator.getCurrentParent();\r
-                Node next = node.getNextSibling();\r
-                while (next != null &&\r
-                       (next.getType() == TokenStream.LABEL ||\r
-                        next.getType() == TokenStream.TARGET))\r
-                    next = next.getNextSibling();\r
-                if (next == null)\r
-                    break;\r
-                parent.addChildAfter(breakTarget, next);\r
-                node.putProp(Node.BREAK_PROP, breakTarget);\r
-                \r
-                if (next.getType() == TokenStream.LOOP) {\r
-                    node.putProp(Node.CONTINUE_PROP, \r
-                                 next.getProp(Node.CONTINUE_PROP));\r
-                }   \r
-\r
-                loops.push(node);\r
-                loopEnds.push(breakTarget);\r
-\r
-                break;\r
-              }\r
-\r
-              case TokenStream.SWITCH:\r
-              {\r
-                Node breakTarget = new Node(TokenStream.TARGET);\r
-                Node parent = iterator.getCurrentParent();\r
-                parent.addChildAfter(breakTarget, node);\r
-\r
-                // make all children siblings except for selector\r
-                Node sib = node;\r
-                Node child = node.getFirstChild().next;\r
-                while (child != null) {\r
-                    Node next = child.next;\r
-                    node.removeChild(child);\r
-                    parent.addChildAfter(child, sib);\r
-                    sib = child;\r
-                    child = next;\r
-                }\r
-\r
-                node.putProp(Node.BREAK_PROP, breakTarget);\r
-                loops.push(node);\r
-                loopEnds.push(breakTarget);\r
-                node.putProp(Node.CASES_PROP, new Vector(13));\r
-                break;\r
-              }\r
-\r
-              case TokenStream.DEFAULT:\r
-              case TokenStream.CASE:\r
-              {\r
-                Node sw = (Node) loops.peek();\r
-                if (type == TokenStream.CASE) {\r
-                    Vector cases = (Vector) sw.getProp(Node.CASES_PROP);\r
-                    cases.addElement(node);\r
-                } else {\r
-                    sw.putProp(Node.DEFAULT_PROP, node);\r
-                }\r
-                break;\r
-              }\r
-\r
-              case TokenStream.NEWLOCAL : {\r
-                    Integer localCount\r
-                            = (Integer)(tree.getProp(Node.LOCALCOUNT_PROP));\r
-                    if (localCount == null) {\r
-                        tree.putProp(Node.LOCALCOUNT_PROP, new Integer(1));\r
-                    }\r
-                    else {\r
-                        tree.putProp(Node.LOCALCOUNT_PROP,\r
-                                        new Integer(localCount.intValue() + 1));\r
-                    }\r
-                }\r
-                break;\r
-\r
-              case TokenStream.LOOP:\r
-                loops.push(node);\r
-                loopEnds.push(node.getProp(Node.BREAK_PROP));\r
-                break;\r
-\r
-              case TokenStream.WITH:\r
-              {\r
-                if (inFunction) {\r
-                    // With statements require an activation object.\r
-                    ((FunctionNode) tree).setRequiresActivation(true);\r
-                }\r
-                loops.push(node);\r
-                Node leave = node.getNextSibling();\r
-                if (leave.getType() != TokenStream.LEAVEWITH) {\r
-                    throw new RuntimeException("Unexpected tree");\r
-                }\r
-                loopEnds.push(leave);\r
-                break;\r
-              }\r
-\r
-              case TokenStream.TRY:\r
-              {\r
-                Node finallytarget = (Node)node.getProp(Node.FINALLY_PROP);\r
-                if (finallytarget != null) {\r
-                    hasFinally = true;\r
-                    loops.push(node);\r
-                    loopEnds.push(finallytarget);\r
-                }\r
-                Integer localCount\r
-                        = (Integer)(tree.getProp(Node.LOCALCOUNT_PROP));\r
-                if (localCount == null) {\r
-                    tree.putProp(Node.LOCALCOUNT_PROP, new Integer(1));\r
-                }\r
-                else {\r
-                    tree.putProp(Node.LOCALCOUNT_PROP,\r
-                                 new Integer(localCount.intValue() + 1));\r
-                }\r
-                break;\r
-              }\r
-\r
-              case TokenStream.TARGET:\r
-              case TokenStream.LEAVEWITH:\r
-                if (!loopEnds.empty() && loopEnds.peek() == node) {\r
-                    loopEnds.pop();\r
-                    loops.pop();\r
-                }\r
-                break;\r
-\r
-              case TokenStream.RETURN:\r
-              {\r
-                /* If we didn't support try/finally, it wouldn't be\r
-                 * necessary to put LEAVEWITH nodes here... but as\r
-                 * we do need a series of JSR FINALLY nodes before\r
-                 * each RETURN, we need to ensure that each finally\r
-                 * block gets the correct scope... which could mean\r
-                 * that some LEAVEWITH nodes are necessary.\r
-                 */\r
-                if (!hasFinally)\r
-                    break;     // skip the whole mess.\r
-\r
-                Node parent = iterator.getCurrentParent();\r
-                for (int i=loops.size()-1; i >= 0; i--) {\r
-                    Node n = (Node) loops.elementAt(i);\r
-                    int elemtype = n.getType();\r
-                    if (elemtype == TokenStream.TRY) {\r
-                        Node jsrnode = new Node(TokenStream.JSR);\r
-                        Object jsrtarget = n.getProp(Node.FINALLY_PROP);\r
-                        jsrnode.putProp(Node.TARGET_PROP, jsrtarget);\r
-                        parent.addChildBefore(jsrnode, node);\r
-                    } else if (elemtype == TokenStream.WITH) {\r
-                        parent.addChildBefore(new Node(TokenStream.LEAVEWITH),\r
-                                              node);\r
-                    }\r
-                }\r
-                break;\r
-              }\r
-\r
-              case TokenStream.BREAK:\r
-              case TokenStream.CONTINUE:\r
-              {\r
-                Node loop = null;\r
-                boolean labelled = node.hasChildren();\r
-                String id = null;\r
-                if (labelled) {\r
-                    /* get the label */\r
-                    Node child = node.getFirstChild();\r
-                    id = child.getString();\r
-                    node.removeChild(child);\r
-                }\r
-\r
-                int i;\r
-                Node parent = iterator.getCurrentParent();\r
-                for (i=loops.size()-1; i >= 0; i--) {\r
-                    Node n = (Node) loops.elementAt(i);\r
-                    int elemtype = n.getType();\r
-                    if (elemtype == TokenStream.WITH) {\r
-                        parent.addChildBefore(new Node(TokenStream.LEAVEWITH),\r
-                                              node);\r
-                    } else if (elemtype == TokenStream.TRY) {\r
-                        Node jsrFinally = new Node(TokenStream.JSR);\r
-                        Object jsrTarget = n.getProp(Node.FINALLY_PROP);\r
-                        jsrFinally.putProp(Node.TARGET_PROP, jsrTarget);\r
-                        parent.addChildBefore(jsrFinally, node);\r
-                    } else if (!labelled &&\r
-                               (elemtype == TokenStream.LOOP ||\r
-                                (elemtype == TokenStream.SWITCH &&\r
-                                 type == TokenStream.BREAK)))\r
-                    {\r
-                        /* if it's a simple break/continue, break from the\r
-                         * nearest enclosing loop or switch\r
-                         */\r
-                        loop = n;\r
-                        break;\r
-                    } else if (labelled &&\r
-                               elemtype == TokenStream.LABEL &&\r
-                               id.equals((String)n.getProp(Node.LABEL_PROP)))\r
-                    {\r
-                        loop = n;\r
-                        break;\r
-                    }\r
-                }\r
-                int propType = type == TokenStream.BREAK\r
-                               ? Node.BREAK_PROP\r
-                               : Node.CONTINUE_PROP;\r
-                Node target = loop == null \r
-                              ? null\r
-                              : (Node) loop.getProp(propType);\r
-                if (loop == null || target == null) {\r
-                    String message;\r
-                    if (!labelled) {\r
-                        // didn't find an appropriate target\r
-                        if (type == TokenStream.CONTINUE) {\r
-                            message = Context.getMessage\r
-                                ("msg.continue.outside", null);\r
-                        } else {\r
-                            message = Context.getMessage\r
-                                ("msg.bad.break", null);\r
-                        }\r
-                    } else if (loop != null) {\r
-                        message = Context.getMessage0("msg.continue.nonloop");\r
-                    } else {\r
-                        Object[] errArgs = { id };\r
-                        message = Context.getMessage\r
-                            ("msg.undef.label", errArgs);\r
-                    }\r
-                    reportMessage(Context.getContext(), message, node, \r
-                                  tree, true, scope);\r
-                    node.setType(TokenStream.NOP);\r
-                    break;\r
-                }\r
-                node.setType(TokenStream.GOTO);\r
-                node.putProp(Node.TARGET_PROP, target);\r
-                break;\r
-              }\r
-\r
-              case TokenStream.CALL:\r
-                if (isSpecialCallName(tree, node))\r
-                    node.putProp(Node.SPECIALCALL_PROP, Boolean.TRUE);\r
-                visitCall(node, tree);\r
-                break;\r
-\r
-              case TokenStream.NEW:\r
-                if (isSpecialCallName(tree, node))\r
-                    node.putProp(Node.SPECIALCALL_PROP, Boolean.TRUE);\r
-                visitNew(node, tree);\r
-                break;\r
-\r
-              case TokenStream.DOT:\r
-              {\r
-                Node right = node.getLastChild();\r
-                right.setType(TokenStream.STRING);\r
-                break;\r
-              }\r
-\r
-              case TokenStream.EXPRSTMT:\r
-                node.setType(inFunction ? TokenStream.POP : TokenStream.POPV);\r
-                break;\r
-\r
-              case TokenStream.OBJECT:\r
-              {\r
-                Vector regexps = (Vector) tree.getProp(Node.REGEXP_PROP);\r
-                if (regexps == null) {\r
-                    regexps = new Vector(3);\r
-                    tree.putProp(Node.REGEXP_PROP, regexps);\r
-                }\r
-                regexps.addElement(node);\r
-                Node n = new Node(TokenStream.OBJECT);\r
-                iterator.replaceCurrent(n);\r
-                n.putProp(Node.REGEXP_PROP, node);\r
-                break;\r
-              }\r
-\r
-              case TokenStream.VAR:\r
-              {\r
-                ShallowNodeIterator i = node.getChildIterator();\r
-                Node result = new Node(TokenStream.BLOCK);\r
-                while (i.hasMoreElements()) {\r
-                    Node n = i.nextNode();\r
-                    if (!n.hasChildren())\r
-                        continue;\r
-                    Node init = n.getFirstChild();\r
-                    n.removeChild(init);\r
-                    Node asn = (Node) irFactory.createAssignment(\r
-                                        TokenStream.NOP, n, init, null,\r
-                                        false);\r
-                    Node pop = new Node(TokenStream.POP, asn, node.getDatum());\r
-                    result.addChildToBack(pop);\r
-                }\r
-                iterator.replaceCurrent(result);\r
-                break;\r
-              }\r
-\r
-              case TokenStream.DELPROP:\r
-              case TokenStream.SETNAME:\r
-              {\r
-                if (!inFunction || inWithStatement())\r
-                    break;\r
-                Node bind = node.getFirstChild();\r
-                if (bind == null || bind.getType() != TokenStream.BINDNAME)\r
-                    break;\r
-                String name = bind.getString();\r
-                Context cx = Context.getCurrentContext();\r
-                if (cx != null && cx.isActivationNeeded(name)) {\r
-                    // use of "arguments" requires an activation object.\r
-                    ((FunctionNode) tree).setRequiresActivation(true);\r
-                }\r
-                VariableTable vars = getVariableTable(tree);\r
-                if (vars.getVariable(name) != null) {\r
-                    if (type == TokenStream.SETNAME) {\r
-                        node.setType(TokenStream.SETVAR);\r
-                        bind.setType(TokenStream.STRING);\r
-                    } else {\r
-                        // Local variables are by definition permanent\r
-                        Node n = new Node(TokenStream.PRIMARY,\r
-                                          new Integer(TokenStream.FALSE));\r
-                        iterator.replaceCurrent(n);\r
-                    }\r
-                }\r
-                break;\r
-              }\r
-              \r
-              case TokenStream.GETPROP:\r
-                if (inFunction) {\r
-                    Node n = node.getFirstChild().getNextSibling();\r
-                    String name = n == null ? "" : n.getString();\r
-                    Context cx = Context.getCurrentContext();\r
-                    if ((cx != null && cx.isActivationNeeded(name)) ||\r
-                        (name.equals("length") && \r
-                         Context.getContext().getLanguageVersion() == \r
-                         Context.VERSION_1_2))\r
-                    {\r
-                        // Use of "arguments" or "length" in 1.2 requires \r
-                        // an activation object.\r
-                        ((FunctionNode) tree).setRequiresActivation(true);\r
-                    }\r
-                }\r
-                break;\r
-\r
-              case TokenStream.NAME:\r
-              {\r
-                if (!inFunction || inWithStatement())\r
-                    break;\r
-                String name = node.getString();\r
-                Context cx = Context.getCurrentContext();\r
-                if (cx != null && cx.isActivationNeeded(name)) {\r
-                    // Use of "arguments" requires an activation object.\r
-                    ((FunctionNode) tree).setRequiresActivation(true);\r
-                }\r
-                VariableTable vars = getVariableTable(tree);\r
-                if (vars.getVariable(name) != null) {\r
-                    node.setType(TokenStream.GETVAR);\r
-                }\r
-                break;\r
-              }\r
-            }\r
-        }\r
-\r
-        return tree;\r
-    }\r
-\r
-    protected void addVariables(Node tree, VariableTable vars) {\r
-        // OPT: a whole pass to collect variables seems expensive.\r
-        // Could special case to go into statements only.\r
-        boolean inFunction = tree.getType() == TokenStream.FUNCTION;\r
-        PreorderNodeIterator iterator = tree.getPreorderIterator();\r
-        Hashtable ht = null;\r
-        Node node;\r
-        while ((node = iterator.nextNode()) != null) {\r
-            int nodeType = node.getType();\r
-            if (inFunction && nodeType == TokenStream.FUNCTION &&\r
-                node != tree && \r
-                ((FunctionNode) node.getProp(Node.FUNCTION_PROP)).getFunctionType() == \r
-                    FunctionNode.FUNCTION_EXPRESSION_STATEMENT) \r
-            {\r
-                // In a function with both "var x" and "function x",\r
-                // disregard the var statement, independent of order.\r
-                String name = node.getString();\r
-                if (name == null)\r
-                    continue;\r
-                vars.removeLocal(name);\r
-                if (ht == null)\r
-                    ht = new Hashtable();\r
-                ht.put(name, Boolean.TRUE);\r
-            }\r
-            if (nodeType != TokenStream.VAR)\r
-                continue;\r
-            ShallowNodeIterator i = node.getChildIterator();\r
-            while (i.hasMoreElements()) {\r
-                Node n = i.nextNode();\r
-                if (ht == null || ht.get(n.getString()) == null)\r
-                    vars.addLocal(n.getString());\r
-            }\r
-        }\r
-        String name = (String) tree.getDatum();\r
-        if (inFunction && ((FunctionNode) tree).getFunctionType() ==\r
-                          FunctionNode.FUNCTION_EXPRESSION &&\r
-            name != null && name.length() > 0 &&\r
-            vars.getVariable(name) == null)\r
-        {\r
-            // A function expression needs to have its name as a variable\r
-            // (if it isn't already allocated as a variable). See \r
-            // ECMA Ch. 13.  We add code to the beginning of the function\r
-            // to initialize a local variable of the function's name\r
-            // to the function value.\r
-            vars.addLocal(name);\r
-            Node block = tree.getLastChild();\r
-            Node setFn = new Node(TokenStream.POP,\r
-                            new Node(TokenStream.SETVAR,\r
-                                new Node(TokenStream.STRING, name),\r
-                                new Node(TokenStream.PRIMARY,\r
-                                    new Integer(TokenStream.THISFN))));\r
-            block.addChildrenToFront(setFn);\r
-        }\r
-    }\r
-\r
-    protected void addParameters(FunctionNode fnNode) {\r
-        VariableTable vars = fnNode.getVariableTable();\r
-        Node args = fnNode.getFirstChild();\r
-        if (args.getType() == TokenStream.LP && vars.getParameterCount() == 0)\r
-        {\r
-            // Add parameters\r
-            ShallowNodeIterator i = args.getChildIterator();\r
-            while (i.hasMoreElements()) {\r
-                Node n = i.nextNode();\r
-                String arg = n.getString();\r
-                vars.addParameter(arg);\r
-            }\r
-        }\r
-    }\r
-    \r
-    protected void visitNew(Node node, Node tree) {\r
-    }\r
-\r
-    protected void visitCall(Node node, Node tree) {\r
-        /*\r
-         * For\r
-         *      Call(GetProp(a, b), c, d)   // or GetElem...\r
-         * we wish to evaluate as\r
-         *      Call(GetProp(tmp=a, b), tmp, c, d)\r
-         *\r
-         * for\r
-         *      Call(Name("a"), b, c)\r
-         * we wish to evaluate as\r
-         *      Call(GetProp(tmp=GetBase("a"), "a"), tmp, b, c)\r
-         *\r
-         * and for\r
-         *      Call(a, b, c);\r
-         * we wish to evaluate as\r
-         *      Call(tmp=a, Parent(tmp), c, d)\r
-         */\r
-        Node left = node.getFirstChild();\r
-        // count the arguments\r
-        int argCount = 0;\r
-        Node arg = left.getNextSibling();\r
-        while (arg != null) {\r
-            arg = arg.getNextSibling();\r
-            argCount++;\r
-        }\r
-        boolean addGetThis = false;\r
-        if (left.getType() == TokenStream.NAME) {\r
-            VariableTable vars = getVariableTable(tree);\r
-            String name = left.getString();\r
-            if (inFunction && vars.getVariable(name) != null && \r
-                !inWithStatement()) \r
-            {\r
-                // call to a var. Transform to Call(GetVar("a"), b, c)\r
-                left.setType(TokenStream.GETVAR);\r
-                // fall through to code to add GetParent\r
-            } else {\r
-                // transform to Call(GetProp(GetBase("a"), "a"), b, c)\r
-\r
-                node.removeChild(left);\r
-                left.setType(TokenStream.GETBASE);\r
-                Node str = left.cloneNode();\r
-                str.setType(TokenStream.STRING);\r
-                Node getProp = new Node(TokenStream.GETPROP, left, str);\r
-                node.addChildToFront(getProp);\r
-                left = getProp;\r
-\r
-                // Conditionally set a flag to add a GETTHIS node.\r
-                // The getThis entry in the runtime will take a\r
-                // Scriptable object intended to be used as a 'this'\r
-                // and make sure that it is neither a With object or\r
-                // an activation object.\r
-                // Executing getThis requires at least two instanceof\r
-                // tests, so we only include it if we are currently\r
-                // inside a 'with' statement, or if we are executing\r
-                // a script (to protect against an eval inside a with).\r
-                addGetThis = inWithStatement() || !inFunction;\r
-                // fall through to GETPROP code\r
-            }\r
-        }\r
-        if (left.getType() != TokenStream.GETPROP &&\r
-            left.getType() != TokenStream.GETELEM)\r
-        {\r
-            node.removeChild(left);\r
-            Node tmp = irFactory.createNewTemp(left);\r
-            Node use = irFactory.createUseTemp(tmp);\r
-            use.putProp(Node.TEMP_PROP, tmp);\r
-            Node parent = new Node(TokenStream.PARENT, use);\r
-            node.addChildToFront(parent);\r
-            node.addChildToFront(tmp);\r
-            return;\r
-        }\r
-        Node leftLeft = left.getFirstChild();\r
-        left.removeChild(leftLeft);\r
-        Node tmp = irFactory.createNewTemp(leftLeft);\r
-        left.addChildToFront(tmp);\r
-        Node use = irFactory.createUseTemp(tmp);\r
-        use.putProp(Node.TEMP_PROP, tmp);\r
-        if (addGetThis)\r
-            use = new Node(TokenStream.GETTHIS, use);\r
-        node.addChildAfter(use, left);\r
-    }\r
-\r
-    protected boolean inWithStatement() {\r
-        for (int i=loops.size()-1; i >= 0; i--) {\r
-            Node n = (Node) loops.elementAt(i);\r
-            if (n.getType() == TokenStream.WITH)\r
-                return true;\r
-        }\r
-        return false;\r
-    }\r
-\r
-    /**\r
-     * Return true if the node is a call to a function that requires \r
-     * access to the enclosing activation object.\r
-     */\r
-    private boolean isSpecialCallName(Node tree, Node node) {\r
-        Node left = node.getFirstChild();\r
-        boolean isSpecial = false;\r
-        if (left.getType() == TokenStream.NAME) {\r
-            String name = left.getString();\r
-            isSpecial = name.equals("eval") || name.equals("With");\r
-        } else {\r
-            if (left.getType() == TokenStream.GETPROP) {\r
-                String name = left.getLastChild().getString();\r
-                isSpecial = name.equals("exec");\r
-            }\r
-        }\r
-        if (isSpecial) {\r
-            // Calls to these functions require activation objects.\r
-            if (inFunction)\r
-                ((FunctionNode) tree).setRequiresActivation(true);\r
-            return true;\r
-        }\r
-        return false;\r
-    }\r
-\r
-    protected VariableTable createVariableTable() {\r
-        return new VariableTable();\r
-    }\r
-\r
-    protected VariableTable getVariableTable(Node tree) {\r
-        if (inFunction) {\r
-            return ((FunctionNode)tree).getVariableTable();\r
-        }\r
-        VariableTable result = (VariableTable)(tree.getProp(Node.VARS_PROP));\r
-        if (result == null) {\r
-            result = createVariableTable();\r
-            tree.putProp(Node.VARS_PROP, result);\r
-        }\r
-        return result;\r
-    }\r
-    \r
-    protected void reportMessage(Context cx, String msg, Node stmt, \r
-                                 Node tree, boolean isError,\r
-                                 Scriptable scope)\r
-    {\r
-        Object obj = stmt.getDatum();\r
-        int lineno = 0;\r
-        if (obj != null && obj instanceof Integer)\r
-            lineno = ((Integer) obj).intValue();\r
-        Object prop = tree == null \r
-                      ? null\r
-                      : tree.getProp(Node.SOURCENAME_PROP);\r
-        if (isError) {\r
-            if (scope != null)\r
-            throw NativeGlobal.constructError(\r
-                        cx, "SyntaxError", msg, scope, \r
-                        (String) prop, lineno, 0, null);\r
-            else\r
-                cx.reportError(msg, (String) prop, lineno, null, 0);\r
-        }\r
-        else\r
-            cx.reportWarning(msg, (String) prop, lineno, null, 0);        \r
-    }\r
-\r
-    protected Stack loops;\r
-    protected Stack loopEnds;\r
-    protected boolean inFunction;\r
-    protected IRFactory irFactory;\r
-}\r
-\r