aboutsummaryrefslogtreecommitdiffstats
path: root/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Parser.java.orig
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Parser.java.orig')
-rw-r--r--trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Parser.java.orig2159
1 files changed, 0 insertions, 2159 deletions
diff --git a/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Parser.java.orig b/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Parser.java.orig
deleted file mode 100644
index 628bb42..0000000
--- a/trunk/infrastructure/yuicompressor/src/yuicompressor/org/mozilla/javascript/Parser.java.orig
+++ /dev/null
@@ -1,2159 +0,0 @@
-/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Rhino code, released
- * May 6, 1999.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1997-1999
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Mike Ang
- * Igor Bukanov
- * Yuh-Ruey Chen
- * Ethan Hugg
- * Bob Jervis
- * Terry Lucas
- * Mike McCabe
- * Milen Nankov
- *
- * Alternatively, the contents of this file may be used under the terms of
- * the GNU General Public License Version 2 or later (the "GPL"), in which
- * case the provisions of the GPL are applicable instead of those above. If
- * you wish to allow use of your version of this file only under the terms of
- * the GPL and not to allow others to use your version of this file under the
- * MPL, indicate your decision by deleting the provisions above and replacing
- * them with the notice and other provisions required by the GPL. If you do
- * not delete the provisions above, a recipient may use your version of this
- * file under either the MPL or the GPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-package org.mozilla.javascript;
-
-import java.io.Reader;
-import java.io.IOException;
-import java.util.Hashtable;
-
-/**
- * This class implements the JavaScript parser.
- *
- * It is based on the C source files jsparse.c and jsparse.h
- * in the jsref package.
- *
- * @see TokenStream
- *
- * @author Mike McCabe
- * @author Brendan Eich
- */
-
-public class Parser
-{
- // TokenInformation flags : currentFlaggedToken stores them together
- // with token type
- final static int
- CLEAR_TI_MASK = 0xFFFF, // mask to clear token information bits
- TI_AFTER_EOL = 1 << 16, // first token of the source line
- TI_CHECK_LABEL = 1 << 17; // indicates to check for label
-
- CompilerEnvirons compilerEnv;
- private ErrorReporter errorReporter;
- private String sourceURI;
- boolean calledByCompileFunction;
-
- private TokenStream ts;
- private int currentFlaggedToken;
- private int syntaxErrorCount;
-
- private IRFactory nf;
-
- private int nestingOfFunction;
-
- private Decompiler decompiler;
- private String encodedSource;
-
-// The following are per function variables and should be saved/restored
-// during function parsing.
-// XXX Move to separated class?
- ScriptOrFnNode currentScriptOrFn;
- private int nestingOfWith;
- private Hashtable labelSet; // map of label names into nodes
- private ObjArray loopSet;
- private ObjArray loopAndSwitchSet;
- private boolean hasReturnValue;
- private int functionEndFlags;
-// end of per function variables
-
- // Exception to unwind
- private static class ParserException extends RuntimeException
- {
- static final long serialVersionUID = 5882582646773765630L;
- }
-
- public Parser(CompilerEnvirons compilerEnv, ErrorReporter errorReporter)
- {
- this.compilerEnv = compilerEnv;
- this.errorReporter = errorReporter;
- }
-
- protected Decompiler createDecompiler(CompilerEnvirons compilerEnv)
- {
- return new Decompiler();
- }
-
- void addStrictWarning(String messageId, String messageArg)
- {
- if (compilerEnv.isStrictMode())
- addWarning(messageId, messageArg);
- }
-
- void addWarning(String messageId, String messageArg)
- {
- String message = ScriptRuntime.getMessage1(messageId, messageArg);
- if (compilerEnv.reportWarningAsError()) {
- ++syntaxErrorCount;
- errorReporter.error(message, sourceURI, ts.getLineno(),
- ts.getLine(), ts.getOffset());
- } else
- errorReporter.warning(message, sourceURI, ts.getLineno(),
- ts.getLine(), ts.getOffset());
- }
-
- void addError(String messageId)
- {
- ++syntaxErrorCount;
- String message = ScriptRuntime.getMessage0(messageId);
- errorReporter.error(message, sourceURI, ts.getLineno(),
- ts.getLine(), ts.getOffset());
- }
-
- void addError(String messageId, String messageArg)
- {
- ++syntaxErrorCount;
- String message = ScriptRuntime.getMessage1(messageId, messageArg);
- errorReporter.error(message, sourceURI, ts.getLineno(),
- ts.getLine(), ts.getOffset());
- }
-
- RuntimeException reportError(String messageId)
- {
- addError(messageId);
-
- // Throw a ParserException exception to unwind the recursive descent
- // parse.
- throw new ParserException();
- }
-
- private int peekToken()
- throws IOException
- {
- int tt = currentFlaggedToken;
- if (tt == Token.EOF) {
- tt = ts.getToken();
- if (tt == Token.EOL) {
- do {
- tt = ts.getToken();
- } while (tt == Token.EOL);
- tt |= TI_AFTER_EOL;
- }
- currentFlaggedToken = tt;
- }
- return tt & CLEAR_TI_MASK;
- }
-
- private int peekFlaggedToken()
- throws IOException
- {
- peekToken();
- return currentFlaggedToken;
- }
-
- private void consumeToken()
- {
- currentFlaggedToken = Token.EOF;
- }
-
- private int nextToken()
- throws IOException
- {
- int tt = peekToken();
- consumeToken();
- return tt;
- }
-
- private int nextFlaggedToken()
- throws IOException
- {
- peekToken();
- int ttFlagged = currentFlaggedToken;
- consumeToken();
- return ttFlagged;
- }
-
- private boolean matchToken(int toMatch)
- throws IOException
- {
- int tt = peekToken();
- if (tt != toMatch) {
- return false;
- }
- consumeToken();
- return true;
- }
-
- private int peekTokenOrEOL()
- throws IOException
- {
- int tt = peekToken();
- // Check for last peeked token flags
- if ((currentFlaggedToken & TI_AFTER_EOL) != 0) {
- tt = Token.EOL;
- }
- return tt;
- }
-
- private void setCheckForLabel()
- {
- if ((currentFlaggedToken & CLEAR_TI_MASK) != Token.NAME)
- throw Kit.codeBug();
- currentFlaggedToken |= TI_CHECK_LABEL;
- }
-
- private void mustMatchToken(int toMatch, String messageId)
- throws IOException, ParserException
- {
- if (!matchToken(toMatch)) {
- reportError(messageId);
- }
- }
-
- private void mustHaveXML()
- {
- if (!compilerEnv.isXmlAvailable()) {
- reportError("msg.XML.not.available");
- }
- }
-
- public String getEncodedSource()
- {
- return encodedSource;
- }
-
- public boolean eof()
- {
- return ts.eof();
- }
-
- boolean insideFunction()
- {
- return nestingOfFunction != 0;
- }
-
- private Node enterLoop(Node loopLabel)
- {
- Node loop = nf.createLoopNode(loopLabel, ts.getLineno());
- if (loopSet == null) {
- loopSet = new ObjArray();
- if (loopAndSwitchSet == null) {
- loopAndSwitchSet = new ObjArray();
- }
- }
- loopSet.push(loop);
- loopAndSwitchSet.push(loop);
- return loop;
- }
-
- private void exitLoop()
- {
- loopSet.pop();
- loopAndSwitchSet.pop();
- }
-
- private Node enterSwitch(Node switchSelector, int lineno)
- {
- Node switchNode = nf.createSwitch(switchSelector, lineno);
- if (loopAndSwitchSet == null) {
- loopAndSwitchSet = new ObjArray();
- }
- loopAndSwitchSet.push(switchNode);
- return switchNode;
- }
-
- private void exitSwitch()
- {
- loopAndSwitchSet.pop();
- }
-
- /*
- * Build a parse tree from the given sourceString.
- *
- * @return an Object representing the parsed
- * program. If the parse fails, null will be returned. (The
- * parse failure will result in a call to the ErrorReporter from
- * CompilerEnvirons.)
- */
- public ScriptOrFnNode parse(String sourceString,
- String sourceURI, int lineno)
- {
- this.sourceURI = sourceURI;
- this.ts = new TokenStream(this, null, sourceString, lineno);
- try {
- return parse();
- } catch (IOException ex) {
- // Should never happen
- throw new IllegalStateException();
- }
- }
-
- /*
- * Build a parse tree from the given sourceString.
- *
- * @return an Object representing the parsed
- * program. If the parse fails, null will be returned. (The
- * parse failure will result in a call to the ErrorReporter from
- * CompilerEnvirons.)
- */
- public ScriptOrFnNode parse(Reader sourceReader,
- String sourceURI, int lineno)
- throws IOException
- {
- this.sourceURI = sourceURI;
- this.ts = new TokenStream(this, sourceReader, null, lineno);
- return parse();
- }
-
- private ScriptOrFnNode parse()
- throws IOException
- {
- this.decompiler = createDecompiler(compilerEnv);
- this.nf = new IRFactory(this);
- currentScriptOrFn = nf.createScript();
- int sourceStartOffset = decompiler.getCurrentOffset();
- this.encodedSource = null;
- decompiler.addToken(Token.SCRIPT);
-
- this.currentFlaggedToken = Token.EOF;
- this.syntaxErrorCount = 0;
-
- int baseLineno = ts.getLineno(); // line number where source starts
-
- /* so we have something to add nodes to until
- * we've collected all the source */
- Node pn = nf.createLeaf(Token.BLOCK);
-
- try {
- for (;;) {
- int tt = peekToken();
-
- if (tt <= Token.EOF) {
- break;
- }
-
- Node n;
- if (tt == Token.FUNCTION) {
- consumeToken();
- try {
- n = function(calledByCompileFunction
- ? FunctionNode.FUNCTION_EXPRESSION
- : FunctionNode.FUNCTION_STATEMENT);
- } catch (ParserException e) {
- break;
- }
- } else {
- n = statement();
- }
- nf.addChildToBack(pn, n);
- }
- } catch (StackOverflowError ex) {
- String msg = ScriptRuntime.getMessage0(
- "msg.too.deep.parser.recursion");
- throw Context.reportRuntimeError(msg, sourceURI,
- ts.getLineno(), null, 0);
- }
-
- if (this.syntaxErrorCount != 0) {
- String msg = String.valueOf(this.syntaxErrorCount);
- msg = ScriptRuntime.getMessage1("msg.got.syntax.errors", msg);
- throw errorReporter.runtimeError(msg, sourceURI, baseLineno,
- null, 0);
- }
-
- currentScriptOrFn.setSourceName(sourceURI);
- currentScriptOrFn.setBaseLineno(baseLineno);
- currentScriptOrFn.setEndLineno(ts.getLineno());
-
- int sourceEndOffset = decompiler.getCurrentOffset();
- currentScriptOrFn.setEncodedSourceBounds(sourceStartOffset,
- sourceEndOffset);
-
- nf.initScript(currentScriptOrFn, pn);
-
- if (compilerEnv.isGeneratingSource()) {
- encodedSource = decompiler.getEncodedSource();
- }
- this.decompiler = null; // It helps GC
-
- return currentScriptOrFn;
- }
-
- /*
- * The C version of this function takes an argument list,
- * which doesn't seem to be needed for tree generation...
- * it'd only be useful for checking argument hiding, which
- * I'm not doing anyway...
- */
- private Node parseFunctionBody()
- throws IOException
- {
- ++nestingOfFunction;
- Node pn = nf.createBlock(ts.getLineno());
- try {
- bodyLoop: for (;;) {
- Node n;
- int tt = peekToken();
- switch (tt) {
- case Token.ERROR:
- case Token.EOF:
- case Token.RC:
- break bodyLoop;
-
- case Token.FUNCTION:
- consumeToken();
- n = function(FunctionNode.FUNCTION_STATEMENT);
- break;
- default:
- n = statement();
- break;
- }
- nf.addChildToBack(pn, n);
- }
- } catch (ParserException e) {
- // Ignore it
- } finally {
- --nestingOfFunction;
- }
-
- return pn;
- }
-
- private Node function(int functionType)
- throws IOException, ParserException
- {
- int syntheticType = functionType;
- int baseLineno = ts.getLineno(); // line number where source starts
-
- int functionSourceStart = decompiler.markFunctionStart(functionType);
- String name;
- Node memberExprNode = null;
- if (matchToken(Token.NAME)) {
- name = ts.getString();
- decompiler.addName(name);
- if (!matchToken(Token.LP)) {
- if (compilerEnv.isAllowMemberExprAsFunctionName()) {
- // Extension to ECMA: if 'function <name>' does not follow
- // by '(', assume <name> starts memberExpr
- Node memberExprHead = nf.createName(name);
- name = "";
- memberExprNode = memberExprTail(false, memberExprHead);
- }
- mustMatchToken(Token.LP, "msg.no.paren.parms");
- }
- } else if (matchToken(Token.LP)) {
- // Anonymous function
- name = "";
- } else {
- name = "";
- if (compilerEnv.isAllowMemberExprAsFunctionName()) {
- // Note that memberExpr can not start with '(' like
- // in function (1+2).toString(), because 'function (' already
- // processed as anonymous function
- memberExprNode = memberExpr(false);
- }
- mustMatchToken(Token.LP, "msg.no.paren.parms");
- }
-
- if (memberExprNode != null) {
- syntheticType = FunctionNode.FUNCTION_EXPRESSION;
- }
-
- boolean nested = insideFunction();
-
- FunctionNode fnNode = nf.createFunction(name);
- if (nested || nestingOfWith > 0) {
- // 1. Nested functions are not affected by the dynamic scope flag
- // as dynamic scope is already a parent of their scope.
- // 2. Functions defined under the with statement also immune to
- // this setup, in which case dynamic scope is ignored in favor
- // of with object.
- fnNode.itsIgnoreDynamicScope = true;
- }
-
- int functionIndex = currentScriptOrFn.addFunction(fnNode);
-
- int functionSourceEnd;
-
- ScriptOrFnNode savedScriptOrFn = currentScriptOrFn;
- currentScriptOrFn = fnNode;
- int savedNestingOfWith = nestingOfWith;
- nestingOfWith = 0;
- Hashtable savedLabelSet = labelSet;
- labelSet = null;
- ObjArray savedLoopSet = loopSet;
- loopSet = null;
- ObjArray savedLoopAndSwitchSet = loopAndSwitchSet;
- loopAndSwitchSet = null;
- boolean savedHasReturnValue = hasReturnValue;
- int savedFunctionEndFlags = functionEndFlags;
-
- Node body;
- try {
- decompiler.addToken(Token.LP);
- if (!matchToken(Token.RP)) {
- boolean first = true;
- do {
- if (!first)
- decompiler.addToken(Token.COMMA);
- first = false;
- mustMatchToken(Token.NAME, "msg.no.parm");
- String s = ts.getString();
- if (fnNode.hasParamOrVar(s)) {
- addWarning("msg.dup.parms", s);
- }
- fnNode.addParam(s);
- decompiler.addName(s);
- } while (matchToken(Token.COMMA));
-
- mustMatchToken(Token.RP, "msg.no.paren.after.parms");
- }
- decompiler.addToken(Token.RP);
-
- mustMatchToken(Token.LC, "msg.no.brace.body");
- decompiler.addEOL(Token.LC);
- body = parseFunctionBody();
- mustMatchToken(Token.RC, "msg.no.brace.after.body");
-
- if (compilerEnv.isStrictMode() && !body.hasConsistentReturnUsage())
- {
- String msg = name.length() > 0 ? "msg.no.return.value"
- : "msg.anon.no.return.value";
- addStrictWarning(msg, name);
- }
-
- decompiler.addToken(Token.RC);
- functionSourceEnd = decompiler.markFunctionEnd(functionSourceStart);
- if (functionType != FunctionNode.FUNCTION_EXPRESSION) {
- // Add EOL only if function is not part of expression
- // since it gets SEMI + EOL from Statement in that case
- decompiler.addToken(Token.EOL);
- }
- }
- finally {
- hasReturnValue = savedHasReturnValue;
- functionEndFlags = savedFunctionEndFlags;
- loopAndSwitchSet = savedLoopAndSwitchSet;
- loopSet = savedLoopSet;
- labelSet = savedLabelSet;
- nestingOfWith = savedNestingOfWith;
- currentScriptOrFn = savedScriptOrFn;
- }
-
- fnNode.setEncodedSourceBounds(functionSourceStart, functionSourceEnd);
- fnNode.setSourceName(sourceURI);
- fnNode.setBaseLineno(baseLineno);
- fnNode.setEndLineno(ts.getLineno());
-
- if (name != null) {
- int index = currentScriptOrFn.getParamOrVarIndex(name);
- if (index >= 0 && index < currentScriptOrFn.getParamCount())
- addStrictWarning("msg.var.hides.arg", name);
- }
-
- Node pn = nf.initFunction(fnNode, functionIndex, body, syntheticType);
- if (memberExprNode != null) {
- pn = nf.createAssignment(Token.ASSIGN, memberExprNode, pn);
- if (functionType != FunctionNode.FUNCTION_EXPRESSION) {
- // XXX check JScript behavior: should it be createExprStatement?
- pn = nf.createExprStatementNoReturn(pn, baseLineno);
- }
- }
- return pn;
- }
-
- private Node statements()
- throws IOException
- {
- Node pn = nf.createBlock(ts.getLineno());
-
- int tt;
- while((tt = peekToken()) > Token.EOF && tt != Token.RC) {
- nf.addChildToBack(pn, statement());
- }
-
- return pn;
- }
-
- private Node condition()
- throws IOException, ParserException
- {
- mustMatchToken(Token.LP, "msg.no.paren.cond");
- decompiler.addToken(Token.LP);
- Node pn = expr(false);
- mustMatchToken(Token.RP, "msg.no.paren.after.cond");
- decompiler.addToken(Token.RP);
-
- // Report strict warning on code like "if (a = 7) ...". Suppress the
- // warning if the condition is parenthesized, like "if ((a = 7)) ...".
- if (pn.getProp(Node.PARENTHESIZED_PROP) == null &&
- (pn.getType() == Token.SETNAME || pn.getType() == Token.SETPROP ||
- pn.getType() == Token.SETELEM))
- {
- addStrictWarning("msg.equal.as.assign", "");
- }
- return pn;
- }
-
- // match a NAME; return null if no match.
- private Node matchJumpLabelName()
- throws IOException, ParserException
- {
- Node label = null;
-
- int tt = peekTokenOrEOL();
- if (tt == Token.NAME) {
- consumeToken();
- String name = ts.getString();
- decompiler.addName(name);
- if (labelSet != null) {
- label = (Node)labelSet.get(name);
- }
- if (label == null) {
- reportError("msg.undef.label");
- }
- }
-
- return label;
- }
-
- private Node statement()
- throws IOException
- {
- try {
- Node pn = statementHelper(null);
- if (pn != null) {
- if (compilerEnv.isStrictMode() && !pn.hasSideEffects())
- addStrictWarning("msg.no.side.effects", "");
- return pn;
- }
- } catch (ParserException e) { }
-
- // skip to end of statement
- int lineno = ts.getLineno();
- guessingStatementEnd: for (;;) {
- int tt = peekTokenOrEOL();
- consumeToken();
- switch (tt) {
- case Token.ERROR:
- case Token.EOF:
- case Token.EOL:
- case Token.SEMI:
- break guessingStatementEnd;
- }
- }
- return nf.createExprStatement(nf.createName("error"), lineno);
- }
-
- /**
- * Whether the "catch (e: e instanceof Exception) { ... }" syntax
- * is implemented.
- */
-
- private Node statementHelper(Node statementLabel)
- throws IOException, ParserException
- {
- Node pn = null;
-
- int tt;
-
- tt = peekToken();
-
- switch(tt) {
- case Token.IF: {
- consumeToken();
-
- decompiler.addToken(Token.IF);
- int lineno = ts.getLineno();
- Node cond = condition();
- decompiler.addEOL(Token.LC);
- Node ifTrue = statement();
- Node ifFalse = null;
- if (matchToken(Token.ELSE)) {
- decompiler.addToken(Token.RC);
- decompiler.addToken(Token.ELSE);
- decompiler.addEOL(Token.LC);
- ifFalse = statement();
- }
- decompiler.addEOL(Token.RC);
- pn = nf.createIf(cond, ifTrue, ifFalse, lineno);
- return pn;
- }
-
- case Token.SWITCH: {
- consumeToken();
-
- decompiler.addToken(Token.SWITCH);
- int lineno = ts.getLineno();
- mustMatchToken(Token.LP, "msg.no.paren.switch");
- decompiler.addToken(Token.LP);
- pn = enterSwitch(expr(false), lineno);
- try {
- mustMatchToken(Token.RP, "msg.no.paren.after.switch");
- decompiler.addToken(Token.RP);
- mustMatchToken(Token.LC, "msg.no.brace.switch");
- decompiler.addEOL(Token.LC);
-
- boolean hasDefault = false;
- switchLoop: for (;;) {
- tt = nextToken();
- Node caseExpression;
- switch (tt) {
- case Token.RC:
- break switchLoop;
-
- case Token.CASE:
- decompiler.addToken(Token.CASE);
- caseExpression = expr(false);
- mustMatchToken(Token.COLON, "msg.no.colon.case");
- decompiler.addEOL(Token.COLON);
- break;
-
- case Token.DEFAULT:
- if (hasDefault) {
- reportError("msg.double.switch.default");
- }
- decompiler.addToken(Token.DEFAULT);
- hasDefault = true;
- caseExpression = null;
- mustMatchToken(Token.COLON, "msg.no.colon.case");
- decompiler.addEOL(Token.COLON);
- break;
-
- default:
- reportError("msg.bad.switch");
- break switchLoop;
- }
-
- Node block = nf.createLeaf(Token.BLOCK);
- while ((tt = peekToken()) != Token.RC
- && tt != Token.CASE
- && tt != Token.DEFAULT
- && tt != Token.EOF)
- {
- nf.addChildToBack(block, statement());
- }
-
- // caseExpression == null => add default lable
- nf.addSwitchCase(pn, caseExpression, block);
- }
- decompiler.addEOL(Token.RC);
- nf.closeSwitch(pn);
- } finally {
- exitSwitch();
- }
- return pn;
- }
-
- case Token.WHILE: {
- consumeToken();
- decompiler.addToken(Token.WHILE);
-
- Node loop = enterLoop(statementLabel);
- try {
- Node cond = condition();
- decompiler.addEOL(Token.LC);
- Node body = statement();
- decompiler.addEOL(Token.RC);
- pn = nf.createWhile(loop, cond, body);
- } finally {
- exitLoop();
- }
- return pn;
- }
-
- case Token.DO: {
- consumeToken();
- decompiler.addToken(Token.DO);
- decompiler.addEOL(Token.LC);
-
- Node loop = enterLoop(statementLabel);
- try {
- Node body = statement();
- decompiler.addToken(Token.RC);
- mustMatchToken(Token.WHILE, "msg.no.while.do");
- decompiler.addToken(Token.WHILE);
- Node cond = condition();
- pn = nf.createDoWhile(loop, body, cond);
- } finally {
- exitLoop();
- }
- // Always auto-insert semicon to follow SpiderMonkey:
- // It is required by EMAScript but is ignored by the rest of
- // world, see bug 238945
- matchToken(Token.SEMI);
- decompiler.addEOL(Token.SEMI);
- return pn;
- }
-
- case Token.FOR: {
- consumeToken();
- boolean isForEach = false;
- decompiler.addToken(Token.FOR);
-
- Node loop = enterLoop(statementLabel);
- try {
-
- Node init; // Node init is also foo in 'foo in Object'
- Node cond; // Node cond is also object in 'foo in Object'
- Node incr = null; // to kill warning
- Node body;
-
- // See if this is a for each () instead of just a for ()
- if (matchToken(Token.NAME)) {
- decompiler.addName(ts.getString());
- if (ts.getString().equals("each")) {
- isForEach = true;
- } else {
- reportError("msg.no.paren.for");
- }
- }
-
- mustMatchToken(Token.LP, "msg.no.paren.for");
- decompiler.addToken(Token.LP);
- tt = peekToken();
- if (tt == Token.SEMI) {
- init = nf.createLeaf(Token.EMPTY);
- } else {
- if (tt == Token.VAR) {
- // set init to a var list or initial
- consumeToken(); // consume the 'var' token
- init = variables(Token.FOR);
- }
- else {
- init = expr(true);
- }
- }
-
- if (matchToken(Token.IN)) {
- decompiler.addToken(Token.IN);
- // 'cond' is the object over which we're iterating
- cond = expr(false);
- } else { // ordinary for loop
- mustMatchToken(Token.SEMI, "msg.no.semi.for");
- decompiler.addToken(Token.SEMI);
- if (peekToken() == Token.SEMI) {
- // no loop condition
- cond = nf.createLeaf(Token.EMPTY);
- } else {
- cond = expr(false);
- }
-
- mustMatchToken(Token.SEMI, "msg.no.semi.for.cond");
- decompiler.addToken(Token.SEMI);
- if (peekToken() == Token.RP) {
- incr = nf.createLeaf(Token.EMPTY);
- } else {
- incr = expr(false);
- }
- }
-
- mustMatchToken(Token.RP, "msg.no.paren.for.ctrl");
- decompiler.addToken(Token.RP);
- decompiler.addEOL(Token.LC);
- body = statement();
- decompiler.addEOL(Token.RC);
-
- if (incr == null) {
- // cond could be null if 'in obj' got eaten
- // by the init node.
- pn = nf.createForIn(loop, init, cond, body, isForEach);
- } else {
- pn = nf.createFor(loop, init, cond, incr, body);
- }
- } finally {
- exitLoop();
- }
- return pn;
- }
-
- case Token.TRY: {
- consumeToken();
- int lineno = ts.getLineno();
-
- Node tryblock;
- Node catchblocks = null;
- Node finallyblock = null;
-
- decompiler.addToken(Token.TRY);
- decompiler.addEOL(Token.LC);
- tryblock = statement();
- decompiler.addEOL(Token.RC);
-
- catchblocks = nf.createLeaf(Token.BLOCK);
-
- boolean sawDefaultCatch = false;
- int peek = peekToken();
- if (peek == Token.CATCH) {
- while (matchToken(Token.CATCH)) {
- if (sawDefaultCatch) {
- reportError("msg.catch.unreachable");
- }
- decompiler.addToken(Token.CATCH);
- mustMatchToken(Token.LP, "msg.no.paren.catch");
- decompiler.addToken(Token.LP);
-
- mustMatchToken(Token.NAME, "msg.bad.catchcond");
- String varName = ts.getString();
- decompiler.addName(varName);
-
- Node catchCond = null;
- if (matchToken(Token.IF)) {
- decompiler.addToken(Token.IF);
- catchCond = expr(false);
- } else {
- sawDefaultCatch = true;
- }
-
- mustMatchToken(Token.RP, "msg.bad.catchcond");
- decompiler.addToken(Token.RP);
- mustMatchToken(Token.LC, "msg.no.brace.catchblock");
- decompiler.addEOL(Token.LC);
-
- nf.addChildToBack(catchblocks,
- nf.createCatch(varName, catchCond,
- statements(),
- ts.getLineno()));
-
- mustMatchToken(Token.RC, "msg.no.brace.after.body");
- decompiler.addEOL(Token.RC);
- }
- } else if (peek != Token.FINALLY) {
- mustMatchToken(Token.FINALLY, "msg.try.no.catchfinally");
- }
-
- if (matchToken(Token.FINALLY)) {
- decompiler.addToken(Token.FINALLY);
- decompiler.addEOL(Token.LC);
- finallyblock = statement();
- decompiler.addEOL(Token.RC);
- }
-
- pn = nf.createTryCatchFinally(tryblock, catchblocks,
- finallyblock, lineno);
-
- return pn;
- }
-
- case Token.THROW: {
- consumeToken();
- if (peekTokenOrEOL() == Token.EOL) {
- // ECMAScript does not allow new lines before throw expression,
- // see bug 256617
- reportError("msg.bad.throw.eol");
- }
-
- int lineno = ts.getLineno();
- decompiler.addToken(Token.THROW);
- pn = nf.createThrow(expr(false), lineno);
- break;
- }
-
- case Token.BREAK: {
- consumeToken();
- int lineno = ts.getLineno();
-
- decompiler.addToken(Token.BREAK);
-
- // matchJumpLabelName only matches if there is one
- Node breakStatement = matchJumpLabelName();
- if (breakStatement == null) {
- if (loopAndSwitchSet == null || loopAndSwitchSet.size() == 0) {
- reportError("msg.bad.break");
- return null;
- }
- breakStatement = (Node)loopAndSwitchSet.peek();
- }
- pn = nf.createBreak(breakStatement, lineno);
- break;
- }
-
- case Token.CONTINUE: {
- consumeToken();
- int lineno = ts.getLineno();
-
- decompiler.addToken(Token.CONTINUE);
-
- Node loop;
- // matchJumpLabelName only matches if there is one
- Node label = matchJumpLabelName();
- if (label == null) {
- if (loopSet == null || loopSet.size() == 0) {
- reportError("msg.continue.outside");
- return null;
- }
- loop = (Node)loopSet.peek();
- } else {
- loop = nf.getLabelLoop(label);
- if (loop == null) {
- reportError("msg.continue.nonloop");
- return null;
- }
- }
- pn = nf.createContinue(loop, lineno);
- break;
- }
-
- case Token.WITH: {
- consumeToken();
-
- decompiler.addToken(Token.WITH);
- int lineno = ts.getLineno();
- mustMatchToken(Token.LP, "msg.no.paren.with");
- decompiler.addToken(Token.LP);
- Node obj = expr(false);
- mustMatchToken(Token.RP, "msg.no.paren.after.with");
- decompiler.addToken(Token.RP);
- decompiler.addEOL(Token.LC);
-
- ++nestingOfWith;
- Node body;
- try {
- body = statement();
- } finally {
- --nestingOfWith;
- }
-
- decompiler.addEOL(Token.RC);
-
- pn = nf.createWith(obj, body, lineno);
- return pn;
- }
-
- case Token.CONST:
- case Token.VAR: {
- consumeToken();
- pn = variables(tt);
- break;
- }
-
- case Token.RETURN: {
- if (!insideFunction()) {
- reportError("msg.bad.return");
- }
- consumeToken();
- decompiler.addToken(Token.RETURN);
- int lineno = ts.getLineno();
-
- Node retExpr;
- /* This is ugly, but we don't want to require a semicolon. */
- tt = peekTokenOrEOL();
- switch (tt) {
- case Token.SEMI:
- case Token.RC:
- case Token.EOF:
- case Token.EOL:
- case Token.ERROR:
- retExpr = null;
- break;
- default:
- retExpr = expr(false);
- hasReturnValue = true;
- }
- pn = nf.createReturn(retExpr, lineno);
-
- // see if we need a strict mode warning
- if (retExpr == null) {
- if (functionEndFlags == Node.END_RETURNS_VALUE)
- addStrictWarning("msg.return.inconsistent", "");
-
- functionEndFlags |= Node.END_RETURNS;
- } else {
- if (functionEndFlags == Node.END_RETURNS)
- addStrictWarning("msg.return.inconsistent", "");
-
- functionEndFlags |= Node.END_RETURNS_VALUE;
- }
-
- break;
- }
-
- case Token.LC:
- consumeToken();
- if (statementLabel != null) {
- decompiler.addToken(Token.LC);
- }
- pn = statements();
- mustMatchToken(Token.RC, "msg.no.brace.block");
- if (statementLabel != null) {
- decompiler.addEOL(Token.RC);
- }
- return pn;
-
- case Token.ERROR:
- // Fall thru, to have a node for error recovery to work on
- case Token.SEMI:
- consumeToken();
- pn = nf.createLeaf(Token.EMPTY);
- return pn;
-
- case Token.FUNCTION: {
- consumeToken();
- pn = function(FunctionNode.FUNCTION_EXPRESSION_STATEMENT);
- return pn;
- }
-
- case Token.DEFAULT :
- consumeToken();
- mustHaveXML();
-
- decompiler.addToken(Token.DEFAULT);
- int nsLine = ts.getLineno();
-
- if (!(matchToken(Token.NAME)
- && ts.getString().equals("xml")))
- {
- reportError("msg.bad.namespace");
- }
- decompiler.addName(" xml");
-
- if (!(matchToken(Token.NAME)
- && ts.getString().equals("namespace")))
- {
- reportError("msg.bad.namespace");
- }
- decompiler.addName(" namespace");
-
- if (!matchToken(Token.ASSIGN)) {
- reportError("msg.bad.namespace");
- }
- decompiler.addToken(Token.ASSIGN);
-
- Node expr = expr(false);
- pn = nf.createDefaultNamespace(expr, nsLine);
- break;
-
- case Token.NAME: {
- int lineno = ts.getLineno();
- String name = ts.getString();
- setCheckForLabel();
- pn = expr(false);
- if (pn.getType() != Token.LABEL) {
- pn = nf.createExprStatement(pn, lineno);
- } else {
- // Parsed the label: push back token should be
- // colon that primaryExpr left untouched.
- if (peekToken() != Token.COLON) Kit.codeBug();
- consumeToken();
- // depend on decompiling lookahead to guess that that
- // last name was a label.
- decompiler.addName(name);
- decompiler.addEOL(Token.COLON);
-
- if (labelSet == null) {
- labelSet = new Hashtable();
- } else if (labelSet.containsKey(name)) {
- reportError("msg.dup.label");
- }
-
- boolean firstLabel;
- if (statementLabel == null) {
- firstLabel = true;
- statementLabel = pn;
- } else {
- // Discard multiple label nodes and use only
- // the first: it allows to simplify IRFactory
- firstLabel = false;
- }
- labelSet.put(name, statementLabel);
- try {
- pn = statementHelper(statementLabel);
- } finally {
- labelSet.remove(name);
- }
- if (firstLabel) {
- pn = nf.createLabeledStatement(statementLabel, pn);
- }
- return pn;
- }
- break;
- }
-
- default: {
- int lineno = ts.getLineno();
- pn = expr(false);
- pn = nf.createExprStatement(pn, lineno);
- break;
- }
- }
-
- int ttFlagged = peekFlaggedToken();
- switch (ttFlagged & CLEAR_TI_MASK) {
- case Token.SEMI:
- // Consume ';' as a part of expression
- consumeToken();
- break;
- case Token.ERROR:
- case Token.EOF:
- case Token.RC:
- // Autoinsert ;
- break;
- default:
- if ((ttFlagged & TI_AFTER_EOL) == 0) {
- // Report error if no EOL or autoinsert ; otherwise
- reportError("msg.no.semi.stmt");
- }
- break;
- }
- decompiler.addEOL(Token.SEMI);
-
- return pn;
- }
-
- /**
- * Parse a 'var' or 'const' statement, or a 'var' init list in a for
- * statement.
- * @param context A token value: either VAR, CONST or FOR depending on
- * context.
- * @return The parsed statement
- * @throws IOException
- * @throws ParserException
- */
- private Node variables(int context)
- throws IOException, ParserException
- {
- Node pn;
- boolean first = true;
-
- if (context == Token.CONST){
- pn = nf.createVariables(Token.CONST, ts.getLineno());
- decompiler.addToken(Token.CONST);
- } else {
- pn = nf.createVariables(Token.VAR, ts.getLineno());
- decompiler.addToken(Token.VAR);
- }
-
- for (;;) {
- Node name;
- Node init;
- mustMatchToken(Token.NAME, "msg.bad.var");
- String s = ts.getString();
-
- if (!first)
- decompiler.addToken(Token.COMMA);
- first = false;
-
- decompiler.addName(s);
-
- if (context == Token.CONST) {
- if (!currentScriptOrFn.addConst(s)) {
- // We know it's already defined, since addConst passes if
- // it's not defined at all. The addVar call just confirms
- // what it is.
- if (currentScriptOrFn.addVar(s) != ScriptOrFnNode.DUPLICATE_CONST)
- addError("msg.var.redecl", s);
- else
- addError("msg.const.redecl", s);
- }
- } else {
- int dupState = currentScriptOrFn.addVar(s);
- if (dupState == ScriptOrFnNode.DUPLICATE_CONST)
- addError("msg.const.redecl", s);
- else if (dupState == ScriptOrFnNode.DUPLICATE_PARAMETER)
- addStrictWarning("msg.var.hides.arg", s);
- else if (dupState == ScriptOrFnNode.DUPLICATE_VAR)
- addStrictWarning("msg.var.redecl", s);
- }
- name = nf.createName(s);
-
- // omitted check for argument hiding
-
- if (matchToken(Token.ASSIGN)) {
- decompiler.addToken(Token.ASSIGN);
-
- init = assignExpr(context == Token.FOR);
- nf.addChildToBack(name, init);
- }
- nf.addChildToBack(pn, name);
- if (!matchToken(Token.COMMA))
- break;
- }
- return pn;
- }
-
- private Node expr(boolean inForInit)
- throws IOException, ParserException
- {
- Node pn = assignExpr(inForInit);
- while (matchToken(Token.COMMA)) {
- decompiler.addToken(Token.COMMA);
- if (compilerEnv.isStrictMode() && !pn.hasSideEffects())
- addStrictWarning("msg.no.side.effects", "");
- pn = nf.createBinary(Token.COMMA, pn, assignExpr(inForInit));
- }
- return pn;
- }
-
- private Node assignExpr(boolean inForInit)
- throws IOException, ParserException
- {
- Node pn = condExpr(inForInit);
-
- int tt = peekToken();
- if (Token.FIRST_ASSIGN <= tt && tt <= Token.LAST_ASSIGN) {
- consumeToken();
- decompiler.addToken(tt);
- pn = nf.createAssignment(tt, pn, assignExpr(inForInit));
- }
-
- return pn;
- }
-
- private Node condExpr(boolean inForInit)
- throws IOException, ParserException
- {
- Node pn = orExpr(inForInit);
-
- if (matchToken(Token.HOOK)) {
- decompiler.addToken(Token.HOOK);
- Node ifTrue = assignExpr(false);
- mustMatchToken(Token.COLON, "msg.no.colon.cond");
- decompiler.addToken(Token.COLON);
- Node ifFalse = assignExpr(inForInit);
- return nf.createCondExpr(pn, ifTrue, ifFalse);
- }
-
- return pn;
- }
-
- private Node orExpr(boolean inForInit)
- throws IOException, ParserException
- {
- Node pn = andExpr(inForInit);
- if (matchToken(Token.OR)) {
- decompiler.addToken(Token.OR);
- pn = nf.createBinary(Token.OR, pn, orExpr(inForInit));
- }
-
- return pn;
- }
-
- private Node andExpr(boolean inForInit)
- throws IOException, ParserException
- {
- Node pn = bitOrExpr(inForInit);
- if (matchToken(Token.AND)) {
- decompiler.addToken(Token.AND);
- pn = nf.createBinary(Token.AND, pn, andExpr(inForInit));
- }
-
- return pn;
- }
-
- private Node bitOrExpr(boolean inForInit)
- throws IOException, ParserException
- {
- Node pn = bitXorExpr(inForInit);
- while (matchToken(Token.BITOR)) {
- decompiler.addToken(Token.BITOR);
- pn = nf.createBinary(Token.BITOR, pn, bitXorExpr(inForInit));
- }
- return pn;
- }
-
- private Node bitXorExpr(boolean inForInit)
- throws IOException, ParserException
- {
- Node pn = bitAndExpr(inForInit);
- while (matchToken(Token.BITXOR)) {
- decompiler.addToken(Token.BITXOR);
- pn = nf.createBinary(Token.BITXOR, pn, bitAndExpr(inForInit));
- }
- return pn;
- }
-
- private Node bitAndExpr(boolean inForInit)
- throws IOException, ParserException
- {
- Node pn = eqExpr(inForInit);
- while (matchToken(Token.BITAND)) {
- decompiler.addToken(Token.BITAND);
- pn = nf.createBinary(Token.BITAND, pn, eqExpr(inForInit));
- }
- return pn;
- }
-
- private Node eqExpr(boolean inForInit)
- throws IOException, ParserException
- {
- Node pn = relExpr(inForInit);
- for (;;) {
- int tt = peekToken();
- switch (tt) {
- case Token.EQ:
- case Token.NE:
- case Token.SHEQ:
- case Token.SHNE:
- consumeToken();
- int decompilerToken = tt;
- int parseToken = tt;
- if (compilerEnv.getLanguageVersion() == Context.VERSION_1_2) {
- // JavaScript 1.2 uses shallow equality for == and != .
- // In addition, convert === and !== for decompiler into
- // == and != since the decompiler is supposed to show
- // canonical source and in 1.2 ===, !== are allowed
- // only as an alias to ==, !=.
- switch (tt) {
- case Token.EQ:
- parseToken = Token.SHEQ;
- break;
- case Token.NE:
- parseToken = Token.SHNE;
- break;
- case Token.SHEQ:
- decompilerToken = Token.EQ;
- break;
- case Token.SHNE:
- decompilerToken = Token.NE;
- break;
- }
- }
- decompiler.addToken(decompilerToken);
- pn = nf.createBinary(parseToken, pn, relExpr(inForInit));
- continue;
- }
- break;
- }
- return pn;
- }
-
- private Node relExpr(boolean inForInit)
- throws IOException, ParserException
- {
- Node pn = shiftExpr();
- for (;;) {
- int tt = peekToken();
- switch (tt) {
- case Token.IN:
- if (inForInit)
- break;
- // fall through
- case Token.INSTANCEOF:
- case Token.LE:
- case Token.LT:
- case Token.GE:
- case Token.GT:
- consumeToken();
- decompiler.addToken(tt);
- pn = nf.createBinary(tt, pn, shiftExpr());
- continue;
- }
- break;
- }
- return pn;
- }
-
- private Node shiftExpr()
- throws IOException, ParserException
- {
- Node pn = addExpr();
- for (;;) {
- int tt = peekToken();
- switch (tt) {
- case Token.LSH:
- case Token.URSH:
- case Token.RSH:
- consumeToken();
- decompiler.addToken(tt);
- pn = nf.createBinary(tt, pn, addExpr());
- continue;
- }
- break;
- }
- return pn;
- }
-
- private Node addExpr()
- throws IOException, ParserException
- {
- Node pn = mulExpr();
- for (;;) {
- int tt = peekToken();
- if (tt == Token.ADD || tt == Token.SUB) {
- consumeToken();
- decompiler.addToken(tt);
- // flushNewLines
- pn = nf.createBinary(tt, pn, mulExpr());
- continue;
- }
- break;
- }
-
- return pn;
- }
-
- private Node mulExpr()
- throws IOException, ParserException
- {
- Node pn = unaryExpr();
- for (;;) {
- int tt = peekToken();
- switch (tt) {
- case Token.MUL:
- case Token.DIV:
- case Token.MOD:
- consumeToken();
- decompiler.addToken(tt);
- pn = nf.createBinary(tt, pn, unaryExpr());
- continue;
- }
- break;
- }
-
- return pn;
- }
-
- private Node unaryExpr()
- throws IOException, ParserException
- {
- int tt;
-
- tt = peekToken();
-
- switch(tt) {
- case Token.VOID:
- case Token.NOT:
- case Token.BITNOT:
- case Token.TYPEOF:
- consumeToken();
- decompiler.addToken(tt);
- return nf.createUnary(tt, unaryExpr());
-
- case Token.ADD:
- consumeToken();
- // Convert to special POS token in decompiler and parse tree
- decompiler.addToken(Token.POS);
- return nf.createUnary(Token.POS, unaryExpr());
-
- case Token.SUB:
- consumeToken();
- // Convert to special NEG token in decompiler and parse tree
- decompiler.addToken(Token.NEG);
- return nf.createUnary(Token.NEG, unaryExpr());
-
- case Token.INC:
- case Token.DEC:
- consumeToken();
- decompiler.addToken(tt);
- return nf.createIncDec(tt, false, memberExpr(true));
-
- case Token.DELPROP:
- consumeToken();
- decompiler.addToken(Token.DELPROP);
- return nf.createUnary(Token.DELPROP, unaryExpr());
-
- case Token.ERROR:
- consumeToken();
- break;
-
- // XML stream encountered in expression.
- case Token.LT:
- if (compilerEnv.isXmlAvailable()) {
- consumeToken();
- Node pn = xmlInitializer();
- return memberExprTail(true, pn);
- }
- // Fall thru to the default handling of RELOP
-
- default:
- Node pn = memberExpr(true);
-
- // Don't look across a newline boundary for a postfix incop.
- tt = peekTokenOrEOL();
- if (tt == Token.INC || tt == Token.DEC) {
- consumeToken();
- decompiler.addToken(tt);
- return nf.createIncDec(tt, true, pn);
- }
- return pn;
- }
- return nf.createName("err"); // Only reached on error. Try to continue.
-
- }
-
- private Node xmlInitializer() throws IOException
- {
- int tt = ts.getFirstXMLToken();
- if (tt != Token.XML && tt != Token.XMLEND) {
- reportError("msg.syntax");
- return null;
- }
-
- /* Make a NEW node to append to. */
- Node pnXML = nf.createLeaf(Token.NEW);
-
- String xml = ts.getString();
- boolean fAnonymous = xml.trim().startsWith("<>");
-
- Node pn = nf.createName(fAnonymous ? "XMLList" : "XML");
- nf.addChildToBack(pnXML, pn);
-
- pn = null;
- Node expr;
- for (;;tt = ts.getNextXMLToken()) {
- switch (tt) {
- case Token.XML:
- xml = ts.getString();
- decompiler.addName(xml);
- mustMatchToken(Token.LC, "msg.syntax");
- decompiler.addToken(Token.LC);
- expr = (peekToken() == Token.RC)
- ? nf.createString("")
- : expr(false);
- mustMatchToken(Token.RC, "msg.syntax");
- decompiler.addToken(Token.RC);
- if (pn == null) {
- pn = nf.createString(xml);
- } else {
- pn = nf.createBinary(Token.ADD, pn, nf.createString(xml));
- }
- if (ts.isXMLAttribute()) {
- /* Need to put the result in double quotes */
- expr = nf.createUnary(Token.ESCXMLATTR, expr);
- Node prepend = nf.createBinary(Token.ADD,
- nf.createString("\""),
- expr);
- expr = nf.createBinary(Token.ADD,
- prepend,
- nf.createString("\""));
- } else {
- expr = nf.createUnary(Token.ESCXMLTEXT, expr);
- }
- pn = nf.createBinary(Token.ADD, pn, expr);
- break;
- case Token.XMLEND:
- xml = ts.getString();
- decompiler.addName(xml);
- if (pn == null) {
- pn = nf.createString(xml);
- } else {
- pn = nf.createBinary(Token.ADD, pn, nf.createString(xml));
- }
-
- nf.addChildToBack(pnXML, pn);
- return pnXML;
- default:
- reportError("msg.syntax");
- return null;
- }
- }
- }
-
- private void argumentList(Node listNode)
- throws IOException, ParserException
- {
- boolean matched;
- matched = matchToken(Token.RP);
- if (!matched) {
- boolean first = true;
- do {
- if (!first)
- decompiler.addToken(Token.COMMA);
- first = false;
- nf.addChildToBack(listNode, assignExpr(false));
- } while (matchToken(Token.COMMA));
-
- mustMatchToken(Token.RP, "msg.no.paren.arg");
- }
- decompiler.addToken(Token.RP);
- }
-
- private Node memberExpr(boolean allowCallSyntax)
- throws IOException, ParserException
- {
- int tt;
-
- Node pn;
-
- /* Check for new expressions. */
- tt = peekToken();
- if (tt == Token.NEW) {
- /* Eat the NEW token. */
- consumeToken();
- decompiler.addToken(Token.NEW);
-
- /* Make a NEW node to append to. */
- pn = nf.createCallOrNew(Token.NEW, memberExpr(false));
-
- if (matchToken(Token.LP)) {
- decompiler.addToken(Token.LP);
- /* Add the arguments to pn, if any are supplied. */
- argumentList(pn);
- }
-
- /* XXX there's a check in the C source against
- * "too many constructor arguments" - how many
- * do we claim to support?
- */
-
- /* Experimental syntax: allow an object literal to follow a new expression,
- * which will mean a kind of anonymous class built with the JavaAdapter.
- * the object literal will be passed as an additional argument to the constructor.
- */
- tt = peekToken();
- if (tt == Token.LC) {
- nf.addChildToBack(pn, primaryExpr());
- }
- } else {
- pn = primaryExpr();
- }
-
- return memberExprTail(allowCallSyntax, pn);
- }
-
- private Node memberExprTail(boolean allowCallSyntax, Node pn)
- throws IOException, ParserException
- {
- tailLoop:
- for (;;) {
- int tt = peekToken();
- switch (tt) {
-
- case Token.DOT:
- case Token.DOTDOT:
- {
- int memberTypeFlags;
- String s;
-
- consumeToken();
- decompiler.addToken(tt);
- memberTypeFlags = 0;
- if (tt == Token.DOTDOT) {
- mustHaveXML();
- memberTypeFlags = Node.DESCENDANTS_FLAG;
- }
- if (!compilerEnv.isXmlAvailable()) {
- mustMatchToken(Token.NAME, "msg.no.name.after.dot");
- s = ts.getString();
- decompiler.addName(s);
- pn = nf.createPropertyGet(pn, null, s, memberTypeFlags);
- break;
- }
-
- tt = nextToken();
- switch (tt) {
- // handles: name, ns::name, ns::*, ns::[expr]
- case Token.NAME:
- s = ts.getString();
- decompiler.addName(s);
- pn = propertyName(pn, s, memberTypeFlags);
- break;
-
- // handles: *, *::name, *::*, *::[expr]
- case Token.MUL:
- decompiler.addName("*");
- pn = propertyName(pn, "*", memberTypeFlags);
- break;
-
- // handles: '@attr', '@ns::attr', '@ns::*', '@ns::*',
- // '@::attr', '@::*', '@*', '@*::attr', '@*::*'
- case Token.XMLATTR:
- decompiler.addToken(Token.XMLATTR);
- pn = attributeAccess(pn, memberTypeFlags);
- break;
-
- default:
- reportError("msg.no.name.after.dot");
- }
- }
- break;
-
- case Token.DOTQUERY:
- consumeToken();
- mustHaveXML();
- decompiler.addToken(Token.DOTQUERY);
- pn = nf.createDotQuery(pn, expr(false), ts.getLineno());
- mustMatchToken(Token.RP, "msg.no.paren");
- decompiler.addToken(Token.RP);
- break;
-
- case Token.LB:
- consumeToken();
- decompiler.addToken(Token.LB);
- pn = nf.createElementGet(pn, null, expr(false), 0);
- mustMatchToken(Token.RB, "msg.no.bracket.index");
- decompiler.addToken(Token.RB);
- break;
-
- case Token.LP:
- if (!allowCallSyntax) {
- break tailLoop;
- }
- consumeToken();
- decompiler.addToken(Token.LP);
- pn = nf.createCallOrNew(Token.CALL, pn);
- /* Add the arguments to pn, if any are supplied. */
- argumentList(pn);
- break;
-
- default:
- break tailLoop;
- }
- }
- return pn;
- }
-
- /*
- * Xml attribute expression:
- * '@attr', '@ns::attr', '@ns::*', '@ns::*', '@*', '@*::attr', '@*::*'
- */
- private Node attributeAccess(Node pn, int memberTypeFlags)
- throws IOException
- {
- memberTypeFlags |= Node.ATTRIBUTE_FLAG;
- int tt = nextToken();
-
- switch (tt) {
- // handles: @name, @ns::name, @ns::*, @ns::[expr]
- case Token.NAME:
- {
- String s = ts.getString();
- decompiler.addName(s);
- pn = propertyName(pn, s, memberTypeFlags);
- }
- break;
-
- // handles: @*, @*::name, @*::*, @*::[expr]
- case Token.MUL:
- decompiler.addName("*");
- pn = propertyName(pn, "*", memberTypeFlags);
- break;
-
- // handles @[expr]
- case Token.LB:
- decompiler.addToken(Token.LB);
- pn = nf.createElementGet(pn, null, expr(false), memberTypeFlags);
- mustMatchToken(Token.RB, "msg.no.bracket.index");
- decompiler.addToken(Token.RB);
- break;
-
- default:
- reportError("msg.no.name.after.xmlAttr");
- pn = nf.createPropertyGet(pn, null, "?", memberTypeFlags);
- break;
- }
-
- return pn;
- }
-
- /**
- * Check if :: follows name in which case it becomes qualified name
- */
- private Node propertyName(Node pn, String name, int memberTypeFlags)
- throws IOException, ParserException
- {
- String namespace = null;
- if (matchToken(Token.COLONCOLON)) {
- decompiler.addToken(Token.COLONCOLON);
- namespace = name;
-
- int tt = nextToken();
- switch (tt) {
- // handles name::name
- case Token.NAME:
- name = ts.getString();
- decompiler.addName(name);
- break;
-
- // handles name::*
- case Token.MUL:
- decompiler.addName("*");
- name = "*";
- break;
-
- // handles name::[expr]
- case Token.LB:
- decompiler.addToken(Token.LB);
- pn = nf.createElementGet(pn, namespace, expr(false),
- memberTypeFlags);
- mustMatchToken(Token.RB, "msg.no.bracket.index");
- decompiler.addToken(Token.RB);
- return pn;
-
- default:
- reportError("msg.no.name.after.coloncolon");
- name = "?";
- }
- }
-
- pn = nf.createPropertyGet(pn, namespace, name, memberTypeFlags);
- return pn;
- }
-
- private Node primaryExpr()
- throws IOException, ParserException
- {
- Node pn;
-
- int ttFlagged = nextFlaggedToken();
- int tt = ttFlagged & CLEAR_TI_MASK;
-
- switch(tt) {
-
- case Token.FUNCTION:
- return function(FunctionNode.FUNCTION_EXPRESSION);
-
- case Token.LB: {
- ObjArray elems = new ObjArray();
- int skipCount = 0;
- decompiler.addToken(Token.LB);
- boolean after_lb_or_comma = true;
- for (;;) {
- tt = peekToken();
-
- if (tt == Token.COMMA) {
- consumeToken();
- decompiler.addToken(Token.COMMA);
- if (!after_lb_or_comma) {
- after_lb_or_comma = true;
- } else {
- elems.add(null);
- ++skipCount;
- }
- } else if (tt == Token.RB) {
- consumeToken();
- decompiler.addToken(Token.RB);
- break;
- } else {
- if (!after_lb_or_comma) {
- reportError("msg.no.bracket.arg");
- }
- elems.add(assignExpr(false));
- after_lb_or_comma = false;
- }
- }
- return nf.createArrayLiteral(elems, skipCount);
- }
-
- case Token.LC: {
- ObjArray elems = new ObjArray();
- decompiler.addToken(Token.LC);
- if (!matchToken(Token.RC)) {
-
- boolean first = true;
- commaloop:
- do {
- Object property;
-
- if (!first)
- decompiler.addToken(Token.COMMA);
- else
- first = false;
-
- tt = peekToken();
- switch(tt) {
- case Token.NAME:
- case Token.STRING:
- consumeToken();
- // map NAMEs to STRINGs in object literal context
- // but tell the decompiler the proper type
- String s = ts.getString();
- if (tt == Token.NAME) {
- if (s.equals("get") &&
- peekToken() == Token.NAME) {
- decompiler.addToken(Token.GET);
- consumeToken();
- s = ts.getString();
- decompiler.addName(s);
- property = ScriptRuntime.getIndexObject(s);
- if (!getterSetterProperty(elems, property,
- true))
- break commaloop;
- break;
- } else if (s.equals("set") &&
- peekToken() == Token.NAME) {
- decompiler.addToken(Token.SET);
- consumeToken();
- s = ts.getString();
- decompiler.addName(s);
- property = ScriptRuntime.getIndexObject(s);
- if (!getterSetterProperty(elems, property,
- false))
- break commaloop;
- break;
- }
- decompiler.addName(s);
- } else {
- decompiler.addString(s);
- }
- property = ScriptRuntime.getIndexObject(s);
- plainProperty(elems, property);
- break;
-
- case Token.NUMBER:
- consumeToken();
- double n = ts.getNumber();
- decompiler.addNumber(n);
- property = ScriptRuntime.getIndexObject(n);
- plainProperty(elems, property);
- break;
-
- case Token.RC:
- // trailing comma is OK.
- break commaloop;
- default:
- reportError("msg.bad.prop");
- break commaloop;
- }
- } while (matchToken(Token.COMMA));
-
- mustMatchToken(Token.RC, "msg.no.brace.prop");
- }
- decompiler.addToken(Token.RC);
- return nf.createObjectLiteral(elems);
- }
-
- case Token.LP:
-
- /* Brendan's IR-jsparse.c makes a new node tagged with
- * TOK_LP here... I'm not sure I understand why. Isn't
- * the grouping already implicit in the structure of the
- * parse tree? also TOK_LP is already overloaded (I
- * think) in the C IR as 'function call.' */
- decompiler.addToken(Token.LP);
- pn = expr(false);
- pn.putProp(Node.PARENTHESIZED_PROP, Boolean.TRUE);
- decompiler.addToken(Token.RP);
- mustMatchToken(Token.RP, "msg.no.paren");
- return pn;
-
- case Token.XMLATTR:
- mustHaveXML();
- decompiler.addToken(Token.XMLATTR);
- pn = attributeAccess(null, 0);
- return pn;
-
- case Token.NAME: {
- String name = ts.getString();
- if ((ttFlagged & TI_CHECK_LABEL) != 0) {
- if (peekToken() == Token.COLON) {
- // Do not consume colon, it is used as unwind indicator
- // to return to statementHelper.
- // XXX Better way?
- return nf.createLabel(ts.getLineno());
- }
- }
-
- decompiler.addName(name);
- if (compilerEnv.isXmlAvailable()) {
- pn = propertyName(null, name, 0);
- } else {
- pn = nf.createName(name);
- }
- return pn;
- }
-
- case Token.NUMBER: {
- double n = ts.getNumber();
- decompiler.addNumber(n);
- return nf.createNumber(n);
- }
-
- case Token.STRING: {
- String s = ts.getString();
- decompiler.addString(s);
- return nf.createString(s);
- }
-
- case Token.DIV:
- case Token.ASSIGN_DIV: {
- // Got / or /= which should be treated as regexp in fact
- ts.readRegExp(tt);
- String flags = ts.regExpFlags;
- ts.regExpFlags = null;
- String re = ts.getString();
- decompiler.addRegexp(re, flags);
- int index = currentScriptOrFn.addRegexp(re, flags);
- return nf.createRegExp(index);
- }
-
- case Token.NULL:
- case Token.THIS:
- case Token.FALSE:
- case Token.TRUE:
- decompiler.addToken(tt);
- return nf.createLeaf(tt);
-
- case Token.RESERVED:
- reportError("msg.reserved.id");
- break;
-
- case Token.ERROR:
- /* the scanner or one of its subroutines reported the error. */
- break;
-
- case Token.EOF:
- reportError("msg.unexpected.eof");
- break;
-
- default:
- reportError("msg.syntax");
- break;
- }
- return null; // should never reach here
- }
-
- private void plainProperty(ObjArray elems, Object property)
- throws IOException {
- mustMatchToken(Token.COLON, "msg.no.colon.prop");
-
- // OBJLIT is used as ':' in object literal for
- // decompilation to solve spacing ambiguity.
- decompiler.addToken(Token.OBJECTLIT);
- elems.add(property);
- elems.add(assignExpr(false));
- }
-
- private boolean getterSetterProperty(ObjArray elems, Object property,
- boolean isGetter) throws IOException {
- Node f = function(FunctionNode.FUNCTION_EXPRESSION);
- if (f.getType() != Token.FUNCTION) {
- reportError("msg.bad.prop");
- return false;
- }
- int fnIndex = f.getExistingIntProp(Node.FUNCTION_PROP);
- FunctionNode fn = currentScriptOrFn.getFunctionNode(fnIndex);
- if (fn.getFunctionName().length() != 0) {
- reportError("msg.bad.prop");
- return false;
- }
- elems.add(property);
- if (isGetter) {
- elems.add(nf.createUnary(Token.GET, f));
- } else {
- elems.add(nf.createUnary(Token.SET, f));
- }
- return true;
- }
-}