0001: /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
0002: *
0003: * ***** BEGIN LICENSE BLOCK *****
0004: * Version: MPL 1.1/GPL 2.0
0005: *
0006: * The contents of this file are subject to the Mozilla Public License Version
0007: * 1.1 (the "License"); you may not use this file except in compliance with
0008: * the License. You may obtain a copy of the License at
0009: * http://www.mozilla.org/MPL/
0010: *
0011: * Software distributed under the License is distributed on an "AS IS" basis,
0012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0013: * for the specific language governing rights and limitations under the
0014: * License.
0015: *
0016: * The Original Code is Rhino code, released
0017: * May 6, 1999.
0018: *
0019: * The Initial Developer of the Original Code is
0020: * Netscape Communications Corporation.
0021: * Portions created by the Initial Developer are Copyright (C) 1997-1999
0022: * the Initial Developer. All Rights Reserved.
0023: *
0024: * Contributor(s):
0025: * Norris Boyd
0026: * Igor Bukanov
0027: * Ethan Hugg
0028: * Bob Jervis
0029: * Terry Lucas
0030: * Milen Nankov
0031: *
0032: * Alternatively, the contents of this file may be used under the terms of
0033: * the GNU General Public License Version 2 or later (the "GPL"), in which
0034: * case the provisions of the GPL are applicable instead of those above. If
0035: * you wish to allow use of your version of this file only under the terms of
0036: * the GPL and not to allow others to use your version of this file under the
0037: * MPL, indicate your decision by deleting the provisions above and replacing
0038: * them with the notice and other provisions required by the GPL. If you do
0039: * not delete the provisions above, a recipient may use your version of this
0040: * file under either the MPL or the GPL.
0041: *
0042: * ***** END LICENSE BLOCK ***** */
0043:
0044: package org.mozilla.javascript;
0045:
0046: /**
0047: * This class allows the creation of nodes, and follows the Factory pattern.
0048: *
0049: * @see Node
0050: * @author Mike McCabe
0051: * @author Norris Boyd
0052: */
0053: final class IRFactory {
0054: IRFactory(Parser parser) {
0055: this .parser = parser;
0056: }
0057:
0058: ScriptOrFnNode createScript() {
0059: return new ScriptOrFnNode(Token.SCRIPT);
0060: }
0061:
0062: /**
0063: * Script (for associating file/url names with toplevel scripts.)
0064: */
0065: void initScript(ScriptOrFnNode scriptNode, Node body) {
0066: Node children = body.getFirstChild();
0067: if (children != null) {
0068: scriptNode.addChildrenToBack(children);
0069: }
0070: }
0071:
0072: /**
0073: * Leaf
0074: */
0075: Node createLeaf(int nodeType) {
0076: return new Node(nodeType);
0077: }
0078:
0079: Node createLeaf(int nodeType, int nodeOp) {
0080: return new Node(nodeType, nodeOp);
0081: }
0082:
0083: /**
0084: * Statement leaf nodes.
0085: */
0086:
0087: Node createSwitch(Node expr, int lineno) {
0088: //
0089: // The switch will be rewritten from:
0090: //
0091: // switch (expr) {
0092: // case test1: statements1;
0093: // ...
0094: // default: statementsDefault;
0095: // ...
0096: // case testN: statementsN;
0097: // }
0098: //
0099: // to:
0100: //
0101: // {
0102: // switch (expr) {
0103: // case test1: goto label1;
0104: // ...
0105: // case testN: goto labelN;
0106: // }
0107: // goto labelDefault;
0108: // label1:
0109: // statements1;
0110: // ...
0111: // labelDefault:
0112: // statementsDefault;
0113: // ...
0114: // labelN:
0115: // statementsN;
0116: // breakLabel:
0117: // }
0118: //
0119: // where inside switch each "break;" without label will be replaced
0120: // by "goto breakLabel".
0121: //
0122: // If the original switch does not have the default label, then
0123: // the transformed code would contain after the switch instead of
0124: // goto labelDefault;
0125: // the following goto:
0126: // goto breakLabel;
0127: //
0128:
0129: Node.Jump switchNode = new Node.Jump(Token.SWITCH, expr, lineno);
0130: Node block = new Node(Token.BLOCK, switchNode);
0131: return block;
0132: }
0133:
0134: /**
0135: * If caseExpression argument is null it indicate default label.
0136: */
0137: void addSwitchCase(Node switchBlock, Node caseExpression,
0138: Node statements) {
0139: if (switchBlock.getType() != Token.BLOCK)
0140: throw Kit.codeBug();
0141: Node.Jump switchNode = (Node.Jump) switchBlock.getFirstChild();
0142: if (switchNode.getType() != Token.SWITCH)
0143: throw Kit.codeBug();
0144:
0145: Node gotoTarget = Node.newTarget();
0146: if (caseExpression != null) {
0147: Node.Jump caseNode = new Node.Jump(Token.CASE,
0148: caseExpression);
0149: caseNode.target = gotoTarget;
0150: switchNode.addChildToBack(caseNode);
0151: } else {
0152: switchNode.setDefault(gotoTarget);
0153: }
0154: switchBlock.addChildToBack(gotoTarget);
0155: switchBlock.addChildToBack(statements);
0156: }
0157:
0158: void closeSwitch(Node switchBlock) {
0159: if (switchBlock.getType() != Token.BLOCK)
0160: throw Kit.codeBug();
0161: Node.Jump switchNode = (Node.Jump) switchBlock.getFirstChild();
0162: if (switchNode.getType() != Token.SWITCH)
0163: throw Kit.codeBug();
0164:
0165: Node switchBreakTarget = Node.newTarget();
0166: // switchNode.target is only used by NodeTransformer
0167: // to detect switch end
0168: switchNode.target = switchBreakTarget;
0169:
0170: Node defaultTarget = switchNode.getDefault();
0171: if (defaultTarget == null) {
0172: defaultTarget = switchBreakTarget;
0173: }
0174:
0175: switchBlock.addChildAfter(makeJump(Token.GOTO, defaultTarget),
0176: switchNode);
0177: switchBlock.addChildToBack(switchBreakTarget);
0178: }
0179:
0180: Node createVariables(int token, int lineno) {
0181: return new Node(token, lineno);
0182: }
0183:
0184: Node createExprStatement(Node expr, int lineno) {
0185: int type;
0186: if (parser.insideFunction()) {
0187: type = Token.EXPR_VOID;
0188: } else {
0189: type = Token.EXPR_RESULT;
0190: }
0191: return new Node(type, expr, lineno);
0192: }
0193:
0194: Node createExprStatementNoReturn(Node expr, int lineno) {
0195: return new Node(Token.EXPR_VOID, expr, lineno);
0196: }
0197:
0198: Node createDefaultNamespace(Node expr, int lineno) {
0199: // default xml namespace requires activation
0200: setRequiresActivation();
0201: Node n = createUnary(Token.DEFAULTNAMESPACE, expr);
0202: Node result = createExprStatement(n, lineno);
0203: return result;
0204: }
0205:
0206: /**
0207: * Name
0208: */
0209: Node createName(String name) {
0210: checkActivationName(name, Token.NAME);
0211: return Node.newString(Token.NAME, name);
0212: }
0213:
0214: /**
0215: * String (for literals)
0216: */
0217: Node createString(String string) {
0218: return Node.newString(string);
0219: }
0220:
0221: /**
0222: * Number (for literals)
0223: */
0224: Node createNumber(double number) {
0225: return Node.newNumber(number);
0226: }
0227:
0228: /**
0229: * Catch clause of try/catch/finally
0230: * @param varName the name of the variable to bind to the exception
0231: * @param catchCond the condition under which to catch the exception.
0232: * May be null if no condition is given.
0233: * @param stmts the statements in the catch clause
0234: * @param lineno the starting line number of the catch clause
0235: */
0236: Node createCatch(String varName, Node catchCond, Node stmts,
0237: int lineno) {
0238: if (catchCond == null) {
0239: catchCond = new Node(Token.EMPTY);
0240: }
0241: return new Node(Token.CATCH, createName(varName), catchCond,
0242: stmts, lineno);
0243: }
0244:
0245: /**
0246: * Throw
0247: */
0248: Node createThrow(Node expr, int lineno) {
0249: return new Node(Token.THROW, expr, lineno);
0250: }
0251:
0252: /**
0253: * Return
0254: */
0255: Node createReturn(Node expr, int lineno) {
0256: return expr == null ? new Node(Token.RETURN, lineno)
0257: : new Node(Token.RETURN, expr, lineno);
0258: }
0259:
0260: /**
0261: * Label
0262: */
0263: Node createLabel(int lineno) {
0264: return new Node.Jump(Token.LABEL, lineno);
0265: }
0266:
0267: Node getLabelLoop(Node label) {
0268: return ((Node.Jump) label).getLoop();
0269: }
0270:
0271: /**
0272: * Label
0273: */
0274: Node createLabeledStatement(Node labelArg, Node statement) {
0275: Node.Jump label = (Node.Jump) labelArg;
0276:
0277: // Make a target and put it _after_ the statement
0278: // node. And in the LABEL node, so breaks get the
0279: // right target.
0280:
0281: Node breakTarget = Node.newTarget();
0282: Node block = new Node(Token.BLOCK, label, statement,
0283: breakTarget);
0284: label.target = breakTarget;
0285:
0286: return block;
0287: }
0288:
0289: /**
0290: * Break (possibly labeled)
0291: */
0292: Node createBreak(Node breakStatement, int lineno) {
0293: Node.Jump n = new Node.Jump(Token.BREAK, lineno);
0294: Node.Jump jumpStatement;
0295: int t = breakStatement.getType();
0296: if (t == Token.LOOP || t == Token.LABEL) {
0297: jumpStatement = (Node.Jump) breakStatement;
0298: } else if (t == Token.BLOCK
0299: && breakStatement.getFirstChild().getType() == Token.SWITCH) {
0300: jumpStatement = (Node.Jump) breakStatement.getFirstChild();
0301: } else {
0302: throw Kit.codeBug();
0303: }
0304: n.setJumpStatement(jumpStatement);
0305: return n;
0306: }
0307:
0308: /**
0309: * Continue (possibly labeled)
0310: */
0311: Node createContinue(Node loop, int lineno) {
0312: if (loop.getType() != Token.LOOP)
0313: Kit.codeBug();
0314: Node.Jump n = new Node.Jump(Token.CONTINUE, lineno);
0315: n.setJumpStatement((Node.Jump) loop);
0316: return n;
0317: }
0318:
0319: /**
0320: * Statement block
0321: * Creates the empty statement block
0322: * Must make subsequent calls to add statements to the node
0323: */
0324: Node createBlock(int lineno) {
0325: return new Node(Token.BLOCK, lineno);
0326: }
0327:
0328: FunctionNode createFunction(String name) {
0329: return new FunctionNode(name);
0330: }
0331:
0332: Node initFunction(FunctionNode fnNode, int functionIndex,
0333: Node statements, int functionType) {
0334: fnNode.itsFunctionType = functionType;
0335: fnNode.addChildToBack(statements);
0336:
0337: int functionCount = fnNode.getFunctionCount();
0338: if (functionCount != 0) {
0339: // Functions containing other functions require activation objects
0340: fnNode.itsNeedsActivation = true;
0341: for (int i = 0; i != functionCount; ++i) {
0342: FunctionNode fn = fnNode.getFunctionNode(i);
0343: // nested function expression statements overrides var
0344: if (fn.getFunctionType() == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) {
0345: String name = fn.getFunctionName();
0346: if (name != null && name.length() != 0) {
0347: fnNode.removeParamOrVar(name);
0348: }
0349: }
0350: }
0351: }
0352:
0353: if (functionType == FunctionNode.FUNCTION_EXPRESSION) {
0354: String name = fnNode.getFunctionName();
0355: if (name != null && name.length() != 0
0356: && !fnNode.hasParamOrVar(name)) {
0357: // A function expression needs to have its name as a
0358: // variable (if it isn't already allocated as a variable).
0359: // See ECMA Ch. 13. We add code to the beginning of the
0360: // function to initialize a local variable of the
0361: // function's name to the function value.
0362: if (fnNode.addVar(name) == ScriptOrFnNode.DUPLICATE_CONST)
0363: parser.addError("msg.const.redecl", name, null);
0364: Node setFn = new Node(Token.EXPR_VOID, new Node(
0365: Token.SETNAME, Node.newString(Token.BINDNAME,
0366: name), new Node(Token.THISFN)));
0367: statements.addChildrenToFront(setFn);
0368: }
0369: }
0370:
0371: // Add return to end if needed.
0372: Node lastStmt = statements.getLastChild();
0373: if (lastStmt == null || lastStmt.getType() != Token.RETURN) {
0374: statements.addChildToBack(new Node(Token.RETURN));
0375: }
0376:
0377: // <netbeans>
0378: // Node result = Node.newString(Token.FUNCTION,
0379: // fnNode.getFunctionName());
0380: // result.putIntProp(Node.FUNCTION_PROP, functionIndex);
0381: // // Track functions directly in the AST
0382: // result.addChildToBack(fnNode);
0383: Node result = fnNode;
0384: // </netbeans>
0385: return result;
0386: }
0387:
0388: /**
0389: * Add a child to the back of the given node. This function
0390: * breaks the Factory abstraction, but it removes a requirement
0391: * from implementors of Node.
0392: */
0393: void addChildToBack(Node parent, Node child) {
0394: parent.addChildToBack(child);
0395: }
0396:
0397: /**
0398: * Create loop node. The parser will later call
0399: * createWhile|createDoWhile|createFor|createForIn
0400: * to finish loop generation.
0401: */
0402: Node createLoopNode(Node loopLabel, int lineno) {
0403: Node.Jump result = new Node.Jump(Token.LOOP, lineno);
0404: if (loopLabel != null) {
0405: ((Node.Jump) loopLabel).setLoop(result);
0406: }
0407: return result;
0408: }
0409:
0410: /**
0411: * While
0412: */
0413: Node createWhile(Node loop, Node cond, Node body) {
0414: return createLoop((Node.Jump) loop, LOOP_WHILE, body, cond,
0415: null, null);
0416: }
0417:
0418: /**
0419: * DoWhile
0420: */
0421: Node createDoWhile(Node loop, Node body, Node cond) {
0422: return createLoop((Node.Jump) loop, LOOP_DO_WHILE, body, cond,
0423: null, null);
0424: }
0425:
0426: /**
0427: * For
0428: */
0429: Node createFor(Node loop, Node init, Node test, Node incr, Node body) {
0430: return createLoop((Node.Jump) loop, LOOP_FOR, body, test, init,
0431: incr);
0432: }
0433:
0434: private Node createLoop(Node.Jump loop, int loopType, Node body,
0435: Node cond, Node init, Node incr) {
0436: Node bodyTarget = Node.newTarget();
0437: Node condTarget = Node.newTarget();
0438: // <netbeans>
0439: int sourceOffset = parser.getStartOffset();
0440: bodyTarget.setSourceBounds(body.getSourceStart(), body
0441: .getSourceStart());
0442: condTarget.setSourceBounds(cond.getSourceStart(), cond
0443: .getSourceStart());
0444: // </netbeans>
0445: if (loopType == LOOP_FOR && cond.getType() == Token.EMPTY) {
0446: cond = new Node(Token.TRUE);
0447: }
0448: Node.Jump IFEQ = new Node.Jump(Token.IFEQ, cond);
0449: IFEQ.target = bodyTarget;
0450: Node breakTarget = Node.newTarget();
0451: // <netbeans>
0452: breakTarget.setSourceBounds(sourceOffset, sourceOffset);
0453: // </netbeans>
0454:
0455: loop.addChildToBack(bodyTarget);
0456: loop.addChildrenToBack(body);
0457: if (loopType == LOOP_WHILE || loopType == LOOP_FOR) {
0458: // propagate lineno to condition
0459: loop.addChildrenToBack(new Node(Token.EMPTY, loop
0460: .getLineno()));
0461: }
0462: loop.addChildToBack(condTarget);
0463: loop.addChildToBack(IFEQ);
0464: loop.addChildToBack(breakTarget);
0465:
0466: loop.target = breakTarget;
0467: Node continueTarget = condTarget;
0468:
0469: if (loopType == LOOP_WHILE || loopType == LOOP_FOR) {
0470: // Just add a GOTO to the condition in the do..while
0471: loop.addChildToFront(makeJump(Token.GOTO, condTarget));
0472:
0473: if (loopType == LOOP_FOR) {
0474: if (init.getType() != Token.EMPTY) {
0475: if (init.getType() != Token.VAR) {
0476: init = new Node(Token.EXPR_VOID, init);
0477: }
0478: loop.addChildToFront(init);
0479: }
0480: Node incrTarget = Node.newTarget();
0481: // <netbeans>
0482: incrTarget.setSourceBounds(sourceOffset, sourceOffset);
0483: // </netbeans>
0484: loop.addChildAfter(incrTarget, body);
0485: if (incr.getType() != Token.EMPTY) {
0486: incr = new Node(Token.EXPR_VOID, incr);
0487: loop.addChildAfter(incr, incrTarget);
0488: }
0489: continueTarget = incrTarget;
0490: }
0491: }
0492:
0493: loop.setContinue(continueTarget);
0494:
0495: return loop;
0496: }
0497:
0498: /**
0499: * For .. In
0500: *
0501: */
0502: Node createForIn(Node loop, Node lhs, Node obj, Node body,
0503: boolean isForEach) {
0504: // <netbeans>
0505: int startOffset = loop.getSourceStart();
0506: // </netbeans>
0507: int type = lhs.getType();
0508:
0509: Node lvalue;
0510: if (type == Token.VAR) {
0511: /*
0512: * check that there was only one variable given.
0513: * we can't do this in the parser, because then the
0514: * parser would have to know something about the
0515: * 'init' node of the for-in loop.
0516: */
0517: Node lastChild = lhs.getLastChild();
0518: if (lhs.getFirstChild() != lastChild) {
0519: parser.reportError("msg.mult.index");
0520: }
0521: lvalue = Node.newString(Token.NAME, lastChild.getString());
0522: // <netbeans>
0523: //parser.setSourceOffsets(lvalue, parser.getStartOffset());
0524: lvalue.setSourceBounds(lastChild.getSourceStart(),
0525: lastChild.getSourceEnd());
0526: // </netbeans>
0527: } else {
0528: lvalue = makeReference(lhs);
0529: if (lvalue == null) {
0530: parser.reportError("msg.bad.for.in.lhs");
0531: return obj;
0532: }
0533: }
0534:
0535: Node localBlock = new Node(Token.LOCAL_BLOCK);
0536:
0537: int initType = (isForEach) ? Token.ENUM_INIT_VALUES
0538: : Token.ENUM_INIT_KEYS;
0539: Node init = new Node(initType, obj);
0540: init.putProp(Node.LOCAL_BLOCK_PROP, localBlock);
0541: Node cond = new Node(Token.ENUM_NEXT);
0542: cond.putProp(Node.LOCAL_BLOCK_PROP, localBlock);
0543: Node id = new Node(Token.ENUM_ID);
0544: id.putProp(Node.LOCAL_BLOCK_PROP, localBlock);
0545:
0546: Node newBody = new Node(Token.BLOCK);
0547: Node assign = simpleAssignment(lvalue, id);
0548: // <netbeans>
0549: assign.setSourceBounds(lvalue.getSourceStart(), lvalue
0550: .getSourceEnd());
0551: // </netbeans>
0552: newBody.addChildToBack(new Node(Token.EXPR_VOID, assign));
0553: newBody.addChildToBack(body);
0554: // <netbeans>
0555: newBody.setSourceBounds(body.getSourceStart(), body
0556: .getSourceEnd());
0557: // </netbeans>
0558:
0559: loop = createWhile(loop, cond, newBody);
0560: loop.addChildToFront(init);
0561: if (type == Token.VAR)
0562: loop.addChildToFront(lhs);
0563: localBlock.addChildToBack(loop);
0564: // <netbeans>
0565: localBlock.setSourceBounds(startOffset, parser.getEndOffset());
0566: // </netbeans>
0567:
0568: return localBlock;
0569: }
0570:
0571: /**
0572: * Try/Catch/Finally
0573: *
0574: * The IRFactory tries to express as much as possible in the tree;
0575: * the responsibilities remaining for Codegen are to add the Java
0576: * handlers: (Either (but not both) of TARGET and FINALLY might not
0577: * be defined)
0578:
0579: * - a catch handler for javascript exceptions that unwraps the
0580: * exception onto the stack and GOTOes to the catch target
0581:
0582: * - a finally handler
0583:
0584: * ... and a goto to GOTO around these handlers.
0585: */
0586: Node createTryCatchFinally(Node tryBlock, Node catchBlocks,
0587: Node finallyBlock, int lineno) {
0588: // <netbeans>
0589: int startOffset = tryBlock.getSourceStart();
0590: // </netbeans>
0591: boolean hasFinally = (finallyBlock != null)
0592: && (finallyBlock.getType() != Token.BLOCK || finallyBlock
0593: .hasChildren());
0594:
0595: // short circuit
0596: if (tryBlock.getType() == Token.BLOCK
0597: && !tryBlock.hasChildren() && !hasFinally) {
0598: return tryBlock;
0599: }
0600:
0601: boolean hasCatch = catchBlocks.hasChildren();
0602:
0603: // short circuit
0604: if (!hasFinally && !hasCatch) {
0605: // bc finally might be an empty block...
0606: return tryBlock;
0607: }
0608:
0609: Node handlerBlock = new Node(Token.LOCAL_BLOCK);
0610: Node.Jump pn = new Node.Jump(Token.TRY, tryBlock, lineno);
0611: pn.putProp(Node.LOCAL_BLOCK_PROP, handlerBlock);
0612:
0613: if (hasCatch) {
0614: // jump around catch code
0615: Node endCatch = Node.newTarget();
0616: pn.addChildToBack(makeJump(Token.GOTO, endCatch));
0617:
0618: // make a TARGET for the catch that the tcf node knows about
0619: Node catchTarget = Node.newTarget();
0620: pn.target = catchTarget;
0621: // mark it
0622: pn.addChildToBack(catchTarget);
0623:
0624: //
0625: // Given
0626: //
0627: // try {
0628: // tryBlock;
0629: // } catch (e if condition1) {
0630: // something1;
0631: // ...
0632: //
0633: // } catch (e if conditionN) {
0634: // somethingN;
0635: // } catch (e) {
0636: // somethingDefault;
0637: // }
0638: //
0639: // rewrite as
0640: //
0641: // try {
0642: // tryBlock;
0643: // goto after_catch:
0644: // } catch (x) {
0645: // with (newCatchScope(e, x)) {
0646: // if (condition1) {
0647: // something1;
0648: // goto after_catch;
0649: // }
0650: // }
0651: // ...
0652: // with (newCatchScope(e, x)) {
0653: // if (conditionN) {
0654: // somethingN;
0655: // goto after_catch;
0656: // }
0657: // }
0658: // with (newCatchScope(e, x)) {
0659: // somethingDefault;
0660: // goto after_catch;
0661: // }
0662: // }
0663: // after_catch:
0664: //
0665: // If there is no default catch, then the last with block
0666: // arround "somethingDefault;" is replaced by "rethrow;"
0667:
0668: // It is assumed that catch handler generation will store
0669: // exeception object in handlerBlock register
0670:
0671: // Block with local for exception scope objects
0672: Node catchScopeBlock = new Node(Token.LOCAL_BLOCK);
0673:
0674: // expects catchblocks children to be (cond block) pairs.
0675: Node cb = catchBlocks.getFirstChild();
0676: boolean hasDefault = false;
0677: int scopeIndex = 0;
0678: while (cb != null) {
0679: int catchLineNo = cb.getLineno();
0680:
0681: Node name = cb.getFirstChild();
0682: Node cond = name.getNext();
0683: Node catchStatement = cond.getNext();
0684: cb.removeChild(name);
0685: cb.removeChild(cond);
0686: cb.removeChild(catchStatement);
0687:
0688: // Add goto to the catch statement to jump out of catch
0689: // but prefix it with LEAVEWITH since try..catch produces
0690: // "with"code in order to limit the scope of the exception
0691: // object.
0692: catchStatement
0693: .addChildToBack(new Node(Token.LEAVEWITH));
0694: catchStatement.addChildToBack(makeJump(Token.GOTO,
0695: endCatch));
0696:
0697: // Create condition "if" when present
0698: Node condStmt;
0699: if (cond.getType() == Token.EMPTY) {
0700: condStmt = catchStatement;
0701: hasDefault = true;
0702: } else {
0703: condStmt = createIf(cond, catchStatement, null,
0704: catchLineNo);
0705: }
0706:
0707: // Generate code to create the scope object and store
0708: // it in catchScopeBlock register
0709: Node catchScope = new Node(Token.CATCH_SCOPE, name,
0710: createUseLocal(handlerBlock));
0711: // TODO - add positions here to catchScope!
0712:
0713: catchScope.putProp(Node.LOCAL_BLOCK_PROP,
0714: catchScopeBlock);
0715: catchScope
0716: .putIntProp(Node.CATCH_SCOPE_PROP, scopeIndex);
0717: catchScopeBlock.addChildToBack(catchScope);
0718:
0719: // Add with statement based on catch scope object
0720: catchScopeBlock.addChildToBack(createWith(
0721: createUseLocal(catchScopeBlock), condStmt,
0722: catchLineNo));
0723:
0724: // move to next cb
0725: cb = cb.getNext();
0726: ++scopeIndex;
0727: }
0728: pn.addChildToBack(catchScopeBlock);
0729: if (!hasDefault) {
0730: // Generate code to rethrow if no catch clause was executed
0731: Node rethrow = new Node(Token.RETHROW);
0732: rethrow.putProp(Node.LOCAL_BLOCK_PROP, handlerBlock);
0733: pn.addChildToBack(rethrow);
0734: }
0735:
0736: pn.addChildToBack(endCatch);
0737: }
0738:
0739: if (hasFinally) {
0740: Node finallyTarget = Node.newTarget();
0741: pn.setFinally(finallyTarget);
0742:
0743: // add jsr finally to the try block
0744: pn.addChildToBack(makeJump(Token.JSR, finallyTarget));
0745:
0746: // jump around finally code
0747: Node finallyEnd = Node.newTarget();
0748: pn.addChildToBack(makeJump(Token.GOTO, finallyEnd));
0749:
0750: pn.addChildToBack(finallyTarget);
0751: Node fBlock = new Node(Token.FINALLY, finallyBlock);
0752: fBlock.putProp(Node.LOCAL_BLOCK_PROP, handlerBlock);
0753: pn.addChildToBack(fBlock);
0754:
0755: pn.addChildToBack(finallyEnd);
0756: }
0757: handlerBlock.addChildToBack(pn);
0758: // <netbeans>
0759: handlerBlock
0760: .setSourceBounds(startOffset, parser.getEndOffset());
0761: // </netbeans>
0762: return handlerBlock;
0763: }
0764:
0765: /**
0766: * Throw, Return, Label, Break and Continue are defined in ASTFactory.
0767: */
0768:
0769: /**
0770: * With
0771: */
0772: Node createWith(Node obj, Node body, int lineno) {
0773: setRequiresActivation();
0774: Node result = new Node(Token.BLOCK, lineno);
0775: result.addChildToBack(new Node(Token.ENTERWITH, obj));
0776: Node bodyNode = new Node(Token.WITH, body, lineno);
0777: result.addChildrenToBack(bodyNode);
0778: result.addChildToBack(new Node(Token.LEAVEWITH));
0779: return result;
0780: }
0781:
0782: /**
0783: * DOTQUERY
0784: */
0785: public Node createDotQuery(Node obj, Node body, int lineno) {
0786: setRequiresActivation();
0787: Node result = new Node(Token.DOTQUERY, obj, body, lineno);
0788: return result;
0789: }
0790:
0791: Node createArrayLiteral(ObjArray elems, int skipCount) {
0792: int length = elems.size();
0793: int[] skipIndexes = null;
0794: if (skipCount != 0) {
0795: skipIndexes = new int[skipCount];
0796: }
0797: Node array = new Node(Token.ARRAYLIT);
0798: for (int i = 0, j = 0; i != length; ++i) {
0799: Node elem = (Node) elems.get(i);
0800: if (elem != null) {
0801: array.addChildToBack(elem);
0802: } else {
0803: skipIndexes[j] = i;
0804: ++j;
0805: }
0806: }
0807: if (skipCount != 0) {
0808: array.putProp(Node.SKIP_INDEXES_PROP, skipIndexes);
0809: }
0810: return array;
0811: }
0812:
0813: /**
0814: * Object Literals
0815: * <BR> createObjectLiteral rewrites its argument as object
0816: * creation plus object property entries, so later compiler
0817: * stages don't need to know about object literals.
0818: */
0819: Node createObjectLiteral(ObjArray elems) {
0820: int size = elems.size() / 2;
0821: Node object = new Node(Token.OBJECTLIT);
0822: Object[] properties;
0823: if (size == 0) {
0824: properties = ScriptRuntime.emptyArgs;
0825: } else {
0826: properties = new Object[size];
0827: for (int i = 0; i != size; ++i) {
0828: properties[i] = elems.get(2 * i);
0829: Node value = (Node) elems.get(2 * i + 1);
0830: object.addChildToBack(value);
0831: }
0832: }
0833: object.putProp(Node.OBJECT_IDS_PROP, properties);
0834: return object;
0835: }
0836:
0837: /**
0838: * Regular expressions
0839: */
0840: Node createRegExp(int regexpIndex) {
0841: Node n = new Node(Token.REGEXP);
0842: n.putIntProp(Node.REGEXP_PROP, regexpIndex);
0843: return n;
0844: }
0845:
0846: /**
0847: * If statement
0848: */
0849: Node createIf(Node cond, Node ifTrue, Node ifFalse, int lineno) {
0850: int condStatus = isAlwaysDefinedBoolean(cond);
0851: if (condStatus == ALWAYS_TRUE_BOOLEAN) {
0852: return ifTrue;
0853: } else if (condStatus == ALWAYS_FALSE_BOOLEAN) {
0854: if (ifFalse != null) {
0855: return ifFalse;
0856: }
0857: // Replace if (false) xxx by empty block
0858: return new Node(Token.BLOCK, lineno);
0859: }
0860:
0861: Node result = new Node(Token.BLOCK, lineno);
0862: Node ifNotTarget = Node.newTarget();
0863: Node.Jump IFNE = new Node.Jump(Token.IFNE, cond);
0864: IFNE.target = ifNotTarget;
0865:
0866: result.addChildToBack(IFNE);
0867: result.addChildrenToBack(ifTrue);
0868:
0869: if (ifFalse != null) {
0870: Node endTarget = Node.newTarget();
0871: result.addChildToBack(makeJump(Token.GOTO, endTarget));
0872: result.addChildToBack(ifNotTarget);
0873: result.addChildrenToBack(ifFalse);
0874: result.addChildToBack(endTarget);
0875: } else {
0876: result.addChildToBack(ifNotTarget);
0877: }
0878:
0879: return result;
0880: }
0881:
0882: Node createCondExpr(Node cond, Node ifTrue, Node ifFalse) {
0883: int condStatus = isAlwaysDefinedBoolean(cond);
0884: if (condStatus == ALWAYS_TRUE_BOOLEAN) {
0885: return ifTrue;
0886: } else if (condStatus == ALWAYS_FALSE_BOOLEAN) {
0887: return ifFalse;
0888: }
0889: return new Node(Token.HOOK, cond, ifTrue, ifFalse);
0890: }
0891:
0892: /**
0893: * Unary
0894: */
0895: Node createUnary(int nodeType, Node child) {
0896: int childType = child.getType();
0897: switch (nodeType) {
0898: case Token.DELPROP: {
0899: Node n;
0900: if (childType == Token.NAME) {
0901: // Transform Delete(Name "a")
0902: // to Delete(Bind("a"), String("a"))
0903: child.setType(Token.BINDNAME);
0904: Node left = child;
0905: Node right = Node.newString(child.getString());
0906: n = new Node(nodeType, left, right);
0907: } else if (childType == Token.GETPROP
0908: || childType == Token.GETELEM) {
0909: Node left = child.getFirstChild();
0910: Node right = child.getLastChild();
0911: child.removeChild(left);
0912: child.removeChild(right);
0913: n = new Node(nodeType, left, right);
0914: } else if (childType == Token.GET_REF) {
0915: Node ref = child.getFirstChild();
0916: child.removeChild(ref);
0917: n = new Node(Token.DEL_REF, ref);
0918: } else {
0919: n = new Node(Token.TRUE);
0920: }
0921: return n;
0922: }
0923: case Token.TYPEOF:
0924: if (childType == Token.NAME) {
0925: child.setType(Token.TYPEOFNAME);
0926: return child;
0927: }
0928: break;
0929: case Token.BITNOT:
0930: if (childType == Token.NUMBER) {
0931: int value = ScriptRuntime.toInt32(child.getDouble());
0932: child.setDouble(~value);
0933: return child;
0934: }
0935: break;
0936: case Token.NEG:
0937: if (childType == Token.NUMBER) {
0938: child.setDouble(-child.getDouble());
0939: return child;
0940: }
0941: break;
0942: case Token.NOT: {
0943: int status = isAlwaysDefinedBoolean(child);
0944: if (status != 0) {
0945: int type;
0946: if (status == ALWAYS_TRUE_BOOLEAN) {
0947: type = Token.FALSE;
0948: } else {
0949: type = Token.TRUE;
0950: }
0951: if (childType == Token.TRUE || childType == Token.FALSE) {
0952: child.setType(type);
0953: return child;
0954: }
0955: return new Node(type);
0956: }
0957: break;
0958: }
0959: }
0960: return new Node(nodeType, child);
0961: }
0962:
0963: Node createCallOrNew(int nodeType, Node child) {
0964: int type = Node.NON_SPECIALCALL;
0965: if (child.getType() == Token.NAME) {
0966: String name = child.getString();
0967: if (name.equals("eval")) {
0968: type = Node.SPECIALCALL_EVAL;
0969: } else if (name.equals("With")) {
0970: type = Node.SPECIALCALL_WITH;
0971: }
0972: } else if (child.getType() == Token.GETPROP) {
0973: String name = child.getLastChild().getString();
0974: if (name.equals("eval")) {
0975: type = Node.SPECIALCALL_EVAL;
0976: }
0977: }
0978: Node node = new Node(nodeType, child);
0979: if (type != Node.NON_SPECIALCALL) {
0980: // Calls to these functions require activation objects.
0981: setRequiresActivation();
0982: node.putIntProp(Node.SPECIALCALL_PROP, type);
0983: }
0984: return node;
0985: }
0986:
0987: Node createIncDec(int nodeType, boolean post, Node child) {
0988: child = makeReference(child);
0989: if (child == null) {
0990: String msg;
0991: if (nodeType == Token.DEC) {
0992: msg = "msg.bad.decr";
0993: } else {
0994: msg = "msg.bad.incr";
0995: }
0996: parser.reportError(msg);
0997: return null;
0998: }
0999:
1000: int childType = child.getType();
1001:
1002: switch (childType) {
1003: case Token.NAME:
1004: case Token.GETPROP:
1005: case Token.GETELEM:
1006: case Token.GET_REF: {
1007: Node n = new Node(nodeType, child);
1008: int incrDecrMask = 0;
1009: if (nodeType == Token.DEC) {
1010: incrDecrMask |= Node.DECR_FLAG;
1011: }
1012: if (post) {
1013: incrDecrMask |= Node.POST_FLAG;
1014: }
1015: n.putIntProp(Node.INCRDECR_PROP, incrDecrMask);
1016: return n;
1017: }
1018: }
1019: throw Kit.codeBug();
1020: }
1021:
1022: Node createPropertyGet(Node target, String namespace, String name,
1023: int memberTypeFlags) {
1024: if (namespace == null && memberTypeFlags == 0) {
1025: if (target == null) {
1026: return createName(name);
1027: }
1028: checkActivationName(name, Token.GETPROP);
1029: if (ScriptRuntime.isSpecialProperty(name)) {
1030: Node ref = new Node(Token.REF_SPECIAL, target);
1031: ref.putProp(Node.NAME_PROP, name);
1032: return new Node(Token.GET_REF, ref);
1033: }
1034: return new Node(Token.GETPROP, target, createString(name));
1035: }
1036: Node elem = createString(name);
1037: memberTypeFlags |= Node.PROPERTY_FLAG;
1038: return createMemberRefGet(target, namespace, elem,
1039: memberTypeFlags);
1040: }
1041:
1042: Node createElementGet(Node target, String namespace, Node elem,
1043: int memberTypeFlags) {
1044: // OPT: could optimize to createPropertyGet
1045: // iff elem is string that can not be number
1046: if (namespace == null && memberTypeFlags == 0) {
1047: // stand-alone [aaa] as primary expression is array literal
1048: // declaration and should not come here!
1049: if (target == null)
1050: throw Kit.codeBug();
1051: return new Node(Token.GETELEM, target, elem);
1052: }
1053: return createMemberRefGet(target, namespace, elem,
1054: memberTypeFlags);
1055: }
1056:
1057: private Node createMemberRefGet(Node target, String namespace,
1058: Node elem, int memberTypeFlags) {
1059: Node nsNode = null;
1060: if (namespace != null) {
1061: // See 11.1.2 in ECMA 357
1062: if (namespace.equals("*")) {
1063: nsNode = new Node(Token.NULL);
1064: } else {
1065: nsNode = createName(namespace);
1066: }
1067: }
1068: Node ref;
1069: if (target == null) {
1070: if (namespace == null) {
1071: ref = new Node(Token.REF_NAME, elem);
1072: } else {
1073: ref = new Node(Token.REF_NS_NAME, nsNode, elem);
1074: }
1075: } else {
1076: if (namespace == null) {
1077: ref = new Node(Token.REF_MEMBER, target, elem);
1078: } else {
1079: ref = new Node(Token.REF_NS_MEMBER, target, nsNode,
1080: elem);
1081: }
1082: }
1083: if (memberTypeFlags != 0) {
1084: ref.putIntProp(Node.MEMBER_TYPE_PROP, memberTypeFlags);
1085: }
1086: return new Node(Token.GET_REF, ref);
1087: }
1088:
1089: /**
1090: * Binary
1091: */
1092: Node createBinary(int nodeType, Node left, Node right) {
1093: switch (nodeType) {
1094:
1095: case Token.ADD:
1096: // numerical addition and string concatenation
1097: if (left.type == Token.STRING) {
1098: String s2;
1099: if (right.type == Token.STRING) {
1100: s2 = right.getString();
1101: } else if (right.type == Token.NUMBER) {
1102: s2 = ScriptRuntime.numberToString(
1103: right.getDouble(), 10);
1104: } else {
1105: break;
1106: }
1107: String s1 = left.getString();
1108: left.setString(s1.concat(s2));
1109: return left;
1110: } else if (left.type == Token.NUMBER) {
1111: if (right.type == Token.NUMBER) {
1112: left
1113: .setDouble(left.getDouble()
1114: + right.getDouble());
1115: return left;
1116: } else if (right.type == Token.STRING) {
1117: String s1, s2;
1118: s1 = ScriptRuntime.numberToString(left.getDouble(),
1119: 10);
1120: s2 = right.getString();
1121: right.setString(s1.concat(s2));
1122: return right;
1123: }
1124: }
1125: // can't do anything if we don't know both types - since
1126: // 0 + object is supposed to call toString on the object and do
1127: // string concantenation rather than addition
1128: break;
1129:
1130: case Token.SUB:
1131: // numerical subtraction
1132: if (left.type == Token.NUMBER) {
1133: double ld = left.getDouble();
1134: if (right.type == Token.NUMBER) {
1135: //both numbers
1136: left.setDouble(ld - right.getDouble());
1137: return left;
1138: } else if (ld == 0.0) {
1139: // first 0: 0-x -> -x
1140: return new Node(Token.NEG, right);
1141: }
1142: } else if (right.type == Token.NUMBER) {
1143: if (right.getDouble() == 0.0) {
1144: //second 0: x - 0 -> +x
1145: // can not make simply x because x - 0 must be number
1146: return new Node(Token.POS, left);
1147: }
1148: }
1149: break;
1150:
1151: case Token.MUL:
1152: // numerical multiplication
1153: if (left.type == Token.NUMBER) {
1154: double ld = left.getDouble();
1155: if (right.type == Token.NUMBER) {
1156: //both numbers
1157: left.setDouble(ld * right.getDouble());
1158: return left;
1159: } else if (ld == 1.0) {
1160: // first 1: 1 * x -> +x
1161: return new Node(Token.POS, right);
1162: }
1163: } else if (right.type == Token.NUMBER) {
1164: if (right.getDouble() == 1.0) {
1165: //second 1: x * 1 -> +x
1166: // can not make simply x because x - 0 must be number
1167: return new Node(Token.POS, left);
1168: }
1169: }
1170: // can't do x*0: Infinity * 0 gives NaN, not 0
1171: break;
1172:
1173: case Token.DIV:
1174: // number division
1175: if (right.type == Token.NUMBER) {
1176: double rd = right.getDouble();
1177: if (left.type == Token.NUMBER) {
1178: // both constants -- just divide, trust Java to handle x/0
1179: left.setDouble(left.getDouble() / rd);
1180: return left;
1181: } else if (rd == 1.0) {
1182: // second 1: x/1 -> +x
1183: // not simply x to force number convertion
1184: return new Node(Token.POS, left);
1185: }
1186: }
1187: break;
1188:
1189: case Token.AND: {
1190: // Since x && y gives x, not false, when Boolean(x) is false,
1191: // and y, not Boolean(y), when Boolean(x) is true, x && y
1192: // can only be simplified if x is defined. See bug 309957.
1193:
1194: int leftStatus = isAlwaysDefinedBoolean(left);
1195: if (leftStatus == ALWAYS_FALSE_BOOLEAN) {
1196: // if the first one is false, just return it
1197: return left;
1198: } else if (leftStatus == ALWAYS_TRUE_BOOLEAN) {
1199: // if first is true, set to second
1200: return right;
1201: }
1202: break;
1203: }
1204:
1205: case Token.OR: {
1206: // Since x || y gives x, not true, when Boolean(x) is true,
1207: // and y, not Boolean(y), when Boolean(x) is false, x || y
1208: // can only be simplified if x is defined. See bug 309957.
1209:
1210: int leftStatus = isAlwaysDefinedBoolean(left);
1211: if (leftStatus == ALWAYS_TRUE_BOOLEAN) {
1212: // if the first one is true, just return it
1213: return left;
1214: } else if (leftStatus == ALWAYS_FALSE_BOOLEAN) {
1215: // if first is false, set to second
1216: return right;
1217: }
1218: break;
1219: }
1220: }
1221:
1222: return new Node(nodeType, left, right);
1223: }
1224:
1225: private Node simpleAssignment(Node left, Node right) {
1226: int nodeType = left.getType();
1227: switch (nodeType) {
1228: case Token.NAME:
1229: left.setType(Token.BINDNAME);
1230: return new Node(Token.SETNAME, left, right);
1231:
1232: case Token.GETPROP:
1233: case Token.GETELEM: {
1234: Node obj = left.getFirstChild();
1235: Node id = left.getLastChild();
1236: int type;
1237: if (nodeType == Token.GETPROP) {
1238: type = Token.SETPROP;
1239: } else {
1240: type = Token.SETELEM;
1241: }
1242: return new Node(type, obj, id, right);
1243: }
1244: case Token.GET_REF: {
1245: Node ref = left.getFirstChild();
1246: checkMutableReference(ref);
1247: return new Node(Token.SET_REF, ref, right);
1248: }
1249: }
1250:
1251: throw Kit.codeBug();
1252: }
1253:
1254: private void checkMutableReference(Node n) {
1255: int memberTypeFlags = n.getIntProp(Node.MEMBER_TYPE_PROP, 0);
1256: if ((memberTypeFlags & Node.DESCENDANTS_FLAG) != 0) {
1257: parser.reportError("msg.bad.assign.left");
1258: }
1259: }
1260:
1261: Node createAssignment(int assignType, Node left, Node right) {
1262: left = makeReference(left);
1263: if (left == null) {
1264: parser.reportError("msg.bad.assign.left");
1265: return right;
1266: }
1267:
1268: int assignOp;
1269: switch (assignType) {
1270: case Token.ASSIGN:
1271: return simpleAssignment(left, right);
1272: case Token.ASSIGN_BITOR:
1273: assignOp = Token.BITOR;
1274: break;
1275: case Token.ASSIGN_BITXOR:
1276: assignOp = Token.BITXOR;
1277: break;
1278: case Token.ASSIGN_BITAND:
1279: assignOp = Token.BITAND;
1280: break;
1281: case Token.ASSIGN_LSH:
1282: assignOp = Token.LSH;
1283: break;
1284: case Token.ASSIGN_RSH:
1285: assignOp = Token.RSH;
1286: break;
1287: case Token.ASSIGN_URSH:
1288: assignOp = Token.URSH;
1289: break;
1290: case Token.ASSIGN_ADD:
1291: assignOp = Token.ADD;
1292: break;
1293: case Token.ASSIGN_SUB:
1294: assignOp = Token.SUB;
1295: break;
1296: case Token.ASSIGN_MUL:
1297: assignOp = Token.MUL;
1298: break;
1299: case Token.ASSIGN_DIV:
1300: assignOp = Token.DIV;
1301: break;
1302: case Token.ASSIGN_MOD:
1303: assignOp = Token.MOD;
1304: break;
1305: default:
1306: throw Kit.codeBug();
1307: }
1308:
1309: int nodeType = left.getType();
1310: switch (nodeType) {
1311: case Token.NAME: {
1312: String s = left.getString();
1313:
1314: Node opLeft = Node.newString(Token.NAME, s);
1315: // <netbeans>
1316: opLeft.setSourceBounds(left.getSourceStart(), left
1317: .getSourceEnd());
1318: // </netbeans>
1319: Node op = new Node(assignOp, opLeft, right);
1320: Node lvalueLeft = Node.newString(Token.BINDNAME, s);
1321: // <netbeans>
1322: lvalueLeft.setSourceBounds(left.getSourceStart(), left
1323: .getSourceEnd());
1324: // </netbeans>
1325: return new Node(Token.SETNAME, lvalueLeft, op);
1326: }
1327: case Token.GETPROP:
1328: case Token.GETELEM: {
1329: Node obj = left.getFirstChild();
1330: Node id = left.getLastChild();
1331:
1332: int type = nodeType == Token.GETPROP ? Token.SETPROP_OP
1333: : Token.SETELEM_OP;
1334:
1335: Node opLeft = new Node(Token.USE_STACK);
1336: Node op = new Node(assignOp, opLeft, right);
1337: return new Node(type, obj, id, op);
1338: }
1339: case Token.GET_REF: {
1340: Node ref = left.getFirstChild();
1341: checkMutableReference(ref);
1342: Node opLeft = new Node(Token.USE_STACK);
1343: Node op = new Node(assignOp, opLeft, right);
1344: return new Node(Token.SET_REF_OP, ref, op);
1345: }
1346: }
1347:
1348: throw Kit.codeBug();
1349: }
1350:
1351: Node createUseLocal(Node localBlock) {
1352: if (Token.LOCAL_BLOCK != localBlock.getType())
1353: throw Kit.codeBug();
1354: Node result = new Node(Token.LOCAL_LOAD);
1355: // <netbeans>
1356: result.setSourceBounds(localBlock.getSourceStart(), localBlock
1357: .getSourceEnd());
1358: // </netbeans>
1359: result.putProp(Node.LOCAL_BLOCK_PROP, localBlock);
1360: return result;
1361: }
1362:
1363: private Node.Jump makeJump(int type, Node target) {
1364: Node.Jump n = new Node.Jump(type);
1365: // <netbeans>
1366: int pos = parser.getStartOffset();
1367: n.setSourceBounds(pos, pos);
1368: // </netbeans>
1369: n.target = target;
1370: return n;
1371: }
1372:
1373: private Node makeReference(Node node) {
1374: int type = node.getType();
1375: switch (type) {
1376: case Token.NAME:
1377: case Token.GETPROP:
1378: case Token.GETELEM:
1379: case Token.GET_REF:
1380: return node;
1381: case Token.CALL:
1382: node.setType(Token.REF_CALL);
1383: return new Node(Token.GET_REF, node);
1384: }
1385: // Signal caller to report error
1386: return null;
1387: }
1388:
1389: // Check if Node always mean true or false in boolean context
1390: private static int isAlwaysDefinedBoolean(Node node) {
1391: switch (node.getType()) {
1392: case Token.FALSE:
1393: case Token.NULL:
1394: return ALWAYS_FALSE_BOOLEAN;
1395: case Token.TRUE:
1396: return ALWAYS_TRUE_BOOLEAN;
1397: case Token.NUMBER: {
1398: double num = node.getDouble();
1399: if (num == num && num != 0.0) {
1400: return ALWAYS_TRUE_BOOLEAN;
1401: } else {
1402: return ALWAYS_FALSE_BOOLEAN;
1403: }
1404: }
1405: }
1406: return 0;
1407: }
1408:
1409: // Commented-out: no longer used
1410: // private static boolean hasSideEffects(Node exprTree)
1411: // {
1412: // switch (exprTree.getType()) {
1413: // case Token.INC:
1414: // case Token.DEC:
1415: // case Token.SETPROP:
1416: // case Token.SETELEM:
1417: // case Token.SETNAME:
1418: // case Token.CALL:
1419: // case Token.NEW:
1420: // return true;
1421: // default:
1422: // Node child = exprTree.getFirstChild();
1423: // while (child != null) {
1424: // if (hasSideEffects(child))
1425: // return true;
1426: // child = child.getNext();
1427: // }
1428: // break;
1429: // }
1430: // return false;
1431: // }
1432:
1433: private void checkActivationName(String name, int token) {
1434: if (parser.insideFunction()) {
1435: boolean activation = false;
1436: if ("arguments".equals(name)
1437: || (parser.compilerEnv.activationNames != null && parser.compilerEnv.activationNames
1438: .containsKey(name))) {
1439: activation = true;
1440: } else if ("length".equals(name)) {
1441: if (token == Token.GETPROP
1442: && parser.compilerEnv.getLanguageVersion() == Context.VERSION_1_2) {
1443: // Use of "length" in 1.2 requires an activation object.
1444: activation = true;
1445: }
1446: }
1447: if (activation) {
1448: setRequiresActivation();
1449: }
1450: }
1451: }
1452:
1453: private void setRequiresActivation() {
1454: if (parser.insideFunction()) {
1455: ((FunctionNode) parser.currentScriptOrFn).itsNeedsActivation = true;
1456: }
1457: }
1458:
1459: private Parser parser;
1460:
1461: private static final int LOOP_DO_WHILE = 0;
1462: private static final int LOOP_WHILE = 1;
1463: private static final int LOOP_FOR = 2;
1464:
1465: private static final int ALWAYS_TRUE_BOOLEAN = 1;
1466: private static final int ALWAYS_FALSE_BOOLEAN = -1;
1467: }
|