From 89bda83e0570ab87c6e449f5955613d5385e90b3 Mon Sep 17 00:00:00 2001 From: "alexanders@b2ef00c0-3703-41da-baef-cfe82387ac0c" Date: Wed, 3 Feb 2010 00:50:41 +0000 Subject: removed obsolete svn folder from hg tree --HG-- extra : convert_revision : svn%3Ab2ef00c0-3703-41da-baef-cfe82387ac0c/trunk%408 --- .../src/org/mozilla/javascript/IRFactory.java | 1607 -------------------- 1 file changed, 1607 deletions(-) delete mode 100644 trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IRFactory.java (limited to 'trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IRFactory.java') diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IRFactory.java b/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IRFactory.java deleted file mode 100644 index 1f51cb1..0000000 --- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/IRFactory.java +++ /dev/null @@ -1,1607 +0,0 @@ -/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Rhino code, released - * May 6, 1999. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1997-1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Norris Boyd - * Igor Bukanov - * Ethan Hugg - * Bob Jervis - * Terry Lucas - * Milen Nankov - * - * Alternatively, the contents of this file may be used under the terms of - * the GNU General Public License Version 2 or later (the "GPL"), in which - * case the provisions of the GPL are applicable instead of those above. If - * you wish to allow use of your version of this file only under the terms of - * the GPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replacing - * them with the notice and other provisions required by the GPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the GPL. - * - * ***** END LICENSE BLOCK ***** */ - -package org.mozilla.javascript; - -import java.util.List; -import java.util.ArrayList; - -/** - * This class allows the creation of nodes, and follows the Factory pattern. - * - * @see Node - * @author Mike McCabe - * @author Norris Boyd - */ -final class IRFactory -{ - IRFactory(Parser parser) - { - this.parser = parser; - } - - ScriptOrFnNode createScript() - { - return new ScriptOrFnNode(Token.SCRIPT); - } - - /** - * Script (for associating file/url names with toplevel scripts.) - */ - void initScript(ScriptOrFnNode scriptNode, Node body) - { - Node children = body.getFirstChild(); - if (children != null) { scriptNode.addChildrenToBack(children); } - } - - /** - * Leaf - */ - Node createLeaf(int nodeType) - { - return new Node(nodeType); - } - - /** - * Statement leaf nodes. - */ - - Node createSwitch(Node expr, int lineno) - { - // - // The switch will be rewritten from: - // - // switch (expr) { - // case test1: statements1; - // ... - // default: statementsDefault; - // ... - // case testN: statementsN; - // } - // - // to: - // - // { - // switch (expr) { - // case test1: goto label1; - // ... - // case testN: goto labelN; - // } - // goto labelDefault; - // label1: - // statements1; - // ... - // labelDefault: - // statementsDefault; - // ... - // labelN: - // statementsN; - // breakLabel: - // } - // - // where inside switch each "break;" without label will be replaced - // by "goto breakLabel". - // - // If the original switch does not have the default label, then - // the transformed code would contain after the switch instead of - // goto labelDefault; - // the following goto: - // goto breakLabel; - // - - Node.Jump switchNode = new Node.Jump(Token.SWITCH, expr, lineno); - Node block = new Node(Token.BLOCK, switchNode); - return block; - } - - /** - * If caseExpression argument is null it indicate default label. - */ - void addSwitchCase(Node switchBlock, Node caseExpression, Node statements) - { - if (switchBlock.getType() != Token.BLOCK) throw Kit.codeBug(); - Node.Jump switchNode = (Node.Jump)switchBlock.getFirstChild(); - if (switchNode.getType() != Token.SWITCH) throw Kit.codeBug(); - - Node gotoTarget = Node.newTarget(); - if (caseExpression != null) { - Node.Jump caseNode = new Node.Jump(Token.CASE, caseExpression); - caseNode.target = gotoTarget; - switchNode.addChildToBack(caseNode); - } else { - switchNode.setDefault(gotoTarget); - } - switchBlock.addChildToBack(gotoTarget); - switchBlock.addChildToBack(statements); - } - - void closeSwitch(Node switchBlock) - { - if (switchBlock.getType() != Token.BLOCK) throw Kit.codeBug(); - Node.Jump switchNode = (Node.Jump)switchBlock.getFirstChild(); - if (switchNode.getType() != Token.SWITCH) throw Kit.codeBug(); - - Node switchBreakTarget = Node.newTarget(); - // switchNode.target is only used by NodeTransformer - // to detect switch end - switchNode.target = switchBreakTarget; - - Node defaultTarget = switchNode.getDefault(); - if (defaultTarget == null) { - defaultTarget = switchBreakTarget; - } - - switchBlock.addChildAfter(makeJump(Token.GOTO, defaultTarget), - switchNode); - switchBlock.addChildToBack(switchBreakTarget); - } - - Node createVariables(int token, int lineno) - { - return new Node(token, lineno); - } - - Node createExprStatement(Node expr, int lineno) - { - int type; - if (parser.insideFunction()) { - type = Token.EXPR_VOID; - } else { - type = Token.EXPR_RESULT; - } - return new Node(type, expr, lineno); - } - - Node createExprStatementNoReturn(Node expr, int lineno) - { - return new Node(Token.EXPR_VOID, expr, lineno); - } - - Node createDefaultNamespace(Node expr, int lineno) - { - // default xml namespace requires activation - setRequiresActivation(); - Node n = createUnary(Token.DEFAULTNAMESPACE, expr); - Node result = createExprStatement(n, lineno); - return result; - } - - /** - * Name - */ - Node createName(String name) - { - checkActivationName(name, Token.NAME); - return Node.newString(Token.NAME, name); - } - - private Node createName(int type, String name, Node child) - { - Node result = createName(name); - result.setType(type); - if (child != null) - result.addChildToBack(child); - return result; - } - - /** - * String (for literals) - */ - Node createString(String string) - { - return Node.newString(string); - } - - /** - * Number (for literals) - */ - Node createNumber(double number) - { - return Node.newNumber(number); - } - - /** - * Catch clause of try/catch/finally - * @param varName the name of the variable to bind to the exception - * @param catchCond the condition under which to catch the exception. - * May be null if no condition is given. - * @param stmts the statements in the catch clause - * @param lineno the starting line number of the catch clause - */ - Node createCatch(String varName, Node catchCond, Node stmts, int lineno) - { - if (catchCond == null) { - catchCond = new Node(Token.EMPTY); - } - return new Node(Token.CATCH, createName(varName), - catchCond, stmts, lineno); - } - - /** - * Throw - */ - Node createThrow(Node expr, int lineno) - { - return new Node(Token.THROW, expr, lineno); - } - - /** - * Return - */ - Node createReturn(Node expr, int lineno) - { - return expr == null - ? new Node(Token.RETURN, lineno) - : new Node(Token.RETURN, expr, lineno); - } - - /** - * Debugger - */ - Node createDebugger(int lineno) - { - return new Node(Token.DEBUGGER, lineno); - } - - /** - * Label - */ - Node createLabel(int lineno) - { - return new Node.Jump(Token.LABEL, lineno); - } - - Node getLabelLoop(Node label) - { - return ((Node.Jump)label).getLoop(); - } - - /** - * Label - */ - Node createLabeledStatement(Node labelArg, Node statement) - { - Node.Jump label = (Node.Jump)labelArg; - - // Make a target and put it _after_ the statement - // node. And in the LABEL node, so breaks get the - // right target. - - Node breakTarget = Node.newTarget(); - Node block = new Node(Token.BLOCK, label, statement, breakTarget); - label.target = breakTarget; - - return block; - } - - /** - * Break (possibly labeled) - */ - Node createBreak(Node breakStatement, int lineno) - { - Node.Jump n = new Node.Jump(Token.BREAK, lineno); - Node.Jump jumpStatement; - int t = breakStatement.getType(); - if (t == Token.LOOP || t == Token.LABEL) { - jumpStatement = (Node.Jump)breakStatement; - } else if (t == Token.BLOCK - && breakStatement.getFirstChild().getType() == Token.SWITCH) - { - jumpStatement = (Node.Jump)breakStatement.getFirstChild(); - } else { - throw Kit.codeBug(); - } - n.setJumpStatement(jumpStatement); - return n; - } - - /** - * Continue (possibly labeled) - */ - Node createContinue(Node loop, int lineno) - { - if (loop.getType() != Token.LOOP) Kit.codeBug(); - Node.Jump n = new Node.Jump(Token.CONTINUE, lineno); - n.setJumpStatement((Node.Jump)loop); - return n; - } - - /** - * Statement block - * Creates the empty statement block - * Must make subsequent calls to add statements to the node - */ - Node createBlock(int lineno) - { - return new Node(Token.BLOCK, lineno); - } - - FunctionNode createFunction(String name) - { - return new FunctionNode(name); - } - - Node initFunction(FunctionNode fnNode, int functionIndex, - Node statements, int functionType) - { - fnNode.itsFunctionType = functionType; - fnNode.addChildToBack(statements); - - int functionCount = fnNode.getFunctionCount(); - if (functionCount != 0) { - // Functions containing other functions require activation objects - fnNode.itsNeedsActivation = true; - } - - if (functionType == FunctionNode.FUNCTION_EXPRESSION) { - String name = fnNode.getFunctionName(); - if (name != null && name.length() != 0) { - // A function expression needs to have its name as a - // variable (if it isn't already allocated as a variable). - // See ECMA Ch. 13. We add code to the beginning of the - // function to initialize a local variable of the - // function's name to the function value. - Node setFn = new Node(Token.EXPR_VOID, - new Node(Token.SETNAME, - Node.newString(Token.BINDNAME, name), - new Node(Token.THISFN))); - statements.addChildrenToFront(setFn); - } - } - - // Add return to end if needed. - Node lastStmt = statements.getLastChild(); - if (lastStmt == null || lastStmt.getType() != Token.RETURN) { - statements.addChildToBack(new Node(Token.RETURN)); - } - - Node result = Node.newString(Token.FUNCTION, - fnNode.getFunctionName()); - result.putIntProp(Node.FUNCTION_PROP, functionIndex); - return result; - } - - /** - * Add a child to the back of the given node. This function - * breaks the Factory abstraction, but it removes a requirement - * from implementors of Node. - */ - void addChildToBack(Node parent, Node child) - { - parent.addChildToBack(child); - } - - /** - * Create a node that can be used to hold lexically scoped variable - * definitions (via let declarations). - * - * @param token the token of the node to create - * @param lineno line number of source - * @return the created node - */ - Node createScopeNode(int token, int lineno) { - return new Node.Scope(token, lineno); - } - - /** - * Create loop node. The parser will later call - * createWhile|createDoWhile|createFor|createForIn - * to finish loop generation. - */ - Node createLoopNode(Node loopLabel, int lineno) - { - Node.Jump result = new Node.Scope(Token.LOOP, lineno); - if (loopLabel != null) { - ((Node.Jump)loopLabel).setLoop(result); - } - return result; - } - - /** - * While - */ - Node createWhile(Node loop, Node cond, Node body) - { - return createLoop((Node.Jump)loop, LOOP_WHILE, body, cond, - null, null); - } - - /** - * DoWhile - */ - Node createDoWhile(Node loop, Node body, Node cond) - { - return createLoop((Node.Jump)loop, LOOP_DO_WHILE, body, cond, - null, null); - } - - /** - * For - */ - Node createFor(Node loop, Node init, Node test, Node incr, Node body) - { - if (init.getType() == Token.LET) { - // rewrite "for (let i=s; i < N; i++)..." as - // "let (i=s) { for (; i < N; i++)..." so that "s" is evaluated - // outside the scope of the for. - Node.Scope let = Node.Scope.splitScope((Node.Scope)loop); - let.setType(Token.LET); - let.addChildrenToBack(init); - let.addChildToBack(createLoop((Node.Jump)loop, LOOP_FOR, body, test, - new Node(Token.EMPTY), incr)); - return let; - } - return createLoop((Node.Jump)loop, LOOP_FOR, body, test, init, incr); - } - - private Node createLoop(Node.Jump loop, int loopType, Node body, Node cond, - Node init, Node incr) - { - Node bodyTarget = Node.newTarget(); - Node condTarget = Node.newTarget(); - if (loopType == LOOP_FOR && cond.getType() == Token.EMPTY) { - cond = new Node(Token.TRUE); - } - Node.Jump IFEQ = new Node.Jump(Token.IFEQ, cond); - IFEQ.target = bodyTarget; - Node breakTarget = Node.newTarget(); - - loop.addChildToBack(bodyTarget); - loop.addChildrenToBack(body); - if (loopType == LOOP_WHILE || loopType == LOOP_FOR) { - // propagate lineno to condition - loop.addChildrenToBack(new Node(Token.EMPTY, loop.getLineno())); - } - loop.addChildToBack(condTarget); - loop.addChildToBack(IFEQ); - loop.addChildToBack(breakTarget); - - loop.target = breakTarget; - Node continueTarget = condTarget; - - if (loopType == LOOP_WHILE || loopType == LOOP_FOR) { - // Just add a GOTO to the condition in the do..while - loop.addChildToFront(makeJump(Token.GOTO, condTarget)); - - if (loopType == LOOP_FOR) { - int initType = init.getType(); - if (initType != Token.EMPTY) { - if (initType != Token.VAR && initType != Token.LET) { - init = new Node(Token.EXPR_VOID, init); - } - loop.addChildToFront(init); - } - Node incrTarget = Node.newTarget(); - loop.addChildAfter(incrTarget, body); - if (incr.getType() != Token.EMPTY) { - incr = new Node(Token.EXPR_VOID, incr); - loop.addChildAfter(incr, incrTarget); - } - continueTarget = incrTarget; - } - } - - loop.setContinue(continueTarget); - - return loop; - } - - /** - * For .. In - * - */ - Node createForIn(int declType, Node loop, Node lhs, Node obj, Node body, - boolean isForEach) - { - int destructuring = -1; - int destructuringLen = 0; - Node lvalue; - int type = lhs.getType(); - if (type == Token.VAR || type == Token.LET) { - Node lastChild = lhs.getLastChild(); - if (lhs.getFirstChild() != lastChild) { - /* - * check that there was only one variable given. - * we can't do this in the parser, because then the - * parser would have to know something about the - * 'init' node of the for-in loop. - */ - parser.reportError("msg.mult.index"); - } - if (lastChild.getType() == Token.ARRAYLIT || - lastChild.getType() == Token.OBJECTLIT) - { - type = destructuring = lastChild.getType(); - lvalue = lastChild; - destructuringLen = lastChild.getIntProp( - Node.DESTRUCTURING_ARRAY_LENGTH, 0); - } else if (lastChild.getType() == Token.NAME) { - lvalue = Node.newString(Token.NAME, lastChild.getString()); - } else { - parser.reportError("msg.bad.for.in.lhs"); - return obj; - } - } else if (type == Token.ARRAYLIT || type == Token.OBJECTLIT) { - destructuring = type; - lvalue = lhs; - destructuringLen = lhs.getIntProp(Node.DESTRUCTURING_ARRAY_LENGTH, 0); - } else { - lvalue = makeReference(lhs); - if (lvalue == null) { - parser.reportError("msg.bad.for.in.lhs"); - return obj; - } - } - - Node localBlock = new Node(Token.LOCAL_BLOCK); - int initType = (isForEach) ? Token.ENUM_INIT_VALUES : - (destructuring != -1) ? Token.ENUM_INIT_ARRAY : - Token.ENUM_INIT_KEYS; - Node init = new Node(initType, obj); - init.putProp(Node.LOCAL_BLOCK_PROP, localBlock); - Node cond = new Node(Token.ENUM_NEXT); - cond.putProp(Node.LOCAL_BLOCK_PROP, localBlock); - Node id = new Node(Token.ENUM_ID); - id.putProp(Node.LOCAL_BLOCK_PROP, localBlock); - - Node newBody = new Node(Token.BLOCK); - Node assign; - if (destructuring != -1) { - assign = createDestructuringAssignment(declType, lvalue, id); - if (!isForEach && (destructuring == Token.OBJECTLIT || - destructuringLen != 2)) - { - // destructuring assignment is only allowed in for..each or - // with an array type of length 2 (to hold key and value) - parser.reportError("msg.bad.for.in.destruct"); - } - } else { - assign = simpleAssignment(lvalue, id); - } - newBody.addChildToBack(new Node(Token.EXPR_VOID, assign)); - newBody.addChildToBack(body); - - loop = createWhile(loop, cond, newBody); - loop.addChildToFront(init); - if (type == Token.VAR || type == Token.LET) - loop.addChildToFront(lhs); - localBlock.addChildToBack(loop); - - return localBlock; - } - - /** - * Try/Catch/Finally - * - * The IRFactory tries to express as much as possible in the tree; - * the responsibilities remaining for Codegen are to add the Java - * handlers: (Either (but not both) of TARGET and FINALLY might not - * be defined) - - * - a catch handler for javascript exceptions that unwraps the - * exception onto the stack and GOTOes to the catch target - - * - a finally handler - - * ... and a goto to GOTO around these handlers. - */ - Node createTryCatchFinally(Node tryBlock, Node catchBlocks, - Node finallyBlock, int lineno) - { - boolean hasFinally = (finallyBlock != null) - && (finallyBlock.getType() != Token.BLOCK - || finallyBlock.hasChildren()); - - // short circuit - if (tryBlock.getType() == Token.BLOCK && !tryBlock.hasChildren() - && !hasFinally) - { - return tryBlock; - } - - boolean hasCatch = catchBlocks.hasChildren(); - - // short circuit - if (!hasFinally && !hasCatch) { - // bc finally might be an empty block... - return tryBlock; - } - - - Node handlerBlock = new Node(Token.LOCAL_BLOCK); - Node.Jump pn = new Node.Jump(Token.TRY, tryBlock, lineno); - pn.putProp(Node.LOCAL_BLOCK_PROP, handlerBlock); - - if (hasCatch) { - // jump around catch code - Node endCatch = Node.newTarget(); - pn.addChildToBack(makeJump(Token.GOTO, endCatch)); - - // make a TARGET for the catch that the tcf node knows about - Node catchTarget = Node.newTarget(); - pn.target = catchTarget; - // mark it - pn.addChildToBack(catchTarget); - - // - // Given - // - // try { - // tryBlock; - // } catch (e if condition1) { - // something1; - // ... - // - // } catch (e if conditionN) { - // somethingN; - // } catch (e) { - // somethingDefault; - // } - // - // rewrite as - // - // try { - // tryBlock; - // goto after_catch: - // } catch (x) { - // with (newCatchScope(e, x)) { - // if (condition1) { - // something1; - // goto after_catch; - // } - // } - // ... - // with (newCatchScope(e, x)) { - // if (conditionN) { - // somethingN; - // goto after_catch; - // } - // } - // with (newCatchScope(e, x)) { - // somethingDefault; - // goto after_catch; - // } - // } - // after_catch: - // - // If there is no default catch, then the last with block - // arround "somethingDefault;" is replaced by "rethrow;" - - // It is assumed that catch handler generation will store - // exeception object in handlerBlock register - - // Block with local for exception scope objects - Node catchScopeBlock = new Node(Token.LOCAL_BLOCK); - - // expects catchblocks children to be (cond block) pairs. - Node cb = catchBlocks.getFirstChild(); - boolean hasDefault = false; - int scopeIndex = 0; - while (cb != null) { - int catchLineNo = cb.getLineno(); - - Node name = cb.getFirstChild(); - Node cond = name.getNext(); - Node catchStatement = cond.getNext(); - cb.removeChild(name); - cb.removeChild(cond); - cb.removeChild(catchStatement); - - // Add goto to the catch statement to jump out of catch - // but prefix it with LEAVEWITH since try..catch produces - // "with"code in order to limit the scope of the exception - // object. - catchStatement.addChildToBack(new Node(Token.LEAVEWITH)); - catchStatement.addChildToBack(makeJump(Token.GOTO, endCatch)); - - // Create condition "if" when present - Node condStmt; - if (cond.getType() == Token.EMPTY) { - condStmt = catchStatement; - hasDefault = true; - } else { - condStmt = createIf(cond, catchStatement, null, - catchLineNo); - } - - // Generate code to create the scope object and store - // it in catchScopeBlock register - Node catchScope = new Node(Token.CATCH_SCOPE, name, - createUseLocal(handlerBlock)); - catchScope.putProp(Node.LOCAL_BLOCK_PROP, catchScopeBlock); - catchScope.putIntProp(Node.CATCH_SCOPE_PROP, scopeIndex); - catchScopeBlock.addChildToBack(catchScope); - - // Add with statement based on catch scope object - catchScopeBlock.addChildToBack( - createWith(createUseLocal(catchScopeBlock), condStmt, - catchLineNo)); - - // move to next cb - cb = cb.getNext(); - ++scopeIndex; - } - pn.addChildToBack(catchScopeBlock); - if (!hasDefault) { - // Generate code to rethrow if no catch clause was executed - Node rethrow = new Node(Token.RETHROW); - rethrow.putProp(Node.LOCAL_BLOCK_PROP, handlerBlock); - pn.addChildToBack(rethrow); - } - - pn.addChildToBack(endCatch); - } - - if (hasFinally) { - Node finallyTarget = Node.newTarget(); - pn.setFinally(finallyTarget); - - // add jsr finally to the try block - pn.addChildToBack(makeJump(Token.JSR, finallyTarget)); - - // jump around finally code - Node finallyEnd = Node.newTarget(); - pn.addChildToBack(makeJump(Token.GOTO, finallyEnd)); - - pn.addChildToBack(finallyTarget); - Node fBlock = new Node(Token.FINALLY, finallyBlock); - fBlock.putProp(Node.LOCAL_BLOCK_PROP, handlerBlock); - pn.addChildToBack(fBlock); - - pn.addChildToBack(finallyEnd); - } - handlerBlock.addChildToBack(pn); - return handlerBlock; - } - - /** - * Throw, Return, Label, Break and Continue are defined in ASTFactory. - */ - - /** - * With - */ - Node createWith(Node obj, Node body, int lineno) - { - setRequiresActivation(); - Node result = new Node(Token.BLOCK, lineno); - result.addChildToBack(new Node(Token.ENTERWITH, obj)); - Node bodyNode = new Node(Token.WITH, body, lineno); - result.addChildrenToBack(bodyNode); - result.addChildToBack(new Node(Token.LEAVEWITH)); - return result; - } - - /** - * DOTQUERY - */ - public Node createDotQuery (Node obj, Node body, int lineno) - { - setRequiresActivation(); - Node result = new Node(Token.DOTQUERY, obj, body, lineno); - return result; - } - - Node createArrayLiteral(ObjArray elems, int skipCount, int destructuringLen) - { - int length = elems.size(); - int[] skipIndexes = null; - if (skipCount != 0) { - skipIndexes = new int[skipCount]; - } - Node array = new Node(Token.ARRAYLIT); - for (int i = 0, j = 0; i != length; ++i) { - Node elem = (Node)elems.get(i); - if (elem != null) { - array.addChildToBack(elem); - } else { - skipIndexes[j] = i; - ++j; - } - } - if (skipCount != 0) { - array.putProp(Node.SKIP_INDEXES_PROP, skipIndexes); - } - array.putIntProp(Node.DESTRUCTURING_ARRAY_LENGTH, destructuringLen); - return array; - } - - /** - * Object Literals - *
createObjectLiteral rewrites its argument as object - * creation plus object property entries, so later compiler - * stages don't need to know about object literals. - */ - Node createObjectLiteral(ObjArray elems) - { - int size = elems.size() / 2; - Node object = new Node(Token.OBJECTLIT); - Object[] properties; - if (size == 0) { - properties = ScriptRuntime.emptyArgs; - } else { - properties = new Object[size]; - for (int i = 0; i != size; ++i) { - properties[i] = elems.get(2 * i); - Node value = (Node)elems.get(2 * i + 1); - object.addChildToBack(value); - } - } - object.putProp(Node.OBJECT_IDS_PROP, properties); - return object; - } - - /** - * Regular expressions - */ - Node createRegExp(int regexpIndex) - { - Node n = new Node(Token.REGEXP); - n.putIntProp(Node.REGEXP_PROP, regexpIndex); - return n; - } - - /** - * If statement - */ - Node createIf(Node cond, Node ifTrue, Node ifFalse, int lineno) - { - int condStatus = isAlwaysDefinedBoolean(cond); - if (condStatus == ALWAYS_TRUE_BOOLEAN) { - return ifTrue; - } else if (condStatus == ALWAYS_FALSE_BOOLEAN) { - if (ifFalse != null) { - return ifFalse; - } - // Replace if (false) xxx by empty block - return new Node(Token.BLOCK, lineno); - } - - Node result = new Node(Token.BLOCK, lineno); - Node ifNotTarget = Node.newTarget(); - Node.Jump IFNE = new Node.Jump(Token.IFNE, cond); - IFNE.target = ifNotTarget; - - result.addChildToBack(IFNE); - result.addChildrenToBack(ifTrue); - - if (ifFalse != null) { - Node endTarget = Node.newTarget(); - result.addChildToBack(makeJump(Token.GOTO, endTarget)); - result.addChildToBack(ifNotTarget); - result.addChildrenToBack(ifFalse); - result.addChildToBack(endTarget); - } else { - result.addChildToBack(ifNotTarget); - } - - return result; - } - - Node createCondExpr(Node cond, Node ifTrue, Node ifFalse) - { - int condStatus = isAlwaysDefinedBoolean(cond); - if (condStatus == ALWAYS_TRUE_BOOLEAN) { - return ifTrue; - } else if (condStatus == ALWAYS_FALSE_BOOLEAN) { - return ifFalse; - } - return new Node(Token.HOOK, cond, ifTrue, ifFalse); - } - - /** - * Unary - */ - Node createUnary(int nodeType, Node child) - { - int childType = child.getType(); - switch (nodeType) { - case Token.DELPROP: { - Node n; - if (childType == Token.NAME) { - // Transform Delete(Name "a") - // to Delete(Bind("a"), String("a")) - child.setType(Token.BINDNAME); - Node left = child; - Node right = Node.newString(child.getString()); - n = new Node(nodeType, left, right); - } else if (childType == Token.GETPROP || - childType == Token.GETELEM) - { - Node left = child.getFirstChild(); - Node right = child.getLastChild(); - child.removeChild(left); - child.removeChild(right); - n = new Node(nodeType, left, right); - } else if (childType == Token.GET_REF) { - Node ref = child.getFirstChild(); - child.removeChild(ref); - n = new Node(Token.DEL_REF, ref); - } else { - n = new Node(Token.TRUE); - } - return n; - } - case Token.TYPEOF: - if (childType == Token.NAME) { - child.setType(Token.TYPEOFNAME); - return child; - } - break; - case Token.BITNOT: - if (childType == Token.NUMBER) { - int value = ScriptRuntime.toInt32(child.getDouble()); - child.setDouble(~value); - return child; - } - break; - case Token.NEG: - if (childType == Token.NUMBER) { - child.setDouble(-child.getDouble()); - return child; - } - break; - case Token.NOT: { - int status = isAlwaysDefinedBoolean(child); - if (status != 0) { - int type; - if (status == ALWAYS_TRUE_BOOLEAN) { - type = Token.FALSE; - } else { - type = Token.TRUE; - } - if (childType == Token.TRUE || childType == Token.FALSE) { - child.setType(type); - return child; - } - return new Node(type); - } - break; - } - } - return new Node(nodeType, child); - } - - Node createYield(Node child, int lineno) - { - if (!parser.insideFunction()) { - parser.reportError("msg.bad.yield"); - } - setRequiresActivation(); - setIsGenerator(); - if (child != null) - return new Node(Token.YIELD, child, lineno); - else - return new Node(Token.YIELD, lineno); - } - - Node createCallOrNew(int nodeType, Node child) - { - int type = Node.NON_SPECIALCALL; - if (child.getType() == Token.NAME) { - String name = child.getString(); - if (name.equals("eval")) { - type = Node.SPECIALCALL_EVAL; - } else if (name.equals("With")) { - type = Node.SPECIALCALL_WITH; - } - } else if (child.getType() == Token.GETPROP) { - String name = child.getLastChild().getString(); - if (name.equals("eval")) { - type = Node.SPECIALCALL_EVAL; - } - } - Node node = new Node(nodeType, child); - if (type != Node.NON_SPECIALCALL) { - // Calls to these functions require activation objects. - setRequiresActivation(); - node.putIntProp(Node.SPECIALCALL_PROP, type); - } - return node; - } - - Node createIncDec(int nodeType, boolean post, Node child) - { - child = makeReference(child); - if (child == null) { - String msg; - if (nodeType == Token.DEC) { - msg = "msg.bad.decr"; - } else { - msg = "msg.bad.incr"; - } - parser.reportError(msg); - return null; - } - - int childType = child.getType(); - - switch (childType) { - case Token.NAME: - case Token.GETPROP: - case Token.GETELEM: - case Token.GET_REF: { - Node n = new Node(nodeType, child); - int incrDecrMask = 0; - if (nodeType == Token.DEC) { - incrDecrMask |= Node.DECR_FLAG; - } - if (post) { - incrDecrMask |= Node.POST_FLAG; - } - n.putIntProp(Node.INCRDECR_PROP, incrDecrMask); - return n; - } - } - throw Kit.codeBug(); - } - - Node createPropertyGet(Node target, String namespace, String name, - int memberTypeFlags) - { - if (namespace == null && memberTypeFlags == 0) { - if (target == null) { - return createName(name); - } - checkActivationName(name, Token.GETPROP); - if (ScriptRuntime.isSpecialProperty(name)) { - Node ref = new Node(Token.REF_SPECIAL, target); - ref.putProp(Node.NAME_PROP, name); - return new Node(Token.GET_REF, ref); - } - return new Node(Token.GETPROP, target, createString(name)); - } - Node elem = createString(name); - memberTypeFlags |= Node.PROPERTY_FLAG; - return createMemberRefGet(target, namespace, elem, memberTypeFlags); - } - - Node createElementGet(Node target, String namespace, Node elem, - int memberTypeFlags) - { - // OPT: could optimize to createPropertyGet - // iff elem is string that can not be number - if (namespace == null && memberTypeFlags == 0) { - // stand-alone [aaa] as primary expression is array literal - // declaration and should not come here! - if (target == null) throw Kit.codeBug(); - return new Node(Token.GETELEM, target, elem); - } - return createMemberRefGet(target, namespace, elem, memberTypeFlags); - } - - private Node createMemberRefGet(Node target, String namespace, Node elem, - int memberTypeFlags) - { - Node nsNode = null; - if (namespace != null) { - // See 11.1.2 in ECMA 357 - if (namespace.equals("*")) { - nsNode = new Node(Token.NULL); - } else { - nsNode = createName(namespace); - } - } - Node ref; - if (target == null) { - if (namespace == null) { - ref = new Node(Token.REF_NAME, elem); - } else { - ref = new Node(Token.REF_NS_NAME, nsNode, elem); - } - } else { - if (namespace == null) { - ref = new Node(Token.REF_MEMBER, target, elem); - } else { - ref = new Node(Token.REF_NS_MEMBER, target, nsNode, elem); - } - } - if (memberTypeFlags != 0) { - ref.putIntProp(Node.MEMBER_TYPE_PROP, memberTypeFlags); - } - return new Node(Token.GET_REF, ref); - } - - /** - * Binary - */ - Node createBinary(int nodeType, Node left, Node right) - { - switch (nodeType) { - - case Token.ADD: - // numerical addition and string concatenation - if (left.type == Token.STRING) { - String s2; - if (right.type == Token.STRING) { - s2 = right.getString(); - } else if (right.type == Token.NUMBER) { - s2 = ScriptRuntime.numberToString(right.getDouble(), 10); - } else { - break; - } - String s1 = left.getString(); - left.setString(s1.concat(s2)); - return left; - } else if (left.type == Token.NUMBER) { - if (right.type == Token.NUMBER) { - left.setDouble(left.getDouble() + right.getDouble()); - return left; - } else if (right.type == Token.STRING) { - String s1, s2; - s1 = ScriptRuntime.numberToString(left.getDouble(), 10); - s2 = right.getString(); - right.setString(s1.concat(s2)); - return right; - } - } - // can't do anything if we don't know both types - since - // 0 + object is supposed to call toString on the object and do - // string concantenation rather than addition - break; - - case Token.SUB: - // numerical subtraction - if (left.type == Token.NUMBER) { - double ld = left.getDouble(); - if (right.type == Token.NUMBER) { - //both numbers - left.setDouble(ld - right.getDouble()); - return left; - } else if (ld == 0.0) { - // first 0: 0-x -> -x - return new Node(Token.NEG, right); - } - } else if (right.type == Token.NUMBER) { - if (right.getDouble() == 0.0) { - //second 0: x - 0 -> +x - // can not make simply x because x - 0 must be number - return new Node(Token.POS, left); - } - } - break; - - case Token.MUL: - // numerical multiplication - if (left.type == Token.NUMBER) { - double ld = left.getDouble(); - if (right.type == Token.NUMBER) { - //both numbers - left.setDouble(ld * right.getDouble()); - return left; - } else if (ld == 1.0) { - // first 1: 1 * x -> +x - return new Node(Token.POS, right); - } - } else if (right.type == Token.NUMBER) { - if (right.getDouble() == 1.0) { - //second 1: x * 1 -> +x - // can not make simply x because x - 0 must be number - return new Node(Token.POS, left); - } - } - // can't do x*0: Infinity * 0 gives NaN, not 0 - break; - - case Token.DIV: - // number division - if (right.type == Token.NUMBER) { - double rd = right.getDouble(); - if (left.type == Token.NUMBER) { - // both constants -- just divide, trust Java to handle x/0 - left.setDouble(left.getDouble() / rd); - return left; - } else if (rd == 1.0) { - // second 1: x/1 -> +x - // not simply x to force number convertion - return new Node(Token.POS, left); - } - } - break; - - case Token.AND: { - // Since x && y gives x, not false, when Boolean(x) is false, - // and y, not Boolean(y), when Boolean(x) is true, x && y - // can only be simplified if x is defined. See bug 309957. - - int leftStatus = isAlwaysDefinedBoolean(left); - if (leftStatus == ALWAYS_FALSE_BOOLEAN) { - // if the first one is false, just return it - return left; - } else if (leftStatus == ALWAYS_TRUE_BOOLEAN) { - // if first is true, set to second - return right; - } - break; - } - - case Token.OR: { - // Since x || y gives x, not true, when Boolean(x) is true, - // and y, not Boolean(y), when Boolean(x) is false, x || y - // can only be simplified if x is defined. See bug 309957. - - int leftStatus = isAlwaysDefinedBoolean(left); - if (leftStatus == ALWAYS_TRUE_BOOLEAN) { - // if the first one is true, just return it - return left; - } else if (leftStatus == ALWAYS_FALSE_BOOLEAN) { - // if first is false, set to second - return right; - } - break; - } - } - - return new Node(nodeType, left, right); - } - - private Node simpleAssignment(Node left, Node right) - { - int nodeType = left.getType(); - switch (nodeType) { - case Token.NAME: - left.setType(Token.BINDNAME); - return new Node(Token.SETNAME, left, right); - - case Token.GETPROP: - case Token.GETELEM: { - Node obj = left.getFirstChild(); - Node id = left.getLastChild(); - int type; - if (nodeType == Token.GETPROP) { - type = Token.SETPROP; - } else { - type = Token.SETELEM; - } - return new Node(type, obj, id, right); - } - case Token.GET_REF: { - Node ref = left.getFirstChild(); - checkMutableReference(ref); - return new Node(Token.SET_REF, ref, right); - } - } - - throw Kit.codeBug(); - } - - private void checkMutableReference(Node n) - { - int memberTypeFlags = n.getIntProp(Node.MEMBER_TYPE_PROP, 0); - if ((memberTypeFlags & Node.DESCENDANTS_FLAG) != 0) { - parser.reportError("msg.bad.assign.left"); - } - } - - Node createAssignment(int assignType, Node left, Node right) - { - Node ref = makeReference(left); - if (ref == null) { - if (left.getType() == Token.ARRAYLIT || - left.getType() == Token.OBJECTLIT) - { - if (assignType != Token.ASSIGN) { - parser.reportError("msg.bad.destruct.op"); - return right; - } - return createDestructuringAssignment(-1, left, right); - } - parser.reportError("msg.bad.assign.left"); - return right; - } - left = ref; - - int assignOp; - switch (assignType) { - case Token.ASSIGN: - return simpleAssignment(left, right); - case Token.ASSIGN_BITOR: assignOp = Token.BITOR; break; - case Token.ASSIGN_BITXOR: assignOp = Token.BITXOR; break; - case Token.ASSIGN_BITAND: assignOp = Token.BITAND; break; - case Token.ASSIGN_LSH: assignOp = Token.LSH; break; - case Token.ASSIGN_RSH: assignOp = Token.RSH; break; - case Token.ASSIGN_URSH: assignOp = Token.URSH; break; - case Token.ASSIGN_ADD: assignOp = Token.ADD; break; - case Token.ASSIGN_SUB: assignOp = Token.SUB; break; - case Token.ASSIGN_MUL: assignOp = Token.MUL; break; - case Token.ASSIGN_DIV: assignOp = Token.DIV; break; - case Token.ASSIGN_MOD: assignOp = Token.MOD; break; - default: throw Kit.codeBug(); - } - - int nodeType = left.getType(); - switch (nodeType) { - case Token.NAME: { - Node op = new Node(assignOp, left, right); - Node lvalueLeft = Node.newString(Token.BINDNAME, left.getString()); - return new Node(Token.SETNAME, lvalueLeft, op); - } - case Token.GETPROP: - case Token.GETELEM: { - Node obj = left.getFirstChild(); - Node id = left.getLastChild(); - - int type = nodeType == Token.GETPROP - ? Token.SETPROP_OP - : Token.SETELEM_OP; - - Node opLeft = new Node(Token.USE_STACK); - Node op = new Node(assignOp, opLeft, right); - return new Node(type, obj, id, op); - } - case Token.GET_REF: { - ref = left.getFirstChild(); - checkMutableReference(ref); - Node opLeft = new Node(Token.USE_STACK); - Node op = new Node(assignOp, opLeft, right); - return new Node(Token.SET_REF_OP, ref, op); - } - } - - throw Kit.codeBug(); - } - - /** - * Given a destructuring assignment with a left hand side parsed - * as an array or object literal and a right hand side expression, - * rewrite as a series of assignments to the variables defined in - * left from property accesses to the expression on the right. - * @param type declaration type: Token.VAR or Token.LET or -1 - * @param left array or object literal containing NAME nodes for - * variables to assign - * @param right expression to assign from - * @return expression that performs a series of assignments to - * the variables defined in left - */ - Node createDestructuringAssignment(int type, Node left, Node right) - { - String tempName = parser.currentScriptOrFn.getNextTempName(); - Node result = destructuringAssignmentHelper(type, left, right, - tempName); - Node comma = result.getLastChild(); - comma.addChildToBack(createName(tempName)); - return result; - } - - private Node destructuringAssignmentHelper(int variableType, Node left, - Node right, String tempName) - { - Node result = createScopeNode(Token.LETEXPR, - parser.getCurrentLineNumber()); - result.addChildToFront(new Node(Token.LET, - createName(Token.NAME, tempName, right))); - try { - parser.pushScope(result); - parser.defineSymbol(Token.LET, tempName); - } finally { - parser.popScope(); - } - Node comma = new Node(Token.COMMA); - result.addChildToBack(comma); - final int setOp = variableType == Token.CONST ? Token.SETCONST - : Token.SETNAME; - List destructuringNames = new ArrayList(); - boolean empty = true; - int type = left.getType(); - if (type == Token.ARRAYLIT) { - int index = 0; - int[] skipIndices = (int[])left.getProp(Node.SKIP_INDEXES_PROP); - int skip = 0; - Node n = left.getFirstChild(); - for (;;) { - if (skipIndices != null) { - while (skip < skipIndices.length && - skipIndices[skip] == index) { - skip++; - index++; - } - } - if (n == null) - break; - Node rightElem = new Node(Token.GETELEM, - createName(tempName), - createNumber(index)); - if (n.getType() == Token.NAME) { - String name = n.getString(); - comma.addChildToBack(new Node(setOp, - createName(Token.BINDNAME, name, null), - rightElem)); - if (variableType != -1) { - parser.defineSymbol(variableType, name); - destructuringNames.add(name); - } - } else { - comma.addChildToBack( - destructuringAssignmentHelper(variableType, n, - rightElem, - parser.currentScriptOrFn.getNextTempName())); - } - index++; - empty = false; - n = n.getNext(); - } - } else if (type == Token.OBJECTLIT) { - int index = 0; - Object[] propertyIds = (Object[]) - left.getProp(Node.OBJECT_IDS_PROP); - for (Node n = left.getFirstChild(); n != null; n = n.getNext()) - { - Object id = propertyIds[index]; - Node rightElem = id instanceof String - ? new Node(Token.GETPROP, - createName(tempName), - createString((String)id)) - : new Node(Token.GETELEM, - createName(tempName), - createNumber(((Number)id).intValue())); - if (n.getType() == Token.NAME) { - String name = n.getString(); - comma.addChildToBack(new Node(setOp, - createName(Token.BINDNAME, name, null), - rightElem)); - if (variableType != -1) { - parser.defineSymbol(variableType, name); - destructuringNames.add(name); - } - } else { - comma.addChildToBack( - destructuringAssignmentHelper(variableType, n, - rightElem, - parser.currentScriptOrFn.getNextTempName())); - } - index++; - empty = false; - } - } else if (type == Token.GETPROP || type == Token.GETELEM) { - comma.addChildToBack(simpleAssignment(left, createName(tempName))); - } else { - parser.reportError("msg.bad.assign.left"); - } - if (empty) { - // Don't want a COMMA node with no children. Just add a zero. - comma.addChildToBack(createNumber(0)); - } - result.putProp(Node.DESTRUCTURING_NAMES, destructuringNames); - return result; - } - - Node createUseLocal(Node localBlock) - { - if (Token.LOCAL_BLOCK != localBlock.getType()) throw Kit.codeBug(); - Node result = new Node(Token.LOCAL_LOAD); - result.putProp(Node.LOCAL_BLOCK_PROP, localBlock); - return result; - } - - private Node.Jump makeJump(int type, Node target) - { - Node.Jump n = new Node.Jump(type); - n.target = target; - return n; - } - - private Node makeReference(Node node) - { - int type = node.getType(); - switch (type) { - case Token.NAME: - case Token.GETPROP: - case Token.GETELEM: - case Token.GET_REF: - return node; - case Token.CALL: - node.setType(Token.REF_CALL); - return new Node(Token.GET_REF, node); - } - // Signal caller to report error - return null; - } - - // Check if Node always mean true or false in boolean context - private static int isAlwaysDefinedBoolean(Node node) - { - switch (node.getType()) { - case Token.FALSE: - case Token.NULL: - return ALWAYS_FALSE_BOOLEAN; - case Token.TRUE: - return ALWAYS_TRUE_BOOLEAN; - case Token.NUMBER: { - double num = node.getDouble(); - if (num == num && num != 0.0) { - return ALWAYS_TRUE_BOOLEAN; - } else { - return ALWAYS_FALSE_BOOLEAN; - } - } - } - return 0; - } - - private void checkActivationName(String name, int token) - { - if (parser.insideFunction()) { - boolean activation = false; - if ("arguments".equals(name) - || (parser.compilerEnv.activationNames != null - && parser.compilerEnv.activationNames.containsKey(name))) - { - activation = true; - } else if ("length".equals(name)) { - if (token == Token.GETPROP - && parser.compilerEnv.getLanguageVersion() - == Context.VERSION_1_2) - { - // Use of "length" in 1.2 requires an activation object. - activation = true; - } - } - if (activation) { - setRequiresActivation(); - } - } - } - - private void setRequiresActivation() - { - if (parser.insideFunction()) { - ((FunctionNode)parser.currentScriptOrFn).itsNeedsActivation = true; - } - } - - private void setIsGenerator() - { - if (parser.insideFunction()) { - ((FunctionNode)parser.currentScriptOrFn).itsIsGenerator = true; - } - } - - private Parser parser; - - private static final int LOOP_DO_WHILE = 0; - private static final int LOOP_WHILE = 1; - private static final int LOOP_FOR = 2; - - private static final int ALWAYS_TRUE_BOOLEAN = 1; - private static final int ALWAYS_FALSE_BOOLEAN = -1; -} -- cgit v1.2.3