+++ /dev/null
-/* -*- 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