Source Code Cross Referenced for IRFactory.java in  » Scripting » rhino » org » mozilla » javascript » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Scripting » rhino » org.mozilla.javascript 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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