Source Code Cross Referenced for Parser.java in  » EJB-Server-resin-3.1.5 » ecmascript » com » caucho » es » parser » 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 » EJB Server resin 3.1.5 » ecmascript » com.caucho.es.parser 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
0003:         *
0004:         * This file is part of Resin(R) Open Source
0005:         *
0006:         * Each copy or derived work must preserve the copyright notice and this
0007:         * notice unmodified.
0008:         *
0009:         * Resin Open Source is free software; you can redistribute it and/or modify
0010:         * it under the terms of the GNU General Public License as published by
0011:         * the Free Software Foundation; either version 2 of the License, or
0012:         * (at your option) any later version.
0013:         *
0014:         * Resin Open Source is distributed in the hope that it will be useful,
0015:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
0017:         * of NON-INFRINGEMENT.  See the GNU General Public License for more
0018:         * details.
0019:         *
0020:         * You should have received a copy of the GNU General Public License
0021:         * along with Resin Open Source; if not, write to the
0022:         *   Free SoftwareFoundation, Inc.
0023:         *   59 Temple Place, Suite 330
0024:         *   Boston, MA 02111-1307  USA
0025:         *
0026:         * @author Scott Ferguson
0027:         */
0028:
0029:        package com.caucho.es.parser;
0030:
0031:        import com.caucho.es.ESBase;
0032:        import com.caucho.es.ESException;
0033:        import com.caucho.es.ESId;
0034:        import com.caucho.es.ESParseException;
0035:        import com.caucho.es.Script;
0036:        import com.caucho.java.JavaCompiler;
0037:        import com.caucho.java.LineMap;
0038:        import com.caucho.loader.SimpleLoader;
0039:        import com.caucho.log.Log;
0040:        import com.caucho.server.util.CauchoSystem;
0041:        import com.caucho.util.CharBuffer;
0042:        import com.caucho.util.IntArray;
0043:        import com.caucho.util.L10N;
0044:        import com.caucho.vfs.MergePath;
0045:        import com.caucho.vfs.Path;
0046:        import com.caucho.vfs.ReadStream;
0047:        import com.caucho.vfs.Vfs;
0048:        import com.caucho.vfs.WriteStream;
0049:
0050:        import java.io.IOException;
0051:        import java.util.ArrayList;
0052:        import java.util.logging.Logger;
0053:
0054:        /**
0055:         * Parser is a factory for generating compiled Script objects.
0056:         *
0057:         * <p>Most applications will use the <code>parse(String)</code> interface
0058:         * to parse JavaScript.  That method will try to load a precompiled
0059:         * script from the work directory before trying to parse it.
0060:         *
0061:         * <p>Applications will often set the script path a directory for
0062:         * script and include the classpath in the path.  Applications will
0063:         * often override the work dir for a more appropriate work directory.
0064:         *
0065:         * <code><pre>
0066:         * package com.caucho.vfs.*;
0067:         * package com.caucho.es.*;
0068:         *
0069:         * ...
0070:         *
0071:         * com.caucho.es.parser.Parser parser;
0072:         * parser = new com.caucho.es.parser.Parser();
0073:         *
0074:         * // configure the path to search for *.js files
0075:         * MergePath scriptPath = new MergePath();
0076:         * scriptPath.addMergePath(Vfs.lookup("/home/ferg/js"));
0077:         * ClassLoader loader = Thread.currentThread().contextClassLoader();
0078:         * scriptPath.addClassPath(loader);
0079:         * parser.setScriptPath(scriptPath);
0080:         *
0081:         * // configure the directory storing compiled scripts
0082:         * Path workPath = Vfs.lookup("/tmp/caucho/work");
0083:         * parser.setWorkDir(workPath);
0084:         * 
0085:         * Script script = parser.parse("test.js");
0086:         * </pre></code>
0087:         */
0088:        public class Parser {
0089:            private static final Logger log = Log.open(Parser.class);
0090:            private static final L10N L = new L10N(Parser.class);
0091:            private static final Object LOCK = new Object();
0092:
0093:            static ESId CLINIT = ESId.intern("__clinit__");
0094:            static ESId PROTOTYPE = ESId.intern("prototype");
0095:            static ESId FINALLY = ESId.intern("finally");
0096:            static ESId ANONYMOUS = ESId.intern("anonymous");
0097:            static ESId OBJECT = ESId.intern("Object");
0098:            static ESId REGEXP = ESId.intern("RegExp");
0099:            static ESId ARRAY = ESId.intern("Array");
0100:            static ESId LENGTH = ESId.intern("length");
0101:            static ESId PACKAGES = ESId.intern("Packages");
0102:            static ESId JAVA = ESId.intern("java");
0103:            static ESId COM = ESId.intern("com");
0104:            static ESId CAUCHO = ESId.intern("caucho");
0105:
0106:            static final int PREC_DOT = 1;
0107:            static final int PREC_POST = PREC_DOT;
0108:            static final int PREC_FUN = PREC_POST + 1;
0109:            static final int PREC_UMINUS = PREC_FUN + 1;
0110:            static final int PREC_TIMES = PREC_UMINUS + 1;
0111:            static final int PREC_PLUS = PREC_TIMES + 1;
0112:            static final int PREC_SHIFT = PREC_PLUS + 1;
0113:            static final int PREC_CMP = PREC_SHIFT + 1;
0114:            static final int PREC_EQ = PREC_CMP + 1;
0115:            static final int PREC_BITAND = PREC_EQ + 1;
0116:            static final int PREC_BITXOR = PREC_BITAND + 1;
0117:            static final int PREC_BITOR = PREC_BITXOR + 1;
0118:            static final int PREC_AND = PREC_BITOR + 1;
0119:            static final int PREC_OR = PREC_AND + 1;
0120:            static final int PREC_COND = PREC_OR + 1;
0121:            static final int PREC_ASSIGN = PREC_COND + 1;
0122:            static final int PREC_COMMA = PREC_ASSIGN + 1;
0123:            static final int PREC_MAX = PREC_COMMA + 1;
0124:
0125:            ClassLoader parentLoader;
0126:            ClassLoader loader;
0127:
0128:            Path scriptPath;
0129:            boolean isEval;
0130:            // Name of the generated class
0131:            String className;
0132:
0133:            Lexer lexer;
0134:            IntArray hashes = new IntArray();
0135:
0136:            ArrayList importList = new ArrayList();
0137:
0138:            ParseClass parseClass;
0139:            Function globalFunction;
0140:            Function staticFunction;
0141:            Function function; // the current prototype, i.e. class
0142:            Block block;
0143:
0144:            LineMap lineMap;
0145:            Path workPath;
0146:            //JavaCompiler compiler;
0147:            boolean isFast;
0148:
0149:            public Parser() {
0150:                workPath = CauchoSystem.getWorkPath();
0151:                //compiler.setEncoding("utf8");
0152:                addImport("java.lang.*");
0153:                addImport("com.caucho.jslib.*");
0154:            }
0155:
0156:            /**
0157:             * Sets the parent class loader.  If unspecified, defaults to the context
0158:             * classloader.  Most applications will just use the default.
0159:             *
0160:             * @param parentLoader the classloader to be used for the script's parent.
0161:             */
0162:            public void setParentLoader(ClassLoader parentLoader) {
0163:                this .parentLoader = parentLoader;
0164:            }
0165:
0166:            /**
0167:             * Internal method to set the actual class loader.
0168:             * Normally, this should only be called from com.caucho.es functions.
0169:             */
0170:            public void setClassLoader(ClassLoader loader) {
0171:                this .loader = loader;
0172:            }
0173:
0174:            /**
0175:             * Returns the current class loader.  If null, creates from the parent
0176:             * loader and the work-dir.
0177:             */
0178:            ClassLoader getClassLoader() {
0179:                if (loader != null)
0180:                    return loader;
0181:
0182:                if (parentLoader != null)
0183:                    loader = SimpleLoader.create(parentLoader, workPath, null);
0184:                else
0185:                    loader = SimpleLoader.create(null, workPath, null);
0186:
0187:                return loader;
0188:            }
0189:
0190:            /**
0191:             * Sets the path to search for imported javascript source files.
0192:             * Normally, ScriptPath will be a MergePath.  If the MergePath
0193:             * adds the classpath, then JavaScript files can be put in the
0194:             * normal Java classpath.
0195:             *
0196:             * <p>If the ScriptPath is not specified, it will use the
0197:             * current directory and the classpath from the context class loader.
0198:             *
0199:             * <code><pre>
0200:             * MergePath scriptPath = new MergePath();
0201:             * scriptPath.addMergePath(Vfs.lookup("/home/ferg/js"));
0202:             *
0203:             * ClassLoader loader = Thread.currentThread().contextClassLoader();
0204:             * scriptPath.addClassPath(loader);
0205:             *
0206:             * parser.setScriptPath(scriptPath);
0207:             * </pre></code>
0208:             *
0209:             * @param scriptPath path to search for imported scripts.
0210:             */
0211:            public void setScriptPath(Path scriptPath) {
0212:                this .scriptPath = scriptPath;
0213:            }
0214:
0215:            /**
0216:             * Returns the path to search for imported javascript.  Normally, scriptPath
0217:             * will be a MergePath.
0218:             *
0219:             * @param scriptPath path to search for imported scripts.
0220:             */
0221:            public Path getScriptPath() {
0222:                return scriptPath;
0223:            }
0224:
0225:            /**
0226:             * Adds a package/script to be automatically imported by the script.
0227:             * Each import is the equivalent of adding the following javascript:
0228:             *
0229:             * <code><pre>
0230:             * package <em>name</em>;
0231:             * </pre></code>
0232:             *
0233:             * @param name package or script name to be automatically imported.
0234:             */
0235:            public void addImport(String name) {
0236:                if (!importList.contains(name))
0237:                    importList.add(name);
0238:            }
0239:
0240:            /**
0241:             * Sets "fast" mode, i.e. JavaScript 2.0.  Fast mode lets the compiler
0242:             * make assumptions about types and classes, e.g. that class methods
0243:             * won't change dynamically.  This lets the compiler generate more code
0244:             * that directly translates to Java calls.
0245:             */
0246:            public void setFast(boolean isFast) {
0247:                this .isFast = isFast;
0248:            }
0249:
0250:            /**
0251:             * Sets a line number map.  For generated files like JSP or XTP,
0252:             * the error messages need an extra translation to get to the original
0253:             * line numbers.
0254:             */
0255:            public void setLineMap(LineMap lineMap) {
0256:                this .lineMap = lineMap;
0257:            }
0258:
0259:            /**
0260:             * Sets the name of the generated java class.  If unset, the parser will
0261:             * mangle the input name.
0262:             */
0263:            public void setClassName(String name) {
0264:                this .className = name;
0265:            }
0266:
0267:            /**
0268:             * Sets the directory for generated *.java and *.class files.
0269:             * The parser will check this directory for any precompiled javascript
0270:             * classes.  The default work-dir is /tmp/caucho on unix and
0271:             * c:\temp\caucho on windows.
0272:             *
0273:             * @param path the work directory.
0274:             */
0275:            public void setWorkDir(Path path) {
0276:                workPath = path;
0277:            }
0278:
0279:            /**
0280:             * Returns the directory for generated *.java and *.class files.
0281:             */
0282:            public Path getWorkDir() {
0283:                return workPath;
0284:            }
0285:
0286:            /**
0287:             * Main application parsing method.  The parser will try to load
0288:             * the compiled script.  If the compiled script exists and the
0289:             * source file has not changed, parse will return the old script.
0290:             * Otherwise, it will parse and compile the javascript.
0291:             *
0292:             * @param name the name of the javascript source.
0293:             *
0294:             * @return the parsed script
0295:             */
0296:            public Script parse(String name) throws ESException, IOException {
0297:                Path path;
0298:
0299:                try {
0300:                    String className;
0301:
0302:                    if (this .className != null)
0303:                        className = this .className;
0304:                    else
0305:                        className = "_js." + JavaCompiler.mangleName(name);
0306:
0307:                    if (scriptPath == null) {
0308:                        MergePath mergePath = new MergePath();
0309:                        mergePath.addMergePath(Vfs.lookup());
0310:                        ClassLoader parentLoader = this .parentLoader;
0311:                        if (parentLoader == null)
0312:                            parentLoader = Thread.currentThread()
0313:                                    .getContextClassLoader();
0314:
0315:                        mergePath.addClassPath(parentLoader);
0316:                        scriptPath = mergePath;
0317:                    }
0318:
0319:                    Script script = loadScript(className);
0320:
0321:                    if (!script.isModified()) {
0322:                        script.setScriptPath(getScriptPath());
0323:                        script.setClassDir(workPath);
0324:                        return script;
0325:                    }
0326:                } catch (Throwable e) {
0327:                }
0328:
0329:                path = getScriptPath().lookup(name);
0330:
0331:                ReadStream is = path.openRead();
0332:                try {
0333:                    return parse(is, name, 1);
0334:                } finally {
0335:                    is.close();
0336:                }
0337:            }
0338:
0339:            /**
0340:             * Alternative parsing method when the application only has an open
0341:             * stream to the file.  Since this method will always compile a new script,
0342:             * it can be significantly slower than the <code>parse(String)</code>
0343:             * method.
0344:             *
0345:             * @param is a read stream to the javascript source.
0346:             *
0347:             * @return the parsed script.
0348:             */
0349:            public Script parse(ReadStream is) throws ESException, IOException {
0350:                return parse(is, null, 1);
0351:            }
0352:
0353:            /**
0354:             * An alternative parsing method given an open stream, a filename and
0355:             * a line number.
0356:             *
0357:             * @param is a stream to the javascript source.
0358:             * @param name filename to use for error messages.
0359:             * @param line initial line number.
0360:             *
0361:             * @return the compiled script
0362:             */
0363:            public Script parse(ReadStream is, String name, int line)
0364:                    throws ESException, IOException {
0365:                if (name == null)
0366:                    name = is.getUserPath();
0367:
0368:                if (line <= 0)
0369:                    line = 1;
0370:
0371:                return parse(is, name, line, false);
0372:            }
0373:
0374:            /**
0375:             * Parses a script for the JavaScript "eval" expression.  The
0376:             * semantics for "eval" are slightly different from standard
0377:             * scripts.
0378:             *
0379:             * @param is stream to the eval source.
0380:             * @param name filename to use for error messages
0381:             * @param line initial line number to use for error messages.
0382:             *
0383:             * @return the compiled script.
0384:             */
0385:            public Script parseEval(ReadStream is, String name, int line)
0386:                    throws ESException, IOException {
0387:                if (name == null)
0388:                    name = "eval";
0389:
0390:                if (line <= 0)
0391:                    line = 1;
0392:
0393:                return parse(is, name, line, true);
0394:            }
0395:
0396:            /**
0397:             * The main parser method.
0398:             *
0399:             * @param is stream to read the script.
0400:             * @param name the filename to use for error messages.
0401:             * @param line the line number to use for error messages.
0402:             * @param isEval if true, parse for an eval expression.
0403:             *
0404:             * @return the compiled javascript
0405:             */
0406:            private Script parse(ReadStream is, String name, int line,
0407:                    boolean isEval) throws ESException, IOException {
0408:                if (name == null)
0409:                    name = "anonymous";
0410:
0411:                if (line <= 0)
0412:                    line = 1;
0413:
0414:                lexer = new Lexer(is, name, line);
0415:                if (lineMap != null)
0416:                    lexer.setLineMap(lineMap);
0417:
0418:                if (className == null)
0419:                    className = "_js." + JavaCompiler.mangleName(name);
0420:
0421:                if (scriptPath == null) {
0422:                    MergePath mergePath = new MergePath();
0423:                    if (is.getPath() != null)
0424:                        mergePath.addMergePath(is.getPath().getParent());
0425:                    else
0426:                        mergePath.addMergePath(Vfs.lookup());
0427:                    ClassLoader parentLoader = this .parentLoader;
0428:                    if (parentLoader == null)
0429:                        parentLoader = Thread.currentThread()
0430:                                .getContextClassLoader();
0431:
0432:                    mergePath.addClassPath(parentLoader);
0433:                    scriptPath = mergePath;
0434:                }
0435:
0436:                block = null;
0437:
0438:                JavaCompiler compiler = JavaCompiler.create(getClassLoader());
0439:                compiler.setClassDir(workPath);
0440:
0441:                parseClass = new ParseClass(name, className);
0442:                parseClass.setParser(this );
0443:                if (is.getPath() != null && is.getPath().getLastModified() > 0)
0444:                    parseClass.setSourcePath(is.getPath());
0445:
0446:                globalFunction = parseClass.newFunction(null, ESId
0447:                        .intern("global"), false);
0448:                globalFunction.setFast(isFast);
0449:                staticFunction = parseClass.newFunction(null, ESId
0450:                        .intern("__es_static"), false);
0451:                parseClass.setGlobal(globalFunction);
0452:
0453:                if (isEval) {
0454:                    block = Block.create(this , globalFunction);
0455:                    block.finish();
0456:                    function = parseClass.newFunction(globalFunction, ESId
0457:                            .intern("eval"), false);
0458:                    function.setEval();
0459:                } else
0460:                    function = globalFunction;
0461:
0462:                block = Block.create(this , function);
0463:                parseBlock(true);
0464:                block.finish();
0465:
0466:                if (lexer.peek() != Lexer.EOF)
0467:                    throw expect(L.l("end of file"));
0468:
0469:                block = Block.create(this , staticFunction);
0470:                block.finish();
0471:
0472:                synchronized (LOCK) {
0473:                    Path path = workPath.lookup(className.replace('.', '/')
0474:                            + ".java");
0475:                    path.getParent().mkdirs();
0476:
0477:                    WriteStream os = path.openWrite();
0478:                    os.setEncoding("JAVA");
0479:                    parseClass.writeCode(os);
0480:                    os.close();
0481:
0482:                    Script script;
0483:                    try {
0484:                        compiler.compile(className.replace('.', '/') + ".java",
0485:                                null);
0486:                        script = loadScript(className);
0487:                    } catch (Exception e) {
0488:                        throw new ESParseException(e);
0489:                    }
0490:
0491:                    script.setScriptPath(getScriptPath());
0492:                    script.setClassDir(workPath);
0493:
0494:                    return script;
0495:                }
0496:            }
0497:
0498:            /**
0499:             * Tries to load an already compiled script.
0500:             *
0501:             * @param className mangled classname of the script.
0502:             */
0503:            private Script loadScript(String className) throws Exception {
0504:                ClassLoader loader = getClassLoader();
0505:                Class cl = CauchoSystem.loadClass(className, false, loader);
0506:
0507:                Script script = (Script) cl.newInstance();
0508:                script.setScriptPath(getScriptPath());
0509:                script.setClassDir(workPath);
0510:
0511:                return script;
0512:            }
0513:
0514:            /**
0515:             * Parse a function
0516:             */
0517:            private Function parseFunction() throws ESException {
0518:                function.setNeedsScope();
0519:
0520:                ESId id = null;
0521:                if (lexer.peek() == Lexer.IDENTIFIER) {
0522:                    lexer.next();
0523:                    id = lexer.getId();
0524:                }
0525:
0526:                if (lexer.next() != '(')
0527:                    throw expect("`('");
0528:
0529:                if (id != null) {
0530:                    function.addVariable(block, id, null);
0531:                    block.newVar(id).getVar().setType(Expr.TYPE_ES);
0532:                }
0533:
0534:                Block oldBlock = block;
0535:                Function oldFun = function;
0536:                function = parseClass.newFunction(oldFun, id, false);
0537:
0538:                oldFun.addFunction(function);
0539:
0540:                block = Block.create(this , function);
0541:
0542:                boolean isFirst = true;
0543:                while (lexer.peek() != ')') {
0544:                    if (!isFirst && lexer.next() != ',')
0545:                        throw expect("`,'");
0546:                    isFirst = false;
0547:
0548:                    if (lexer.next() != Lexer.IDENTIFIER)
0549:                        throw expect(L.l("formal argument"));
0550:
0551:                    ESId argId = lexer.getId();
0552:
0553:                    Expr type = null;
0554:                    if (lexer.peek() == ':') {
0555:                        lexer.next();
0556:                        type = parseType();
0557:                    }
0558:
0559:                    function.addFormal(block, argId, type);
0560:                }
0561:                lexer.next();
0562:
0563:                if (lexer.peek() == ':') {
0564:                    lexer.next();
0565:                    Expr type = parseType();
0566:
0567:                    function.setReturnType(type);
0568:                }
0569:
0570:                if (lexer.next() != '{')
0571:                    throw expect("`{'");
0572:
0573:                parseBlock(false);
0574:
0575:                if (lexer.next() != '}') {
0576:                    throw expect("`}'");
0577:                }
0578:
0579:                block.finish();
0580:
0581:                Function newFun = function;
0582:
0583:                function = oldFun;
0584:                block = oldBlock;
0585:
0586:                return newFun;
0587:            }
0588:
0589:            /**
0590:             * Parses a list of statements, returning a block representing the
0591:             * statements.
0592:             *
0593:             * @param parent the containing block
0594:             * @param isTop true if this is a top level block
0595:             */
0596:            private void parseBlock(boolean isTop) throws ESException {
0597:                loop: while (true) {
0598:                    switch (lexer.peek()) {
0599:                    case Lexer.UNARY_OP:
0600:                    case Lexer.BANDU_OP:
0601:                    case Lexer.NEW:
0602:                    case Lexer.DELETE:
0603:                    case Lexer.VOID:
0604:                    case Lexer.TYPEOF:
0605:                    case Lexer.POSTFIX:
0606:                    case Lexer.IDENTIFIER:
0607:                    case Lexer.THIS:
0608:                    case Lexer.EVAL:
0609:                    case Lexer.LITERAL:
0610:                    case Lexer.REGEXP:
0611:                    case '(':
0612:                    case '[':
0613:                    case Lexer.HASH_REF:
0614:                    case Lexer.HASH_DEF:
0615:                    case Lexer.FUNCTION:
0616:                        parseStatement();
0617:                        break;
0618:
0619:                    case Lexer.IF:
0620:                    case Lexer.FOR:
0621:                    case Lexer.WHILE:
0622:                    case Lexer.DO:
0623:                    case Lexer.VAR:
0624:                    case Lexer.BREAK:
0625:                    case Lexer.WITH:
0626:                    case Lexer.SYNCHRONIZED:
0627:                    case Lexer.CONTINUE:
0628:                    case Lexer.RETURN:
0629:                    case Lexer.SWITCH:
0630:                    case Lexer.TRY:
0631:                    case Lexer.THROW:
0632:                    case ';':
0633:                        parseStatement();
0634:                        break;
0635:
0636:                    case '{':
0637:                        block = block.startBlock();
0638:                        parseStatement();
0639:                        block = block.finishBlock();
0640:                        break;
0641:
0642:                    case Lexer.CATCH:
0643:                        block.doTry();
0644:                        parseCatch();
0645:                        break;
0646:
0647:                    case Lexer.FINALLY:
0648:                        block.doTry();
0649:                        parseFinally();
0650:                        break;
0651:
0652:                    case Lexer.CLASS:
0653:                        parseClass();
0654:                        break;
0655:
0656:                    case Lexer.IMPORT:
0657:                        parseImport();
0658:                        break;
0659:
0660:                    case Lexer.STATIC:
0661:                        if (true)
0662:                            throw new ESException("nostatus");
0663:                        //parseStatic();
0664:                        break;
0665:
0666:                    default:
0667:                        break loop;
0668:                    }
0669:                }
0670:            }
0671:
0672:            /**
0673:             * Parses a statement.
0674:             */
0675:            private void parseStatement() throws ESException {
0676:                int lexeme = lexer.peek();
0677:                hashes.clear();
0678:                int line = lexer.getLine();
0679:                Expr expr = null;
0680:
0681:                block.setLine(line);
0682:
0683:                if (block.isDead) {
0684:                    switch (lexeme) {
0685:                    case ';':
0686:                    case Lexer.VAR:
0687:                    case Lexer.FUNCTION:
0688:                    case Lexer.CATCH:
0689:                    case Lexer.FINALLY:
0690:                        break;
0691:
0692:                    default:
0693:                        throw error(L.l("can't reach statement"));
0694:                    }
0695:                }
0696:
0697:                switch (lexeme) {
0698:                case Lexer.IDENTIFIER:
0699:                    parseIdentifierStatement();
0700:                    break;
0701:
0702:                case Lexer.UNARY_OP:
0703:                case Lexer.BANDU_OP:
0704:                case Lexer.NEW:
0705:                case Lexer.THIS:
0706:                case Lexer.EVAL:
0707:                case Lexer.LITERAL:
0708:                case Lexer.REGEXP:
0709:                case Lexer.POSTFIX:
0710:                case Lexer.DELETE:
0711:                case Lexer.VOID:
0712:                case Lexer.TYPEOF:
0713:                case '(':
0714:                case '[':
0715:                case Lexer.HASH_REF:
0716:                case Lexer.HASH_DEF:
0717:                    block.addExpr(parseExpression(PREC_MAX, true));
0718:                    parseStatementEnd();
0719:                    break;
0720:
0721:                case Lexer.FUNCTION:
0722:                    lexer.next();
0723:                    Function newFun = parseFunction();
0724:                    break;
0725:
0726:                case Lexer.VAR:
0727:                    parseVar(false);
0728:                    parseStatementEnd();
0729:                    break;
0730:
0731:                case Lexer.BREAK:
0732:                    lexer.next();
0733:                    if (lexer.peek() == Lexer.IDENTIFIER
0734:                            && !lexer.seenLineFeed()) {
0735:                        block.doBreak(lexer.getId());
0736:                        lexer.next();
0737:                    } else
0738:                        block.doBreak();
0739:                    parseStatementEnd();
0740:                    break;
0741:
0742:                case Lexer.CONTINUE:
0743:                    lexer.next();
0744:                    if (lexer.peek() == Lexer.IDENTIFIER
0745:                            && !lexer.seenLineFeed()) {
0746:                        block.doContinue(lexer.getId());
0747:                        lexer.next();
0748:                    } else
0749:                        block.doContinue();
0750:
0751:                    parseStatementEnd();
0752:                    break;
0753:
0754:                case Lexer.RETURN:
0755:                    lexer.next();
0756:
0757:                    if (lexer.peek() == ';' || lexer.peek() == '}'
0758:                            || lexer.seenLineFeed()) {
0759:                        block.doReturn();
0760:                    } else {
0761:                        block.doReturn(parseExpression(PREC_MAX, true));
0762:                    }
0763:
0764:                    parseStatementEnd();
0765:                    break;
0766:
0767:                case Lexer.IF:
0768:                    parseIf();
0769:                    break;
0770:
0771:                case Lexer.SWITCH:
0772:                    parseSwitch();
0773:                    break;
0774:
0775:                case Lexer.WHILE:
0776:                    parseWhile(null);
0777:                    break;
0778:
0779:                case Lexer.DO:
0780:                    parseDo(null);
0781:                    break;
0782:
0783:                case Lexer.FOR:
0784:                    parseFor(null);
0785:                    break;
0786:
0787:                case Lexer.WITH:
0788:                    parseWith();
0789:                    break;
0790:
0791:                case Lexer.SYNCHRONIZED:
0792:                    parseSynchronized();
0793:                    break;
0794:
0795:                case Lexer.TRY:
0796:                    parseTry();
0797:                    break;
0798:
0799:                case Lexer.THROW:
0800:                    lexer.next();
0801:                    block.doThrow(parseExpression(PREC_MAX));
0802:                    break;
0803:
0804:                case ';':
0805:                    lexer.next();
0806:                    break;
0807:
0808:                case '{':
0809:                    lexer.next();
0810:                    parseBlock(false);
0811:                    if (lexer.next() != '}')
0812:                        throw expect("`}'");
0813:                    break;
0814:
0815:                default:
0816:                    throw expect(L.l("statement"));
0817:                }
0818:            }
0819:
0820:            private void parseStatementEnd() throws ESException {
0821:                if (lexer.peek() == ';')
0822:                    lexer.next();
0823:                else if (lexer.peek() == '}' || lexer.peek() == Lexer.EOF
0824:                        || lexer.seenLineFeed()) {
0825:                } else {
0826:                    throw expect("`;'");
0827:                }
0828:            }
0829:
0830:            private void parseIdentifierStatement() throws ESException {
0831:                ESId id = lexer.getId();
0832:                int line = lexer.getLine();
0833:
0834:                lexer.next();
0835:                if (lexer.peek() != ':') {
0836:                    Expr var = getVar(id);
0837:                    Expr expr = parseExprRec(parseTermTail(var, false, true),
0838:                            PREC_MAX, false, true);
0839:                    block.addExpr(expr);
0840:                    parseStatementEnd();
0841:                    return;
0842:                }
0843:
0844:                lexer.next();
0845:
0846:                /*
0847:                if (findLoop(null, id) != null)
0848:                  throw error("duplicate label `" + id + "'");
0849:                 */
0850:
0851:                switch (lexer.peek()) {
0852:                case Lexer.WHILE:
0853:                    parseWhile(id);
0854:                    break;
0855:
0856:                case Lexer.DO:
0857:                    parseDo(id);
0858:                    break;
0859:
0860:                case Lexer.FOR:
0861:                    parseFor(id);
0862:                    break;
0863:
0864:                default:
0865:                    block = block.startBlock(id);
0866:                    parseStatement();
0867:                    block = block.finishBlock();
0868:                    break;
0869:                }
0870:            }
0871:
0872:            private Expr parseType() throws ESException {
0873:                if (lexer.next() != Lexer.IDENTIFIER)
0874:                    throw expect(L.l("identifier"));
0875:
0876:                Expr type = block.newType(lexer.getId());
0877:
0878:                while (lexer.peek() == '.') {
0879:                    lexer.next();
0880:                    if (lexer.next() != Lexer.IDENTIFIER)
0881:                        throw expect(L.l("identifier"));
0882:
0883:                    type = type.fieldReference(lexer.getId());
0884:                }
0885:
0886:                return type;
0887:            }
0888:
0889:            /**
0890:             * if ::= IF '(' expr ')' stmt 
0891:             */
0892:            private void parseIf() throws ESException {
0893:                boolean isFirst = true;
0894:                boolean isDead = true;
0895:
0896:                block = block.create();
0897:
0898:                while (lexer.peek() == Lexer.IF) {
0899:                    lexer.next();
0900:
0901:                    if (lexer.next() != '(')
0902:                        throw expect("`('");
0903:
0904:                    block.startIf(parseBooleanExpression(PREC_MAX), !isFirst);
0905:                    isFirst = false;
0906:
0907:                    if (lexer.next() != ')')
0908:                        throw expect("`)'");
0909:
0910:                    parseStatement();
0911:
0912:                    block.endBlock();
0913:                    if (!block.isDead)
0914:                        isDead = false;
0915:                    block.isDead = false;
0916:
0917:                    if (lexer.peek() != Lexer.ELSE) {
0918:                        block = block.pop();
0919:                        return;
0920:                    }
0921:
0922:                    lexer.next();
0923:                }
0924:
0925:                block.startElse();
0926:                parseStatement();
0927:                block.endBlock();
0928:                if (!block.isDead)
0929:                    isDead = false;
0930:                block = block.pop();
0931:                block.isDead = isDead;
0932:            }
0933:
0934:            /**
0935:             * switch ::= SWITCH '(' expr ')' '{' ((CASE expr:|DEFAULT)+ stmt*)* '}'
0936:             */
0937:            private void parseSwitch() throws ESException {
0938:                lexer.next();
0939:                if (lexer.next() != '(')
0940:                    throw expect("`)'");
0941:
0942:                Expr test = parseExpression(PREC_MAX);
0943:
0944:                if (lexer.next() != ')')
0945:                    throw expect("`)'");
0946:
0947:                if (lexer.next() != '{')
0948:                    throw expect("`{'");
0949:
0950:                ArrayList exprs = new ArrayList();
0951:
0952:                block = block.startSwitch(test);
0953:
0954:                int ch;
0955:                while ((ch = lexer.peek()) != -1 && ch != '}') {
0956:                    switch (ch) {
0957:                    case Lexer.CASE:
0958:                        lexer.next();
0959:                        block.doCase(exprs.size());
0960:                        exprs.add(parseExpression(PREC_MAX));
0961:
0962:                        if (lexer.next() != ':')
0963:                            throw expect("`:'");
0964:                        break;
0965:
0966:                    case Lexer.DEFAULT:
0967:                        lexer.next();
0968:                        if (lexer.next() != ':')
0969:                            throw expect("`:'");
0970:
0971:                        block.doDefault();
0972:                        break;
0973:
0974:                    default:
0975:                        parseStatement();
0976:                    }
0977:                }
0978:
0979:                if (lexer.next() != '}')
0980:                    throw expect("`}'");
0981:
0982:                block = block.fillSwitch(exprs);
0983:            }
0984:
0985:            /**
0986:             * while ::= WHILE '(' expr ')' stmt 
0987:             */
0988:            private void parseWhile(ESId id) throws ESException {
0989:                lexer.next();
0990:                if (lexer.next() != '(')
0991:                    throw expect("`('");
0992:
0993:                Expr expr = parseBooleanExpression(PREC_MAX);
0994:                if (expr instanceof  LiteralExpr
0995:                        && !((LiteralExpr) expr).getLiteral().toBoolean())
0996:                    throw error(L.l("while (false) is never executed."));
0997:                block = block.startWhile(id, expr);
0998:
0999:                if (lexer.next() != ')')
1000:                    throw expect("`)'");
1001:
1002:                parseStatement();
1003:                block = block.endLoop();
1004:            }
1005:
1006:            /**
1007:             * for ::= FOR '(' expr ')' stmt 
1008:             */
1009:            private void parseFor(ESId id) throws ESException {
1010:                lexer.next();
1011:                if (lexer.next() != '(')
1012:                    throw expect("`('");
1013:
1014:                boolean hasValue = false;
1015:                Expr lhs = null;
1016:                if (lexer.peek() == Lexer.VAR) {
1017:                    lhs = parseVar(true);
1018:                } else if (lexer.peek() != ';') {
1019:                    lhs = parseExpression(PREC_MAX);
1020:                } else if (lexer.peek() == Lexer.IN)
1021:                    throw expect(L.l("expression"));
1022:
1023:                if (lexer.peek() == Lexer.IN) {
1024:                    parseForIn(id, lhs);
1025:                    return;
1026:                }
1027:
1028:                if (lhs != null)
1029:                    lhs.exprStatement(block.function);
1030:
1031:                if (lexer.next() != ';')
1032:                    throw expect("`;'");
1033:
1034:                Expr test = null;
1035:                if (lexer.peek() != ';')
1036:                    test = parseExpression(PREC_MAX);
1037:
1038:                if (lexer.next() != ';')
1039:                    throw expect("`;'");
1040:
1041:                Expr incr = null;
1042:                if (lexer.peek() != ')') {
1043:                    incr = parseExpression(PREC_MAX);
1044:                    incr.killValue();
1045:                }
1046:
1047:                if (lexer.next() != ')')
1048:                    throw expect("`)'");
1049:
1050:                if (test instanceof  LiteralExpr
1051:                        && !((LiteralExpr) test).getLiteral().toBoolean())
1052:                    throw error(L.l("for (;false;) is never executed."));
1053:                block = block.startFor(id, test, incr);
1054:                parseStatement();
1055:                block = block.endLoop();
1056:            }
1057:
1058:            private void parseForIn(ESId id, Expr lhs) throws ESException {
1059:                lexer.next();
1060:
1061:                String var = block.newIterator(id, parseExpression(PREC_MAX));
1062:
1063:                if (lexer.next() != ')')
1064:                    throw expect("`)'");
1065:
1066:                block = block.startWhile(id, block.hasNext(var));
1067:
1068:                block.addExpr(lhs.next(var, lhs));
1069:
1070:                parseStatement();
1071:                block = block.endLoop();
1072:            }
1073:
1074:            /**
1075:             * do ::= DO stmt WHILE '(' expr ')'
1076:             */
1077:            private void parseDo(ESId id) throws ESException {
1078:                lexer.next();
1079:
1080:                block = block.startDo(id);
1081:                parseStatement();
1082:
1083:                if (lexer.next() != Lexer.WHILE)
1084:                    throw expect("`while'");
1085:
1086:                if (lexer.next() != '(')
1087:                    throw expect("`('");
1088:
1089:                block = block.endDo(parseBooleanExpression(PREC_MAX));
1090:
1091:                if (lexer.next() != ')')
1092:                    throw expect("`)'");
1093:
1094:                parseStatementEnd();
1095:            }
1096:
1097:            /**
1098:             * with ::= WITH '(' expr ')' stmt 
1099:             */
1100:            private void parseWith() throws ESException {
1101:                lexer.next();
1102:                if (lexer.next() != '(')
1103:                    throw expect("`('");
1104:
1105:                block = block.startWith(parseExpression(PREC_MAX));
1106:
1107:                if (lexer.next() != ')')
1108:                    throw expect("`)'");
1109:
1110:                parseStatement();
1111:
1112:                block = block.endWith();
1113:            }
1114:
1115:            /**
1116:             * var ::= VAR id (= expr)? (, id (= expr)?)*
1117:             */
1118:            private Expr parseVar(boolean keepValue) throws ESException {
1119:                boolean isFirst = true;
1120:                Expr retVar = null;
1121:                do {
1122:                    lexer.next();
1123:
1124:                    if (lexer.next() != Lexer.IDENTIFIER)
1125:                        throw expect(L.l("identifier"));
1126:
1127:                    ESId name = lexer.getId();
1128:
1129:                    Expr type = null;
1130:
1131:                    if (lexer.peek() == ':') {
1132:                        lexer.next();
1133:
1134:                        type = parseType();
1135:                    }
1136:
1137:                    block.defVar(name, type);
1138:
1139:                    if (lexer.peek() == '=') {
1140:                        lexer.next();
1141:
1142:                        Expr var = block.newVar(name, type);
1143:                        Expr value = parseExpression(Parser.PREC_ASSIGN + 1,
1144:                                true);
1145:                        block.evalExpr();
1146:                        var.assign(value).exprStatement(block.function);
1147:                    } else if (keepValue)
1148:                        retVar = block.newVar(name, type);
1149:
1150:                    isFirst = false;
1151:                } while (lexer.peek() == ',');
1152:
1153:                return retVar;
1154:            }
1155:
1156:            /**
1157:             * synchronized ::= SYNCHRONIZED '(' expr ')' stmt 
1158:             */
1159:            private void parseSynchronized() throws ESException {
1160:                lexer.next();
1161:                if (lexer.next() != '(')
1162:                    throw expect("`('");
1163:
1164:                block = block.startSynchronized(parseExpression(PREC_MAX));
1165:
1166:                if (lexer.next() != ')')
1167:                    throw expect("`)'");
1168:
1169:                parseStatement();
1170:
1171:                block = block.endSynchronized();
1172:            }
1173:
1174:            /**
1175:             * try ::= TRY stmt (CATCH | FINALLY)
1176:             */
1177:            private void parseTry() throws ESException {
1178:                lexer.next();
1179:
1180:                block = block.startTry();
1181:                parseStatement();
1182:                block = block.endTry();
1183:
1184:                if (lexer.peek() == Lexer.CATCH) {
1185:                    parseCatch();
1186:                } else if (lexer.peek() == Lexer.FINALLY)
1187:                    parseFinally();
1188:                else
1189:                    throw error(L.l("expected `catch' or `finally' at {0}",
1190:                            getToken()));
1191:            }
1192:
1193:            /**
1194:             * catch ::= CATCH '(' (expr lhs?)? ')' stmt 
1195:             */
1196:            private void parseCatch() throws ESException {
1197:                block.function.disallowJavaLocal();
1198:                // XXX: don't forget catch w/o try
1199:
1200:                boolean oldDead = block.isDead;
1201:                boolean hasCatchall = false;
1202:
1203:                while (lexer.peek() == Lexer.CATCH) {
1204:                    block.isDead = false;
1205:
1206:                    if (hasCatchall)
1207:                        throw error(L.l("catch () must be last catch clause"));
1208:
1209:                    lexer.next();
1210:                    if (lexer.next() != '(')
1211:                        throw expect("`('");
1212:
1213:                    String exceptionClass = "";
1214:                    while (lexer.peek() == Lexer.IDENTIFIER) {
1215:                        lexer.next();
1216:                        exceptionClass = exceptionClass + lexer.getText();
1217:
1218:                        if (lexer.peek() != '.')
1219:                            break;
1220:
1221:                        lexer.next();
1222:                        exceptionClass = exceptionClass + ".";
1223:                        if (lexer.peek() != Lexer.IDENTIFIER)
1224:                            throw expect(L.l("identifier"));
1225:                    }
1226:
1227:                    ESId name = null;
1228:                    if (lexer.peek() == Lexer.IDENTIFIER) {
1229:                        name = lexer.getId();
1230:                        lexer.next();
1231:                    }
1232:
1233:                    if (lexer.next() != ')') {
1234:                        if (exceptionClass.equals(""))
1235:                            throw expect(L.l("identifier"));
1236:                        else
1237:                            throw expect("`)'");
1238:                    }
1239:
1240:                    if (name == null) {
1241:                        name = ESId.intern(exceptionClass);
1242:                        exceptionClass = "java.lang.Exception";
1243:                    }
1244:
1245:                    Expr var = null;
1246:                    if (name != null)
1247:                        var = block.newVar(name);
1248:
1249:                    block = block.startCatch(exceptionClass, var);
1250:                    parseStatement();
1251:                    if (!block.isDead)
1252:                        oldDead = false;
1253:                    block = block.endCatch();
1254:                }
1255:
1256:                block.isDead = oldDead;
1257:                // Don't forget to throw
1258:                if (lexer.peek() == Lexer.FINALLY)
1259:                    parseFinally();
1260:            }
1261:
1262:            /**
1263:             * finally ::= FINALLY stmt
1264:             */
1265:            private void parseFinally() throws ESException {
1266:                boolean oldDead = block.isDead;
1267:                block.isDead = false;
1268:                lexer.next();
1269:
1270:                block = block.startFinally();
1271:
1272:                parseStatement();
1273:
1274:                block = block.endFinally();
1275:                block.isDead = oldDead;
1276:            }
1277:
1278:            static ESId BOGUS = ESId.intern("return ");
1279:
1280:            /**
1281:             * Parse a class
1282:             */
1283:            private void parseClass() throws ESException {
1284:                if (function.getParent() != null)
1285:                    throw error(L.l("`class' only allowed at top level"));
1286:
1287:                lexer.next();
1288:
1289:                if (lexer.next() != Lexer.IDENTIFIER)
1290:                    throw expect("class name");
1291:
1292:                ESId id = lexer.getId();
1293:
1294:                ESId proto = parseExtends();
1295:
1296:                if (lexer.next() != '{')
1297:                    throw expect("`{'");
1298:
1299:                ParseClass oldClass = parseClass;
1300:                Function oldGlobal = globalFunction;
1301:                Function oldStatic = staticFunction;
1302:                Function oldFunction = function;
1303:                Block oldBlock = block;
1304:
1305:                parseClass = oldClass.newClass(id);
1306:                parseClass.setProto(proto);
1307:
1308:                globalFunction = parseClass.newFunction(null, ESId
1309:                        .intern("global"), true);
1310:                staticFunction = parseClass.newFunction(null, ESId
1311:                        .intern("__es_static"), true);
1312:                parseClass.setGlobal(globalFunction);
1313:
1314:                function = globalFunction;
1315:                block = Block.create(this , function);
1316:
1317:                parseBlock(true);
1318:                block.finish();
1319:
1320:                block = Block.create(this , staticFunction);
1321:                block.finish();
1322:
1323:                if (parseClass.getFunction(id) == null) {
1324:                    function = parseClass.newFunction(null, id, false);
1325:                    block = Block.create(this , function);
1326:                    block.finish();
1327:                }
1328:
1329:                block = oldBlock;
1330:                function = oldFunction;
1331:                globalFunction = oldGlobal;
1332:                staticFunction = oldStatic;
1333:                parseClass = oldClass;
1334:
1335:                if (lexer.next() != '}')
1336:                    throw expect("`}'");
1337:            }
1338:
1339:            private ESId parseExtends() throws ESException {
1340:                if (lexer.peek() != Lexer.EXTENDS)
1341:                    return null;
1342:
1343:                lexer.next();
1344:                if (lexer.next() != Lexer.IDENTIFIER)
1345:                    throw expect(L.l("parent class name"));
1346:
1347:                return lexer.getId();
1348:            }
1349:
1350:            private void parseImport() throws ESException {
1351:                CharBuffer path = new CharBuffer();
1352:
1353:                lexer.next();
1354:
1355:                while (true) {
1356:                    if (lexer.peek() == Lexer.BIN_OP && lexer.getOp() == '*') {
1357:                        lexer.next();
1358:                        path.append('*');
1359:                        importList.add(path.close());
1360:                        return;
1361:                    }
1362:
1363:                    if (lexer.peek() != Lexer.IDENTIFIER)
1364:                        throw expect(L.l("identifier"));
1365:
1366:                    path.append(lexer.getText());
1367:
1368:                    lexer.next();
1369:
1370:                    if (lexer.peek() != '.')
1371:                        break;
1372:
1373:                    lexer.next();
1374:                    path.append('.');
1375:                }
1376:
1377:                String className = path.close();
1378:                String pathName = className.replace('.', '/') + ".js";
1379:
1380:                Path importPath = getScriptPath().lookup(pathName);
1381:
1382:                if (importPath.exists()) {
1383:                    function.cl.addImport(pathName);
1384:                    return;
1385:                }
1386:
1387:                try {
1388:                    CauchoSystem.loadClass(className, false, getClassLoader());
1389:
1390:                    importList.add(className);
1391:                } catch (ClassNotFoundException e) {
1392:                    throw error(L.l("can't open import `{0}'", pathName));
1393:                }
1394:            }
1395:
1396:            /*
1397:             private void parseStatic() throws ESException
1398:             {
1399:             if (function.rest != null || staticCode == null)
1400:             throw error("illegal static statement");
1401:
1402:             lexer.next();
1403:
1404:             int oldVar = stmtVar;
1405:             ParseFun oldFun = function;
1406:             try {
1407:             stmtVar = -1;
1408:             function = staticFunction;
1409:             parseStatement(staticCode);
1410:             } finally {
1411:             function = oldFun;
1412:             stmtVar = oldVar;
1413:             }
1414:             } */
1415:
1416:            private Expr parseExpression(int prevPrec, boolean isTop)
1417:                    throws ESException {
1418:                Expr result = parseExprRec(parseTerm(isTop), prevPrec, false,
1419:                        isTop);
1420:                result.getType();
1421:                return result;
1422:            }
1423:
1424:            private Expr parseBooleanExpression(int prevPrec)
1425:                    throws ESException {
1426:                Expr result = parseExprRec(parseTerm(false), prevPrec, true,
1427:                        false);
1428:                result.getType();
1429:                return result;
1430:            }
1431:
1432:            private Expr parseExpression(int prevPrec) throws ESException {
1433:                Expr result = parseExprRec(parseTerm(false), prevPrec, false,
1434:                        false);
1435:                result.getType();
1436:                return result;
1437:            }
1438:
1439:            private Expr parseExpression() throws ESException {
1440:                Expr result = parseExprRec(parseTerm(false), PREC_MAX, false,
1441:                        false);
1442:                result.getType();
1443:                return result;
1444:            }
1445:
1446:            /*
1447:             * parseExpression ()
1448:             *
1449:             * Grammar:
1450:             *   expr ::= obj (op obj)*
1451:             */
1452:            private Expr parseExprRec(Expr lexpr, int prevPrec, boolean isBool,
1453:                    boolean isTop) throws ESException {
1454:                Expr rexpr = null;
1455:                int op = 0;
1456:                int lex = 0;
1457:                int prec = 0;
1458:
1459:                while (true) {
1460:                    boolean doLookahead = false;
1461:                    boolean doPostfix = false;
1462:                    boolean isRightAssoc = false;
1463:                    int nextPrec = 0;
1464:                    int nextOp = 0;
1465:                    int nextLex = 0;
1466:
1467:                    switch (lexer.peek()) {
1468:                    case '=':
1469:                        if (op != 0 && lex != ',')
1470:                            throw error(L
1471:                                    .l("illegal left hand side of assignment"));
1472:                        if (isBool)
1473:                            throw error(L
1474:                                    .l("assignment used as boolean needs parentheses"));
1475:
1476:                    case Lexer.BIN_OP:
1477:                        // careful with and/or for unassigned local variables
1478:                        if (lexer.getOp() == Lexer.AND
1479:                                || lexer.getOp() == Lexer.OR)
1480:                            function.setVars();
1481:                        // fall through
1482:                    case ',':
1483:                    case Lexer.BANDU_OP:
1484:                    case '?':
1485:                        nextLex = lexer.peek();
1486:                        nextOp = lexer.getOp();
1487:                        nextPrec = lexer.getPrecedence();
1488:                        isRightAssoc = lexer.isRightAssoc();
1489:                        doLookahead = true;
1490:                        break;
1491:
1492:                    default:
1493:                        return op != 0 ? lexpr.binaryOp(lex, op, rexpr) : lexpr;
1494:                    }
1495:
1496:                    if (nextPrec >= prevPrec) {
1497:                        return op != 0 ? lexpr.binaryOp(lex, op, rexpr) : lexpr;
1498:                    } else if (prec == 0) {
1499:                    } else if (nextPrec < prec) {
1500:                        rexpr = parseExprRec(rexpr, prec, isBool, isTop);
1501:                        continue;
1502:                    } else {
1503:                        lexpr = op != 0 ? lexpr.binaryOp(lex, op, rexpr)
1504:                                : lexpr;
1505:                    }
1506:
1507:                    prec = nextPrec;
1508:                    lex = nextLex;
1509:                    op = nextOp;
1510:
1511:                    if (doLookahead)
1512:                        lexer.next();
1513:
1514:                    if (isRightAssoc) {
1515:                        /* XXX: is this the right thing to do? + 1 */
1516:                        rexpr = parseExpression(prec + 1, isTop);
1517:                    } else if (op == '?') {
1518:                        function.setVars();
1519:                        Expr mexpr = parseExpression(Parser.PREC_ASSIGN + 1);
1520:                        if (lexer.peek() != ':')
1521:                            throw expect("`:'");
1522:                        lexer.next();
1523:                        rexpr = parseExpression(Parser.PREC_ASSIGN + 1, isTop);
1524:
1525:                        lexpr = lexpr.conditional(mexpr, rexpr);
1526:                        op = 0;
1527:                    } else
1528:                        rexpr = parseTerm(isTop);
1529:                }
1530:            }
1531:
1532:            /*
1533:             * parseTerm
1534:             *
1535:             * term ::= BANDU_OP term
1536:             *      ::= UNARY_OP term
1537:             *      ::= IDENTIFIER termTail
1538:             *      ::= LITERAL termTail
1539:             *      ::= objLiteral termTail
1540:             *      ::= '(' expr ')' termTail
1541:             */
1542:            private Expr parseTerm(boolean isTop) throws ESException {
1543:                int op;
1544:
1545:                switch (lexer.peek()) {
1546:                case Lexer.BANDU_OP:
1547:                case Lexer.UNARY_OP:
1548:                    lexer.next();
1549:                    op = lexer.getOp();
1550:                    return parseTerm(isTop).unaryOp(op);
1551:
1552:                case Lexer.VOID:
1553:                    lexer.next();
1554:                    return parseTerm(isTop).doVoid();
1555:
1556:                case Lexer.TYPEOF:
1557:                    lexer.next();
1558:                    return parseTerm(isTop).typeof();
1559:
1560:                case Lexer.DELETE:
1561:                    lexer.next();
1562:                    return parseTerm(isTop).delete();
1563:
1564:                case Lexer.POSTFIX:
1565:                    lexer.next();
1566:                    op = lexer.getOp();
1567:                    return parseTerm(isTop).prefix(op);
1568:
1569:                case Lexer.LITERAL:
1570:                case Lexer.REGEXP:
1571:                case Lexer.IDENTIFIER:
1572:                case Lexer.THIS:
1573:                case Lexer.EVAL:
1574:                case Lexer.NEW:
1575:                case '(':
1576:                case '{':
1577:                case '[':
1578:                case Lexer.HASH_REF:
1579:                case Lexer.HASH_DEF:
1580:                case Lexer.FUNCTION:
1581:                    return parseLhs(false, isTop);
1582:
1583:                default:
1584:                    throw expect(L.l("expression"));
1585:                }
1586:            }
1587:
1588:            /**
1589:             * Parses the left-hand side of an expression
1590:             *
1591:             * @param hasNew true if this follows a new
1592:             * @return the new expression
1593:             */
1594:            private Expr parseLhs(boolean hasNew, boolean isTop)
1595:                    throws ESException {
1596:                String name;
1597:                int op;
1598:                Expr expr = null;
1599:
1600:                switch (lexer.next()) {
1601:                case Lexer.NEW:
1602:                    return parseTermTail(parseLhs(true, isTop), hasNew, isTop);
1603:
1604:                case Lexer.LITERAL:
1605:                    return parseTermTail(block.newLiteral(lexer.getLiteral()),
1606:                            hasNew, isTop);
1607:
1608:                case Lexer.REGEXP:
1609:                    /*
1610:                    return parseTermTail(block.newRegexp(lexer.getLiteral(),
1611:                                                        lexer.getFlags()),
1612:                    	   hasNew, isTop);
1613:                     */
1614:                    throw new UnsupportedOperationException();
1615:
1616:                case Lexer.IDENTIFIER:
1617:                    return parseTermTail(getVar(lexer.getId()), hasNew, isTop);
1618:
1619:                case Lexer.THIS:
1620:                    return parseTermTail(block.newThis(), hasNew, isTop);
1621:
1622:                case Lexer.EVAL:
1623:                    if (lexer.peek() != '(')
1624:                        throw expect("`('");
1625:                    function.setArguments();
1626:                    return parseTermTail(block.newVar(ESId.intern("eval")),
1627:                            hasNew, false);
1628:
1629:                case '(':
1630:                    expr = parseExpression(PREC_MAX);
1631:                    if (lexer.next() != ')')
1632:                        throw expect("`)'");
1633:                    return parseTermTail(expr, hasNew, isTop);
1634:
1635:                case '{':
1636:                    expr = parseObjectLiteral(-1);
1637:                    if (lexer.next() != '}')
1638:                        throw expect("`}'");
1639:                    return parseTermTail(expr, hasNew, isTop);
1640:
1641:                case '[':
1642:                    expr = parseArrayLiteral(-1);
1643:                    if (lexer.next() != ']')
1644:                        throw expect("`]'");
1645:                    return parseTermTail(expr, hasNew, isTop);
1646:
1647:                case Lexer.FUNCTION:
1648:                    Function newFun = parseFunction();
1649:
1650:                    //function.addFunction(newFun);
1651:                    function.addVariable(block, newFun.id, null);
1652:                    block.newVar(newFun.id).getVar().setType(Expr.TYPE_ES);
1653:                    expr = block.newVar(newFun.id);
1654:                    return parseTermTail(expr, hasNew, isTop);
1655:
1656:                case Lexer.HASH_DEF:
1657:                    switch (lexer.peek()) {
1658:                    case '{':
1659:                        lexer.next();
1660:                        expr = parseObjectLiteral(lexer.intValue);
1661:                        if (lexer.next() != '}')
1662:                            throw expect("`}'");
1663:                        return parseTermTail(expr, hasNew, isTop);
1664:
1665:                    case '[':
1666:                        lexer.next();
1667:                        expr = parseArrayLiteral(lexer.intValue);
1668:                        if (lexer.next() != ']')
1669:                            throw expect("`]'");
1670:                        return parseTermTail(expr, hasNew, isTop);
1671:
1672:                    default:
1673:                        /* XXX:
1674:                        expr = parseLhs(hasNew, isTop);
1675:                        int var = code.newVar();
1676:                        code.store(var);
1677:                        hashes.add(lexer.intValue, var);
1678:                        code.load(var);
1679:                         */
1680:                        return expr;
1681:                    }
1682:                    /*
1683:                    case Lexer.HASH_REF:
1684:                    if (hashes.size() <= lexer.intValue ||
1685:                    hashes.get(lexer.intValue) <= 0)
1686:                    throw error("bad sharp reference at " + getToken());
1687:
1688:                    return parseTermTail(code.load(hashes.get(lexer.intValue)), 
1689:                    	   hasNew, isTop);
1690:                     */
1691:                default:
1692:                    throw expect(L.l("term"));
1693:                }
1694:            }
1695:
1696:            /*
1697:             * parseTermTail
1698:             *
1699:             * termTail ::=
1700:             *          ::= '.' Id termTail
1701:             *          ::= '(' exprList ')' termTail
1702:             *          ::= '[' expr ']' termTail
1703:             *          ::= '++' termTail
1704:             */
1705:            private Expr parseTermTail(Expr term, boolean hasNew, boolean isTop)
1706:                    throws ESException {
1707:                int op;
1708:
1709:                while (true) {
1710:                    switch (lexer.peek()) {
1711:                    case '.':
1712:                        lexer.next();
1713:                        if (lexer.next() != Lexer.IDENTIFIER)
1714:                            throw expect(L.l("property name"));
1715:
1716:                        term = term.fieldReference(lexer.getId());
1717:                        break;
1718:
1719:                    case '(':
1720:                        if (isTop && lexer.seenLineFeed())
1721:                            return term;
1722:
1723:                        lexer.next();
1724:
1725:                        int n = 0;
1726:                        CallExpr call;
1727:                        if (hasNew)
1728:                            call = term.startNew();
1729:                        else
1730:                            call = term.startCall();
1731:
1732:                        while (lexer.peek() != ')') {
1733:                            if (n != 0 && lexer.peek() != ',')
1734:                                throw expect("`,'");
1735:                            else if (n != 0)
1736:                                lexer.next();
1737:
1738:                            call.addCallParam(parseExpression(PREC_COMMA));
1739:                            n++;
1740:                        }
1741:                        lexer.next();
1742:
1743:                        if (hasNew)
1744:                            return call;
1745:                        else
1746:                            term = call;
1747:                        break;
1748:
1749:                    case '[':
1750:                        if (isTop && lexer.seenLineFeed())
1751:                            return term;
1752:
1753:                        lexer.next();
1754:                        term = term.fieldReference(parseExpression(PREC_MAX));
1755:
1756:                        if (lexer.next() != ']')
1757:                            throw expect("`]'");
1758:                        break;
1759:
1760:                    case Lexer.POSTFIX:
1761:                        if (hasNew)
1762:                            return term.startNew();
1763:
1764:                        if (lexer.seenLineFeed())
1765:                            return term;
1766:
1767:                        term = term.postfix(lexer.getOp());
1768:
1769:                        lexer.next();
1770:                        break;
1771:
1772:                    case '@':
1773:                        lexer.next();
1774:
1775:                        term = term.cast(parseType());
1776:                        break;
1777:
1778:                    default:
1779:                        if (hasNew)
1780:                            return term.startNew();
1781:                        else
1782:                            return term;
1783:                    }
1784:                }
1785:            }
1786:
1787:            private Expr parseObjectLiteral(int hash) throws ESException {
1788:                Expr expr = block.newVar(ESId.intern("Object"));
1789:                CallExpr call = expr.startCall();
1790:
1791:                /*
1792:                if (hash >= 0) {
1793:                  if (hashes.size() <= hash)
1794:                hashes.setLength(hash + 1);
1795:                  hashes.add(hash, var);
1796:                }
1797:                 */
1798:
1799:                if (lexer.peek() == ',') {
1800:                    lexer.next();
1801:
1802:                    return call;
1803:                }
1804:
1805:                while (lexer.peek() == Lexer.LITERAL
1806:                        || lexer.peek() == Lexer.IDENTIFIER) {
1807:                    ESId id;
1808:
1809:                    if (lexer.next() == Lexer.LITERAL)
1810:                        id = ESId.intern(lexer.literal.toString());
1811:                    else
1812:                        id = lexer.getId();
1813:
1814:                    if (lexer.next() != ':')
1815:                        throw expect("`:'");
1816:
1817:                    call.addCallParam(block.newLiteral(id));
1818:                    call.addCallParam(parseExpression(PREC_COMMA));
1819:
1820:                    if (lexer.peek() != ',')
1821:                        break;
1822:                    lexer.next();
1823:                }
1824:
1825:                return call;
1826:            }
1827:
1828:            private Expr parseArrayLiteral(int hash) throws ESException {
1829:                Expr expr = block.newVar(ESId.intern("Array"));
1830:
1831:                CallExpr call = expr.startCall();
1832:
1833:                boolean isFirst = true;
1834:                while (lexer.peek() != ']') {
1835:                    if (lexer.peek() == ',') {
1836:                        lexer.next();
1837:                        call.addCallParam(block.newLiteral(ESBase.esUndefined));
1838:                        isFirst = false;
1839:                        continue;
1840:                    }
1841:
1842:                    Expr value = parseExpression(PREC_COMMA);
1843:
1844:                    if (isFirst && lexer.peek() == ']')
1845:                        return block.newArray(value);
1846:
1847:                    if (lexer.peek() != ',') {
1848:                        call.addCallParam(value);
1849:                        break;
1850:                    }
1851:
1852:                    lexer.next();
1853:
1854:                    if (isFirst && lexer.peek() == ']')
1855:                        return block.newArray(value);
1856:
1857:                    isFirst = false;
1858:                    call.addCallParam(value);
1859:                }
1860:
1861:                return call;
1862:            }
1863:
1864:            /**
1865:             * Gets a variable instance.
1866:             */
1867:            private Expr getVar(ESId name) throws ESException {
1868:                if (name == PACKAGES)
1869:                    return new PackageExpr(block);
1870:                else if (name == JAVA)
1871:                    return new PackageExpr(block).fieldReference(JAVA);
1872:                else if (name == CAUCHO)
1873:                    return new PackageExpr(block).fieldReference(COM)
1874:                            .fieldReference(CAUCHO);
1875:                else if (block.hasVar(name))
1876:                    return block.newVar(name);
1877:                else {
1878:                    for (int i = 0; i < importList.size(); i++) {
1879:                        String className = (String) importList.get(i);
1880:
1881:                        if (className.endsWith(".*"))
1882:                            className = className.substring(0, className
1883:                                    .length() - 1)
1884:                                    + name;
1885:
1886:                        try {
1887:                            Class cl = CauchoSystem.loadClass(className, false,
1888:                                    getClassLoader());
1889:
1890:                            return new JavaClassExpr(block, cl);
1891:                        } catch (Throwable e) {
1892:                        }
1893:                    }
1894:
1895:                    return block.newVar(name);
1896:                }
1897:            }
1898:
1899:            /**
1900:             * Returns the current filename being parsed.
1901:             */
1902:            public String getFilename() {
1903:                return lexer.getFilename();
1904:            }
1905:
1906:            /**
1907:             * Creates an error message with the given text.
1908:             */
1909:            ESException error(String text) {
1910:                return lexer.error(text);
1911:            }
1912:
1913:            /**
1914:             * Returns the current token for an error message.
1915:             */
1916:            private String getToken() {
1917:                if (lexer.isEof())
1918:                    return "end of file";
1919:                else
1920:                    return "`" + lexer.getToken() + "'";
1921:            }
1922:
1923:            /**
1924:             * Returns a parse exception when expecting a result.
1925:             */
1926:            private ESException expect(String expect) {
1927:                try {
1928:                    return lexer.error(L.l("expected {0} at {1}", expect,
1929:                            getToken()));
1930:                } catch (Exception e) {
1931:                    e.printStackTrace();
1932:                    return null;
1933:                }
1934:            }
1935:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.