Source Code Cross Referenced for Parser.java in  » Ajax » GWT » com » google » gwt » dev » js » rhino » 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 » Ajax » GWT » com.google.gwt.dev.js.rhino 
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:         * The contents of this file are subject to the Netscape Public
0004:         * License Version 1.1 (the "License"); you may not use this file
0005:         * except in compliance with the License. You may obtain a copy of
0006:         * the License at http://www.mozilla.org/NPL/
0007:         *
0008:         * Software distributed under the License is distributed on an "AS
0009:         * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
0010:         * implied. See the License for the specific language governing
0011:         * rights and limitations under the License.
0012:         *
0013:         * The Original Code is Rhino code, released
0014:         * May 6, 1999.
0015:         *
0016:         * The Initial Developer of the Original Code is Netscape
0017:         * Communications Corporation.  Portions created by Netscape are
0018:         * Copyright (C) 1997-1999 Netscape Communications Corporation. All
0019:         * Rights Reserved.
0020:         *
0021:         * Contributor(s): 
0022:         * Mike Ang
0023:         * Mike McCabe
0024:         *
0025:         * Alternatively, the contents of this file may be used under the
0026:         * terms of the GNU Public License (the "GPL"), in which case the
0027:         * provisions of the GPL are applicable instead of those above.
0028:         * If you wish to allow use of your version of this file only
0029:         * under the terms of the GPL and not to allow others to use your
0030:         * version of this file under the NPL, indicate your decision by
0031:         * deleting the provisions above and replace them with the notice
0032:         * and other provisions required by the GPL.  If you do not delete
0033:         * the provisions above, a recipient may use your version of this
0034:         * file under either the NPL or the GPL.
0035:         */
0036:        // Modified by Google
0037:        package com.google.gwt.dev.js.rhino;
0038:
0039:        import java.io.IOException;
0040:
0041:        /**
0042:         * This class implements the JavaScript parser.
0043:         * 
0044:         * It is based on the C source files jsparse.c and jsparse.h in the jsref
0045:         * package.
0046:         * 
0047:         * @see TokenStream
0048:         * 
0049:         * @author Mike McCabe
0050:         * @author Brendan Eich
0051:         */
0052:
0053:        public class Parser {
0054:
0055:            public Parser(IRFactory nf) {
0056:                this .nf = nf;
0057:            }
0058:
0059:            private void mustMatchToken(TokenStream ts, int toMatch,
0060:                    String messageId) throws IOException, JavaScriptException {
0061:                int tt;
0062:                if ((tt = ts.getToken()) != toMatch) {
0063:                    reportError(ts, messageId);
0064:                    ts.ungetToken(tt); // In case the parser decides to continue
0065:                }
0066:            }
0067:
0068:            private void reportError(TokenStream ts, String messageId)
0069:                    throws JavaScriptException {
0070:                this .ok = false;
0071:                ts.reportSyntaxError(messageId, null);
0072:
0073:                /*
0074:                 * Throw an exception to unwind the recursive descent parse. We use
0075:                 * JavaScriptException here even though it is really a different use of the
0076:                 * exception than it is usually used for.
0077:                 */
0078:                throw new JavaScriptException(messageId);
0079:            }
0080:
0081:            /*
0082:             * Build a parse tree from the given TokenStream.
0083:             * 
0084:             * @param ts the TokenStream to parse
0085:             * 
0086:             * @return an Object representing the parsed program. If the parse fails, null
0087:             * will be returned. (The parse failure will result in a call to the current
0088:             * Context's ErrorReporter.)
0089:             */
0090:            public Object parse(TokenStream ts) throws IOException {
0091:                this .ok = true;
0092:                sourceTop = 0;
0093:                functionNumber = 0;
0094:
0095:                int tt; // last token from getToken();
0096:                int baseLineno = ts.getLineno(); // line number where source starts
0097:
0098:                /*
0099:                 * so we have something to add nodes to until we've collected all the source
0100:                 */
0101:                Object tempBlock = nf.createLeaf(TokenStream.BLOCK);
0102:                ((Node) tempBlock).setIsSyntheticBlock(true);
0103:
0104:                while (true) {
0105:                    ts.flags |= ts.TSF_REGEXP;
0106:                    tt = ts.getToken();
0107:                    ts.flags &= ~ts.TSF_REGEXP;
0108:
0109:                    if (tt <= ts.EOF) {
0110:                        break;
0111:                    }
0112:
0113:                    if (tt == ts.FUNCTION) {
0114:                        try {
0115:                            nf.addChildToBack(tempBlock, function(ts, false));
0116:                        } catch (JavaScriptException e) {
0117:                            this .ok = false;
0118:                            break;
0119:                        }
0120:                    } else {
0121:                        ts.ungetToken(tt);
0122:                        nf.addChildToBack(tempBlock, statement(ts));
0123:                    }
0124:                }
0125:
0126:                if (!this .ok) {
0127:                    // XXX ts.clearPushback() call here?
0128:                    return null;
0129:                }
0130:
0131:                Object pn = nf.createScript(tempBlock, ts.getSourceName(),
0132:                        baseLineno, ts.getLineno(), sourceToString(0));
0133:                ((Node) pn).setIsSyntheticBlock(true);
0134:                return pn;
0135:            }
0136:
0137:            /*
0138:             * The C version of this function takes an argument list, which doesn't seem
0139:             * to be needed for tree generation... it'd only be useful for checking
0140:             * argument hiding, which I'm not doing anyway...
0141:             */
0142:            private Object parseFunctionBody(TokenStream ts) throws IOException {
0143:                int oldflags = ts.flags;
0144:                ts.flags &= ~(TokenStream.TSF_RETURN_EXPR | TokenStream.TSF_RETURN_VOID);
0145:                ts.flags |= TokenStream.TSF_FUNCTION;
0146:
0147:                Object pn = nf.createBlock(ts.getLineno());
0148:                try {
0149:                    int tt;
0150:                    while ((tt = ts.peekToken()) > ts.EOF && tt != ts.RC) {
0151:                        if (tt == TokenStream.FUNCTION) {
0152:                            ts.getToken();
0153:                            nf.addChildToBack(pn, function(ts, false));
0154:                        } else {
0155:                            nf.addChildToBack(pn, statement(ts));
0156:                        }
0157:                    }
0158:                } catch (JavaScriptException e) {
0159:                    this .ok = false;
0160:                } finally {
0161:                    // also in finally block:
0162:                    // flushNewLines, clearPushback.
0163:
0164:                    ts.flags = oldflags;
0165:                }
0166:
0167:                return pn;
0168:            }
0169:
0170:            private Object function(TokenStream ts, boolean isExpr)
0171:                    throws IOException, JavaScriptException {
0172:                int baseLineno = ts.getLineno(); // line number where source starts
0173:
0174:                String name;
0175:                Object memberExprNode = null;
0176:                if (ts.matchToken(ts.NAME)) {
0177:                    name = ts.getString();
0178:                    if (!ts.matchToken(ts.LP)) {
0179:                        if (Context.getContext().hasFeature(
0180:                                Context.FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME)) {
0181:                            // Extension to ECMA: if 'function <name>' does not follow
0182:                            // by '(', assume <name> starts memberExpr
0183:                            sourceAddString(ts.NAME, name);
0184:                            Object memberExprHead = nf.createName(name);
0185:                            name = null;
0186:                            memberExprNode = memberExprTail(ts, false,
0187:                                    memberExprHead);
0188:                        }
0189:                        mustMatchToken(ts, ts.LP, "msg.no.paren.parms");
0190:                    }
0191:                } else if (ts.matchToken(ts.LP)) {
0192:                    // Anonymous function
0193:                    name = null;
0194:                } else {
0195:                    name = null;
0196:                    if (Context.getContext().hasFeature(
0197:                            Context.FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME)) {
0198:                        // Note that memberExpr can not start with '(' like
0199:                        // in (1+2).toString, because 'function (' already
0200:                        // processed as anonymous function
0201:                        memberExprNode = memberExpr(ts, false);
0202:                    }
0203:                    mustMatchToken(ts, ts.LP, "msg.no.paren.parms");
0204:                }
0205:
0206:                if (memberExprNode != null) {
0207:                    // transform 'function' <memberExpr> to <memberExpr> = function
0208:                    // even in the decompilated source
0209:                    sourceAdd((char) ts.ASSIGN);
0210:                    sourceAdd((char) ts.NOP);
0211:                }
0212:
0213:                // save a reference to the function in the enclosing source.
0214:                sourceAdd((char) ts.FUNCTION);
0215:                sourceAdd((char) functionNumber);
0216:                ++functionNumber;
0217:
0218:                // Save current source top to restore it on exit not to include
0219:                // function to parent source
0220:                int savedSourceTop = sourceTop;
0221:                int savedFunctionNumber = functionNumber;
0222:                Object args;
0223:                Object body;
0224:                String source;
0225:                try {
0226:                    functionNumber = 0;
0227:
0228:                    // FUNCTION as the first token in a Source means it's a function
0229:                    // definition, and not a reference.
0230:                    sourceAdd((char) ts.FUNCTION);
0231:                    if (name != null) {
0232:                        sourceAddString(ts.NAME, name);
0233:                    }
0234:                    sourceAdd((char) ts.LP);
0235:                    args = nf.createLeaf(ts.LP);
0236:
0237:                    if (!ts.matchToken(ts.GWT)) {
0238:                        boolean first = true;
0239:                        do {
0240:                            if (!first)
0241:                                sourceAdd((char) ts.COMMA);
0242:                            first = false;
0243:                            mustMatchToken(ts, ts.NAME, "msg.no.parm");
0244:                            String s = ts.getString();
0245:                            nf.addChildToBack(args, nf.createName(s));
0246:
0247:                            sourceAddString(ts.NAME, s);
0248:                        } while (ts.matchToken(ts.COMMA));
0249:
0250:                        mustMatchToken(ts, ts.GWT, "msg.no.paren.after.parms");
0251:                    }
0252:                    sourceAdd((char) ts.GWT);
0253:
0254:                    mustMatchToken(ts, ts.LC, "msg.no.brace.body");
0255:                    sourceAdd((char) ts.LC);
0256:                    sourceAdd((char) ts.EOL);
0257:                    body = parseFunctionBody(ts);
0258:                    mustMatchToken(ts, ts.RC, "msg.no.brace.after.body");
0259:                    sourceAdd((char) ts.RC);
0260:                    // skip the last EOL so nested functions work...
0261:
0262:                    // name might be null;
0263:                    source = sourceToString(savedSourceTop);
0264:                } finally {
0265:                    sourceTop = savedSourceTop;
0266:                    functionNumber = savedFunctionNumber;
0267:                }
0268:
0269:                Object pn = nf.createFunction(name, args, body, ts
0270:                        .getSourceName(), baseLineno, ts.getLineno(), source,
0271:                        isExpr || memberExprNode != null);
0272:                if (memberExprNode != null) {
0273:                    pn = nf.createBinary(ts.ASSIGN, ts.NOP, memberExprNode, pn);
0274:                }
0275:
0276:                // Add EOL but only if function is not part of expression, in which
0277:                // case it gets SEMI + EOL from Statement.
0278:                if (!isExpr) {
0279:                    if (memberExprNode != null) {
0280:                        // Add ';' to make 'function x.f(){}' and 'x.f = function(){}'
0281:                        // to print the same strings when decompiling
0282:                        sourceAdd((char) ts.SEMI);
0283:                    }
0284:                    sourceAdd((char) ts.EOL);
0285:                    wellTerminated(ts, ts.FUNCTION);
0286:                }
0287:
0288:                return pn;
0289:            }
0290:
0291:            private Object statements(TokenStream ts) throws IOException {
0292:                Object pn = nf.createBlock(ts.getLineno());
0293:
0294:                int tt;
0295:                while ((tt = ts.peekToken()) > ts.EOF && tt != ts.RC) {
0296:                    nf.addChildToBack(pn, statement(ts));
0297:                }
0298:
0299:                return pn;
0300:            }
0301:
0302:            private Object condition(TokenStream ts) throws IOException,
0303:                    JavaScriptException {
0304:                Object pn;
0305:                mustMatchToken(ts, ts.LP, "msg.no.paren.cond");
0306:                sourceAdd((char) ts.LP);
0307:                pn = expr(ts, false);
0308:                mustMatchToken(ts, ts.GWT, "msg.no.paren.after.cond");
0309:                sourceAdd((char) ts.GWT);
0310:
0311:                // there's a check here in jsparse.c that corrects = to ==
0312:
0313:                return pn;
0314:            }
0315:
0316:            private boolean wellTerminated(TokenStream ts, int lastExprType)
0317:                    throws IOException, JavaScriptException {
0318:                int tt = ts.peekTokenSameLine();
0319:                if (tt == ts.ERROR) {
0320:                    return false;
0321:                }
0322:
0323:                if (tt != ts.EOF && tt != ts.EOL && tt != ts.SEMI
0324:                        && tt != ts.RC) {
0325:                    int version = Context.getContext().getLanguageVersion();
0326:                    if ((tt == ts.FUNCTION || lastExprType == ts.FUNCTION)
0327:                            && (version < Context.VERSION_1_2)) {
0328:                        /*
0329:                         * Checking against version < 1.2 and version >= 1.0 in the above line
0330:                         * breaks old javascript, so we keep it this way for now... XXX warning
0331:                         * needed?
0332:                         */
0333:                        return true;
0334:                    } else {
0335:                        reportError(ts, "msg.no.semi.stmt");
0336:                    }
0337:                }
0338:                return true;
0339:            }
0340:
0341:            // match a NAME; return null if no match.
0342:            private String matchLabel(TokenStream ts) throws IOException,
0343:                    JavaScriptException {
0344:                int lineno = ts.getLineno();
0345:
0346:                String label = null;
0347:                int tt;
0348:                tt = ts.peekTokenSameLine();
0349:                if (tt == ts.NAME) {
0350:                    ts.getToken();
0351:                    label = ts.getString();
0352:                }
0353:
0354:                if (lineno == ts.getLineno())
0355:                    wellTerminated(ts, ts.ERROR);
0356:
0357:                return label;
0358:            }
0359:
0360:            private Object statement(TokenStream ts) throws IOException {
0361:                try {
0362:                    return statementHelper(ts);
0363:                } catch (JavaScriptException e) {
0364:                    // skip to end of statement
0365:                    int lineno = ts.getLineno();
0366:                    int t;
0367:                    do {
0368:                        t = ts.getToken();
0369:                    } while (t != TokenStream.SEMI && t != TokenStream.EOL
0370:                            && t != TokenStream.EOF && t != TokenStream.ERROR);
0371:                    return nf.createExprStatement(nf.createName("error"),
0372:                            lineno);
0373:                }
0374:            }
0375:
0376:            /**
0377:             * Whether the "catch (e: e instanceof Exception) { ... }" syntax is
0378:             * implemented.
0379:             */
0380:
0381:            private Object statementHelper(TokenStream ts) throws IOException,
0382:                    JavaScriptException {
0383:                Object pn = null;
0384:
0385:                // If skipsemi == true, don't add SEMI + EOL to source at the
0386:                // end of this statment. For compound statements, IF/FOR etc.
0387:                boolean skipsemi = false;
0388:
0389:                int tt;
0390:
0391:                int lastExprType = 0; // For wellTerminated. 0 to avoid warning.
0392:
0393:                tt = ts.getToken();
0394:
0395:                switch (tt) {
0396:                case TokenStream.IF: {
0397:                    skipsemi = true;
0398:
0399:                    sourceAdd((char) ts.IF);
0400:                    int lineno = ts.getLineno();
0401:                    Object cond = condition(ts);
0402:                    sourceAdd((char) ts.LC);
0403:                    sourceAdd((char) ts.EOL);
0404:                    Object ifTrue = statement(ts);
0405:                    Object ifFalse = null;
0406:                    if (ts.matchToken(ts.ELSE)) {
0407:                        sourceAdd((char) ts.RC);
0408:                        sourceAdd((char) ts.ELSE);
0409:                        sourceAdd((char) ts.LC);
0410:                        sourceAdd((char) ts.EOL);
0411:                        ifFalse = statement(ts);
0412:                    }
0413:                    sourceAdd((char) ts.RC);
0414:                    sourceAdd((char) ts.EOL);
0415:                    pn = nf.createIf(cond, ifTrue, ifFalse, lineno);
0416:                    break;
0417:                }
0418:
0419:                case TokenStream.SWITCH: {
0420:                    skipsemi = true;
0421:
0422:                    sourceAdd((char) ts.SWITCH);
0423:                    pn = nf.createSwitch(ts.getLineno());
0424:
0425:                    Object cur_case = null; // to kill warning
0426:                    Object case_statements;
0427:
0428:                    mustMatchToken(ts, ts.LP, "msg.no.paren.switch");
0429:                    sourceAdd((char) ts.LP);
0430:                    nf.addChildToBack(pn, expr(ts, false));
0431:                    mustMatchToken(ts, ts.GWT, "msg.no.paren.after.switch");
0432:                    sourceAdd((char) ts.GWT);
0433:                    mustMatchToken(ts, ts.LC, "msg.no.brace.switch");
0434:                    sourceAdd((char) ts.LC);
0435:                    sourceAdd((char) ts.EOL);
0436:
0437:                    while ((tt = ts.getToken()) != ts.RC && tt != ts.EOF) {
0438:                        switch (tt) {
0439:                        case TokenStream.CASE:
0440:                            sourceAdd((char) ts.CASE);
0441:                            cur_case = nf.createUnary(ts.CASE, expr(ts, false));
0442:                            sourceAdd((char) ts.COLON);
0443:                            sourceAdd((char) ts.EOL);
0444:                            break;
0445:
0446:                        case TokenStream.DEFAULT:
0447:                            cur_case = nf.createLeaf(ts.DEFAULT);
0448:                            sourceAdd((char) ts.DEFAULT);
0449:                            sourceAdd((char) ts.COLON);
0450:                            sourceAdd((char) ts.EOL);
0451:                            // XXX check that there isn't more than one default
0452:                            break;
0453:
0454:                        default:
0455:                            reportError(ts, "msg.bad.switch");
0456:                            break;
0457:                        }
0458:                        mustMatchToken(ts, ts.COLON, "msg.no.colon.case");
0459:
0460:                        case_statements = nf.createLeaf(TokenStream.BLOCK);
0461:                        ((Node) case_statements).setIsSyntheticBlock(true);
0462:
0463:                        while ((tt = ts.peekToken()) != ts.RC && tt != ts.CASE
0464:                                && tt != ts.DEFAULT && tt != ts.EOF) {
0465:                            nf.addChildToBack(case_statements, statement(ts));
0466:                        }
0467:                        // assert cur_case
0468:                        nf.addChildToBack(cur_case, case_statements);
0469:
0470:                        nf.addChildToBack(pn, cur_case);
0471:                    }
0472:                    sourceAdd((char) ts.RC);
0473:                    sourceAdd((char) ts.EOL);
0474:                    break;
0475:                }
0476:
0477:                case TokenStream.WHILE: {
0478:                    skipsemi = true;
0479:
0480:                    sourceAdd((char) ts.WHILE);
0481:                    int lineno = ts.getLineno();
0482:                    Object cond = condition(ts);
0483:                    sourceAdd((char) ts.LC);
0484:                    sourceAdd((char) ts.EOL);
0485:                    Object body = statement(ts);
0486:                    sourceAdd((char) ts.RC);
0487:                    sourceAdd((char) ts.EOL);
0488:
0489:                    pn = nf.createWhile(cond, body, lineno);
0490:                    break;
0491:
0492:                }
0493:
0494:                case TokenStream.DO: {
0495:                    sourceAdd((char) ts.DO);
0496:                    sourceAdd((char) ts.LC);
0497:                    sourceAdd((char) ts.EOL);
0498:
0499:                    int lineno = ts.getLineno();
0500:
0501:                    Object body = statement(ts);
0502:
0503:                    sourceAdd((char) ts.RC);
0504:                    mustMatchToken(ts, ts.WHILE, "msg.no.while.do");
0505:                    sourceAdd((char) ts.WHILE);
0506:                    Object cond = condition(ts);
0507:
0508:                    pn = nf.createDoWhile(body, cond, lineno);
0509:                    break;
0510:                }
0511:
0512:                case TokenStream.FOR: {
0513:                    skipsemi = true;
0514:
0515:                    sourceAdd((char) ts.FOR);
0516:                    int lineno = ts.getLineno();
0517:
0518:                    Object init; // Node init is also foo in 'foo in Object'
0519:                    Object cond; // Node cond is also object in 'foo in Object'
0520:                    Object incr = null; // to kill warning
0521:                    Object body;
0522:
0523:                    mustMatchToken(ts, ts.LP, "msg.no.paren.for");
0524:                    sourceAdd((char) ts.LP);
0525:                    tt = ts.peekToken();
0526:                    if (tt == ts.SEMI) {
0527:                        init = nf.createLeaf(ts.VOID);
0528:                    } else {
0529:                        if (tt == ts.VAR) {
0530:                            // set init to a var list or initial
0531:                            ts.getToken(); // throw away the 'var' token
0532:                            init = variables(ts, true);
0533:                        } else {
0534:                            init = expr(ts, true);
0535:                        }
0536:                    }
0537:
0538:                    tt = ts.peekToken();
0539:                    if (tt == ts.RELOP && ts.getOp() == ts.IN) {
0540:                        ts.matchToken(ts.RELOP);
0541:                        sourceAdd((char) ts.IN);
0542:                        // 'cond' is the object over which we're iterating
0543:                        cond = expr(ts, false);
0544:                    } else { // ordinary for loop
0545:                        mustMatchToken(ts, ts.SEMI, "msg.no.semi.for");
0546:                        sourceAdd((char) ts.SEMI);
0547:                        if (ts.peekToken() == ts.SEMI) {
0548:                            // no loop condition
0549:                            cond = nf.createLeaf(ts.VOID);
0550:                        } else {
0551:                            cond = expr(ts, false);
0552:                        }
0553:
0554:                        mustMatchToken(ts, ts.SEMI, "msg.no.semi.for.cond");
0555:                        sourceAdd((char) ts.SEMI);
0556:                        if (ts.peekToken() == ts.GWT) {
0557:                            incr = nf.createLeaf(ts.VOID);
0558:                        } else {
0559:                            incr = expr(ts, false);
0560:                        }
0561:                    }
0562:
0563:                    mustMatchToken(ts, ts.GWT, "msg.no.paren.for.ctrl");
0564:                    sourceAdd((char) ts.GWT);
0565:                    sourceAdd((char) ts.LC);
0566:                    sourceAdd((char) ts.EOL);
0567:                    body = statement(ts);
0568:                    sourceAdd((char) ts.RC);
0569:                    sourceAdd((char) ts.EOL);
0570:
0571:                    if (incr == null) {
0572:                        // cond could be null if 'in obj' got eaten by the init node.
0573:                        pn = nf.createForIn(init, cond, body, lineno);
0574:                    } else {
0575:                        pn = nf.createFor(init, cond, incr, body, lineno);
0576:                    }
0577:                    break;
0578:                }
0579:
0580:                case TokenStream.TRY: {
0581:                    int lineno = ts.getLineno();
0582:
0583:                    Object tryblock;
0584:                    Object catchblocks = null;
0585:                    Object finallyblock = null;
0586:
0587:                    skipsemi = true;
0588:                    sourceAdd((char) ts.TRY);
0589:                    sourceAdd((char) ts.LC);
0590:                    sourceAdd((char) ts.EOL);
0591:                    tryblock = statement(ts);
0592:                    sourceAdd((char) ts.RC);
0593:                    sourceAdd((char) ts.EOL);
0594:
0595:                    catchblocks = nf.createLeaf(TokenStream.BLOCK);
0596:
0597:                    boolean sawDefaultCatch = false;
0598:                    int peek = ts.peekToken();
0599:                    if (peek == ts.CATCH) {
0600:                        while (ts.matchToken(ts.CATCH)) {
0601:                            if (sawDefaultCatch) {
0602:                                reportError(ts, "msg.catch.unreachable");
0603:                            }
0604:                            sourceAdd((char) ts.CATCH);
0605:                            mustMatchToken(ts, ts.LP, "msg.no.paren.catch");
0606:                            sourceAdd((char) ts.LP);
0607:
0608:                            mustMatchToken(ts, ts.NAME, "msg.bad.catchcond");
0609:                            String varName = ts.getString();
0610:                            sourceAddString(ts.NAME, varName);
0611:
0612:                            Object catchCond = null;
0613:                            if (ts.matchToken(ts.IF)) {
0614:                                sourceAdd((char) ts.IF);
0615:                                catchCond = expr(ts, false);
0616:                            } else {
0617:                                sawDefaultCatch = true;
0618:                            }
0619:
0620:                            mustMatchToken(ts, ts.GWT, "msg.bad.catchcond");
0621:                            sourceAdd((char) ts.GWT);
0622:                            mustMatchToken(ts, ts.LC, "msg.no.brace.catchblock");
0623:                            sourceAdd((char) ts.LC);
0624:                            sourceAdd((char) ts.EOL);
0625:
0626:                            nf.addChildToBack(catchblocks, nf.createCatch(
0627:                                    varName, catchCond, statements(ts), ts
0628:                                            .getLineno()));
0629:
0630:                            mustMatchToken(ts, ts.RC, "msg.no.brace.after.body");
0631:                            sourceAdd((char) ts.RC);
0632:                            sourceAdd((char) ts.EOL);
0633:                        }
0634:                    } else if (peek != ts.FINALLY) {
0635:                        mustMatchToken(ts, ts.FINALLY,
0636:                                "msg.try.no.catchfinally");
0637:                    }
0638:
0639:                    if (ts.matchToken(ts.FINALLY)) {
0640:                        sourceAdd((char) ts.FINALLY);
0641:
0642:                        sourceAdd((char) ts.LC);
0643:                        sourceAdd((char) ts.EOL);
0644:                        finallyblock = statement(ts);
0645:                        sourceAdd((char) ts.RC);
0646:                        sourceAdd((char) ts.EOL);
0647:                    }
0648:
0649:                    pn = nf.createTryCatchFinally(tryblock, catchblocks,
0650:                            finallyblock, lineno);
0651:
0652:                    break;
0653:                }
0654:                case TokenStream.THROW: {
0655:                    int lineno = ts.getLineno();
0656:                    sourceAdd((char) ts.THROW);
0657:                    pn = nf.createThrow(expr(ts, false), lineno);
0658:                    if (lineno == ts.getLineno())
0659:                        wellTerminated(ts, ts.ERROR);
0660:                    break;
0661:                }
0662:                case TokenStream.BREAK: {
0663:                    int lineno = ts.getLineno();
0664:
0665:                    sourceAdd((char) ts.BREAK);
0666:
0667:                    // matchLabel only matches if there is one
0668:                    String label = matchLabel(ts);
0669:                    if (label != null) {
0670:                        sourceAddString(ts.NAME, label);
0671:                    }
0672:                    pn = nf.createBreak(label, lineno);
0673:                    break;
0674:                }
0675:                case TokenStream.CONTINUE: {
0676:                    int lineno = ts.getLineno();
0677:
0678:                    sourceAdd((char) ts.CONTINUE);
0679:
0680:                    // matchLabel only matches if there is one
0681:                    String label = matchLabel(ts);
0682:                    if (label != null) {
0683:                        sourceAddString(ts.NAME, label);
0684:                    }
0685:                    pn = nf.createContinue(label, lineno);
0686:                    break;
0687:                }
0688:                case TokenStream.DEBUGGER: {
0689:                    int lineno = ts.getLineno();
0690:
0691:                    sourceAdd((char) ts.DEBUGGER);
0692:
0693:                    pn = nf.createDebugger(lineno);
0694:                    break;
0695:                }
0696:                case TokenStream.WITH: {
0697:                    // bruce: we don't support this is JSNI code because it's impossible
0698:                    // to identify bindings even passably well
0699:                    //
0700:
0701:                    reportError(ts, "msg.jsni.unsupported.with");
0702:
0703:                    skipsemi = true;
0704:
0705:                    sourceAdd((char) ts.WITH);
0706:                    int lineno = ts.getLineno();
0707:                    mustMatchToken(ts, ts.LP, "msg.no.paren.with");
0708:                    sourceAdd((char) ts.LP);
0709:                    Object obj = expr(ts, false);
0710:                    mustMatchToken(ts, ts.GWT, "msg.no.paren.after.with");
0711:                    sourceAdd((char) ts.GWT);
0712:                    sourceAdd((char) ts.LC);
0713:                    sourceAdd((char) ts.EOL);
0714:
0715:                    Object body = statement(ts);
0716:
0717:                    sourceAdd((char) ts.RC);
0718:                    sourceAdd((char) ts.EOL);
0719:
0720:                    pn = nf.createWith(obj, body, lineno);
0721:                    break;
0722:                }
0723:                case TokenStream.VAR: {
0724:                    int lineno = ts.getLineno();
0725:                    pn = variables(ts, false);
0726:                    if (ts.getLineno() == lineno)
0727:                        wellTerminated(ts, ts.ERROR);
0728:                    break;
0729:                }
0730:                case TokenStream.RETURN: {
0731:                    Object retExpr = null;
0732:                    int lineno = 0;
0733:
0734:                    sourceAdd((char) ts.RETURN);
0735:
0736:                    // bail if we're not in a (toplevel) function
0737:                    if ((ts.flags & ts.TSF_FUNCTION) == 0)
0738:                        reportError(ts, "msg.bad.return");
0739:
0740:                    /* This is ugly, but we don't want to require a semicolon. */
0741:                    ts.flags |= ts.TSF_REGEXP;
0742:                    tt = ts.peekTokenSameLine();
0743:                    ts.flags &= ~ts.TSF_REGEXP;
0744:
0745:                    if (tt != ts.EOF && tt != ts.EOL && tt != ts.SEMI
0746:                            && tt != ts.RC) {
0747:                        lineno = ts.getLineno();
0748:                        retExpr = expr(ts, false);
0749:                        if (ts.getLineno() == lineno)
0750:                            wellTerminated(ts, ts.ERROR);
0751:                        ts.flags |= ts.TSF_RETURN_EXPR;
0752:                    } else {
0753:                        ts.flags |= ts.TSF_RETURN_VOID;
0754:                    }
0755:
0756:                    // XXX ASSERT pn
0757:                    pn = nf.createReturn(retExpr, lineno);
0758:                    break;
0759:                }
0760:                case TokenStream.LC:
0761:                    skipsemi = true;
0762:
0763:                    pn = statements(ts);
0764:                    mustMatchToken(ts, ts.RC, "msg.no.brace.block");
0765:                    break;
0766:
0767:                case TokenStream.ERROR:
0768:                    // Fall thru, to have a node for error recovery to work on
0769:                case TokenStream.EOL:
0770:                case TokenStream.SEMI:
0771:                    pn = nf.createLeaf(ts.VOID);
0772:                    skipsemi = true;
0773:                    break;
0774:
0775:                default: {
0776:                    lastExprType = tt;
0777:                    int tokenno = ts.getTokenno();
0778:                    ts.ungetToken(tt);
0779:                    int lineno = ts.getLineno();
0780:
0781:                    pn = expr(ts, false);
0782:
0783:                    if (ts.peekToken() == ts.COLON) {
0784:                        /*
0785:                         * check that the last thing the tokenizer returned was a NAME and
0786:                         * that only one token was consumed.
0787:                         */
0788:                        if (lastExprType != ts.NAME
0789:                                || (ts.getTokenno() != tokenno))
0790:                            reportError(ts, "msg.bad.label");
0791:
0792:                        ts.getToken(); // eat the COLON
0793:
0794:                        /*
0795:                         * in the C source, the label is associated with the statement that
0796:                         * follows: nf.addChildToBack(pn, statement(ts));
0797:                         */
0798:                        String name = ts.getString();
0799:                        pn = nf.createLabel(name, lineno);
0800:
0801:                        // bruce: added to make it easier to bind labels to the
0802:                        // statements they modify
0803:                        //
0804:                        nf.addChildToBack(pn, statement(ts));
0805:
0806:                        // depend on decompiling lookahead to guess that that
0807:                        // last name was a label.
0808:                        sourceAdd((char) ts.COLON);
0809:                        sourceAdd((char) ts.EOL);
0810:                        return pn;
0811:                    }
0812:
0813:                    if (lastExprType == ts.FUNCTION) {
0814:                        if (nf.getLeafType(pn) != ts.FUNCTION) {
0815:                            reportError(ts, "msg.syntax");
0816:                        }
0817:                    }
0818:
0819:                    pn = nf.createExprStatement(pn, lineno);
0820:
0821:                    /*
0822:                     * Check explicitly against (multi-line) function statement.
0823:                     * 
0824:                     * lastExprEndLine is a hack to fix an automatic semicolon insertion
0825:                     * problem with function expressions; the ts.getLineno() == lineno check
0826:                     * was firing after a function definition even though the next statement
0827:                     * was on a new line, because speculative getToken calls advanced the
0828:                     * line number even when they didn't succeed.
0829:                     */
0830:                    if (ts.getLineno() == lineno
0831:                            || (lastExprType == ts.FUNCTION && ts.getLineno() == lastExprEndLine)) {
0832:                        wellTerminated(ts, lastExprType);
0833:                    }
0834:                    break;
0835:                }
0836:                }
0837:                ts.matchToken(ts.SEMI);
0838:                if (!skipsemi) {
0839:                    sourceAdd((char) ts.SEMI);
0840:                    sourceAdd((char) ts.EOL);
0841:                }
0842:
0843:                return pn;
0844:            }
0845:
0846:            private Object variables(TokenStream ts, boolean inForInit)
0847:                    throws IOException, JavaScriptException {
0848:                Object pn = nf.createVariables(ts.getLineno());
0849:                boolean first = true;
0850:
0851:                sourceAdd((char) ts.VAR);
0852:
0853:                for (;;) {
0854:                    Object name;
0855:                    Object init;
0856:                    mustMatchToken(ts, ts.NAME, "msg.bad.var");
0857:                    String s = ts.getString();
0858:
0859:                    if (!first)
0860:                        sourceAdd((char) ts.COMMA);
0861:                    first = false;
0862:
0863:                    sourceAddString(ts.NAME, s);
0864:                    name = nf.createName(s);
0865:
0866:                    // omitted check for argument hiding
0867:
0868:                    if (ts.matchToken(ts.ASSIGN)) {
0869:                        if (ts.getOp() != ts.NOP)
0870:                            reportError(ts, "msg.bad.var.init");
0871:
0872:                        sourceAdd((char) ts.ASSIGN);
0873:                        sourceAdd((char) ts.NOP);
0874:
0875:                        init = assignExpr(ts, inForInit);
0876:                        nf.addChildToBack(name, init);
0877:                    }
0878:                    nf.addChildToBack(pn, name);
0879:                    if (!ts.matchToken(ts.COMMA))
0880:                        break;
0881:                }
0882:                return pn;
0883:            }
0884:
0885:            private Object expr(TokenStream ts, boolean inForInit)
0886:                    throws IOException, JavaScriptException {
0887:                Object pn = assignExpr(ts, inForInit);
0888:                while (ts.matchToken(ts.COMMA)) {
0889:                    sourceAdd((char) ts.COMMA);
0890:                    pn = nf.createBinary(ts.COMMA, pn,
0891:                            assignExpr(ts, inForInit));
0892:                }
0893:                return pn;
0894:            }
0895:
0896:            private Object assignExpr(TokenStream ts, boolean inForInit)
0897:                    throws IOException, JavaScriptException {
0898:                Object pn = condExpr(ts, inForInit);
0899:
0900:                if (ts.matchToken(ts.ASSIGN)) {
0901:                    // omitted: "invalid assignment left-hand side" check.
0902:                    sourceAdd((char) ts.ASSIGN);
0903:                    sourceAdd((char) ts.getOp());
0904:                    pn = nf.createBinary(ts.ASSIGN, ts.getOp(), pn, assignExpr(
0905:                            ts, inForInit));
0906:                }
0907:
0908:                return pn;
0909:            }
0910:
0911:            private Object condExpr(TokenStream ts, boolean inForInit)
0912:                    throws IOException, JavaScriptException {
0913:                Object ifTrue;
0914:                Object ifFalse;
0915:
0916:                Object pn = orExpr(ts, inForInit);
0917:
0918:                if (ts.matchToken(ts.HOOK)) {
0919:                    sourceAdd((char) ts.HOOK);
0920:                    ifTrue = assignExpr(ts, false);
0921:                    mustMatchToken(ts, ts.COLON, "msg.no.colon.cond");
0922:                    sourceAdd((char) ts.COLON);
0923:                    ifFalse = assignExpr(ts, inForInit);
0924:                    return nf.createTernary(pn, ifTrue, ifFalse);
0925:                }
0926:
0927:                return pn;
0928:            }
0929:
0930:            private Object orExpr(TokenStream ts, boolean inForInit)
0931:                    throws IOException, JavaScriptException {
0932:                Object pn = andExpr(ts, inForInit);
0933:                if (ts.matchToken(ts.OR)) {
0934:                    sourceAdd((char) ts.OR);
0935:                    pn = nf.createBinary(ts.OR, pn, orExpr(ts, inForInit));
0936:                }
0937:
0938:                return pn;
0939:            }
0940:
0941:            private Object andExpr(TokenStream ts, boolean inForInit)
0942:                    throws IOException, JavaScriptException {
0943:                Object pn = bitOrExpr(ts, inForInit);
0944:                if (ts.matchToken(ts.AND)) {
0945:                    sourceAdd((char) ts.AND);
0946:                    pn = nf.createBinary(ts.AND, pn, andExpr(ts, inForInit));
0947:                }
0948:
0949:                return pn;
0950:            }
0951:
0952:            private Object bitOrExpr(TokenStream ts, boolean inForInit)
0953:                    throws IOException, JavaScriptException {
0954:                Object pn = bitXorExpr(ts, inForInit);
0955:                while (ts.matchToken(ts.BITOR)) {
0956:                    sourceAdd((char) ts.BITOR);
0957:                    pn = nf.createBinary(ts.BITOR, pn,
0958:                            bitXorExpr(ts, inForInit));
0959:                }
0960:                return pn;
0961:            }
0962:
0963:            private Object bitXorExpr(TokenStream ts, boolean inForInit)
0964:                    throws IOException, JavaScriptException {
0965:                Object pn = bitAndExpr(ts, inForInit);
0966:                while (ts.matchToken(ts.BITXOR)) {
0967:                    sourceAdd((char) ts.BITXOR);
0968:                    pn = nf.createBinary(ts.BITXOR, pn, bitAndExpr(ts,
0969:                            inForInit));
0970:                }
0971:                return pn;
0972:            }
0973:
0974:            private Object bitAndExpr(TokenStream ts, boolean inForInit)
0975:                    throws IOException, JavaScriptException {
0976:                Object pn = eqExpr(ts, inForInit);
0977:                while (ts.matchToken(ts.BITAND)) {
0978:                    sourceAdd((char) ts.BITAND);
0979:                    pn = nf.createBinary(ts.BITAND, pn, eqExpr(ts, inForInit));
0980:                }
0981:                return pn;
0982:            }
0983:
0984:            private Object eqExpr(TokenStream ts, boolean inForInit)
0985:                    throws IOException, JavaScriptException {
0986:                Object pn = relExpr(ts, inForInit);
0987:                while (ts.matchToken(ts.EQOP)) {
0988:                    sourceAdd((char) ts.EQOP);
0989:                    sourceAdd((char) ts.getOp());
0990:                    pn = nf.createBinary(ts.EQOP, ts.getOp(), pn, relExpr(ts,
0991:                            inForInit));
0992:                }
0993:                return pn;
0994:            }
0995:
0996:            private Object relExpr(TokenStream ts, boolean inForInit)
0997:                    throws IOException, JavaScriptException {
0998:                Object pn = shiftExpr(ts);
0999:                while (ts.matchToken(ts.RELOP)) {
1000:                    int op = ts.getOp();
1001:                    if (inForInit && op == ts.IN) {
1002:                        ts.ungetToken(ts.RELOP);
1003:                        break;
1004:                    }
1005:                    sourceAdd((char) ts.RELOP);
1006:                    sourceAdd((char) op);
1007:                    pn = nf.createBinary(ts.RELOP, op, pn, shiftExpr(ts));
1008:                }
1009:                return pn;
1010:            }
1011:
1012:            private Object shiftExpr(TokenStream ts) throws IOException,
1013:                    JavaScriptException {
1014:                Object pn = addExpr(ts);
1015:                while (ts.matchToken(ts.SHOP)) {
1016:                    sourceAdd((char) ts.SHOP);
1017:                    sourceAdd((char) ts.getOp());
1018:                    pn = nf.createBinary(ts.SHOP, ts.getOp(), pn, addExpr(ts));
1019:                }
1020:                return pn;
1021:            }
1022:
1023:            private Object addExpr(TokenStream ts) throws IOException,
1024:                    JavaScriptException {
1025:                int tt;
1026:                Object pn = mulExpr(ts);
1027:
1028:                while ((tt = ts.getToken()) == ts.ADD || tt == ts.SUB) {
1029:                    sourceAdd((char) tt);
1030:                    // flushNewLines
1031:                    pn = nf.createBinary(tt, pn, mulExpr(ts));
1032:                }
1033:                ts.ungetToken(tt);
1034:
1035:                return pn;
1036:            }
1037:
1038:            private Object mulExpr(TokenStream ts) throws IOException,
1039:                    JavaScriptException {
1040:                int tt;
1041:
1042:                Object pn = unaryExpr(ts);
1043:
1044:                while ((tt = ts.peekToken()) == ts.MUL || tt == ts.DIV
1045:                        || tt == ts.MOD) {
1046:                    tt = ts.getToken();
1047:                    sourceAdd((char) tt);
1048:                    pn = nf.createBinary(tt, pn, unaryExpr(ts));
1049:                }
1050:
1051:                return pn;
1052:            }
1053:
1054:            private Object unaryExpr(TokenStream ts) throws IOException,
1055:                    JavaScriptException {
1056:                int tt;
1057:
1058:                ts.flags |= ts.TSF_REGEXP;
1059:                tt = ts.getToken();
1060:                ts.flags &= ~ts.TSF_REGEXP;
1061:
1062:                switch (tt) {
1063:                case TokenStream.UNARYOP:
1064:                    sourceAdd((char) ts.UNARYOP);
1065:                    sourceAdd((char) ts.getOp());
1066:                    return nf
1067:                            .createUnary(ts.UNARYOP, ts.getOp(), unaryExpr(ts));
1068:
1069:                case TokenStream.ADD:
1070:                case TokenStream.SUB:
1071:                    sourceAdd((char) ts.UNARYOP);
1072:                    sourceAdd((char) tt);
1073:                    return nf.createUnary(ts.UNARYOP, tt, unaryExpr(ts));
1074:
1075:                case TokenStream.INC:
1076:                case TokenStream.DEC:
1077:                    sourceAdd((char) tt);
1078:                    return nf.createUnary(tt, ts.PRE, memberExpr(ts, true));
1079:
1080:                case TokenStream.DELPROP:
1081:                    sourceAdd((char) ts.DELPROP);
1082:                    return nf.createUnary(ts.DELPROP, unaryExpr(ts));
1083:
1084:                case TokenStream.ERROR:
1085:                    break;
1086:
1087:                default:
1088:                    ts.ungetToken(tt);
1089:
1090:                    int lineno = ts.getLineno();
1091:
1092:                    Object pn = memberExpr(ts, true);
1093:
1094:                    /*
1095:                     * don't look across a newline boundary for a postfix incop.
1096:                     * 
1097:                     * the rhino scanner seems to work differently than the js scanner here;
1098:                     * in js, it works to have the line number check precede the peekToken
1099:                     * calls. It'd be better if they had similar behavior...
1100:                     */
1101:                    int peeked;
1102:                    if (((peeked = ts.peekToken()) == ts.INC || peeked == ts.DEC)
1103:                            && ts.getLineno() == lineno) {
1104:                        int pf = ts.getToken();
1105:                        sourceAdd((char) pf);
1106:                        return nf.createUnary(pf, ts.POST, pn);
1107:                    }
1108:                    return pn;
1109:                }
1110:                return nf.createName("err"); // Only reached on error. Try to continue.
1111:
1112:            }
1113:
1114:            private Object argumentList(TokenStream ts, Object listNode)
1115:                    throws IOException, JavaScriptException {
1116:                boolean matched;
1117:                ts.flags |= ts.TSF_REGEXP;
1118:                matched = ts.matchToken(ts.GWT);
1119:                ts.flags &= ~ts.TSF_REGEXP;
1120:                if (!matched) {
1121:                    boolean first = true;
1122:                    do {
1123:                        if (!first)
1124:                            sourceAdd((char) ts.COMMA);
1125:                        first = false;
1126:                        nf.addChildToBack(listNode, assignExpr(ts, false));
1127:                    } while (ts.matchToken(ts.COMMA));
1128:
1129:                    mustMatchToken(ts, ts.GWT, "msg.no.paren.arg");
1130:                }
1131:                sourceAdd((char) ts.GWT);
1132:                return listNode;
1133:            }
1134:
1135:            private Object memberExpr(TokenStream ts, boolean allowCallSyntax)
1136:                    throws IOException, JavaScriptException {
1137:                int tt;
1138:
1139:                Object pn;
1140:
1141:                /* Check for new expressions. */
1142:                ts.flags |= ts.TSF_REGEXP;
1143:                tt = ts.peekToken();
1144:                ts.flags &= ~ts.TSF_REGEXP;
1145:                if (tt == ts.NEW) {
1146:                    /* Eat the NEW token. */
1147:                    ts.getToken();
1148:                    sourceAdd((char) ts.NEW);
1149:
1150:                    /* Make a NEW node to append to. */
1151:                    pn = nf.createLeaf(ts.NEW);
1152:                    nf.addChildToBack(pn, memberExpr(ts, false));
1153:
1154:                    if (ts.matchToken(ts.LP)) {
1155:                        sourceAdd((char) ts.LP);
1156:                        /* Add the arguments to pn, if any are supplied. */
1157:                        pn = argumentList(ts, pn);
1158:                    }
1159:
1160:                    /*
1161:                     * XXX there's a check in the C source against "too many constructor
1162:                     * arguments" - how many do we claim to support?
1163:                     */
1164:
1165:                    /*
1166:                     * Experimental syntax: allow an object literal to follow a new
1167:                     * expression, which will mean a kind of anonymous class built with the
1168:                     * JavaAdapter. the object literal will be passed as an additional
1169:                     * argument to the constructor.
1170:                     */
1171:                    tt = ts.peekToken();
1172:                    if (tt == ts.LC) {
1173:                        nf.addChildToBack(pn, primaryExpr(ts));
1174:                    }
1175:                } else {
1176:                    pn = primaryExpr(ts);
1177:                }
1178:
1179:                return memberExprTail(ts, allowCallSyntax, pn);
1180:            }
1181:
1182:            private Object memberExprTail(TokenStream ts,
1183:                    boolean allowCallSyntax, Object pn) throws IOException,
1184:                    JavaScriptException {
1185:                lastExprEndLine = ts.getLineno();
1186:                int tt;
1187:                while ((tt = ts.getToken()) > ts.EOF) {
1188:                    if (tt == ts.DOT) {
1189:                        sourceAdd((char) ts.DOT);
1190:                        mustMatchToken(ts, ts.NAME, "msg.no.name.after.dot");
1191:                        String s = ts.getString();
1192:                        sourceAddString(ts.NAME, s);
1193:                        pn = nf.createBinary(ts.DOT, pn, nf.createName(ts
1194:                                .getString()));
1195:                        /*
1196:                         * pn = nf.createBinary(ts.DOT, pn, memberExpr(ts)) is the version in
1197:                         * Brendan's IR C version. Not in ECMA... does it reflect the 'new'
1198:                         * operator syntax he mentioned?
1199:                         */
1200:                        lastExprEndLine = ts.getLineno();
1201:                    } else if (tt == ts.LB) {
1202:                        sourceAdd((char) ts.LB);
1203:                        pn = nf.createBinary(ts.LB, pn, expr(ts, false));
1204:
1205:                        mustMatchToken(ts, ts.RB, "msg.no.bracket.index");
1206:                        sourceAdd((char) ts.RB);
1207:                        lastExprEndLine = ts.getLineno();
1208:                    } else if (allowCallSyntax && tt == ts.LP) {
1209:                        /* make a call node */
1210:
1211:                        pn = nf.createUnary(ts.CALL, pn);
1212:                        sourceAdd((char) ts.LP);
1213:
1214:                        /* Add the arguments to pn, if any are supplied. */
1215:                        pn = argumentList(ts, pn);
1216:                        lastExprEndLine = ts.getLineno();
1217:                    } else {
1218:                        ts.ungetToken(tt);
1219:
1220:                        break;
1221:                    }
1222:                }
1223:                return pn;
1224:            }
1225:
1226:            private Object primaryExpr(TokenStream ts) throws IOException,
1227:                    JavaScriptException {
1228:                int tt;
1229:
1230:                Object pn;
1231:
1232:                ts.flags |= ts.TSF_REGEXP;
1233:                tt = ts.getToken();
1234:                ts.flags &= ~ts.TSF_REGEXP;
1235:
1236:                switch (tt) {
1237:
1238:                case TokenStream.FUNCTION:
1239:                    return function(ts, true);
1240:
1241:                case TokenStream.LB: {
1242:                    sourceAdd((char) ts.LB);
1243:                    pn = nf.createLeaf(ts.ARRAYLIT);
1244:
1245:                    ts.flags |= ts.TSF_REGEXP;
1246:                    boolean matched = ts.matchToken(ts.RB);
1247:                    ts.flags &= ~ts.TSF_REGEXP;
1248:
1249:                    if (!matched) {
1250:                        boolean first = true;
1251:                        do {
1252:                            ts.flags |= ts.TSF_REGEXP;
1253:                            tt = ts.peekToken();
1254:                            ts.flags &= ~ts.TSF_REGEXP;
1255:
1256:                            if (!first)
1257:                                sourceAdd((char) ts.COMMA);
1258:                            else
1259:                                first = false;
1260:
1261:                            if (tt == ts.RB) { // to fix [,,,].length behavior...
1262:                                break;
1263:                            }
1264:
1265:                            if (tt == ts.COMMA) {
1266:                                nf.addChildToBack(pn, nf.createLeaf(ts.PRIMARY,
1267:                                        ts.UNDEFINED));
1268:                            } else {
1269:                                nf.addChildToBack(pn, assignExpr(ts, false));
1270:                            }
1271:
1272:                        } while (ts.matchToken(ts.COMMA));
1273:                        mustMatchToken(ts, ts.RB, "msg.no.bracket.arg");
1274:                    }
1275:                    sourceAdd((char) ts.RB);
1276:                    return nf.createArrayLiteral(pn);
1277:                }
1278:
1279:                case TokenStream.LC: {
1280:                    pn = nf.createLeaf(ts.OBJLIT);
1281:
1282:                    sourceAdd((char) ts.LC);
1283:                    if (!ts.matchToken(ts.RC)) {
1284:
1285:                        boolean first = true;
1286:                        commaloop: do {
1287:                            Object property;
1288:
1289:                            if (!first)
1290:                                sourceAdd((char) ts.COMMA);
1291:                            else
1292:                                first = false;
1293:
1294:                            tt = ts.getToken();
1295:                            switch (tt) {
1296:                            // map NAMEs to STRINGs in object literal context.
1297:                            case TokenStream.NAME:
1298:                            case TokenStream.STRING:
1299:                                String s = ts.getString();
1300:                                sourceAddString(ts.NAME, s);
1301:                                property = nf.createString(ts.getString());
1302:                                break;
1303:                            case TokenStream.NUMBER:
1304:                                double n = ts.getNumber();
1305:                                sourceAddNumber(n);
1306:                                property = nf.createNumber(n);
1307:                                break;
1308:                            case TokenStream.RC:
1309:                                // trailing comma is OK.
1310:                                ts.ungetToken(tt);
1311:                                break commaloop;
1312:                            default:
1313:                                reportError(ts, "msg.bad.prop");
1314:                                break commaloop;
1315:                            }
1316:                            mustMatchToken(ts, ts.COLON, "msg.no.colon.prop");
1317:
1318:                            // OBJLIT is used as ':' in object literal for
1319:                            // decompilation to solve spacing ambiguity.
1320:                            sourceAdd((char) ts.OBJLIT);
1321:                            nf.addChildToBack(pn, property);
1322:                            nf.addChildToBack(pn, assignExpr(ts, false));
1323:
1324:                        } while (ts.matchToken(ts.COMMA));
1325:
1326:                        mustMatchToken(ts, ts.RC, "msg.no.brace.prop");
1327:                    }
1328:                    sourceAdd((char) ts.RC);
1329:                    return nf.createObjectLiteral(pn);
1330:                }
1331:
1332:                case TokenStream.LP:
1333:
1334:                    /*
1335:                     * Brendan's IR-jsparse.c makes a new node tagged with TOK_LP here...
1336:                     * I'm not sure I understand why. Isn't the grouping already implicit in
1337:                     * the structure of the parse tree? also TOK_LP is already overloaded (I
1338:                     * think) in the C IR as 'function call.'
1339:                     */
1340:                    sourceAdd((char) ts.LP);
1341:                    pn = expr(ts, false);
1342:                    sourceAdd((char) ts.GWT);
1343:                    mustMatchToken(ts, ts.GWT, "msg.no.paren");
1344:                    return pn;
1345:
1346:                case TokenStream.NAME:
1347:                    String name = ts.getString();
1348:                    sourceAddString(ts.NAME, name);
1349:                    return nf.createName(name);
1350:
1351:                case TokenStream.NUMBER:
1352:                    double n = ts.getNumber();
1353:                    sourceAddNumber(n);
1354:                    return nf.createNumber(n);
1355:
1356:                case TokenStream.STRING:
1357:                    String s = ts.getString();
1358:                    sourceAddString(ts.STRING, s);
1359:                    return nf.createString(s);
1360:
1361:                case TokenStream.REGEXP: {
1362:                    String flags = ts.regExpFlags;
1363:                    ts.regExpFlags = null;
1364:                    String re = ts.getString();
1365:                    sourceAddString(ts.REGEXP, '/' + re + '/' + flags);
1366:                    return nf.createRegExp(re, flags);
1367:                }
1368:
1369:                case TokenStream.PRIMARY:
1370:                    sourceAdd((char) ts.PRIMARY);
1371:                    sourceAdd((char) ts.getOp());
1372:                    return nf.createLeaf(ts.PRIMARY, ts.getOp());
1373:
1374:                case TokenStream.RESERVED:
1375:                    reportError(ts, "msg.reserved.id");
1376:                    break;
1377:
1378:                case TokenStream.ERROR:
1379:                    /* the scanner or one of its subroutines reported the error. */
1380:                    break;
1381:
1382:                default:
1383:                    reportError(ts, "msg.syntax");
1384:                    break;
1385:
1386:                }
1387:                return null; // should never reach here
1388:            }
1389:
1390:            /**
1391:             * The following methods save decompilation information about the source.
1392:             * Source information is returned from the parser as a String associated with
1393:             * function nodes and with the toplevel script. When saved in the constant
1394:             * pool of a class, this string will be UTF-8 encoded, and token values will
1395:             * occupy a single byte.
1396:             * 
1397:             * Source is saved (mostly) as token numbers. The tokens saved pretty much
1398:             * correspond to the token stream of a 'canonical' representation of the input
1399:             * program, as directed by the parser. (There were a few cases where tokens
1400:             * could have been left out where decompiler could easily reconstruct them,
1401:             * but I left them in for clarity). (I also looked adding source collection to
1402:             * TokenStream instead, where I could have limited the changes to a few lines
1403:             * in getToken... but this wouldn't have saved any space in the resulting
1404:             * source representation, and would have meant that I'd have to duplicate
1405:             * parser logic in the decompiler to disambiguate situations where newlines
1406:             * are important.) NativeFunction.decompile expands the tokens back into their
1407:             * string representations, using simple lookahead to correct spacing and
1408:             * indentation.
1409:             * 
1410:             * Token types with associated ops (ASSIGN, SHOP, PRIMARY, etc.) are saved as
1411:             * two-token pairs. Number tokens are stored inline, as a NUMBER token, a
1412:             * character representing the type, and either 1 or 4 characters representing
1413:             * the bit-encoding of the number. String types NAME, STRING and OBJECT are
1414:             * currently stored as a token type, followed by a character giving the length
1415:             * of the string (assumed to be less than 2^16), followed by the characters of
1416:             * the string inlined into the source string. Changing this to some reference
1417:             * to to the string in the compiled class' constant pool would probably save a
1418:             * lot of space... but would require some method of deriving the final
1419:             * constant pool entry from information available at parse time.
1420:             * 
1421:             * Nested functions need a similar mechanism... fortunately the nested
1422:             * functions for a given function are generated in source order. Nested
1423:             * functions are encoded as FUNCTION followed by a function number (encoded as
1424:             * a character), which is enough information to find the proper generated
1425:             * NativeFunction instance.
1426:             * 
1427:             */
1428:            private void sourceAdd(char c) {
1429:                if (sourceTop == sourceBuffer.length) {
1430:                    increaseSourceCapacity(sourceTop + 1);
1431:                }
1432:                sourceBuffer[sourceTop] = c;
1433:                ++sourceTop;
1434:            }
1435:
1436:            private void sourceAddString(int type, String str) {
1437:                int L = str.length();
1438:                // java string length < 2^16?
1439:                if (Context.check && L > Character.MAX_VALUE)
1440:                    Context.codeBug();
1441:
1442:                if (sourceTop + L + 2 > sourceBuffer.length) {
1443:                    increaseSourceCapacity(sourceTop + L + 2);
1444:                }
1445:                sourceAdd((char) type);
1446:                sourceAdd((char) L);
1447:                str.getChars(0, L, sourceBuffer, sourceTop);
1448:                sourceTop += L;
1449:            }
1450:
1451:            private void sourceAddNumber(double n) {
1452:                sourceAdd((char) TokenStream.NUMBER);
1453:
1454:                /*
1455:                 * encode the number in the source stream. Save as NUMBER type (char | char
1456:                 * char char char) where type is 'D' - double, 'S' - short, 'J' - long.
1457:                 * 
1458:                 * We need to retain float vs. integer type info to keep the behavior of
1459:                 * liveconnect type-guessing the same after decompilation. (Liveconnect
1460:                 * tries to present 1.0 to Java as a float/double) OPT: This is no longer
1461:                 * true. We could compress the format.
1462:                 * 
1463:                 * This may not be the most space-efficient encoding; the chars created
1464:                 * below may take up to 3 bytes in constant pool UTF-8 encoding, so a Double
1465:                 * could take up to 12 bytes.
1466:                 */
1467:
1468:                long lbits = (long) n;
1469:                if (lbits != n) {
1470:                    // if it's floating point, save as a Double bit pattern.
1471:                    // (12/15/97 our scanner only returns Double for f.p.)
1472:                    lbits = Double.doubleToLongBits(n);
1473:                    sourceAdd('D');
1474:                    sourceAdd((char) (lbits >> 48));
1475:                    sourceAdd((char) (lbits >> 32));
1476:                    sourceAdd((char) (lbits >> 16));
1477:                    sourceAdd((char) lbits);
1478:                } else {
1479:                    // we can ignore negative values, bc they're already prefixed
1480:                    // by UNARYOP SUB
1481:                    if (Context.check && lbits < 0)
1482:                        Context.codeBug();
1483:
1484:                    // will it fit in a char?
1485:                    // this gives a short encoding for integer values up to 2^16.
1486:                    if (lbits <= Character.MAX_VALUE) {
1487:                        sourceAdd('S');
1488:                        sourceAdd((char) lbits);
1489:                    } else { // Integral, but won't fit in a char. Store as a long.
1490:                        sourceAdd('J');
1491:                        sourceAdd((char) (lbits >> 48));
1492:                        sourceAdd((char) (lbits >> 32));
1493:                        sourceAdd((char) (lbits >> 16));
1494:                        sourceAdd((char) lbits);
1495:                    }
1496:                }
1497:            }
1498:
1499:            private void increaseSourceCapacity(int minimalCapacity) {
1500:                // Call this only when capacity increase is must
1501:                if (Context.check && minimalCapacity <= sourceBuffer.length)
1502:                    Context.codeBug();
1503:                int newCapacity = sourceBuffer.length * 2;
1504:                if (newCapacity < minimalCapacity) {
1505:                    newCapacity = minimalCapacity;
1506:                }
1507:                char[] tmp = new char[newCapacity];
1508:                System.arraycopy(sourceBuffer, 0, tmp, 0, sourceTop);
1509:                sourceBuffer = tmp;
1510:            }
1511:
1512:            private String sourceToString(int offset) {
1513:                if (Context.check && (offset < 0 || sourceTop < offset))
1514:                    Context.codeBug();
1515:                return new String(sourceBuffer, offset, sourceTop - offset);
1516:            }
1517:
1518:            private int lastExprEndLine; // Hack to handle function expr termination.
1519:            private IRFactory nf;
1520:            private ErrorReporter er;
1521:            private boolean ok; // Did the parse encounter an error?
1522:
1523:            private char[] sourceBuffer = new char[128];
1524:            private int sourceTop;
1525:            private int functionNumber;
1526:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.