diff --git a/.idea/ant.xml b/.idea/ant.xml
new file mode 100644
index 00000000..a2a47698
--- /dev/null
+++ b/.idea/ant.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 00000000..35eb1ddf
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 00000000..f61a023f
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ "keyToString": {
+ "RunOnceActivity.OpenProjectViewOnStart": "true",
+ "RunOnceActivity.ShowReadmeOnStart": "true",
+ "WebServerToolWindowFactoryState": "false",
+ "last_opened_file_path": "/Users/hparwani/Documents/yuicompressor",
+ "nodejs_package_manager_path": "npm",
+ "project.structure.last.edited": "Modules",
+ "project.structure.proportion": "0.15",
+ "project.structure.side.proportion": "0.2",
+ "settings.editor.selected.configurable": "preferences.pluginManager"
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1707816736870
+
+
+ 1707816736870
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.xml b/build.xml
index a2663b36..c180fa5b 100644
--- a/build.xml
+++ b/build.xml
@@ -37,7 +37,6 @@
source="1.5">
-
@@ -47,7 +46,6 @@
-
diff --git a/lib/rhino-1.7R2.jar b/lib/rhino-1.7R2.jar
deleted file mode 100644
index c0f85064..00000000
Binary files a/lib/rhino-1.7R2.jar and /dev/null differ
diff --git a/src/com/yahoo/platform/yui/compressor/JavaScriptCompressor.java b/src/com/yahoo/platform/yui/compressor/JavaScriptCompressor.java
deleted file mode 100644
index eb9e1ea5..00000000
--- a/src/com/yahoo/platform/yui/compressor/JavaScriptCompressor.java
+++ /dev/null
@@ -1,1361 +0,0 @@
-/*
- * YUI Compressor
- * http://developer.yahoo.com/yui/compressor/
- * Author: Julien Lecomte - http://www.julienlecomte.net/
- * Copyright (c) 2011 Yahoo! Inc. All rights reserved.
- * The copyrights embodied in the content of this file are licensed
- * by Yahoo! Inc. under the BSD (revised) open source license.
- */
-package com.yahoo.platform.yui.compressor;
-
-import org.mozilla.javascript.*;
-
-import java.io.IOException;
-import java.io.Reader;
-import java.io.Writer;
-import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class JavaScriptCompressor {
-
- static final ArrayList ones;
- static final ArrayList twos;
- static final ArrayList threes;
-
- static final Set builtin = new HashSet();
- static final Map literals = new HashMap();
- static final Set reserved = new HashSet();
-
- static {
-
- // This list contains all the 3 characters or less built-in global
- // symbols available in a browser. Please add to this list if you
- // see anything missing.
- builtin.add("NaN");
- builtin.add("top");
-
- ones = new ArrayList();
- for (char c = 'a'; c <= 'z'; c++)
- ones.add(Character.toString(c));
- for (char c = 'A'; c <= 'Z'; c++)
- ones.add(Character.toString(c));
-
- twos = new ArrayList();
- for (int i = 0; i < ones.size(); i++) {
- String one = (String) ones.get(i);
- for (char c = 'a'; c <= 'z'; c++)
- twos.add(one + Character.toString(c));
- for (char c = 'A'; c <= 'Z'; c++)
- twos.add(one + Character.toString(c));
- for (char c = '0'; c <= '9'; c++)
- twos.add(one + Character.toString(c));
- }
-
- threes = new ArrayList();
- for (int i = 0; i < twos.size(); i++) {
- String two = (String) twos.get(i);
- for (char c = 'a'; c <= 'z'; c++)
- threes.add(two + Character.toString(c));
- for (char c = 'A'; c <= 'Z'; c++)
- threes.add(two + Character.toString(c));
- for (char c = '0'; c <= '9'; c++)
- threes.add(two + Character.toString(c));
- }
-
- // Remove two-letter JavaScript reserved words and built-in globals...
- twos.remove("as");
- twos.remove("is");
- twos.remove("do");
- twos.remove("if");
- twos.remove("in");
- twos.removeAll(builtin);
-
- // Remove three-letter JavaScript reserved words and built-in globals...
- threes.remove("for");
- threes.remove("int");
- threes.remove("new");
- threes.remove("try");
- threes.remove("use");
- threes.remove("var");
- threes.removeAll(builtin);
-
- // That's up to ((26+26)*(1+(26+26+10)))*(1+(26+26+10))-8
- // (206,380 symbols per scope)
-
- // The following list comes from org/mozilla/javascript/Decompiler.java...
- literals.put(new Integer(Token.GET), "get ");
- literals.put(new Integer(Token.SET), "set ");
- literals.put(new Integer(Token.TRUE), "true");
- literals.put(new Integer(Token.FALSE), "false");
- literals.put(new Integer(Token.NULL), "null");
- literals.put(new Integer(Token.THIS), "this");
- literals.put(new Integer(Token.FUNCTION), "function");
- literals.put(new Integer(Token.COMMA), ",");
- literals.put(new Integer(Token.LC), "{");
- literals.put(new Integer(Token.RC), "}");
- literals.put(new Integer(Token.LP), "(");
- literals.put(new Integer(Token.RP), ")");
- literals.put(new Integer(Token.LB), "[");
- literals.put(new Integer(Token.RB), "]");
- literals.put(new Integer(Token.DOT), ".");
- literals.put(new Integer(Token.NEW), "new ");
- literals.put(new Integer(Token.DELPROP), "delete ");
- literals.put(new Integer(Token.IF), "if");
- literals.put(new Integer(Token.ELSE), "else");
- literals.put(new Integer(Token.FOR), "for");
- literals.put(new Integer(Token.IN), " in ");
- literals.put(new Integer(Token.WITH), "with");
- literals.put(new Integer(Token.WHILE), "while");
- literals.put(new Integer(Token.DO), "do");
- literals.put(new Integer(Token.TRY), "try");
- literals.put(new Integer(Token.CATCH), "catch");
- literals.put(new Integer(Token.FINALLY), "finally");
- literals.put(new Integer(Token.THROW), "throw");
- literals.put(new Integer(Token.SWITCH), "switch");
- literals.put(new Integer(Token.BREAK), "break");
- literals.put(new Integer(Token.CONTINUE), "continue");
- literals.put(new Integer(Token.CASE), "case");
- literals.put(new Integer(Token.DEFAULT), "default");
- literals.put(new Integer(Token.RETURN), "return");
- literals.put(new Integer(Token.VAR), "var ");
- literals.put(new Integer(Token.SEMI), ";");
- literals.put(new Integer(Token.ASSIGN), "=");
- literals.put(new Integer(Token.ASSIGN_ADD), "+=");
- literals.put(new Integer(Token.ASSIGN_SUB), "-=");
- literals.put(new Integer(Token.ASSIGN_MUL), "*=");
- literals.put(new Integer(Token.ASSIGN_DIV), "/=");
- literals.put(new Integer(Token.ASSIGN_MOD), "%=");
- literals.put(new Integer(Token.ASSIGN_BITOR), "|=");
- literals.put(new Integer(Token.ASSIGN_BITXOR), "^=");
- literals.put(new Integer(Token.ASSIGN_BITAND), "&=");
- literals.put(new Integer(Token.ASSIGN_LSH), "<<=");
- literals.put(new Integer(Token.ASSIGN_RSH), ">>=");
- literals.put(new Integer(Token.ASSIGN_URSH), ">>>=");
- literals.put(new Integer(Token.HOOK), "?");
- literals.put(new Integer(Token.OBJECTLIT), ":");
- literals.put(new Integer(Token.COLON), ":");
- literals.put(new Integer(Token.OR), "||");
- literals.put(new Integer(Token.AND), "&&");
- literals.put(new Integer(Token.BITOR), "|");
- literals.put(new Integer(Token.BITXOR), "^");
- literals.put(new Integer(Token.BITAND), "&");
- literals.put(new Integer(Token.SHEQ), "===");
- literals.put(new Integer(Token.SHNE), "!==");
- literals.put(new Integer(Token.EQ), "==");
- literals.put(new Integer(Token.NE), "!=");
- literals.put(new Integer(Token.LE), "<=");
- literals.put(new Integer(Token.LT), "<");
- literals.put(new Integer(Token.GE), ">=");
- literals.put(new Integer(Token.GT), ">");
- literals.put(new Integer(Token.INSTANCEOF), " instanceof ");
- literals.put(new Integer(Token.LSH), "<<");
- literals.put(new Integer(Token.RSH), ">>");
- literals.put(new Integer(Token.URSH), ">>>");
- literals.put(new Integer(Token.TYPEOF), "typeof");
- literals.put(new Integer(Token.VOID), "void ");
- literals.put(new Integer(Token.CONST), "const ");
- literals.put(new Integer(Token.NOT), "!");
- literals.put(new Integer(Token.BITNOT), "~");
- literals.put(new Integer(Token.POS), "+");
- literals.put(new Integer(Token.NEG), "-");
- literals.put(new Integer(Token.INC), "++");
- literals.put(new Integer(Token.DEC), "--");
- literals.put(new Integer(Token.ADD), "+");
- literals.put(new Integer(Token.SUB), "-");
- literals.put(new Integer(Token.MUL), "*");
- literals.put(new Integer(Token.DIV), "/");
- literals.put(new Integer(Token.MOD), "%");
- literals.put(new Integer(Token.COLONCOLON), "::");
- literals.put(new Integer(Token.DOTDOT), "..");
- literals.put(new Integer(Token.DOTQUERY), ".(");
- literals.put(new Integer(Token.XMLATTR), "@");
- literals.put(new Integer(Token.LET), "let ");
- literals.put(new Integer(Token.YIELD), "yield ");
-
- // See http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Reserved_Words
-
- // JavaScript 1.5 reserved words
- reserved.add("break");
- reserved.add("case");
- reserved.add("catch");
- reserved.add("continue");
- reserved.add("default");
- reserved.add("delete");
- reserved.add("do");
- reserved.add("else");
- reserved.add("finally");
- reserved.add("for");
- reserved.add("function");
- reserved.add("if");
- reserved.add("in");
- reserved.add("instanceof");
- reserved.add("new");
- reserved.add("return");
- reserved.add("switch");
- reserved.add("this");
- reserved.add("throw");
- reserved.add("try");
- reserved.add("typeof");
- reserved.add("var");
- reserved.add("void");
- reserved.add("while");
- reserved.add("with");
- // Words reserved for future use
- reserved.add("abstract");
- reserved.add("boolean");
- reserved.add("byte");
- reserved.add("char");
- reserved.add("class");
- reserved.add("const");
- reserved.add("debugger");
- reserved.add("double");
- reserved.add("enum");
- reserved.add("export");
- reserved.add("extends");
- reserved.add("final");
- reserved.add("float");
- reserved.add("goto");
- reserved.add("implements");
- reserved.add("import");
- reserved.add("int");
- reserved.add("interface");
- reserved.add("long");
- reserved.add("native");
- reserved.add("package");
- reserved.add("private");
- reserved.add("protected");
- reserved.add("public");
- reserved.add("short");
- reserved.add("static");
- reserved.add("super");
- reserved.add("synchronized");
- reserved.add("throws");
- reserved.add("transient");
- reserved.add("volatile");
- // These are not reserved, but should be taken into account
- // in isValidIdentifier (See jslint source code)
- reserved.add("arguments");
- reserved.add("eval");
- reserved.add("true");
- reserved.add("false");
- reserved.add("Infinity");
- reserved.add("NaN");
- reserved.add("null");
- reserved.add("undefined");
- }
-
- private static int countChar(String haystack, char needle) {
- int idx = 0;
- int count = 0;
- int length = haystack.length();
- while (idx < length) {
- char c = haystack.charAt(idx++);
- if (c == needle) {
- count++;
- }
- }
- return count;
- }
-
- private static int printSourceString(String source, int offset, StringBuffer sb) {
- int length = source.charAt(offset);
- ++offset;
- if ((0x8000 & length) != 0) {
- length = ((0x7FFF & length) << 16) | source.charAt(offset);
- ++offset;
- }
- if (sb != null) {
- String str = source.substring(offset, offset + length);
- sb.append(str);
- }
- return offset + length;
- }
-
- private static int printSourceNumber(String source,
- int offset, StringBuffer sb) {
- double number = 0.0;
- char type = source.charAt(offset);
- ++offset;
- if (type == 'S') {
- if (sb != null) {
- number = source.charAt(offset);
- }
- ++offset;
- } else if (type == 'J' || type == 'D') {
- if (sb != null) {
- long lbits;
- lbits = (long) source.charAt(offset) << 48;
- lbits |= (long) source.charAt(offset + 1) << 32;
- lbits |= (long) source.charAt(offset + 2) << 16;
- lbits |= (long) source.charAt(offset + 3);
- if (type == 'J') {
- number = lbits;
- } else {
- number = Double.longBitsToDouble(lbits);
- }
- }
- offset += 4;
- } else {
- // Bad source
- throw new RuntimeException();
- }
- if (sb != null) {
- sb.append(ScriptRuntime.numberToString(number, 10));
- }
- return offset;
- }
-
- private static ArrayList parse(Reader in, ErrorReporter reporter)
- throws IOException, EvaluatorException {
-
- CompilerEnvirons env = new CompilerEnvirons();
- env.setLanguageVersion(Context.VERSION_1_7);
- Parser parser = new Parser(env, reporter);
- parser.parse(in, null, 1);
- String source = parser.getEncodedSource();
-
- int offset = 0;
- int length = (source != null) ? source.length() : 0;
- ArrayList tokens = new ArrayList();
- StringBuffer sb = new StringBuffer();
-
- while (offset < length) {
- int tt = source.charAt(offset++);
- switch (tt) {
-
- case Token.CONDCOMMENT:
- case Token.KEEPCOMMENT:
- case Token.NAME:
- case Token.REGEXP:
- case Token.STRING:
- sb.setLength(0);
- offset = printSourceString(source, offset, sb);
- tokens.add(new JavaScriptToken(tt, sb.toString()));
- break;
-
- case Token.NUMBER:
- sb.setLength(0);
- offset = printSourceNumber(source, offset, sb);
- tokens.add(new JavaScriptToken(tt, sb.toString()));
- break;
-
- default:
- String literal = (String) literals.get(new Integer(tt));
- if (literal != null) {
- tokens.add(new JavaScriptToken(tt, literal));
- }
- break;
- }
- }
-
- return tokens;
- }
-
- private static void processStringLiterals(ArrayList tokens, boolean merge) {
-
- String tv;
- int i, length = tokens.size();
- JavaScriptToken token, prevToken, nextToken;
-
- if (merge) {
-
- // Concatenate string literals that are being appended wherever
- // it is safe to do so. Note that we take care of the case:
- // "a" + "b".toUpperCase()
-
- for (i = 0; i < length; i++) {
- token = (JavaScriptToken) tokens.get(i);
- switch (token.getType()) {
-
- case Token.ADD:
- if (i > 0 && i < length) {
- prevToken = (JavaScriptToken) tokens.get(i - 1);
- nextToken = (JavaScriptToken) tokens.get(i + 1);
- if (prevToken.getType() == Token.STRING && nextToken.getType() == Token.STRING &&
- (i == length - 1 || ((JavaScriptToken) tokens.get(i + 2)).getType() != Token.DOT)) {
- tokens.set(i - 1, new JavaScriptToken(Token.STRING,
- prevToken.getValue() + nextToken.getValue()));
- tokens.remove(i + 1);
- tokens.remove(i);
- i = i - 1;
- length = length - 2;
- break;
- }
- }
- }
- }
-
- }
-
- // Second pass...
-
- for (i = 0; i < length; i++) {
- token = (JavaScriptToken) tokens.get(i);
- if (token.getType() == Token.STRING) {
- tv = token.getValue();
-
- // Finally, add the quoting characters and escape the string. We use
- // the quoting character that minimizes the amount of escaping to save
- // a few additional bytes.
-
- char quotechar;
- int singleQuoteCount = countChar(tv, '\'');
- int doubleQuoteCount = countChar(tv, '"');
- if (doubleQuoteCount <= singleQuoteCount) {
- quotechar = '"';
- } else {
- quotechar = '\'';
- }
-
- tv = quotechar + escapeString(tv, quotechar) + quotechar;
-
- // String concatenation transforms the old script scheme:
- // '<'+'/script>'
- // into the following:
- // ''
- // which breaks if this code is embedded inside an HTML document.
- // Since this is not the right way to do this, let's fix the code by
- // transforming all "= 0) {
- tv = tv.replaceAll("<\\/script", "<\\\\/script");
- }
-
- tokens.set(i, new JavaScriptToken(Token.STRING, tv));
- }
- }
- }
-
- // Add necessary escaping that was removed in Rhino's tokenizer.
- private static String escapeString(String s, char quotechar) {
-
- assert quotechar == '"' || quotechar == '\'';
-
- if (s == null) {
- return null;
- }
-
- StringBuffer sb = new StringBuffer();
- for (int i = 0, L = s.length(); i < L; i++) {
- int c = s.charAt(i);
- if (c == quotechar) {
- sb.append("\\");
- }
- sb.append((char) c);
- }
-
- return sb.toString();
- }
-
- /*
- * Simple check to see whether a string is a valid identifier name.
- * If a string matches this pattern, it means it IS a valid
- * identifier name. If a string doesn't match it, it does not
- * necessarily mean it is not a valid identifier name.
- */
- private static final Pattern SIMPLE_IDENTIFIER_NAME_PATTERN = Pattern.compile("^[a-zA-Z_][a-zA-Z0-9_]*$");
-
- private static boolean isValidIdentifier(String s) {
- Matcher m = SIMPLE_IDENTIFIER_NAME_PATTERN.matcher(s);
- return (m.matches() && !reserved.contains(s));
- }
-
- /*
- * Transforms obj["foo"] into obj.foo whenever possible, saving 3 bytes.
- */
- private static void optimizeObjectMemberAccess(ArrayList tokens) {
-
- String tv;
- int i, length;
- JavaScriptToken token;
-
- for (i = 0, length = tokens.size(); i < length; i++) {
-
- if (((JavaScriptToken) tokens.get(i)).getType() == Token.LB &&
- i > 0 && i < length - 2 &&
- ((JavaScriptToken) tokens.get(i - 1)).getType() == Token.NAME &&
- ((JavaScriptToken) tokens.get(i + 1)).getType() == Token.STRING &&
- ((JavaScriptToken) tokens.get(i + 2)).getType() == Token.RB) {
- token = (JavaScriptToken) tokens.get(i + 1);
- tv = token.getValue();
- tv = tv.substring(1, tv.length() - 1);
- if (isValidIdentifier(tv)) {
- tokens.set(i, new JavaScriptToken(Token.DOT, "."));
- tokens.set(i + 1, new JavaScriptToken(Token.NAME, tv));
- tokens.remove(i + 2);
- i = i + 2;
- length = length - 1;
- }
- }
- }
- }
-
- /*
- * Transforms 'foo': ... into foo: ... whenever possible, saving 2 bytes.
- */
- private static void optimizeObjLitMemberDecl(ArrayList tokens) {
-
- String tv;
- int i, length;
- JavaScriptToken token;
-
- for (i = 0, length = tokens.size(); i < length; i++) {
- if (((JavaScriptToken) tokens.get(i)).getType() == Token.OBJECTLIT &&
- i > 0 && ((JavaScriptToken) tokens.get(i - 1)).getType() == Token.STRING) {
- token = (JavaScriptToken) tokens.get(i - 1);
- tv = token.getValue();
- tv = tv.substring(1, tv.length() - 1);
- if (isValidIdentifier(tv)) {
- tokens.set(i - 1, new JavaScriptToken(Token.NAME, tv));
- }
- }
- }
- }
-
- private ErrorReporter logger;
-
- private boolean munge;
- private boolean verbose;
-
- private static final int BUILDING_SYMBOL_TREE = 1;
- private static final int CHECKING_SYMBOL_TREE = 2;
-
- private int mode;
- private int offset;
- private int braceNesting;
- private ArrayList tokens;
- private Stack scopes = new Stack();
- private ScriptOrFnScope globalScope = new ScriptOrFnScope(-1, null);
- private Hashtable indexedScopes = new Hashtable();
-
- public JavaScriptCompressor(Reader in, ErrorReporter reporter)
- throws IOException, EvaluatorException {
-
- this.logger = reporter;
- this.tokens = parse(in, reporter);
- }
-
- public void compress(Writer out, Writer mungemap, int linebreak, boolean munge, boolean verbose,
- boolean preserveAllSemiColons, boolean disableOptimizations)
- throws IOException {
-
- this.munge = munge;
- this.verbose = verbose;
-
- processStringLiterals(this.tokens, !disableOptimizations);
-
- if (!disableOptimizations) {
- optimizeObjectMemberAccess(this.tokens);
- optimizeObjLitMemberDecl(this.tokens);
- }
-
- buildSymbolTree();
- // DO NOT TOUCH this.tokens BETWEEN THESE TWO PHASES (BECAUSE OF this.indexedScopes)
- mungeSymboltree();
- StringBuffer sb = printSymbolTree(linebreak, preserveAllSemiColons);
-
- out.write(sb.toString());
-
- if (mungemap != null) {
- printMungeMapping(mungemap);
- }
- }
-
- private ScriptOrFnScope getCurrentScope() {
- return (ScriptOrFnScope) scopes.peek();
- }
-
- private void enterScope(ScriptOrFnScope scope) {
- scopes.push(scope);
- }
-
- private void leaveCurrentScope() {
- scopes.pop();
- }
-
- private JavaScriptToken consumeToken() {
- return (JavaScriptToken) tokens.get(offset++);
- }
-
- private JavaScriptToken getToken(int delta) {
- try {
- return (JavaScriptToken) tokens.get(offset + delta);
- } catch(IndexOutOfBoundsException ex) {
- return null;
- }
- }
-
- /*
- * Returns the identifier for the specified symbol defined in
- * the specified scope or in any scope above it. Returns null
- * if this symbol does not have a corresponding identifier.
- */
- private JavaScriptIdentifier getIdentifier(String symbol, ScriptOrFnScope scope) {
- JavaScriptIdentifier identifier;
- while (scope != null) {
- identifier = scope.getIdentifier(symbol);
- if (identifier != null) {
- return identifier;
- }
- scope = scope.getParentScope();
- }
- return null;
- }
-
- /*
- * If either 'eval' or 'with' is used in a local scope, we must make
- * sure that all containing local scopes don't get munged. Otherwise,
- * the obfuscation would potentially introduce bugs.
- */
- private void protectScopeFromObfuscation(ScriptOrFnScope scope) {
- assert scope != null;
-
- if (scope == globalScope) {
- // The global scope does not get obfuscated,
- // so we don't need to worry about it...
- return;
- }
-
- // Find the highest local scope containing the specified scope.
- while (scope.getParentScope() != globalScope) {
- scope = scope.getParentScope();
- }
-
- assert scope.getParentScope() == globalScope;
- scope.preventMunging();
- }
-
- private String getDebugString(int max) {
- assert max > 0;
- StringBuffer result = new StringBuffer();
- int start = Math.max(offset - max, 0);
- int end = Math.min(offset + max, tokens.size());
- for (int i = start; i < end; i++) {
- JavaScriptToken token = (JavaScriptToken) tokens.get(i);
- if (i == offset - 1) {
- result.append(" ---> ");
- }
- result.append(token.getValue());
- if (i == offset - 1) {
- result.append(" <--- ");
- }
- }
- return result.toString();
- }
-
- private void warn(String message, boolean showDebugString) {
- if (verbose) {
- if (showDebugString) {
- message = message + "\n" + getDebugString(10);
- }
- logger.warning(message, null, -1, null, -1);
- }
- }
-
- private void parseFunctionDeclaration() {
-
- String symbol;
- JavaScriptToken token;
- ScriptOrFnScope currentScope, fnScope;
- JavaScriptIdentifier identifier;
-
- currentScope = getCurrentScope();
-
- token = consumeToken();
- if (token.getType() == Token.NAME) {
- if (mode == BUILDING_SYMBOL_TREE) {
- // Get the name of the function and declare it in the current scope.
- symbol = token.getValue();
- if (currentScope.getIdentifier(symbol) != null) {
- warn("The function " + symbol + " has already been declared in the same scope...", true);
- }
- currentScope.declareIdentifier(symbol);
- }
- token = consumeToken();
- }
-
- assert token.getType() == Token.LP;
- if (mode == BUILDING_SYMBOL_TREE) {
- fnScope = new ScriptOrFnScope(braceNesting, currentScope);
- indexedScopes.put(new Integer(offset), fnScope);
- } else {
- fnScope = (ScriptOrFnScope) indexedScopes.get(new Integer(offset));
- }
-
- // Parse function arguments.
- int argpos = 0;
- while ((token = consumeToken()).getType() != Token.RP) {
- assert token.getType() == Token.NAME ||
- token.getType() == Token.COMMA;
- if (token.getType() == Token.NAME && mode == BUILDING_SYMBOL_TREE) {
- symbol = token.getValue();
- identifier = fnScope.declareIdentifier(symbol);
- if (symbol.equals("$super") && argpos == 0) {
- // Exception for Prototype 1.6...
- identifier.preventMunging();
- }
- argpos++;
- }
- }
-
- token = consumeToken();
- assert token.getType() == Token.LC;
- braceNesting++;
-
- token = getToken(0);
- if (token.getType() == Token.STRING &&
- getToken(1).getType() == Token.SEMI) {
- // This is a hint. Hints are empty statements that look like
- // "localvar1:nomunge, localvar2:nomunge"; They allow developers
- // to prevent specific symbols from getting obfuscated (some heretic
- // implementations, such as Prototype 1.6, require specific variable
- // names, such as $super for example, in order to work appropriately.
- // Note: right now, only "nomunge" is supported in the right hand side
- // of a hint. However, in the future, the right hand side may contain
- // other values.
- consumeToken();
- String hints = token.getValue();
- // Remove the leading and trailing quotes...
- hints = hints.substring(1, hints.length() - 1).trim();
- StringTokenizer st1 = new StringTokenizer(hints, ",");
- while (st1.hasMoreTokens()) {
- String hint = st1.nextToken();
- int idx = hint.indexOf(':');
- if (idx <= 0 || idx >= hint.length() - 1) {
- if (mode == BUILDING_SYMBOL_TREE) {
- // No need to report the error twice, hence the test...
- warn("Invalid hint syntax: " + hint, true);
- }
- break;
- }
- String variableName = hint.substring(0, idx).trim();
- String variableType = hint.substring(idx + 1).trim();
- if (mode == BUILDING_SYMBOL_TREE) {
- fnScope.addHint(variableName, variableType);
- } else if (mode == CHECKING_SYMBOL_TREE) {
- identifier = fnScope.getIdentifier(variableName);
- if (identifier != null) {
- if (variableType.equals("nomunge")) {
- identifier.preventMunging();
- } else {
- warn("Unsupported hint value: " + hint, true);
- }
- } else {
- warn("Hint refers to an unknown identifier: " + hint, true);
- }
- }
- }
- }
-
- parseScope(fnScope);
- }
-
- private void parseCatch() {
-
- String symbol;
- JavaScriptToken token;
- ScriptOrFnScope currentScope;
- JavaScriptIdentifier identifier;
-
- token = getToken(-1);
- assert token.getType() == Token.CATCH;
- token = consumeToken();
- assert token.getType() == Token.LP;
- token = consumeToken();
- assert token.getType() == Token.NAME;
-
- symbol = token.getValue();
- currentScope = getCurrentScope();
-
- if (mode == BUILDING_SYMBOL_TREE) {
- // We must declare the exception identifier in the containing function
- // scope to avoid errors related to the obfuscation process. No need to
- // display a warning if the symbol was already declared here...
- currentScope.declareIdentifier(symbol);
- } else {
- identifier = getIdentifier(symbol, currentScope);
- identifier.incrementRefcount();
- }
-
- token = consumeToken();
- assert token.getType() == Token.RP;
- }
-
- private void parseExpression() {
-
- // Parse the expression until we encounter a comma or a semi-colon
- // in the same brace nesting, bracket nesting and paren nesting.
- // Parse functions if any...
-
- String symbol;
- JavaScriptToken token;
- ScriptOrFnScope currentScope;
- JavaScriptIdentifier identifier;
-
- int expressionBraceNesting = braceNesting;
- int bracketNesting = 0;
- int parensNesting = 0;
-
- int length = tokens.size();
-
- while (offset < length) {
-
- token = consumeToken();
- currentScope = getCurrentScope();
-
- switch (token.getType()) {
-
- case Token.SEMI:
- case Token.COMMA:
- if (braceNesting == expressionBraceNesting &&
- bracketNesting == 0 &&
- parensNesting == 0) {
- return;
- }
- break;
-
- case Token.FUNCTION:
- parseFunctionDeclaration();
- break;
-
- case Token.LC:
- braceNesting++;
- break;
-
- case Token.RC:
- braceNesting--;
- assert braceNesting >= expressionBraceNesting;
- break;
-
- case Token.LB:
- bracketNesting++;
- break;
-
- case Token.RB:
- bracketNesting--;
- break;
-
- case Token.LP:
- parensNesting++;
- break;
-
- case Token.RP:
- parensNesting--;
- break;
-
- case Token.CONDCOMMENT:
- if (mode == BUILDING_SYMBOL_TREE) {
- protectScopeFromObfuscation(currentScope);
- warn("Using JScript conditional comments is not recommended." + (munge ? " Moreover, using JScript conditional comments reduces the level of compression!" : ""), true);
- }
- break;
-
- case Token.NAME:
- symbol = token.getValue();
-
- if (mode == BUILDING_SYMBOL_TREE) {
-
- if (symbol.equals("eval")) {
-
- protectScopeFromObfuscation(currentScope);
- warn("Using 'eval' is not recommended." + (munge ? " Moreover, using 'eval' reduces the level of compression!" : ""), true);
-
- }
-
- } else if (mode == CHECKING_SYMBOL_TREE) {
-
- if ((offset < 2 ||
- (getToken(-2).getType() != Token.DOT &&
- getToken(-2).getType() != Token.GET &&
- getToken(-2).getType() != Token.SET)) &&
- getToken(0).getType() != Token.OBJECTLIT) {
-
- identifier = getIdentifier(symbol, currentScope);
-
- if (identifier == null) {
-
- if (symbol.length() <= 3 && !builtin.contains(symbol)) {
- // Here, we found an undeclared and un-namespaced symbol that is
- // 3 characters or less in length. Declare it in the global scope.
- // We don't need to declare longer symbols since they won't cause
- // any conflict with other munged symbols.
- globalScope.declareIdentifier(symbol);
-
- // I removed the warning since was only being done when
- // for identifiers 3 chars or less, and was just causing
- // noise for people who happen to rely on an externally
- // declared variable that happen to be that short. We either
- // should always warn or never warn -- the fact that we
- // declare the short symbols in the global space doesn't
- // change anything.
- // warn("Found an undeclared symbol: " + symbol, true);
- }
-
- } else {
-
- identifier.incrementRefcount();
- }
- }
- }
- break;
- }
- }
- }
-
- private void parseScope(ScriptOrFnScope scope) {
-
- String symbol;
- JavaScriptToken token;
- JavaScriptIdentifier identifier;
-
- int length = tokens.size();
-
- enterScope(scope);
-
- while (offset < length) {
-
- token = consumeToken();
-
- switch (token.getType()) {
-
- case Token.VAR:
-
- if (mode == BUILDING_SYMBOL_TREE && scope.incrementVarCount() > 1) {
- warn("Try to use a single 'var' statement per scope.", true);
- }
-
- /* FALLSTHROUGH */
-
- case Token.CONST:
-
- // The var keyword is followed by at least one symbol name.
- // If several symbols follow, they are comma separated.
- for (; ;) {
- token = consumeToken();
-
- assert token.getType() == Token.NAME;
-
- if (mode == BUILDING_SYMBOL_TREE) {
- symbol = token.getValue();
- if (scope.getIdentifier(symbol) == null) {
- scope.declareIdentifier(symbol);
- } else {
- warn("The variable " + symbol + " has already been declared in the same scope...", true);
- }
- }
-
- token = getToken(0);
-
- assert token.getType() == Token.SEMI ||
- token.getType() == Token.ASSIGN ||
- token.getType() == Token.COMMA ||
- token.getType() == Token.IN;
-
- if (token.getType() == Token.IN) {
- break;
- } else {
- parseExpression();
- token = getToken(-1);
- if (token.getType() == Token.SEMI) {
- break;
- }
- }
- }
- break;
-
- case Token.FUNCTION:
- parseFunctionDeclaration();
- break;
-
- case Token.LC:
- braceNesting++;
- break;
-
- case Token.RC:
- braceNesting--;
- assert braceNesting >= scope.getBraceNesting();
- if (braceNesting == scope.getBraceNesting()) {
- leaveCurrentScope();
- return;
- }
- break;
-
- case Token.WITH:
- if (mode == BUILDING_SYMBOL_TREE) {
- // Inside a 'with' block, it is impossible to figure out
- // statically whether a symbol is a local variable or an
- // object member. As a consequence, the only thing we can
- // do is turn the obfuscation off for the highest scope
- // containing the 'with' block.
- protectScopeFromObfuscation(scope);
- warn("Using 'with' is not recommended." + (munge ? " Moreover, using 'with' reduces the level of compression!" : ""), true);
- }
- break;
-
- case Token.CATCH:
- parseCatch();
- break;
-
- case Token.CONDCOMMENT:
- if (mode == BUILDING_SYMBOL_TREE) {
- protectScopeFromObfuscation(scope);
- warn("Using JScript conditional comments is not recommended." + (munge ? " Moreover, using JScript conditional comments reduces the level of compression." : ""), true);
- }
- break;
-
- case Token.NAME:
- symbol = token.getValue();
-
- if (mode == BUILDING_SYMBOL_TREE) {
-
- if (symbol.equals("eval")) {
-
- protectScopeFromObfuscation(scope);
- warn("Using 'eval' is not recommended." + (munge ? " Moreover, using 'eval' reduces the level of compression!" : ""), true);
-
- }
-
- } else if (mode == CHECKING_SYMBOL_TREE) {
-
- if ((offset < 2 || getToken(-2).getType() != Token.DOT) &&
- getToken(0).getType() != Token.OBJECTLIT) {
-
- identifier = getIdentifier(symbol, scope);
-
- if (identifier == null) {
-
- if (symbol.length() <= 3 && !builtin.contains(symbol)) {
- // Here, we found an undeclared and un-namespaced symbol that is
- // 3 characters or less in length. Declare it in the global scope.
- // We don't need to declare longer symbols since they won't cause
- // any conflict with other munged symbols.
- globalScope.declareIdentifier(symbol);
- // warn("Found an undeclared symbol: " + symbol, true);
- }
-
- } else {
-
- identifier.incrementRefcount();
- }
- }
- }
- break;
- }
- }
- }
-
- private void buildSymbolTree() {
- offset = 0;
- braceNesting = 0;
- scopes.clear();
- indexedScopes.clear();
- indexedScopes.put(new Integer(0), globalScope);
- mode = BUILDING_SYMBOL_TREE;
- parseScope(globalScope);
- }
-
- private void mungeSymboltree() {
-
- if (!munge) {
- return;
- }
-
- // One problem with obfuscation resides in the use of undeclared
- // and un-namespaced global symbols that are 3 characters or less
- // in length. Here is an example:
- //
- // var declaredGlobalVar;
- //
- // function declaredGlobalFn() {
- // var localvar;
- // localvar = abc; // abc is an undeclared global symbol
- // }
- //
- // In the example above, there is a slim chance that localvar may be
- // munged to 'abc', conflicting with the undeclared global symbol
- // abc, creating a potential bug. The following code detects such
- // global symbols. This must be done AFTER the entire file has been
- // parsed, and BEFORE munging the symbol tree. Note that declaring
- // extra symbols in the global scope won't hurt.
- //
- // Note: Since we go through all the tokens to do this, we also use
- // the opportunity to count how many times each identifier is used.
-
- offset = 0;
- braceNesting = 0;
- scopes.clear();
- mode = CHECKING_SYMBOL_TREE;
- parseScope(globalScope);
- globalScope.munge();
- }
-
- private StringBuffer printSymbolTree(int linebreakpos, boolean preserveAllSemiColons)
- throws IOException {
-
- offset = 0;
- braceNesting = 0;
- scopes.clear();
-
- String symbol;
- JavaScriptToken token;
- JavaScriptToken lastToken = getToken(0);
- ScriptOrFnScope currentScope;
- JavaScriptIdentifier identifier;
-
- int length = tokens.size();
- StringBuffer result = new StringBuffer();
-
- int linestartpos = 0;
-
- enterScope(globalScope);
-
- while (offset < length) {
-
- token = consumeToken();
- symbol = token.getValue();
- currentScope = getCurrentScope();
- switch (token.getType()) {
- case Token.GET:
- case Token.SET:
- lastToken = token;
-
- case Token.NAME:
-
- if (offset >= 2 && getToken(-2).getType() == Token.DOT ||
- getToken(0).getType() == Token.OBJECTLIT) {
-
- result.append(symbol);
-
- } else {
-
- identifier = getIdentifier(symbol, currentScope);
- if (identifier != null) {
- if (identifier.getMungedValue() != null) {
- result.append(identifier.getMungedValue());
- } else {
- result.append(symbol);
- }
- if (currentScope != globalScope && identifier.getRefcount() == 0) {
- warn("The symbol " + symbol + " is declared but is apparently never used.\nThis code can probably be written in a more compact way.", true);
- }
- } else {
- result.append(symbol);
- }
- }
- break;
-
- case Token.REGEXP:
- case Token.STRING:
- result.append(symbol);
- break;
-
- case Token.NUMBER:
- if (getToken(0).getType() == Token.DOT) {
- // calling methods on int requires a leading dot so JS doesn't
- // treat the method as the decimal component of a float
- result.append('(');
- result.append(symbol);
- result.append(')');
- } else {
- result.append(symbol);
- }
- break;
-
- case Token.ADD:
- case Token.SUB:
- result.append((String) literals.get(new Integer(token.getType())));
- if (offset < length) {
- token = getToken(0);
- if (token.getType() == Token.INC ||
- token.getType() == Token.DEC ||
- token.getType() == Token.ADD ||
- token.getType() == Token.DEC) {
- // Handle the case x +/- ++/-- y
- // We must keep a white space here. Otherwise, x +++ y would be
- // interpreted as x ++ + y by the compiler, which is a bug (due
- // to the implicit assignment being done on the wrong variable)
- result.append(' ');
- } else if (token.getType() == Token.POS && getToken(-1).getType() == Token.ADD ||
- token.getType() == Token.NEG && getToken(-1).getType() == Token.SUB) {
- // Handle the case x + + y and x - - y
- result.append(' ');
- }
- }
- break;
-
- case Token.FUNCTION:
- if (lastToken.getType() != Token.GET && lastToken.getType() != Token.SET) {
- result.append("function");
- }
- lastToken = token;
- token = consumeToken();
- if (token.getType() == Token.NAME) {
- result.append(' ');
- symbol = token.getValue();
- identifier = getIdentifier(symbol, currentScope);
- assert identifier != null;
- if (identifier.getMungedValue() != null) {
- result.append(identifier.getMungedValue());
- } else {
- result.append(symbol);
- }
- if (currentScope != globalScope && identifier.getRefcount() == 0) {
- warn("The symbol " + symbol + " is declared but is apparently never used.\nThis code can probably be written in a more compact way.", true);
- }
- token = consumeToken();
- }
- assert token.getType() == Token.LP;
- result.append('(');
- currentScope = (ScriptOrFnScope) indexedScopes.get(new Integer(offset));
- enterScope(currentScope);
- while ((token = consumeToken()).getType() != Token.RP) {
- assert token.getType() == Token.NAME || token.getType() == Token.COMMA;
- if (token.getType() == Token.NAME) {
- symbol = token.getValue();
- identifier = getIdentifier(symbol, currentScope);
- assert identifier != null;
- if (identifier.getMungedValue() != null) {
- result.append(identifier.getMungedValue());
- } else {
- result.append(symbol);
- }
- } else if (token.getType() == Token.COMMA) {
- result.append(',');
- }
- }
- result.append(')');
- token = consumeToken();
- assert token.getType() == Token.LC;
- result.append('{');
- braceNesting++;
- token = getToken(0);
- if (token.getType() == Token.STRING &&
- getToken(1).getType() == Token.SEMI) {
- // This is a hint. Skip it!
- consumeToken();
- consumeToken();
- }
- break;
-
- case Token.RETURN:
- case Token.TYPEOF:
- result.append(literals.get(new Integer(token.getType())));
- // No space needed after 'return' and 'typeof' when followed
- // by '(', '[', '{', a string or a regexp.
- if (offset < length) {
- token = getToken(0);
- if (token.getType() != Token.LP &&
- token.getType() != Token.LB &&
- token.getType() != Token.LC &&
- token.getType() != Token.STRING &&
- token.getType() != Token.REGEXP &&
- token.getType() != Token.SEMI) {
- result.append(' ');
- }
- }
- break;
-
- case Token.CASE:
- case Token.THROW:
- result.append(literals.get(new Integer(token.getType())));
- // White-space needed after 'case' and 'throw' when not followed by a string.
- if (offset < length && getToken(0).getType() != Token.STRING) {
- result.append(' ');
- }
- break;
-
- case Token.BREAK:
- case Token.CONTINUE:
- result.append(literals.get(new Integer(token.getType())));
- if (offset < length && getToken(0).getType() != Token.SEMI) {
- // If 'break' or 'continue' is not followed by a semi-colon, it must
- // be followed by a label, hence the need for a white space.
- result.append(' ');
- }
- break;
-
- case Token.LC:
- result.append('{');
- braceNesting++;
- break;
-
- case Token.RC:
- result.append('}');
- braceNesting--;
- assert braceNesting >= currentScope.getBraceNesting();
- if (braceNesting == currentScope.getBraceNesting()) {
- leaveCurrentScope();
- }
- break;
-
- case Token.SEMI:
- // No need to output a semi-colon if the next character is a right-curly...
- if (preserveAllSemiColons || offset < length && getToken(0).getType() != Token.RC) {
- result.append(';');
- }
-
- if (linebreakpos >= 0 && result.length() - linestartpos > linebreakpos) {
- // Some source control tools don't like it when files containing lines longer
- // than, say 8000 characters, are checked in. The linebreak option is used in
- // that case to split long lines after a specific column.
- result.append('\n');
- linestartpos = result.length();
- }
- break;
-
- case Token.COMMA:
- // No need to output a comma if the next character is a right-curly or a right-square bracket
- if (offset < length && getToken(0).getType() != Token.RC && getToken(0).getType() != Token.RB) {
- result.append(',');
- }
- break;
-
- case Token.CONDCOMMENT:
- case Token.KEEPCOMMENT:
- if (result.length() > 0 && result.charAt(result.length() - 1) != '\n') {
- result.append("\n");
- }
- result.append("/*");
- if (token.getType() == Token.KEEPCOMMENT) {
- result.append("!");
- }
- result.append(symbol);
- result.append("*/\n");
- break;
-
- default:
- String literal = (String) literals.get(new Integer(token.getType()));
- if (literal != null) {
- result.append(literal);
- } else {
- warn("This symbol cannot be printed: " + symbol, true);
- }
- break;
- }
- }
-
- // Append a semi-colon at the end, even if unnecessary semi-colons are
- // supposed to be removed. This is especially useful when concatenating
- // several minified files (the absence of an ending semi-colon at the
- // end of one file may very likely cause a syntax error)
- if (!preserveAllSemiColons &&
- result.length() > 0 &&
- getToken(-1).getType() != Token.CONDCOMMENT &&
- getToken(-1).getType() != Token.KEEPCOMMENT) {
- if (result.charAt(result.length() - 1) == '\n') {
- result.setCharAt(result.length() - 1, ';');
- } else {
- result.append(';');
- }
- }
-
- return result;
- }
-
- private void printMungeMapping(Writer map) throws IOException {
- StringBuffer sb = new StringBuffer();
- globalScope.getFullMapping(sb, "");
- map.write(sb.toString());
- }
-}
diff --git a/src/com/yahoo/platform/yui/compressor/JavaScriptIdentifier.java b/src/com/yahoo/platform/yui/compressor/JavaScriptIdentifier.java
deleted file mode 100644
index 1ac3ac11..00000000
--- a/src/com/yahoo/platform/yui/compressor/JavaScriptIdentifier.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * YUI Compressor
- * http://developer.yahoo.com/yui/compressor/
- * Author: Julien Lecomte - http://www.julienlecomte.net/
- * Copyright (c) 2011 Yahoo! Inc. All rights reserved.
- * The copyrights embodied in the content of this file are licensed
- * by Yahoo! Inc. under the BSD (revised) open source license.
- */
-package com.yahoo.platform.yui.compressor;
-
-import org.mozilla.javascript.Token;
-
-/**
- * JavaScriptIdentifier represents a variable/function identifier.
- */
-class JavaScriptIdentifier extends JavaScriptToken {
-
- private int refcount = 0;
- private String mungedValue;
- private ScriptOrFnScope declaredScope;
- private boolean markedForMunging = true;
-
- JavaScriptIdentifier(String value, ScriptOrFnScope declaredScope) {
- super(Token.NAME, value);
- this.declaredScope = declaredScope;
- }
-
- ScriptOrFnScope getDeclaredScope() {
- return declaredScope;
- }
-
- void setMungedValue(String value) {
- mungedValue = value;
- }
-
- String getMungedValue() {
- return mungedValue;
- }
-
- void preventMunging() {
- markedForMunging = false;
- }
-
- boolean isMarkedForMunging() {
- return markedForMunging;
- }
-
- void incrementRefcount() {
- refcount++;
- }
-
- int getRefcount() {
- return refcount;
- }
-}
diff --git a/src/com/yahoo/platform/yui/compressor/JavaScriptToken.java b/src/com/yahoo/platform/yui/compressor/JavaScriptToken.java
deleted file mode 100644
index 52baaf05..00000000
--- a/src/com/yahoo/platform/yui/compressor/JavaScriptToken.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * YUI Compressor
- * http://developer.yahoo.com/yui/compressor/
- * Author: Julien Lecomte - http://www.julienlecomte.net/
- * Copyright (c) 2011 Yahoo! Inc. All rights reserved.
- * The copyrights embodied in the content of this file are licensed
- * by Yahoo! Inc. under the BSD (revised) open source license.
- */
-package com.yahoo.platform.yui.compressor;
-
-public class JavaScriptToken {
-
- private int type;
- private String value;
-
- JavaScriptToken(int type, String value) {
- this.type = type;
- this.value = value;
- }
-
- int getType() {
- return type;
- }
-
- String getValue() {
- return value;
- }
-}
diff --git a/src/com/yahoo/platform/yui/compressor/ScriptOrFnScope.java b/src/com/yahoo/platform/yui/compressor/ScriptOrFnScope.java
deleted file mode 100644
index 4b7b836b..00000000
--- a/src/com/yahoo/platform/yui/compressor/ScriptOrFnScope.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * YUI Compressor
- * http://developer.yahoo.com/yui/compressor/
- * Author: Julien Lecomte - http://www.julienlecomte.net/
- * Copyright (c) 2011 Yahoo! Inc. All rights reserved.
- * The copyrights embodied in the content of this file are licensed
- * by Yahoo! Inc. under the BSD (revised) open source license.
- */
-package com.yahoo.platform.yui.compressor;
-
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.Hashtable;
-
-class ScriptOrFnScope {
-
- private int braceNesting;
- private ScriptOrFnScope parentScope;
- private ArrayList subScopes;
- private Hashtable identifiers = new Hashtable();
- private Hashtable hints = new Hashtable();
- private boolean markedForMunging = true;
- private int varcount = 0;
-
- ScriptOrFnScope(int braceNesting, ScriptOrFnScope parentScope) {
- this.braceNesting = braceNesting;
- this.parentScope = parentScope;
- this.subScopes = new ArrayList();
- if (parentScope != null) {
- parentScope.subScopes.add(this);
- }
- }
-
- int getBraceNesting() {
- return braceNesting;
- }
-
- ScriptOrFnScope getParentScope() {
- return parentScope;
- }
-
- JavaScriptIdentifier declareIdentifier(String symbol) {
- JavaScriptIdentifier identifier = (JavaScriptIdentifier) identifiers.get(symbol);
- if (identifier == null) {
- identifier = new JavaScriptIdentifier(symbol, this);
- identifiers.put(symbol, identifier);
- }
- return identifier;
- }
-
- JavaScriptIdentifier getIdentifier(String symbol) {
- return (JavaScriptIdentifier) identifiers.get(symbol);
- }
-
- void addHint(String variableName, String variableType) {
- hints.put(variableName, variableType);
- }
-
- void preventMunging() {
- if (parentScope != null) {
- // The symbols in the global scope don't get munged,
- // but the sub-scopes it contains do get munged.
- markedForMunging = false;
- }
- }
-
- private ArrayList getUsedSymbols() {
- ArrayList result = new ArrayList();
- Enumeration elements = identifiers.elements();
- while (elements.hasMoreElements()) {
- JavaScriptIdentifier identifier = (JavaScriptIdentifier) elements.nextElement();
- String mungedValue = identifier.getMungedValue();
- if (mungedValue == null) {
- mungedValue = identifier.getValue();
- }
- result.add(mungedValue);
- }
- return result;
- }
-
- private ArrayList getAllUsedSymbols() {
- ArrayList result = new ArrayList();
- ScriptOrFnScope scope = this;
- while (scope != null) {
- result.addAll(scope.getUsedSymbols());
- scope = scope.parentScope;
- }
- return result;
- }
-
- int incrementVarCount() {
- varcount++;
- return varcount;
- }
-
- public void getFullMapping(StringBuffer outBuffer, String mungedPrefix) {
- Enumeration elements = identifiers.elements();
- while (elements.hasMoreElements()) {
- JavaScriptIdentifier identifier = (JavaScriptIdentifier) elements.nextElement();
- String mungedValue = identifier.getMungedValue();
- if (mungedValue == null) {
- mungedValue = identifier.getValue();
- }
- outBuffer.append(mungedPrefix + mungedValue);
- outBuffer.append(": ");
- outBuffer.append(identifier.getValue() + "\n");
- }
-
- for (int i = 0; i < subScopes.size(); i++) {
- ScriptOrFnScope scope = (ScriptOrFnScope) subScopes.get(i);
- scope.getFullMapping(outBuffer, "\t"+mungedPrefix);
- }
- }
-
- void munge() {
-
- if (!markedForMunging) {
- // Stop right here if this scope was flagged as unsafe for munging.
- return;
- }
-
- int pickFromSet = 1;
-
- // Do not munge symbols in the global scope!
- if (parentScope != null) {
-
- ArrayList freeSymbols = new ArrayList();
-
- freeSymbols.addAll(JavaScriptCompressor.ones);
- freeSymbols.removeAll(getAllUsedSymbols());
- if (freeSymbols.size() == 0) {
- pickFromSet = 2;
- freeSymbols.addAll(JavaScriptCompressor.twos);
- freeSymbols.removeAll(getAllUsedSymbols());
- }
- if (freeSymbols.size() == 0) {
- pickFromSet = 3;
- freeSymbols.addAll(JavaScriptCompressor.threes);
- freeSymbols.removeAll(getAllUsedSymbols());
- }
- if (freeSymbols.size() == 0) {
- throw new IllegalStateException("The YUI Compressor ran out of symbols. Aborting...");
- }
-
- Enumeration elements = identifiers.elements();
- while (elements.hasMoreElements()) {
- if (freeSymbols.size() == 0) {
- pickFromSet++;
- if (pickFromSet == 2) {
- freeSymbols.addAll(JavaScriptCompressor.twos);
- } else if (pickFromSet == 3) {
- freeSymbols.addAll(JavaScriptCompressor.threes);
- } else {
- throw new IllegalStateException("The YUI Compressor ran out of symbols. Aborting...");
- }
- // It is essential to remove the symbols already used in
- // the containing scopes, or some of the variables declared
- // in the containing scopes will be redeclared, which can
- // lead to errors.
- freeSymbols.removeAll(getAllUsedSymbols());
- }
-
- String mungedValue;
- JavaScriptIdentifier identifier = (JavaScriptIdentifier) elements.nextElement();
- if (identifier.isMarkedForMunging()) {
- mungedValue = (String) freeSymbols.remove(0);
- } else {
- mungedValue = identifier.getValue();
- }
- identifier.setMungedValue(mungedValue);
- }
- }
-
- for (int i = 0; i < subScopes.size(); i++) {
- ScriptOrFnScope scope = (ScriptOrFnScope) subScopes.get(i);
- scope.munge();
- }
- }
-}
diff --git a/src/com/yahoo/platform/yui/compressor/YUICompressor.java b/src/com/yahoo/platform/yui/compressor/YUICompressor.java
index 6342563a..7c688a83 100644
--- a/src/com/yahoo/platform/yui/compressor/YUICompressor.java
+++ b/src/com/yahoo/platform/yui/compressor/YUICompressor.java
@@ -9,8 +9,6 @@
package com.yahoo.platform.yui.compressor;
import jargs.gnu.CmdLineParser;
-import org.mozilla.javascript.ErrorReporter;
-import org.mozilla.javascript.EvaluatorException;
import java.io.*;
import java.nio.charset.Charset;
@@ -111,7 +109,7 @@ public static void main(String args[]) {
} else {
pattern = output.split(":");
}
-
+
try {
String mungemapFilename = (String) parser.getOptionValue(mungemapFilenameOpt);
if (mungemapFilename != null) {
@@ -158,65 +156,7 @@ public static void main(String args[]) {
outputFilename = inputFilename.replaceFirst(pattern[0], pattern[1]);
}
- if (type.equalsIgnoreCase("js")) {
-
- try {
- final String localFilename = inputFilename;
-
- JavaScriptCompressor compressor = new JavaScriptCompressor(in, new ErrorReporter() {
-
- public void warning(String message, String sourceName,
- int line, String lineSource, int lineOffset) {
- System.err.println("\n[WARNING] in " + localFilename);
- if (line < 0) {
- System.err.println(" " + message);
- } else {
- System.err.println(" " + line + ':' + lineOffset + ':' + message);
- }
- }
-
- public void error(String message, String sourceName,
- int line, String lineSource, int lineOffset) {
- System.err.println("[ERROR] in " + localFilename);
- if (line < 0) {
- System.err.println(" " + message);
- } else {
- System.err.println(" " + line + ':' + lineOffset + ':' + message);
- }
- }
-
- public EvaluatorException runtimeError(String message, String sourceName,
- int line, String lineSource, int lineOffset) {
- error(message, sourceName, line, lineSource, lineOffset);
- return new EvaluatorException(message);
- }
- });
-
- // Close the input stream first, and then open the output stream,
- // in case the output file should override the input file.
- in.close(); in = null;
-
- if (outputFilename == null) {
- out = new OutputStreamWriter(System.out, charset);
- } else {
- out = new OutputStreamWriter(new FileOutputStream(outputFilename), charset);
- if (mungemap != null) {
- mungemap.write("\n\nFile: "+outputFilename+"\n\n");
- }
- }
-
- compressor.compress(out, mungemap, linebreakpos, munge, verbose,
- preserveAllSemiColons, disableOptimizations);
-
- } catch (EvaluatorException e) {
-
- e.printStackTrace();
- // Return a special error code used specifically by the web front-end.
- System.exit(2);
-
- }
-
- } else if (type.equalsIgnoreCase("css")) {
+ if (type.equalsIgnoreCase("css")) {
CssCompressor compressor = new CssCompressor(in);
diff --git a/src/org/mozilla/javascript/Decompiler.java b/src/org/mozilla/javascript/Decompiler.java
deleted file mode 100644
index 3b4b903f..00000000
--- a/src/org/mozilla/javascript/Decompiler.java
+++ /dev/null
@@ -1,916 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- *
- * Version: MPL 1.1
- *
- * 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 org/mozilla/javascript/Decompiler.java,
- * a component of the Rhino Library ( http://www.mozilla.org/rhino/ )
- * This file is a modification of the Original Code developed
- * for YUI Compressor.
- *
- * The Initial Developer of the Original Code is Mozilla Foundation
- *
- * Copyright (c) 2009 Mozilla Foundation. All Rights Reserved.
- *
- * Contributor(s): Yahoo! Inc. 2009
- *
- * ***** END LICENSE BLOCK ***** */
-
-package org.mozilla.javascript;
-
-/**
- * The following class save decompilation information about the source.
- * Source information is returned from the parser as a String
- * associated with function nodes and with the toplevel script. When
- * saved in the constant pool of a class, this string will be UTF-8
- * encoded, and token values will occupy a single byte.
-
- * Source is saved (mostly) as token numbers. The tokens saved pretty
- * much correspond to the token stream of a 'canonical' representation
- * of the input program, as directed by the parser. (There were a few
- * cases where tokens could have been left out where decompiler could
- * easily reconstruct them, but I left them in for clarity). (I also
- * looked adding source collection to TokenStream instead, where I
- * could have limited the changes to a few lines in getToken... but
- * this wouldn't have saved any space in the resulting source
- * representation, and would have meant that I'd have to duplicate
- * parser logic in the decompiler to disambiguate situations where
- * newlines are important.) The function decompile expands the
- * tokens back into their string representations, using simple
- * lookahead to correct spacing and indentation.
- *
- * Assignments are saved as two-token pairs (Token.ASSIGN, op). Number tokens
- * are stored inline, as a NUMBER token, a character representing the type, and
- * either 1 or 4 characters representing the bit-encoding of the number. String
- * types NAME, STRING and OBJECT are currently stored as a token type,
- * followed by a character giving the length of the string (assumed to
- * be less than 2^16), followed by the characters of the string
- * inlined into the source string. Changing this to some reference to
- * to the string in the compiled class' constant pool would probably
- * save a lot of space... but would require some method of deriving
- * the final constant pool entry from information available at parse
- * time.
- */
-public class Decompiler
-{
- /**
- * Flag to indicate that the decompilation should omit the
- * function header and trailing brace.
- */
- public static final int ONLY_BODY_FLAG = 1 << 0;
-
- /**
- * Flag to indicate that the decompilation generates toSource result.
- */
- public static final int TO_SOURCE_FLAG = 1 << 1;
-
- /**
- * Decompilation property to specify initial ident value.
- */
- public static final int INITIAL_INDENT_PROP = 1;
-
- /**
- * Decompilation property to specify default identation offset.
- */
- public static final int INDENT_GAP_PROP = 2;
-
- /**
- * Decompilation property to specify identation offset for case labels.
- */
- public static final int CASE_GAP_PROP = 3;
-
- // Marker to denote the last RC of function so it can be distinguished from
- // the last RC of object literals in case of function expressions
- private static final int FUNCTION_END = Token.LAST_TOKEN + 1;
-
- String getEncodedSource()
- {
- return sourceToString(0);
- }
-
- int getCurrentOffset()
- {
- return sourceTop;
- }
-
- int markFunctionStart(int functionType)
- {
- int savedOffset = getCurrentOffset();
- addToken(Token.FUNCTION);
- append((char)functionType);
- return savedOffset;
- }
-
- int markFunctionEnd(int functionStart)
- {
- int offset = getCurrentOffset();
- append((char)FUNCTION_END);
- return offset;
- }
-
- void addToken(int token)
- {
- if (!(0 <= token && token <= Token.LAST_TOKEN))
- throw new IllegalArgumentException();
-
- append((char)token);
- }
-
- void addEOL(int token)
- {
- if (!(0 <= token && token <= Token.LAST_TOKEN))
- throw new IllegalArgumentException();
-
- append((char)token);
- append((char)Token.EOL);
- }
-
- void addName(String str)
- {
- addToken(Token.NAME);
- appendString(str);
- }
-
- void addString(String str)
- {
- addToken(Token.STRING);
- appendString(str);
- }
-
- void addRegexp(String regexp, String flags)
- {
- addToken(Token.REGEXP);
- appendString('/' + regexp + '/' + flags);
- }
-
- void addJScriptConditionalComment(String str)
- {
- addToken(Token.CONDCOMMENT);
- appendString(str);
- }
-
- void addPreservedComment(String str)
- {
- addToken(Token.KEEPCOMMENT);
- appendString(str);
- }
-
- void addNumber(double n)
- {
- addToken(Token.NUMBER);
-
- /* encode the number in the source stream.
- * Save as NUMBER type (char | char char char char)
- * where type is
- * 'D' - double, 'S' - short, 'J' - long.
-
- * We need to retain float vs. integer type info to keep the
- * behavior of liveconnect type-guessing the same after
- * decompilation. (Liveconnect tries to present 1.0 to Java
- * as a float/double)
- * OPT: This is no longer true. We could compress the format.
-
- * This may not be the most space-efficient encoding;
- * the chars created below may take up to 3 bytes in
- * constant pool UTF-8 encoding, so a Double could take
- * up to 12 bytes.
- */
-
- long lbits = (long)n;
- if (lbits != n) {
- // if it's floating point, save as a Double bit pattern.
- // (12/15/97 our scanner only returns Double for f.p.)
- lbits = Double.doubleToLongBits(n);
- append('D');
- append((char)(lbits >> 48));
- append((char)(lbits >> 32));
- append((char)(lbits >> 16));
- append((char)lbits);
- }
- else {
- // we can ignore negative values, bc they're already prefixed
- // by NEG
- if (lbits < 0) Kit.codeBug();
-
- // will it fit in a char?
- // this gives a short encoding for integer values up to 2^16.
- if (lbits <= Character.MAX_VALUE) {
- append('S');
- append((char)lbits);
- }
- else { // Integral, but won't fit in a char. Store as a long.
- append('J');
- append((char)(lbits >> 48));
- append((char)(lbits >> 32));
- append((char)(lbits >> 16));
- append((char)lbits);
- }
- }
- }
-
- private void appendString(String str)
- {
- int L = str.length();
- int lengthEncodingSize = 1;
- if (L >= 0x8000) {
- lengthEncodingSize = 2;
- }
- int nextTop = sourceTop + lengthEncodingSize + L;
- if (nextTop > sourceBuffer.length) {
- increaseSourceCapacity(nextTop);
- }
- if (L >= 0x8000) {
- // Use 2 chars to encode strings exceeding 32K, were the highest
- // bit in the first char indicates presence of the next byte
- sourceBuffer[sourceTop] = (char)(0x8000 | (L >>> 16));
- ++sourceTop;
- }
- sourceBuffer[sourceTop] = (char)L;
- ++sourceTop;
- str.getChars(0, L, sourceBuffer, sourceTop);
- sourceTop = nextTop;
- }
-
- private void append(char c)
- {
- if (sourceTop == sourceBuffer.length) {
- increaseSourceCapacity(sourceTop + 1);
- }
- sourceBuffer[sourceTop] = c;
- ++sourceTop;
- }
-
- private void increaseSourceCapacity(int minimalCapacity)
- {
- // Call this only when capacity increase is must
- if (minimalCapacity <= sourceBuffer.length) Kit.codeBug();
- int newCapacity = sourceBuffer.length * 2;
- if (newCapacity < minimalCapacity) {
- newCapacity = minimalCapacity;
- }
- char[] tmp = new char[newCapacity];
- System.arraycopy(sourceBuffer, 0, tmp, 0, sourceTop);
- sourceBuffer = tmp;
- }
-
- private String sourceToString(int offset)
- {
- if (offset < 0 || sourceTop < offset) Kit.codeBug();
- return new String(sourceBuffer, offset, sourceTop - offset);
- }
-
- /**
- * Decompile the source information associated with this js
- * function/script back into a string. For the most part, this
- * just means translating tokens back to their string
- * representations; there's a little bit of lookahead logic to
- * decide the proper spacing/indentation. Most of the work in
- * mapping the original source to the prettyprinted decompiled
- * version is done by the parser.
- *
- * @param source encoded source tree presentation
- *
- * @param flags flags to select output format
- *
- * @param properties indentation properties
- *
- */
- public static String decompile(String source, int flags,
- UintMap properties)
- {
- int length = source.length();
- if (length == 0) { return ""; }
-
- int indent = properties.getInt(INITIAL_INDENT_PROP, 0);
- if (indent < 0) throw new IllegalArgumentException();
- int indentGap = properties.getInt(INDENT_GAP_PROP, 4);
- if (indentGap < 0) throw new IllegalArgumentException();
- int caseGap = properties.getInt(CASE_GAP_PROP, 2);
- if (caseGap < 0) throw new IllegalArgumentException();
-
- StringBuffer result = new StringBuffer();
- boolean justFunctionBody = (0 != (flags & Decompiler.ONLY_BODY_FLAG));
- boolean toSource = (0 != (flags & Decompiler.TO_SOURCE_FLAG));
-
- // Spew tokens in source, for debugging.
- // as TYPE number char
- if (printSource) {
- System.err.println("length:" + length);
- for (int i = 0; i < length; ++i) {
- // Note that tokenToName will fail unless Context.printTrees
- // is true.
- String tokenname = null;
- if (Token.printNames) {
- tokenname = Token.name(source.charAt(i));
- }
- if (tokenname == null) {
- tokenname = "---";
- }
- String pad = tokenname.length() > 7
- ? "\t"
- : "\t\t";
- System.err.println
- (tokenname
- + pad + (int)source.charAt(i)
- + "\t'" + ScriptRuntime.escapeString
- (source.substring(i, i+1))
- + "'");
- }
- System.err.println();
- }
-
- int braceNesting = 0;
- boolean afterFirstEOL = false;
- int i = 0;
- int topFunctionType;
- if (source.charAt(i) == Token.SCRIPT) {
- ++i;
- topFunctionType = -1;
- } else {
- topFunctionType = source.charAt(i + 1);
- }
-
- if (!toSource) {
- // add an initial newline to exactly match js.
- result.append('\n');
- for (int j = 0; j < indent; j++)
- result.append(' ');
- } else {
- if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION) {
- result.append('(');
- }
- }
-
- while (i < length) {
- switch(source.charAt(i)) {
- case Token.GET:
- case Token.SET:
- result.append(source.charAt(i) == Token.GET ? "get " : "set ");
- ++i;
- i = printSourceString(source, i + 1, false, result);
- // Now increment one more to get past the FUNCTION token
- ++i;
- break;
-
- case Token.NAME:
- case Token.REGEXP: // re-wrapped in '/'s in parser...
- i = printSourceString(source, i + 1, false, result);
- continue;
-
- case Token.STRING:
- i = printSourceString(source, i + 1, true, result);
- continue;
-
- case Token.NUMBER:
- i = printSourceNumber(source, i + 1, result);
- continue;
-
- case Token.TRUE:
- result.append("true");
- break;
-
- case Token.FALSE:
- result.append("false");
- break;
-
- case Token.NULL:
- result.append("null");
- break;
-
- case Token.THIS:
- result.append("this");
- break;
-
- case Token.FUNCTION:
- ++i; // skip function type
- result.append("function ");
- break;
-
- case FUNCTION_END:
- // Do nothing
- break;
-
- case Token.COMMA:
- result.append(", ");
- break;
-
- case Token.LC:
- ++braceNesting;
- if (Token.EOL == getNext(source, length, i))
- indent += indentGap;
- result.append('{');
- break;
-
- case Token.RC: {
- --braceNesting;
- /* don't print the closing RC if it closes the
- * toplevel function and we're called from
- * decompileFunctionBody.
- */
- if (justFunctionBody && braceNesting == 0)
- break;
-
- result.append('}');
- switch (getNext(source, length, i)) {
- case Token.EOL:
- case FUNCTION_END:
- indent -= indentGap;
- break;
- case Token.WHILE:
- case Token.ELSE:
- indent -= indentGap;
- result.append(' ');
- break;
- }
- break;
- }
- case Token.LP:
- result.append('(');
- break;
-
- case Token.RP:
- result.append(')');
- if (Token.LC == getNext(source, length, i))
- result.append(' ');
- break;
-
- case Token.LB:
- result.append('[');
- break;
-
- case Token.RB:
- result.append(']');
- break;
-
- case Token.EOL: {
- if (toSource) break;
- boolean newLine = true;
- if (!afterFirstEOL) {
- afterFirstEOL = true;
- if (justFunctionBody) {
- /* throw away just added 'function name(...) {'
- * and restore the original indent
- */
- result.setLength(0);
- indent -= indentGap;
- newLine = false;
- }
- }
- if (newLine) {
- result.append('\n');
- }
-
- /* add indent if any tokens remain,
- * less setback if next token is
- * a label, case or default.
- */
- if (i + 1 < length) {
- int less = 0;
- int nextToken = source.charAt(i + 1);
- if (nextToken == Token.CASE
- || nextToken == Token.DEFAULT)
- {
- less = indentGap - caseGap;
- } else if (nextToken == Token.RC) {
- less = indentGap;
- }
-
- /* elaborate check against label... skip past a
- * following inlined NAME and look for a COLON.
- */
- else if (nextToken == Token.NAME) {
- int afterName = getSourceStringEnd(source, i + 2);
- if (source.charAt(afterName) == Token.COLON)
- less = indentGap;
- }
-
- for (; less < indent; less++)
- result.append(' ');
- }
- break;
- }
- case Token.DOT:
- result.append('.');
- break;
-
- case Token.NEW:
- result.append("new ");
- break;
-
- case Token.DELPROP:
- result.append("delete ");
- break;
-
- case Token.IF:
- result.append("if ");
- break;
-
- case Token.ELSE:
- result.append("else ");
- break;
-
- case Token.FOR:
- result.append("for ");
- break;
-
- case Token.IN:
- result.append(" in ");
- break;
-
- case Token.WITH:
- result.append("with ");
- break;
-
- case Token.WHILE:
- result.append("while ");
- break;
-
- case Token.DO:
- result.append("do ");
- break;
-
- case Token.TRY:
- result.append("try ");
- break;
-
- case Token.CATCH:
- result.append("catch ");
- break;
-
- case Token.FINALLY:
- result.append("finally ");
- break;
-
- case Token.THROW:
- result.append("throw ");
- break;
-
- case Token.SWITCH:
- result.append("switch ");
- break;
-
- case Token.BREAK:
- result.append("break");
- if (Token.NAME == getNext(source, length, i))
- result.append(' ');
- break;
-
- case Token.CONTINUE:
- result.append("continue");
- if (Token.NAME == getNext(source, length, i))
- result.append(' ');
- break;
-
- case Token.CASE:
- result.append("case ");
- break;
-
- case Token.DEFAULT:
- result.append("default");
- break;
-
- case Token.RETURN:
- result.append("return");
- if (Token.SEMI != getNext(source, length, i))
- result.append(' ');
- break;
-
- case Token.VAR:
- result.append("var ");
- break;
-
- case Token.LET:
- result.append("let ");
- break;
-
- case Token.SEMI:
- result.append(';');
- if (Token.EOL != getNext(source, length, i)) {
- // separators in FOR
- result.append(' ');
- }
- break;
-
- case Token.ASSIGN:
- result.append(" = ");
- break;
-
- case Token.ASSIGN_ADD:
- result.append(" += ");
- break;
-
- case Token.ASSIGN_SUB:
- result.append(" -= ");
- break;
-
- case Token.ASSIGN_MUL:
- result.append(" *= ");
- break;
-
- case Token.ASSIGN_DIV:
- result.append(" /= ");
- break;
-
- case Token.ASSIGN_MOD:
- result.append(" %= ");
- break;
-
- case Token.ASSIGN_BITOR:
- result.append(" |= ");
- break;
-
- case Token.ASSIGN_BITXOR:
- result.append(" ^= ");
- break;
-
- case Token.ASSIGN_BITAND:
- result.append(" &= ");
- break;
-
- case Token.ASSIGN_LSH:
- result.append(" <<= ");
- break;
-
- case Token.ASSIGN_RSH:
- result.append(" >>= ");
- break;
-
- case Token.ASSIGN_URSH:
- result.append(" >>>= ");
- break;
-
- case Token.HOOK:
- result.append(" ? ");
- break;
-
- case Token.OBJECTLIT:
- // pun OBJECTLIT to mean colon in objlit property
- // initialization.
- // This needs to be distinct from COLON in the general case
- // to distinguish from the colon in a ternary... which needs
- // different spacing.
- result.append(':');
- break;
-
- case Token.COLON:
- if (Token.EOL == getNext(source, length, i))
- // it's the end of a label
- result.append(':');
- else
- // it's the middle part of a ternary
- result.append(" : ");
- break;
-
- case Token.OR:
- result.append(" || ");
- break;
-
- case Token.AND:
- result.append(" && ");
- break;
-
- case Token.BITOR:
- result.append(" | ");
- break;
-
- case Token.BITXOR:
- result.append(" ^ ");
- break;
-
- case Token.BITAND:
- result.append(" & ");
- break;
-
- case Token.SHEQ:
- result.append(" === ");
- break;
-
- case Token.SHNE:
- result.append(" !== ");
- break;
-
- case Token.EQ:
- result.append(" == ");
- break;
-
- case Token.NE:
- result.append(" != ");
- break;
-
- case Token.LE:
- result.append(" <= ");
- break;
-
- case Token.LT:
- result.append(" < ");
- break;
-
- case Token.GE:
- result.append(" >= ");
- break;
-
- case Token.GT:
- result.append(" > ");
- break;
-
- case Token.INSTANCEOF:
- result.append(" instanceof ");
- break;
-
- case Token.LSH:
- result.append(" << ");
- break;
-
- case Token.RSH:
- result.append(" >> ");
- break;
-
- case Token.URSH:
- result.append(" >>> ");
- break;
-
- case Token.TYPEOF:
- result.append("typeof ");
- break;
-
- case Token.VOID:
- result.append("void ");
- break;
-
- case Token.CONST:
- result.append("const ");
- break;
-
- case Token.YIELD:
- result.append("yield ");
- break;
-
- case Token.NOT:
- result.append('!');
- break;
-
- case Token.BITNOT:
- result.append('~');
- break;
-
- case Token.POS:
- result.append('+');
- break;
-
- case Token.NEG:
- result.append('-');
- break;
-
- case Token.INC:
- result.append("++");
- break;
-
- case Token.DEC:
- result.append("--");
- break;
-
- case Token.ADD:
- result.append(" + ");
- break;
-
- case Token.SUB:
- result.append(" - ");
- break;
-
- case Token.MUL:
- result.append(" * ");
- break;
-
- case Token.DIV:
- result.append(" / ");
- break;
-
- case Token.MOD:
- result.append(" % ");
- break;
-
- case Token.COLONCOLON:
- result.append("::");
- break;
-
- case Token.DOTDOT:
- result.append("..");
- break;
-
- case Token.DOTQUERY:
- result.append(".(");
- break;
-
- case Token.XMLATTR:
- result.append('@');
- break;
-
- default:
- // If we don't know how to decompile it, raise an exception.
- throw new RuntimeException("Token: " +
- Token.name(source.charAt(i)));
- }
- ++i;
- }
-
- if (!toSource) {
- // add that trailing newline if it's an outermost function.
- if (!justFunctionBody)
- result.append('\n');
- } else {
- if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION) {
- result.append(')');
- }
- }
-
- return result.toString();
- }
-
- private static int getNext(String source, int length, int i)
- {
- return (i + 1 < length) ? source.charAt(i + 1) : Token.EOF;
- }
-
- private static int getSourceStringEnd(String source, int offset)
- {
- return printSourceString(source, offset, false, null);
- }
-
- private static int printSourceString(String source, int offset,
- boolean asQuotedString,
- StringBuffer sb)
- {
- int length = source.charAt(offset);
- ++offset;
- if ((0x8000 & length) != 0) {
- length = ((0x7FFF & length) << 16) | source.charAt(offset);
- ++offset;
- }
- if (sb != null) {
- String str = source.substring(offset, offset + length);
- if (!asQuotedString) {
- sb.append(str);
- } else {
- sb.append('"');
- sb.append(ScriptRuntime.escapeString(str));
- sb.append('"');
- }
- }
- return offset + length;
- }
-
- private static int printSourceNumber(String source, int offset,
- StringBuffer sb)
- {
- double number = 0.0;
- char type = source.charAt(offset);
- ++offset;
- if (type == 'S') {
- if (sb != null) {
- int ival = source.charAt(offset);
- number = ival;
- }
- ++offset;
- } else if (type == 'J' || type == 'D') {
- if (sb != null) {
- long lbits;
- lbits = (long)source.charAt(offset) << 48;
- lbits |= (long)source.charAt(offset + 1) << 32;
- lbits |= (long)source.charAt(offset + 2) << 16;
- lbits |= source.charAt(offset + 3);
- if (type == 'J') {
- number = lbits;
- } else {
- number = Double.longBitsToDouble(lbits);
- }
- }
- offset += 4;
- } else {
- // Bad source
- throw new RuntimeException();
- }
- if (sb != null) {
- sb.append(ScriptRuntime.numberToString(number, 10));
- }
- return offset;
- }
-
- private char[] sourceBuffer = new char[128];
-
-// Per script/function source buffer top: parent source does not include a
-// nested functions source and uses function index as a reference instead.
- private int sourceTop;
-
-// whether to do a debug print of the source information, when decompiling.
- private static final boolean printSource = false;
-
-}
diff --git a/src/org/mozilla/javascript/Decompiler.java.orig b/src/org/mozilla/javascript/Decompiler.java.orig
deleted file mode 100644
index cdb00b76..00000000
--- a/src/org/mozilla/javascript/Decompiler.java.orig
+++ /dev/null
@@ -1,910 +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
- * Bob Jervis
- * Mike McCabe
- *
- * 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;
-
-/**
- * The following class save decompilation information about the source.
- * Source information is returned from the parser as a String
- * associated with function nodes and with the toplevel script. When
- * saved in the constant pool of a class, this string will be UTF-8
- * encoded, and token values will occupy a single byte.
-
- * Source is saved (mostly) as token numbers. The tokens saved pretty
- * much correspond to the token stream of a 'canonical' representation
- * of the input program, as directed by the parser. (There were a few
- * cases where tokens could have been left out where decompiler could
- * easily reconstruct them, but I left them in for clarity). (I also
- * looked adding source collection to TokenStream instead, where I
- * could have limited the changes to a few lines in getToken... but
- * this wouldn't have saved any space in the resulting source
- * representation, and would have meant that I'd have to duplicate
- * parser logic in the decompiler to disambiguate situations where
- * newlines are important.) The function decompile expands the
- * tokens back into their string representations, using simple
- * lookahead to correct spacing and indentation.
- *
- * Assignments are saved as two-token pairs (Token.ASSIGN, op). Number tokens
- * are stored inline, as a NUMBER token, a character representing the type, and
- * either 1 or 4 characters representing the bit-encoding of the number. String
- * types NAME, STRING and OBJECT are currently stored as a token type,
- * followed by a character giving the length of the string (assumed to
- * be less than 2^16), followed by the characters of the string
- * inlined into the source string. Changing this to some reference to
- * to the string in the compiled class' constant pool would probably
- * save a lot of space... but would require some method of deriving
- * the final constant pool entry from information available at parse
- * time.
- */
-public class Decompiler
-{
- /**
- * Flag to indicate that the decompilation should omit the
- * function header and trailing brace.
- */
- public static final int ONLY_BODY_FLAG = 1 << 0;
-
- /**
- * Flag to indicate that the decompilation generates toSource result.
- */
- public static final int TO_SOURCE_FLAG = 1 << 1;
-
- /**
- * Decompilation property to specify initial ident value.
- */
- public static final int INITIAL_INDENT_PROP = 1;
-
- /**
- * Decompilation property to specify default identation offset.
- */
- public static final int INDENT_GAP_PROP = 2;
-
- /**
- * Decompilation property to specify identation offset for case labels.
- */
- public static final int CASE_GAP_PROP = 3;
-
- // Marker to denote the last RC of function so it can be distinguished from
- // the last RC of object literals in case of function expressions
- private static final int FUNCTION_END = Token.LAST_TOKEN + 1;
-
- String getEncodedSource()
- {
- return sourceToString(0);
- }
-
- int getCurrentOffset()
- {
- return sourceTop;
- }
-
- int markFunctionStart(int functionType)
- {
- int savedOffset = getCurrentOffset();
- addToken(Token.FUNCTION);
- append((char)functionType);
- return savedOffset;
- }
-
- int markFunctionEnd(int functionStart)
- {
- int offset = getCurrentOffset();
- append((char)FUNCTION_END);
- return offset;
- }
-
- void addToken(int token)
- {
- if (!(0 <= token && token <= Token.LAST_TOKEN))
- throw new IllegalArgumentException();
-
- append((char)token);
- }
-
- void addEOL(int token)
- {
- if (!(0 <= token && token <= Token.LAST_TOKEN))
- throw new IllegalArgumentException();
-
- append((char)token);
- append((char)Token.EOL);
- }
-
- void addName(String str)
- {
- addToken(Token.NAME);
- appendString(str);
- }
-
- void addString(String str)
- {
- addToken(Token.STRING);
- appendString(str);
- }
-
- void addRegexp(String regexp, String flags)
- {
- addToken(Token.REGEXP);
- appendString('/' + regexp + '/' + flags);
- }
-
- void addNumber(double n)
- {
- addToken(Token.NUMBER);
-
- /* encode the number in the source stream.
- * Save as NUMBER type (char | char char char char)
- * where type is
- * 'D' - double, 'S' - short, 'J' - long.
-
- * We need to retain float vs. integer type info to keep the
- * behavior of liveconnect type-guessing the same after
- * decompilation. (Liveconnect tries to present 1.0 to Java
- * as a float/double)
- * OPT: This is no longer true. We could compress the format.
-
- * This may not be the most space-efficient encoding;
- * the chars created below may take up to 3 bytes in
- * constant pool UTF-8 encoding, so a Double could take
- * up to 12 bytes.
- */
-
- long lbits = (long)n;
- if (lbits != n) {
- // if it's floating point, save as a Double bit pattern.
- // (12/15/97 our scanner only returns Double for f.p.)
- lbits = Double.doubleToLongBits(n);
- append('D');
- append((char)(lbits >> 48));
- append((char)(lbits >> 32));
- append((char)(lbits >> 16));
- append((char)lbits);
- }
- else {
- // we can ignore negative values, bc they're already prefixed
- // by NEG
- if (lbits < 0) Kit.codeBug();
-
- // will it fit in a char?
- // this gives a short encoding for integer values up to 2^16.
- if (lbits <= Character.MAX_VALUE) {
- append('S');
- append((char)lbits);
- }
- else { // Integral, but won't fit in a char. Store as a long.
- append('J');
- append((char)(lbits >> 48));
- append((char)(lbits >> 32));
- append((char)(lbits >> 16));
- append((char)lbits);
- }
- }
- }
-
- private void appendString(String str)
- {
- int L = str.length();
- int lengthEncodingSize = 1;
- if (L >= 0x8000) {
- lengthEncodingSize = 2;
- }
- int nextTop = sourceTop + lengthEncodingSize + L;
- if (nextTop > sourceBuffer.length) {
- increaseSourceCapacity(nextTop);
- }
- if (L >= 0x8000) {
- // Use 2 chars to encode strings exceeding 32K, were the highest
- // bit in the first char indicates presence of the next byte
- sourceBuffer[sourceTop] = (char)(0x8000 | (L >>> 16));
- ++sourceTop;
- }
- sourceBuffer[sourceTop] = (char)L;
- ++sourceTop;
- str.getChars(0, L, sourceBuffer, sourceTop);
- sourceTop = nextTop;
- }
-
- private void append(char c)
- {
- if (sourceTop == sourceBuffer.length) {
- increaseSourceCapacity(sourceTop + 1);
- }
- sourceBuffer[sourceTop] = c;
- ++sourceTop;
- }
-
- private void increaseSourceCapacity(int minimalCapacity)
- {
- // Call this only when capacity increase is must
- if (minimalCapacity <= sourceBuffer.length) Kit.codeBug();
- int newCapacity = sourceBuffer.length * 2;
- if (newCapacity < minimalCapacity) {
- newCapacity = minimalCapacity;
- }
- char[] tmp = new char[newCapacity];
- System.arraycopy(sourceBuffer, 0, tmp, 0, sourceTop);
- sourceBuffer = tmp;
- }
-
- private String sourceToString(int offset)
- {
- if (offset < 0 || sourceTop < offset) Kit.codeBug();
- return new String(sourceBuffer, offset, sourceTop - offset);
- }
-
- /**
- * Decompile the source information associated with this js
- * function/script back into a string. For the most part, this
- * just means translating tokens back to their string
- * representations; there's a little bit of lookahead logic to
- * decide the proper spacing/indentation. Most of the work in
- * mapping the original source to the prettyprinted decompiled
- * version is done by the parser.
- *
- * @param source encoded source tree presentation
- *
- * @param flags flags to select output format
- *
- * @param properties indentation properties
- *
- */
- public static String decompile(String source, int flags,
- UintMap properties)
- {
- int length = source.length();
- if (length == 0) { return ""; }
-
- int indent = properties.getInt(INITIAL_INDENT_PROP, 0);
- if (indent < 0) throw new IllegalArgumentException();
- int indentGap = properties.getInt(INDENT_GAP_PROP, 4);
- if (indentGap < 0) throw new IllegalArgumentException();
- int caseGap = properties.getInt(CASE_GAP_PROP, 2);
- if (caseGap < 0) throw new IllegalArgumentException();
-
- StringBuffer result = new StringBuffer();
- boolean justFunctionBody = (0 != (flags & Decompiler.ONLY_BODY_FLAG));
- boolean toSource = (0 != (flags & Decompiler.TO_SOURCE_FLAG));
-
- // Spew tokens in source, for debugging.
- // as TYPE number char
- if (printSource) {
- System.err.println("length:" + length);
- for (int i = 0; i < length; ++i) {
- // Note that tokenToName will fail unless Context.printTrees
- // is true.
- String tokenname = null;
- if (Token.printNames) {
- tokenname = Token.name(source.charAt(i));
- }
- if (tokenname == null) {
- tokenname = "---";
- }
- String pad = tokenname.length() > 7
- ? "\t"
- : "\t\t";
- System.err.println
- (tokenname
- + pad + (int)source.charAt(i)
- + "\t'" + ScriptRuntime.escapeString
- (source.substring(i, i+1))
- + "'");
- }
- System.err.println();
- }
-
- int braceNesting = 0;
- boolean afterFirstEOL = false;
- int i = 0;
- int topFunctionType;
- if (source.charAt(i) == Token.SCRIPT) {
- ++i;
- topFunctionType = -1;
- } else {
- topFunctionType = source.charAt(i + 1);
- }
-
- if (!toSource) {
- // add an initial newline to exactly match js.
- result.append('\n');
- for (int j = 0; j < indent; j++)
- result.append(' ');
- } else {
- if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION) {
- result.append('(');
- }
- }
-
- while (i < length) {
- switch(source.charAt(i)) {
- case Token.GET:
- case Token.SET:
- result.append(source.charAt(i) == Token.GET ? "get " : "set ");
- ++i;
- i = printSourceString(source, i + 1, false, result);
- // Now increment one more to get past the FUNCTION token
- ++i;
- break;
-
- case Token.NAME:
- case Token.REGEXP: // re-wrapped in '/'s in parser...
- i = printSourceString(source, i + 1, false, result);
- continue;
-
- case Token.STRING:
- i = printSourceString(source, i + 1, true, result);
- continue;
-
- case Token.NUMBER:
- i = printSourceNumber(source, i + 1, result);
- continue;
-
- case Token.TRUE:
- result.append("true");
- break;
-
- case Token.FALSE:
- result.append("false");
- break;
-
- case Token.NULL:
- result.append("null");
- break;
-
- case Token.THIS:
- result.append("this");
- break;
-
- case Token.FUNCTION:
- ++i; // skip function type
- result.append("function ");
- break;
-
- case FUNCTION_END:
- // Do nothing
- break;
-
- case Token.COMMA:
- result.append(", ");
- break;
-
- case Token.LC:
- ++braceNesting;
- if (Token.EOL == getNext(source, length, i))
- indent += indentGap;
- result.append('{');
- break;
-
- case Token.RC: {
- --braceNesting;
- /* don't print the closing RC if it closes the
- * toplevel function and we're called from
- * decompileFunctionBody.
- */
- if (justFunctionBody && braceNesting == 0)
- break;
-
- result.append('}');
- switch (getNext(source, length, i)) {
- case Token.EOL:
- case FUNCTION_END:
- indent -= indentGap;
- break;
- case Token.WHILE:
- case Token.ELSE:
- indent -= indentGap;
- result.append(' ');
- break;
- }
- break;
- }
- case Token.LP:
- result.append('(');
- break;
-
- case Token.RP:
- result.append(')');
- if (Token.LC == getNext(source, length, i))
- result.append(' ');
- break;
-
- case Token.LB:
- result.append('[');
- break;
-
- case Token.RB:
- result.append(']');
- break;
-
- case Token.EOL: {
- if (toSource) break;
- boolean newLine = true;
- if (!afterFirstEOL) {
- afterFirstEOL = true;
- if (justFunctionBody) {
- /* throw away just added 'function name(...) {'
- * and restore the original indent
- */
- result.setLength(0);
- indent -= indentGap;
- newLine = false;
- }
- }
- if (newLine) {
- result.append('\n');
- }
-
- /* add indent if any tokens remain,
- * less setback if next token is
- * a label, case or default.
- */
- if (i + 1 < length) {
- int less = 0;
- int nextToken = source.charAt(i + 1);
- if (nextToken == Token.CASE
- || nextToken == Token.DEFAULT)
- {
- less = indentGap - caseGap;
- } else if (nextToken == Token.RC) {
- less = indentGap;
- }
-
- /* elaborate check against label... skip past a
- * following inlined NAME and look for a COLON.
- */
- else if (nextToken == Token.NAME) {
- int afterName = getSourceStringEnd(source, i + 2);
- if (source.charAt(afterName) == Token.COLON)
- less = indentGap;
- }
-
- for (; less < indent; less++)
- result.append(' ');
- }
- break;
- }
- case Token.DOT:
- result.append('.');
- break;
-
- case Token.NEW:
- result.append("new ");
- break;
-
- case Token.DELPROP:
- result.append("delete ");
- break;
-
- case Token.IF:
- result.append("if ");
- break;
-
- case Token.ELSE:
- result.append("else ");
- break;
-
- case Token.FOR:
- result.append("for ");
- break;
-
- case Token.IN:
- result.append(" in ");
- break;
-
- case Token.WITH:
- result.append("with ");
- break;
-
- case Token.WHILE:
- result.append("while ");
- break;
-
- case Token.DO:
- result.append("do ");
- break;
-
- case Token.TRY:
- result.append("try ");
- break;
-
- case Token.CATCH:
- result.append("catch ");
- break;
-
- case Token.FINALLY:
- result.append("finally ");
- break;
-
- case Token.THROW:
- result.append("throw ");
- break;
-
- case Token.SWITCH:
- result.append("switch ");
- break;
-
- case Token.BREAK:
- result.append("break");
- if (Token.NAME == getNext(source, length, i))
- result.append(' ');
- break;
-
- case Token.CONTINUE:
- result.append("continue");
- if (Token.NAME == getNext(source, length, i))
- result.append(' ');
- break;
-
- case Token.CASE:
- result.append("case ");
- break;
-
- case Token.DEFAULT:
- result.append("default");
- break;
-
- case Token.RETURN:
- result.append("return");
- if (Token.SEMI != getNext(source, length, i))
- result.append(' ');
- break;
-
- case Token.VAR:
- result.append("var ");
- break;
-
- case Token.SEMI:
- result.append(';');
- if (Token.EOL != getNext(source, length, i)) {
- // separators in FOR
- result.append(' ');
- }
- break;
-
- case Token.ASSIGN:
- result.append(" = ");
- break;
-
- case Token.ASSIGN_ADD:
- result.append(" += ");
- break;
-
- case Token.ASSIGN_SUB:
- result.append(" -= ");
- break;
-
- case Token.ASSIGN_MUL:
- result.append(" *= ");
- break;
-
- case Token.ASSIGN_DIV:
- result.append(" /= ");
- break;
-
- case Token.ASSIGN_MOD:
- result.append(" %= ");
- break;
-
- case Token.ASSIGN_BITOR:
- result.append(" |= ");
- break;
-
- case Token.ASSIGN_BITXOR:
- result.append(" ^= ");
- break;
-
- case Token.ASSIGN_BITAND:
- result.append(" &= ");
- break;
-
- case Token.ASSIGN_LSH:
- result.append(" <<= ");
- break;
-
- case Token.ASSIGN_RSH:
- result.append(" >>= ");
- break;
-
- case Token.ASSIGN_URSH:
- result.append(" >>>= ");
- break;
-
- case Token.HOOK:
- result.append(" ? ");
- break;
-
- case Token.OBJECTLIT:
- // pun OBJECTLIT to mean colon in objlit property
- // initialization.
- // This needs to be distinct from COLON in the general case
- // to distinguish from the colon in a ternary... which needs
- // different spacing.
- result.append(':');
- break;
-
- case Token.COLON:
- if (Token.EOL == getNext(source, length, i))
- // it's the end of a label
- result.append(':');
- else
- // it's the middle part of a ternary
- result.append(" : ");
- break;
-
- case Token.OR:
- result.append(" || ");
- break;
-
- case Token.AND:
- result.append(" && ");
- break;
-
- case Token.BITOR:
- result.append(" | ");
- break;
-
- case Token.BITXOR:
- result.append(" ^ ");
- break;
-
- case Token.BITAND:
- result.append(" & ");
- break;
-
- case Token.SHEQ:
- result.append(" === ");
- break;
-
- case Token.SHNE:
- result.append(" !== ");
- break;
-
- case Token.EQ:
- result.append(" == ");
- break;
-
- case Token.NE:
- result.append(" != ");
- break;
-
- case Token.LE:
- result.append(" <= ");
- break;
-
- case Token.LT:
- result.append(" < ");
- break;
-
- case Token.GE:
- result.append(" >= ");
- break;
-
- case Token.GT:
- result.append(" > ");
- break;
-
- case Token.INSTANCEOF:
- result.append(" instanceof ");
- break;
-
- case Token.LSH:
- result.append(" << ");
- break;
-
- case Token.RSH:
- result.append(" >> ");
- break;
-
- case Token.URSH:
- result.append(" >>> ");
- break;
-
- case Token.TYPEOF:
- result.append("typeof ");
- break;
-
- case Token.VOID:
- result.append("void ");
- break;
-
- case Token.CONST:
- result.append("const ");
- break;
-
- case Token.NOT:
- result.append('!');
- break;
-
- case Token.BITNOT:
- result.append('~');
- break;
-
- case Token.POS:
- result.append('+');
- break;
-
- case Token.NEG:
- result.append('-');
- break;
-
- case Token.INC:
- result.append("++");
- break;
-
- case Token.DEC:
- result.append("--");
- break;
-
- case Token.ADD:
- result.append(" + ");
- break;
-
- case Token.SUB:
- result.append(" - ");
- break;
-
- case Token.MUL:
- result.append(" * ");
- break;
-
- case Token.DIV:
- result.append(" / ");
- break;
-
- case Token.MOD:
- result.append(" % ");
- break;
-
- case Token.COLONCOLON:
- result.append("::");
- break;
-
- case Token.DOTDOT:
- result.append("..");
- break;
-
- case Token.DOTQUERY:
- result.append(".(");
- break;
-
- case Token.XMLATTR:
- result.append('@');
- break;
-
- default:
- // If we don't know how to decompile it, raise an exception.
- throw new RuntimeException("Token: " +
- Token.name(source.charAt(i)));
- }
- ++i;
- }
-
- if (!toSource) {
- // add that trailing newline if it's an outermost function.
- if (!justFunctionBody)
- result.append('\n');
- } else {
- if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION) {
- result.append(')');
- }
- }
-
- return result.toString();
- }
-
- private static int getNext(String source, int length, int i)
- {
- return (i + 1 < length) ? source.charAt(i + 1) : Token.EOF;
- }
-
- private static int getSourceStringEnd(String source, int offset)
- {
- return printSourceString(source, offset, false, null);
- }
-
- private static int printSourceString(String source, int offset,
- boolean asQuotedString,
- StringBuffer sb)
- {
- int length = source.charAt(offset);
- ++offset;
- if ((0x8000 & length) != 0) {
- length = ((0x7FFF & length) << 16) | source.charAt(offset);
- ++offset;
- }
- if (sb != null) {
- String str = source.substring(offset, offset + length);
- if (!asQuotedString) {
- sb.append(str);
- } else {
- sb.append('"');
- sb.append(ScriptRuntime.escapeString(str));
- sb.append('"');
- }
- }
- return offset + length;
- }
-
- private static int printSourceNumber(String source, int offset,
- StringBuffer sb)
- {
- double number = 0.0;
- char type = source.charAt(offset);
- ++offset;
- if (type == 'S') {
- if (sb != null) {
- int ival = source.charAt(offset);
- number = ival;
- }
- ++offset;
- } else if (type == 'J' || type == 'D') {
- if (sb != null) {
- long lbits;
- lbits = (long)source.charAt(offset) << 48;
- lbits |= (long)source.charAt(offset + 1) << 32;
- lbits |= (long)source.charAt(offset + 2) << 16;
- lbits |= source.charAt(offset + 3);
- if (type == 'J') {
- number = lbits;
- } else {
- number = Double.longBitsToDouble(lbits);
- }
- }
- offset += 4;
- } else {
- // Bad source
- throw new RuntimeException();
- }
- if (sb != null) {
- sb.append(ScriptRuntime.numberToString(number, 10));
- }
- return offset;
- }
-
- private char[] sourceBuffer = new char[128];
-
-// Per script/function source buffer top: parent source does not include a
-// nested functions source and uses function index as a reference instead.
- private int sourceTop;
-
-// whether to do a debug print of the source information, when decompiling.
- private static final boolean printSource = false;
-
-}
diff --git a/src/org/mozilla/javascript/Parser.java b/src/org/mozilla/javascript/Parser.java
deleted file mode 100644
index 984358a6..00000000
--- a/src/org/mozilla/javascript/Parser.java
+++ /dev/null
@@ -1,2498 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
-*
-* Version: MPL 1.1
-*
-* 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 org/mozilla/javascript/Parser.java,
-* a component of the Rhino Library ( http://www.mozilla.org/rhino/ )
-* This file is a modification of the Original Code developed
-* for YUI Compressor.
-*
-* The Initial Developer of the Original Code is Mozilla Foundation
-*
-* Copyright (c) 2009 Mozilla Foundation. All Rights Reserved.
-*
-* Contributor(s): Yahoo! Inc. 2009
-*
-* ***** END LICENSE BLOCK ***** */
-
-package org.mozilla.javascript;
-
-import java.io.Reader;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * 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;
- Node.Scope currentScope;
- private int nestingOfWith;
- private Map labelSet; // map of label names into nodes
- private ObjArray loopSet;
- private ObjArray loopAndSwitchSet;
- private int endFlags;
-// end of per function variables
-
- public int getCurrentLineNumber() {
- return ts.getLineno();
- }
-
- // 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;
- }
-
- void pushScope(Node node) {
- Node.Scope scopeNode = (Node.Scope) node;
- if (scopeNode.getParentScope() != null) throw Kit.codeBug();
- scopeNode.setParent(currentScope);
- currentScope = scopeNode;
- }
-
- void popScope() {
- currentScope = currentScope.getParentScope();
- }
-
- private Node enterLoop(Node loopLabel, boolean doPushScope)
- {
- 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);
- if (doPushScope) {
- pushScope(loop);
- }
- return loop;
- }
-
- private void exitLoop(boolean doPopScope)
- {
- loopSet.pop();
- loopAndSwitchSet.pop();
- if (doPopScope) {
- popScope();
- }
- }
-
- 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();
- currentScope = currentScriptOrFn;
- 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 ' does not follow
- // by '(', assume 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;
- }
-
- if (syntheticType != FunctionNode.FUNCTION_EXPRESSION &&
- name.length() > 0)
- {
- // Function statements define a symbol in the enclosing scope
- defineSymbol(Token.FUNCTION, false, name);
- }
-
- 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;
- Node.Scope savedCurrentScope = currentScope;
- currentScope = fnNode;
- int savedNestingOfWith = nestingOfWith;
- nestingOfWith = 0;
- Map savedLabelSet = labelSet;
- labelSet = null;
- ObjArray savedLoopSet = loopSet;
- loopSet = null;
- ObjArray savedLoopAndSwitchSet = loopAndSwitchSet;
- loopAndSwitchSet = null;
- int savedFunctionEndFlags = endFlags;
- endFlags = 0;
-
- Node destructuring = null;
- Node body;
- try {
- decompiler.addToken(Token.LP);
- if (!matchToken(Token.RP)) {
- boolean first = true;
- do {
- if (!first)
- decompiler.addToken(Token.COMMA);
- first = false;
- int tt = peekToken();
- if (tt == Token.LB || tt == Token.LC) {
- // Destructuring assignment for parameters: add a
- // dummy parameter name, and add a statement to the
- // body to initialize variables from the destructuring
- // assignment
- if (destructuring == null) {
- destructuring = new Node(Token.COMMA);
- }
- String parmName = currentScriptOrFn.getNextTempName();
- defineSymbol(Token.LP, false, parmName);
- destructuring.addChildToBack(
- nf.createDestructuringAssignment(Token.VAR,
- primaryExpr(), nf.createName(parmName)));
- } else {
- mustMatchToken(Token.NAME, "msg.no.parm");
- String s = ts.getString();
- defineSymbol(Token.LP, false, 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();
- if (destructuring != null) {
- body.addChildToFront(
- new Node(Token.EXPR_VOID, destructuring, ts.getLineno()));
- }
- 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);
- }
-
- if (syntheticType == FunctionNode.FUNCTION_EXPRESSION &&
- name.length() > 0 && currentScope.getSymbol(name) == null)
- {
- // Function expressions define a name only in the body of the
- // function, and only if not hidden by a parameter name
- defineSymbol(Token.FUNCTION, false, 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 {
- endFlags = savedFunctionEndFlags;
- loopAndSwitchSet = savedLoopAndSwitchSet;
- loopSet = savedLoopSet;
- labelSet = savedLabelSet;
- nestingOfWith = savedNestingOfWith;
- currentScriptOrFn = savedScriptOrFn;
- currentScope = savedCurrentScope;
- }
-
- fnNode.setEncodedSourceBounds(functionSourceStart, functionSourceEnd);
- fnNode.setSourceName(sourceURI);
- fnNode.setBaseLineno(baseLineno);
- fnNode.setEndLineno(ts.getLineno());
-
- 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(Node scope)
- throws IOException
- {
- Node pn = scope != null ? scope : 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 = 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);
- }
-
- private Node statementHelper(Node statementLabel)
- throws IOException, ParserException
- {
- Node pn = null;
- int 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 label
- 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, true);
- try {
- Node cond = condition();
- decompiler.addEOL(Token.LC);
- Node body = statement();
- decompiler.addEOL(Token.RC);
- pn = nf.createWhile(loop, cond, body);
- } finally {
- exitLoop(true);
- }
- return pn;
- }
-
- case Token.DO: {
- consumeToken();
- decompiler.addToken(Token.DO);
- decompiler.addEOL(Token.LC);
-
- Node loop = enterLoop(statementLabel, true);
- 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(true);
- }
- // Always auto-insert semicolon to follow SpiderMonkey:
- // It is required by ECMAScript 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, true);
- 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;
- Node body;
- int declType = -1;
-
- // 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 || tt == Token.LET) {
- // set init to a var list or initial
- consumeToken(); // consume the token
- decompiler.addToken(tt);
- init = variables(true, tt);
- declType = tt;
- }
- 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(declType, loop, init, cond, body,
- isForEach);
- } else {
- pn = nf.createFor(loop, init, cond, incr, body);
- }
- } finally {
- exitLoop(true);
- }
- return pn;
- }
-
- case Token.TRY: {
- consumeToken();
- int lineno = ts.getLineno();
-
- Node tryblock;
- Node catchblocks = null;
- Node finallyblock = null;
-
- decompiler.addToken(Token.TRY);
- if (peekToken() != Token.LC) {
- reportError("msg.no.brace.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(null),
- 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();
- decompiler.addToken(tt);
- pn = variables(false, tt);
- break;
- }
-
- case Token.LET: {
- consumeToken();
- decompiler.addToken(Token.LET);
- if (peekToken() == Token.LP) {
- return let(true);
- } else {
- pn = variables(false, tt);
- if (peekToken() == Token.SEMI)
- break;
- return pn;
- }
- }
-
- case Token.RETURN:
- case Token.YIELD: {
- pn = returnOrYield(tt, false);
- break;
- }
-
- case Token.DEBUGGER:
- consumeToken();
- decompiler.addToken(Token.DEBUGGER);
- pn = nf.createDebugger(ts.getLineno());
- break;
-
- case Token.LC:
- consumeToken();
- if (statementLabel != null) {
- decompiler.addToken(Token.LC);
- }
- Node scope = nf.createScopeNode(Token.BLOCK, ts.getLineno());
- pushScope(scope);
- try {
- statements(scope);
- mustMatchToken(Token.RC, "msg.no.brace.block");
- if (statementLabel != null) {
- decompiler.addEOL(Token.RC);
- }
- return scope;
- } finally {
- popScope();
- }
-
- 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 HashMap();
- } 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;
- }
-
- /**
- * Returns whether or not the bits in the mask have changed to all set.
- * @param before bits before change
- * @param after bits after change
- * @param mask mask for bits
- * @return true if all the bits in the mask are set in "after" but not
- * "before"
- */
- private static final boolean nowAllSet(int before, int after, int mask)
- {
- return ((before & mask) != mask) && ((after & mask) == mask);
- }
-
- private Node returnOrYield(int tt, boolean exprContext)
- throws IOException, ParserException
- {
- if (!insideFunction()) {
- reportError(tt == Token.RETURN ? "msg.bad.return"
- : "msg.bad.yield");
- }
- consumeToken();
- decompiler.addToken(tt);
- int lineno = ts.getLineno();
-
- Node e;
- /* This is ugly, but we don't want to require a semicolon. */
- switch (peekTokenOrEOL()) {
- case Token.SEMI:
- case Token.RC:
- case Token.EOF:
- case Token.EOL:
- case Token.ERROR:
- case Token.RB:
- case Token.RP:
- case Token.YIELD:
- e = null;
- break;
- default:
- e = expr(false);
- break;
- }
-
- int before = endFlags;
- Node ret;
-
- if (tt == Token.RETURN) {
- if (e == null ) {
- endFlags |= Node.END_RETURNS;
- } else {
- endFlags |= Node.END_RETURNS_VALUE;
- }
- ret = nf.createReturn(e, lineno);
-
- // see if we need a strict mode warning
- if (nowAllSet(before, endFlags,
- Node.END_RETURNS|Node.END_RETURNS_VALUE))
- {
- addStrictWarning("msg.return.inconsistent", "");
- }
- } else {
- endFlags |= Node.END_YIELDS;
- ret = nf.createYield(e, lineno);
- if (!exprContext)
- ret = new Node(Token.EXPR_VOID, ret, lineno);
- }
-
- // see if we are mixing yields and value returns.
- if (nowAllSet(before, endFlags,
- Node.END_YIELDS|Node.END_RETURNS_VALUE))
- {
- String name = ((FunctionNode)currentScriptOrFn).getFunctionName();
- if (name.length() == 0)
- addError("msg.anon.generator.returns", "");
- else
- addError("msg.generator.returns", name);
- }
-
- return ret;
- }
-
- /**
- * Parse a 'var' or 'const' statement, or a 'var' init list in a for
- * statement.
- * @param inFor true if we are currently in the midst of the init
- * clause of a for.
- * @param declType A token value: either VAR, CONST, or LET depending on
- * context.
- * @return The parsed statement
- * @throws IOException
- * @throws ParserException
- */
- private Node variables(boolean inFor, int declType)
- throws IOException, ParserException
- {
- Node result = nf.createVariables(declType, ts.getLineno());
- boolean first = true;
- for (;;) {
- Node destructuring = null;
- String s = null;
- int tt = peekToken();
- if (tt == Token.LB || tt == Token.LC) {
- // Destructuring assignment, e.g., var [a,b] = ...
- destructuring = primaryExpr();
- } else {
- // Simple variable name
- mustMatchToken(Token.NAME, "msg.bad.var");
- s = ts.getString();
-
- if (!first)
- decompiler.addToken(Token.COMMA);
- first = false;
-
- decompiler.addName(s);
- defineSymbol(declType, inFor, s);
- }
-
- Node init = null;
- if (matchToken(Token.ASSIGN)) {
- decompiler.addToken(Token.ASSIGN);
- init = assignExpr(inFor);
- }
-
- if (destructuring != null) {
- if (init == null) {
- if (!inFor)
- reportError("msg.destruct.assign.no.init");
- nf.addChildToBack(result, destructuring);
- } else {
- nf.addChildToBack(result,
- nf.createDestructuringAssignment(declType,
- destructuring, init));
- }
- } else {
- Node name = nf.createName(s);
- if (init != null)
- nf.addChildToBack(name, init);
- nf.addChildToBack(result, name);
- }
-
- if (!matchToken(Token.COMMA))
- break;
- }
- return result;
- }
-
-
- private Node let(boolean isStatement)
- throws IOException, ParserException
- {
- mustMatchToken(Token.LP, "msg.no.paren.after.let");
- decompiler.addToken(Token.LP);
- Node result = nf.createScopeNode(Token.LET, ts.getLineno());
- pushScope(result);
- try {
- Node vars = variables(false, Token.LET);
- nf.addChildToBack(result, vars);
- mustMatchToken(Token.RP, "msg.no.paren.let");
- decompiler.addToken(Token.RP);
- if (isStatement && peekToken() == Token.LC) {
- // let statement
- consumeToken();
- decompiler.addEOL(Token.LC);
- nf.addChildToBack(result, statements(null));
- mustMatchToken(Token.RC, "msg.no.curly.let");
- decompiler.addToken(Token.RC);
- } else {
- // let expression
- result.setType(Token.LETEXPR);
- nf.addChildToBack(result, expr(false));
- if (isStatement) {
- // let expression in statement context
- result = nf.createExprStatement(result, ts.getLineno());
- }
- }
- } finally {
- popScope();
- }
- return result;
- }
-
- void defineSymbol(int declType, boolean ignoreNotInBlock, String name) {
- Node.Scope definingScope = currentScope.getDefiningScope(name);
- Node.Scope.Symbol symbol = definingScope != null
- ? definingScope.getSymbol(name)
- : null;
- boolean error = false;
- if (symbol != null && (symbol.declType == Token.CONST ||
- declType == Token.CONST))
- {
- error = true;
- } else {
- switch (declType) {
- case Token.LET:
- if (symbol != null && definingScope == currentScope) {
- error = symbol.declType == Token.LET;
- }
- int currentScopeType = currentScope.getType();
- if (!ignoreNotInBlock &&
- ((currentScopeType == Token.LOOP) ||
- (currentScopeType == Token.IF)))
- {
- addError("msg.let.decl.not.in.block");
- }
- currentScope.putSymbol(name,
- new Node.Scope.Symbol(declType, name));
- break;
-
- case Token.VAR:
- case Token.CONST:
- case Token.FUNCTION:
- if (symbol != null) {
- if (symbol.declType == Token.VAR)
- addStrictWarning("msg.var.redecl", name);
- else if (symbol.declType == Token.LP) {
- addStrictWarning("msg.var.hides.arg", name);
- }
- } else {
- currentScriptOrFn.putSymbol(name,
- new Node.Scope.Symbol(declType, name));
- }
- break;
-
- case Token.LP:
- if (symbol != null) {
- // must be duplicate parameter. Second parameter hides the
- // first, so go ahead and add the second pararameter
- addWarning("msg.dup.parms", name);
- }
- currentScriptOrFn.putSymbol(name,
- new Node.Scope.Symbol(declType, name));
- break;
-
- default:
- throw Kit.codeBug();
- }
- }
- if (error) {
- addError(symbol.declType == Token.CONST ? "msg.const.redecl" :
- symbol.declType == Token.LET ? "msg.let.redecl" :
- symbol.declType == Token.VAR ? "msg.var.redecl" :
- symbol.declType == Token.FUNCTION ? "msg.fn.redecl" :
- "msg.parm.redecl", name);
- }
- }
-
- 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", "");
- if (peekToken() == Token.YIELD) {
- reportError("msg.yield.parenthesized");
- }
- pn = nf.createBinary(Token.COMMA, pn, assignExpr(inForInit));
- }
- return pn;
- }
-
- private Node assignExpr(boolean inForInit)
- throws IOException, ParserException
- {
- int tt = peekToken();
- if (tt == Token.YIELD) {
- consumeToken();
- return returnOrYield(tt, true);
- }
- Node pn = condExpr(inForInit);
-
- 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("error"); // 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;
- if (peekToken() == Token.YIELD) {
- reportError("msg.yield.parenthesized");
- }
- 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) {
-
- // needed for generator.throw();
- case Token.THROW:
- decompiler.addName("throw");
- pn = propertyName(pn, "throw", memberTypeFlags);
- break;
-
- // 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 arrayComprehension(String arrayName, Node expr)
- throws IOException, ParserException
- {
- if (nextToken() != Token.FOR)
- throw Kit.codeBug(); // shouldn't be here if next token isn't 'for'
- decompiler.addName(" "); // space after array literal expr
- decompiler.addToken(Token.FOR);
- boolean isForEach = false;
- 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);
- String name;
- int tt = peekToken();
- if (tt == Token.LB || tt == Token.LC) {
- // handle destructuring assignment
- name = currentScriptOrFn.getNextTempName();
- defineSymbol(Token.LP, false, name);
- expr = nf.createBinary(Token.COMMA,
- nf.createAssignment(Token.ASSIGN, primaryExpr(),
- nf.createName(name)),
- expr);
- } else if (tt == Token.NAME) {
- consumeToken();
- name = ts.getString();
- decompiler.addName(name);
- } else {
- reportError("msg.bad.var");
- return nf.createNumber(0);
- }
-
- Node init = nf.createName(name);
- // Define as a let since we want the scope of the variable to
- // be restricted to the array comprehension
- defineSymbol(Token.LET, false, name);
-
- mustMatchToken(Token.IN, "msg.in.after.for.name");
- decompiler.addToken(Token.IN);
- Node iterator = expr(false);
- mustMatchToken(Token.RP, "msg.no.paren.for.ctrl");
- decompiler.addToken(Token.RP);
-
- Node body;
- tt = peekToken();
- if (tt == Token.FOR) {
- body = arrayComprehension(arrayName, expr);
- } else {
- Node call = nf.createCallOrNew(Token.CALL,
- nf.createPropertyGet(nf.createName(arrayName), null,
- "push", 0));
- call.addChildToBack(expr);
- body = new Node(Token.EXPR_VOID, call, ts.getLineno());
- if (tt == Token.IF) {
- consumeToken();
- decompiler.addToken(Token.IF);
- int lineno = ts.getLineno();
- Node cond = condition();
- body = nf.createIf(cond, body, null, lineno);
- }
- mustMatchToken(Token.RB, "msg.no.bracket.arg");
- decompiler.addToken(Token.RB);
- }
-
- Node loop = enterLoop(null, true);
- try {
- return nf.createForIn(Token.LET, loop, init, iterator, body,
- isForEach);
- } finally {
- exitLoop(false);
- }
- }
-
- 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;
- int destructuringLen = 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);
- // for ([a,] in obj) is legal, but for ([a] in obj) is
- // not since we have both key and value supplied. The
- // trick is that [a,] and [a] are equivalent in other
- // array literal contexts. So we calculate a special
- // length value just for destructuring assignment.
- destructuringLen = elems.size() +
- (after_lb_or_comma ? 1 : 0);
- break;
- } else if (skipCount == 0 && elems.size() == 1 &&
- tt == Token.FOR)
- {
- Node scopeNode = nf.createScopeNode(Token.ARRAYCOMP,
- ts.getLineno());
- String tempName = currentScriptOrFn.getNextTempName();
- pushScope(scopeNode);
- try {
- defineSymbol(Token.LET, false, tempName);
- Node expr = (Node) elems.get(0);
- Node block = nf.createBlock(ts.getLineno());
- Node init = new Node(Token.EXPR_VOID,
- nf.createAssignment(Token.ASSIGN,
- nf.createName(tempName),
- nf.createCallOrNew(Token.NEW,
- nf.createName("Array"))), ts.getLineno());
- block.addChildToBack(init);
- block.addChildToBack(arrayComprehension(tempName,
- expr));
- scopeNode.addChildToBack(block);
- scopeNode.addChildToBack(nf.createName(tempName));
- return scopeNode;
- } finally {
- popScope();
- }
- } 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, destructuringLen);
- }
-
- 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.LET:
- decompiler.addToken(Token.LET);
- return let(false);
-
- 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;
-
- case Token.CONDCOMMENT:
- String condComment = ts.getString();
- decompiler.addJScriptConditionalComment(condComment);
- return nf.createString(condComment);
-
- case Token.KEEPCOMMENT:
- String keepComment = ts.getString();
- decompiler.addPreservedComment(keepComment);
- return nf.createString(keepComment);
-
- 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;
- }
-}
diff --git a/src/org/mozilla/javascript/Parser.java.orig b/src/org/mozilla/javascript/Parser.java.orig
deleted file mode 100644
index 628bb42f..00000000
--- a/src/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 ' does not follow
- // by '(', assume 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;
- }
-}
diff --git a/src/org/mozilla/javascript/Token.java b/src/org/mozilla/javascript/Token.java
deleted file mode 100644
index 7ee34e2a..00000000
--- a/src/org/mozilla/javascript/Token.java
+++ /dev/null
@@ -1,423 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
-*
-* Version: MPL 1.1
-*
-* 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 org/mozilla/javascript/Token.java,
-* a component of the Rhino Library ( http://www.mozilla.org/rhino/ )
-* This file is a modification of the Original Code developed
-* for YUI Compressor.
-*
-* The Initial Developer of the Original Code is Mozilla Foundation
-*
-* Copyright (c) 2009 Mozilla Foundation. All Rights Reserved.
-*
-* Contributor(s): Yahoo! Inc. 2009
-*
-* ***** END LICENSE BLOCK ***** */
-
-package org.mozilla.javascript;
-
-/**
- * This class implements the JavaScript scanner.
- *
- * It is based on the C source files jsscan.c and jsscan.h
- * in the jsref package.
- *
- * @see org.mozilla.javascript.Parser
- *
- * @author Mike McCabe
- * @author Brendan Eich
- */
-
-public class Token
-{
-
- // debug flags
- public static final boolean printTrees = false;
- static final boolean printICode = false;
- static final boolean printNames = printTrees || printICode;
-
- /**
- * Token types. These values correspond to JSTokenType values in
- * jsscan.c.
- */
-
- public final static int
- // start enum
- ERROR = -1, // well-known as the only code < EOF
- EOF = 0, // end of file token - (not EOF_CHAR)
- EOL = 1, // end of line
-
- // Interpreter reuses the following as bytecodes
- FIRST_BYTECODE_TOKEN = 2,
-
- ENTERWITH = 2,
- LEAVEWITH = 3,
- RETURN = 4,
- GOTO = 5,
- IFEQ = 6,
- IFNE = 7,
- SETNAME = 8,
- BITOR = 9,
- BITXOR = 10,
- BITAND = 11,
- EQ = 12,
- NE = 13,
- LT = 14,
- LE = 15,
- GT = 16,
- GE = 17,
- LSH = 18,
- RSH = 19,
- URSH = 20,
- ADD = 21,
- SUB = 22,
- MUL = 23,
- DIV = 24,
- MOD = 25,
- NOT = 26,
- BITNOT = 27,
- POS = 28,
- NEG = 29,
- NEW = 30,
- DELPROP = 31,
- TYPEOF = 32,
- GETPROP = 33,
- GETPROPNOWARN = 34,
- SETPROP = 35,
- GETELEM = 36,
- SETELEM = 37,
- CALL = 38,
- NAME = 39,
- NUMBER = 40,
- STRING = 41,
- NULL = 42,
- THIS = 43,
- FALSE = 44,
- TRUE = 45,
- SHEQ = 46, // shallow equality (===)
- SHNE = 47, // shallow inequality (!==)
- REGEXP = 48,
- BINDNAME = 49,
- THROW = 50,
- RETHROW = 51, // rethrow caught exception: catch (e if ) use it
- IN = 52,
- INSTANCEOF = 53,
- LOCAL_LOAD = 54,
- GETVAR = 55,
- SETVAR = 56,
- CATCH_SCOPE = 57,
- ENUM_INIT_KEYS = 58,
- ENUM_INIT_VALUES = 59,
- ENUM_INIT_ARRAY= 60,
- ENUM_NEXT = 61,
- ENUM_ID = 62,
- THISFN = 63,
- RETURN_RESULT = 64, // to return previously stored return result
- ARRAYLIT = 65, // array literal
- OBJECTLIT = 66, // object literal
- GET_REF = 67, // *reference
- SET_REF = 68, // *reference = something
- DEL_REF = 69, // delete reference
- REF_CALL = 70, // f(args) = something or f(args)++
- REF_SPECIAL = 71, // reference for special properties like __proto
- YIELD = 72, // JS 1.7 yield pseudo keyword
-
- // For XML support:
- DEFAULTNAMESPACE = 73, // default xml namespace =
- ESCXMLATTR = 74,
- ESCXMLTEXT = 75,
- REF_MEMBER = 76, // Reference for x.@y, x..y etc.
- REF_NS_MEMBER = 77, // Reference for x.ns::y, x..ns::y etc.
- REF_NAME = 78, // Reference for @y, @[y] etc.
- REF_NS_NAME = 79; // Reference for ns::y, @ns::y@[y] etc.
-
- // End of interpreter bytecodes
- public final static int
- LAST_BYTECODE_TOKEN = REF_NS_NAME,
-
- TRY = 80,
- SEMI = 81, // semicolon
- LB = 82, // left and right brackets
- RB = 83,
- LC = 84, // left and right curlies (braces)
- RC = 85,
- LP = 86, // left and right parentheses
- RP = 87,
- COMMA = 88, // comma operator
-
- ASSIGN = 89, // simple assignment (=)
- ASSIGN_BITOR = 90, // |=
- ASSIGN_BITXOR = 91, // ^=
- ASSIGN_BITAND = 92, // |=
- ASSIGN_LSH = 93, // <<=
- ASSIGN_RSH = 94, // >>=
- ASSIGN_URSH = 95, // >>>=
- ASSIGN_ADD = 96, // +=
- ASSIGN_SUB = 97, // -=
- ASSIGN_MUL = 98, // *=
- ASSIGN_DIV = 99, // /=
- ASSIGN_MOD = 100; // %=
-
- public final static int
- FIRST_ASSIGN = ASSIGN,
- LAST_ASSIGN = ASSIGN_MOD,
-
- HOOK = 101, // conditional (?:)
- COLON = 102,
- OR = 103, // logical or (||)
- AND = 104, // logical and (&&)
- INC = 105, // increment/decrement (++ --)
- DEC = 106,
- DOT = 107, // member operator (.)
- FUNCTION = 108, // function keyword
- EXPORT = 109, // export keyword
- IMPORT = 110, // import keyword
- IF = 111, // if keyword
- ELSE = 112, // else keyword
- SWITCH = 113, // switch keyword
- CASE = 114, // case keyword
- DEFAULT = 115, // default keyword
- WHILE = 116, // while keyword
- DO = 117, // do keyword
- FOR = 118, // for keyword
- BREAK = 119, // break keyword
- CONTINUE = 120, // continue keyword
- VAR = 121, // var keyword
- WITH = 122, // with keyword
- CATCH = 123, // catch keyword
- FINALLY = 124, // finally keyword
- VOID = 125, // void keyword
- RESERVED = 126, // reserved keywords
-
- EMPTY = 127,
-
- /* types used for the parse tree - these never get returned
- * by the scanner.
- */
-
- BLOCK = 128, // statement block
- LABEL = 129, // label
- TARGET = 130,
- LOOP = 131,
- EXPR_VOID = 132, // expression statement in functions
- EXPR_RESULT = 133, // expression statement in scripts
- JSR = 134,
- SCRIPT = 135, // top-level node for entire script
- TYPEOFNAME = 136, // for typeof(simple-name)
- USE_STACK = 137,
- SETPROP_OP = 138, // x.y op= something
- SETELEM_OP = 139, // x[y] op= something
- LOCAL_BLOCK = 140,
- SET_REF_OP = 141, // *reference op= something
-
- // For XML support:
- DOTDOT = 142, // member operator (..)
- COLONCOLON = 143, // namespace::name
- XML = 144, // XML type
- DOTQUERY = 145, // .() -- e.g., x.emps.emp.(name == "terry")
- XMLATTR = 146, // @
- XMLEND = 147,
-
- // Optimizer-only-tokens
- TO_OBJECT = 148,
- TO_DOUBLE = 149,
-
- GET = 150, // JS 1.5 get pseudo keyword
- SET = 151, // JS 1.5 set pseudo keyword
- LET = 152, // JS 1.7 let pseudo keyword
- CONST = 153,
- SETCONST = 154,
- SETCONSTVAR = 155,
- ARRAYCOMP = 156, // array comprehension
- LETEXPR = 157,
- WITHEXPR = 158,
- DEBUGGER = 159,
-
- CONDCOMMENT = 160, // JScript conditional comment
- KEEPCOMMENT = 161, // /*! ... */ comment
-
- LAST_TOKEN = 162;
-
- public static String name(int token)
- {
- if (!printNames) {
- return String.valueOf(token);
- }
- switch (token) {
- case ERROR: return "ERROR";
- case EOF: return "EOF";
- case EOL: return "EOL";
- case ENTERWITH: return "ENTERWITH";
- case LEAVEWITH: return "LEAVEWITH";
- case RETURN: return "RETURN";
- case GOTO: return "GOTO";
- case IFEQ: return "IFEQ";
- case IFNE: return "IFNE";
- case SETNAME: return "SETNAME";
- case BITOR: return "BITOR";
- case BITXOR: return "BITXOR";
- case BITAND: return "BITAND";
- case EQ: return "EQ";
- case NE: return "NE";
- case LT: return "LT";
- case LE: return "LE";
- case GT: return "GT";
- case GE: return "GE";
- case LSH: return "LSH";
- case RSH: return "RSH";
- case URSH: return "URSH";
- case ADD: return "ADD";
- case SUB: return "SUB";
- case MUL: return "MUL";
- case DIV: return "DIV";
- case MOD: return "MOD";
- case NOT: return "NOT";
- case BITNOT: return "BITNOT";
- case POS: return "POS";
- case NEG: return "NEG";
- case NEW: return "NEW";
- case DELPROP: return "DELPROP";
- case TYPEOF: return "TYPEOF";
- case GETPROP: return "GETPROP";
- case GETPROPNOWARN: return "GETPROPNOWARN";
- case SETPROP: return "SETPROP";
- case GETELEM: return "GETELEM";
- case SETELEM: return "SETELEM";
- case CALL: return "CALL";
- case NAME: return "NAME";
- case NUMBER: return "NUMBER";
- case STRING: return "STRING";
- case NULL: return "NULL";
- case THIS: return "THIS";
- case FALSE: return "FALSE";
- case TRUE: return "TRUE";
- case SHEQ: return "SHEQ";
- case SHNE: return "SHNE";
- case REGEXP: return "OBJECT";
- case BINDNAME: return "BINDNAME";
- case THROW: return "THROW";
- case RETHROW: return "RETHROW";
- case IN: return "IN";
- case INSTANCEOF: return "INSTANCEOF";
- case LOCAL_LOAD: return "LOCAL_LOAD";
- case GETVAR: return "GETVAR";
- case SETVAR: return "SETVAR";
- case CATCH_SCOPE: return "CATCH_SCOPE";
- case ENUM_INIT_KEYS: return "ENUM_INIT_KEYS";
- case ENUM_INIT_VALUES:return "ENUM_INIT_VALUES";
- case ENUM_INIT_ARRAY: return "ENUM_INIT_ARRAY";
- case ENUM_NEXT: return "ENUM_NEXT";
- case ENUM_ID: return "ENUM_ID";
- case THISFN: return "THISFN";
- case RETURN_RESULT: return "RETURN_RESULT";
- case ARRAYLIT: return "ARRAYLIT";
- case OBJECTLIT: return "OBJECTLIT";
- case GET_REF: return "GET_REF";
- case SET_REF: return "SET_REF";
- case DEL_REF: return "DEL_REF";
- case REF_CALL: return "REF_CALL";
- case REF_SPECIAL: return "REF_SPECIAL";
- case DEFAULTNAMESPACE:return "DEFAULTNAMESPACE";
- case ESCXMLTEXT: return "ESCXMLTEXT";
- case ESCXMLATTR: return "ESCXMLATTR";
- case REF_MEMBER: return "REF_MEMBER";
- case REF_NS_MEMBER: return "REF_NS_MEMBER";
- case REF_NAME: return "REF_NAME";
- case REF_NS_NAME: return "REF_NS_NAME";
- case TRY: return "TRY";
- case SEMI: return "SEMI";
- case LB: return "LB";
- case RB: return "RB";
- case LC: return "LC";
- case RC: return "RC";
- case LP: return "LP";
- case RP: return "RP";
- case COMMA: return "COMMA";
- case ASSIGN: return "ASSIGN";
- case ASSIGN_BITOR: return "ASSIGN_BITOR";
- case ASSIGN_BITXOR: return "ASSIGN_BITXOR";
- case ASSIGN_BITAND: return "ASSIGN_BITAND";
- case ASSIGN_LSH: return "ASSIGN_LSH";
- case ASSIGN_RSH: return "ASSIGN_RSH";
- case ASSIGN_URSH: return "ASSIGN_URSH";
- case ASSIGN_ADD: return "ASSIGN_ADD";
- case ASSIGN_SUB: return "ASSIGN_SUB";
- case ASSIGN_MUL: return "ASSIGN_MUL";
- case ASSIGN_DIV: return "ASSIGN_DIV";
- case ASSIGN_MOD: return "ASSIGN_MOD";
- case HOOK: return "HOOK";
- case COLON: return "COLON";
- case OR: return "OR";
- case AND: return "AND";
- case INC: return "INC";
- case DEC: return "DEC";
- case DOT: return "DOT";
- case FUNCTION: return "FUNCTION";
- case EXPORT: return "EXPORT";
- case IMPORT: return "IMPORT";
- case IF: return "IF";
- case ELSE: return "ELSE";
- case SWITCH: return "SWITCH";
- case CASE: return "CASE";
- case DEFAULT: return "DEFAULT";
- case WHILE: return "WHILE";
- case DO: return "DO";
- case FOR: return "FOR";
- case BREAK: return "BREAK";
- case CONTINUE: return "CONTINUE";
- case VAR: return "VAR";
- case WITH: return "WITH";
- case CATCH: return "CATCH";
- case FINALLY: return "FINALLY";
- case VOID: return "VOID";
- case RESERVED: return "RESERVED";
- case EMPTY: return "EMPTY";
- case BLOCK: return "BLOCK";
- case LABEL: return "LABEL";
- case TARGET: return "TARGET";
- case LOOP: return "LOOP";
- case EXPR_VOID: return "EXPR_VOID";
- case EXPR_RESULT: return "EXPR_RESULT";
- case JSR: return "JSR";
- case SCRIPT: return "SCRIPT";
- case TYPEOFNAME: return "TYPEOFNAME";
- case USE_STACK: return "USE_STACK";
- case SETPROP_OP: return "SETPROP_OP";
- case SETELEM_OP: return "SETELEM_OP";
- case LOCAL_BLOCK: return "LOCAL_BLOCK";
- case SET_REF_OP: return "SET_REF_OP";
- case DOTDOT: return "DOTDOT";
- case COLONCOLON: return "COLONCOLON";
- case XML: return "XML";
- case DOTQUERY: return "DOTQUERY";
- case XMLATTR: return "XMLATTR";
- case XMLEND: return "XMLEND";
- case TO_OBJECT: return "TO_OBJECT";
- case TO_DOUBLE: return "TO_DOUBLE";
- case GET: return "GET";
- case SET: return "SET";
- case LET: return "LET";
- case YIELD: return "YIELD";
- case CONST: return "CONST";
- case SETCONST: return "SETCONST";
- case ARRAYCOMP: return "ARRAYCOMP";
- case WITHEXPR: return "WITHEXPR";
- case LETEXPR: return "LETEXPR";
- case DEBUGGER: return "DEBUGGER";
- }
-
- // Token without name
- throw new IllegalStateException(String.valueOf(token));
- }
-}
diff --git a/src/org/mozilla/javascript/Token.java.orig b/src/org/mozilla/javascript/Token.java.orig
deleted file mode 100644
index 7f7cdc2a..00000000
--- a/src/org/mozilla/javascript/Token.java.orig
+++ /dev/null
@@ -1,417 +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):
- * Roger Lawrence
- * Mike McCabe
- * Igor Bukanov
- * Bob Jervis
- * 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;
-
-/**
- * This class implements the JavaScript scanner.
- *
- * It is based on the C source files jsscan.c and jsscan.h
- * in the jsref package.
- *
- * @see org.mozilla.javascript.Parser
- *
- * @author Mike McCabe
- * @author Brendan Eich
- */
-
-public class Token
-{
-
- // debug flags
- public static final boolean printTrees = false;
- static final boolean printICode = false;
- static final boolean printNames = printTrees || printICode;
-
- /**
- * Token types. These values correspond to JSTokenType values in
- * jsscan.c.
- */
-
- public final static int
- // start enum
- ERROR = -1, // well-known as the only code < EOF
- EOF = 0, // end of file token - (not EOF_CHAR)
- EOL = 1, // end of line
-
- // Interpreter reuses the following as bytecodes
- FIRST_BYTECODE_TOKEN = 2,
-
- ENTERWITH = 2,
- LEAVEWITH = 3,
- RETURN = 4,
- GOTO = 5,
- IFEQ = 6,
- IFNE = 7,
- SETNAME = 8,
- BITOR = 9,
- BITXOR = 10,
- BITAND = 11,
- EQ = 12,
- NE = 13,
- LT = 14,
- LE = 15,
- GT = 16,
- GE = 17,
- LSH = 18,
- RSH = 19,
- URSH = 20,
- ADD = 21,
- SUB = 22,
- MUL = 23,
- DIV = 24,
- MOD = 25,
- NOT = 26,
- BITNOT = 27,
- POS = 28,
- NEG = 29,
- NEW = 30,
- DELPROP = 31,
- TYPEOF = 32,
- GETPROP = 33,
- SETPROP = 34,
- GETELEM = 35,
- SETELEM = 36,
- CALL = 37,
- NAME = 38,
- NUMBER = 39,
- STRING = 40,
- NULL = 41,
- THIS = 42,
- FALSE = 43,
- TRUE = 44,
- SHEQ = 45, // shallow equality (===)
- SHNE = 46, // shallow inequality (!==)
- REGEXP = 47,
- BINDNAME = 48,
- THROW = 49,
- RETHROW = 50, // rethrow caught execetion: catch (e if ) use it
- IN = 51,
- INSTANCEOF = 52,
- LOCAL_LOAD = 53,
- GETVAR = 54,
- SETVAR = 55,
- CATCH_SCOPE = 56,
- ENUM_INIT_KEYS = 57,
- ENUM_INIT_VALUES = 58,
- ENUM_NEXT = 59,
- ENUM_ID = 60,
- THISFN = 61,
- RETURN_RESULT = 62, // to return prevoisly stored return result
- ARRAYLIT = 63, // array literal
- OBJECTLIT = 64, // object literal
- GET_REF = 65, // *reference
- SET_REF = 66, // *reference = something
- DEL_REF = 67, // delete reference
- REF_CALL = 68, // f(args) = something or f(args)++
- REF_SPECIAL = 69, // reference for special properties like __proto
-
- // For XML support:
- DEFAULTNAMESPACE = 70, // default xml namespace =
- ESCXMLATTR = 71,
- ESCXMLTEXT = 72,
- REF_MEMBER = 73, // Reference for x.@y, x..y etc.
- REF_NS_MEMBER = 74, // Reference for x.ns::y, x..ns::y etc.
- REF_NAME = 75, // Reference for @y, @[y] etc.
- REF_NS_NAME = 76; // Reference for ns::y, @ns::y@[y] etc.
-
- // End of interpreter bytecodes
- public final static int
- LAST_BYTECODE_TOKEN = REF_NS_NAME,
-
- TRY = 77,
- SEMI = 78, // semicolon
- LB = 79, // left and right brackets
- RB = 80,
- LC = 81, // left and right curlies (braces)
- RC = 82,
- LP = 83, // left and right parentheses
- RP = 84,
- COMMA = 85, // comma operator
-
- ASSIGN = 86, // simple assignment (=)
- ASSIGN_BITOR = 87, // |=
- ASSIGN_BITXOR = 88, // ^=
- ASSIGN_BITAND = 89, // |=
- ASSIGN_LSH = 90, // <<=
- ASSIGN_RSH = 91, // >>=
- ASSIGN_URSH = 92, // >>>=
- ASSIGN_ADD = 93, // +=
- ASSIGN_SUB = 94, // -=
- ASSIGN_MUL = 95, // *=
- ASSIGN_DIV = 96, // /=
- ASSIGN_MOD = 97; // %=
-
- public final static int
- FIRST_ASSIGN = ASSIGN,
- LAST_ASSIGN = ASSIGN_MOD,
-
- HOOK = 98, // conditional (?:)
- COLON = 99,
- OR = 100, // logical or (||)
- AND = 101, // logical and (&&)
- INC = 102, // increment/decrement (++ --)
- DEC = 103,
- DOT = 104, // member operator (.)
- FUNCTION = 105, // function keyword
- EXPORT = 106, // export keyword
- IMPORT = 107, // import keyword
- IF = 108, // if keyword
- ELSE = 109, // else keyword
- SWITCH = 110, // switch keyword
- CASE = 111, // case keyword
- DEFAULT = 112, // default keyword
- WHILE = 113, // while keyword
- DO = 114, // do keyword
- FOR = 115, // for keyword
- BREAK = 116, // break keyword
- CONTINUE = 117, // continue keyword
- VAR = 118, // var keyword
- WITH = 119, // with keyword
- CATCH = 120, // catch keyword
- FINALLY = 121, // finally keyword
- VOID = 122, // void keyword
- RESERVED = 123, // reserved keywords
-
- EMPTY = 124,
-
- /* types used for the parse tree - these never get returned
- * by the scanner.
- */
-
- BLOCK = 125, // statement block
- LABEL = 126, // label
- TARGET = 127,
- LOOP = 128,
- EXPR_VOID = 129, // expression statement in functions
- EXPR_RESULT = 130, // expression statement in scripts
- JSR = 131,
- SCRIPT = 132, // top-level node for entire script
- TYPEOFNAME = 133, // for typeof(simple-name)
- USE_STACK = 134,
- SETPROP_OP = 135, // x.y op= something
- SETELEM_OP = 136, // x[y] op= something
- LOCAL_BLOCK = 137,
- SET_REF_OP = 138, // *reference op= something
-
- // For XML support:
- DOTDOT = 139, // member operator (..)
- COLONCOLON = 140, // namespace::name
- XML = 141, // XML type
- DOTQUERY = 142, // .() -- e.g., x.emps.emp.(name == "terry")
- XMLATTR = 143, // @
- XMLEND = 144,
-
- // Optimizer-only-tokens
- TO_OBJECT = 145,
- TO_DOUBLE = 146,
-
- GET = 147, // JS 1.5 get pseudo keyword
- SET = 148, // JS 1.5 set pseudo keyword
- CONST = 149,
- SETCONST = 150,
- SETCONSTVAR = 151,
- LAST_TOKEN = 152;
-
- public static String name(int token)
- {
- if (!printNames) {
- return String.valueOf(token);
- }
- switch (token) {
- case ERROR: return "ERROR";
- case EOF: return "EOF";
- case EOL: return "EOL";
- case ENTERWITH: return "ENTERWITH";
- case LEAVEWITH: return "LEAVEWITH";
- case RETURN: return "RETURN";
- case GOTO: return "GOTO";
- case IFEQ: return "IFEQ";
- case IFNE: return "IFNE";
- case SETNAME: return "SETNAME";
- case BITOR: return "BITOR";
- case BITXOR: return "BITXOR";
- case BITAND: return "BITAND";
- case EQ: return "EQ";
- case NE: return "NE";
- case LT: return "LT";
- case LE: return "LE";
- case GT: return "GT";
- case GE: return "GE";
- case LSH: return "LSH";
- case RSH: return "RSH";
- case URSH: return "URSH";
- case ADD: return "ADD";
- case SUB: return "SUB";
- case MUL: return "MUL";
- case DIV: return "DIV";
- case MOD: return "MOD";
- case NOT: return "NOT";
- case BITNOT: return "BITNOT";
- case POS: return "POS";
- case NEG: return "NEG";
- case NEW: return "NEW";
- case DELPROP: return "DELPROP";
- case TYPEOF: return "TYPEOF";
- case GETPROP: return "GETPROP";
- case SETPROP: return "SETPROP";
- case GETELEM: return "GETELEM";
- case SETELEM: return "SETELEM";
- case CALL: return "CALL";
- case NAME: return "NAME";
- case NUMBER: return "NUMBER";
- case STRING: return "STRING";
- case NULL: return "NULL";
- case THIS: return "THIS";
- case FALSE: return "FALSE";
- case TRUE: return "TRUE";
- case SHEQ: return "SHEQ";
- case SHNE: return "SHNE";
- case REGEXP: return "OBJECT";
- case BINDNAME: return "BINDNAME";
- case THROW: return "THROW";
- case RETHROW: return "RETHROW";
- case IN: return "IN";
- case INSTANCEOF: return "INSTANCEOF";
- case LOCAL_LOAD: return "LOCAL_LOAD";
- case GETVAR: return "GETVAR";
- case SETVAR: return "SETVAR";
- case CATCH_SCOPE: return "CATCH_SCOPE";
- case ENUM_INIT_KEYS: return "ENUM_INIT_KEYS";
- case ENUM_INIT_VALUES: return "ENUM_INIT_VALUES";
- case ENUM_NEXT: return "ENUM_NEXT";
- case ENUM_ID: return "ENUM_ID";
- case THISFN: return "THISFN";
- case RETURN_RESULT: return "RETURN_RESULT";
- case ARRAYLIT: return "ARRAYLIT";
- case OBJECTLIT: return "OBJECTLIT";
- case GET_REF: return "GET_REF";
- case SET_REF: return "SET_REF";
- case DEL_REF: return "DEL_REF";
- case REF_CALL: return "REF_CALL";
- case REF_SPECIAL: return "REF_SPECIAL";
- case DEFAULTNAMESPACE:return "DEFAULTNAMESPACE";
- case ESCXMLTEXT: return "ESCXMLTEXT";
- case ESCXMLATTR: return "ESCXMLATTR";
- case REF_MEMBER: return "REF_MEMBER";
- case REF_NS_MEMBER: return "REF_NS_MEMBER";
- case REF_NAME: return "REF_NAME";
- case REF_NS_NAME: return "REF_NS_NAME";
- case TRY: return "TRY";
- case SEMI: return "SEMI";
- case LB: return "LB";
- case RB: return "RB";
- case LC: return "LC";
- case RC: return "RC";
- case LP: return "LP";
- case RP: return "RP";
- case COMMA: return "COMMA";
- case ASSIGN: return "ASSIGN";
- case ASSIGN_BITOR: return "ASSIGN_BITOR";
- case ASSIGN_BITXOR: return "ASSIGN_BITXOR";
- case ASSIGN_BITAND: return "ASSIGN_BITAND";
- case ASSIGN_LSH: return "ASSIGN_LSH";
- case ASSIGN_RSH: return "ASSIGN_RSH";
- case ASSIGN_URSH: return "ASSIGN_URSH";
- case ASSIGN_ADD: return "ASSIGN_ADD";
- case ASSIGN_SUB: return "ASSIGN_SUB";
- case ASSIGN_MUL: return "ASSIGN_MUL";
- case ASSIGN_DIV: return "ASSIGN_DIV";
- case ASSIGN_MOD: return "ASSIGN_MOD";
- case HOOK: return "HOOK";
- case COLON: return "COLON";
- case OR: return "OR";
- case AND: return "AND";
- case INC: return "INC";
- case DEC: return "DEC";
- case DOT: return "DOT";
- case FUNCTION: return "FUNCTION";
- case EXPORT: return "EXPORT";
- case IMPORT: return "IMPORT";
- case IF: return "IF";
- case ELSE: return "ELSE";
- case SWITCH: return "SWITCH";
- case CASE: return "CASE";
- case DEFAULT: return "DEFAULT";
- case WHILE: return "WHILE";
- case DO: return "DO";
- case FOR: return "FOR";
- case BREAK: return "BREAK";
- case CONTINUE: return "CONTINUE";
- case VAR: return "VAR";
- case WITH: return "WITH";
- case CATCH: return "CATCH";
- case FINALLY: return "FINALLY";
- case RESERVED: return "RESERVED";
- case EMPTY: return "EMPTY";
- case BLOCK: return "BLOCK";
- case LABEL: return "LABEL";
- case TARGET: return "TARGET";
- case LOOP: return "LOOP";
- case EXPR_VOID: return "EXPR_VOID";
- case EXPR_RESULT: return "EXPR_RESULT";
- case JSR: return "JSR";
- case SCRIPT: return "SCRIPT";
- case TYPEOFNAME: return "TYPEOFNAME";
- case USE_STACK: return "USE_STACK";
- case SETPROP_OP: return "SETPROP_OP";
- case SETELEM_OP: return "SETELEM_OP";
- case LOCAL_BLOCK: return "LOCAL_BLOCK";
- case SET_REF_OP: return "SET_REF_OP";
- case DOTDOT: return "DOTDOT";
- case COLONCOLON: return "COLONCOLON";
- case XML: return "XML";
- case DOTQUERY: return "DOTQUERY";
- case XMLATTR: return "XMLATTR";
- case XMLEND: return "XMLEND";
- case TO_OBJECT: return "TO_OBJECT";
- case TO_DOUBLE: return "TO_DOUBLE";
- case GET: return "GET";
- case SET: return "SET";
- case CONST: return "CONST";
- case SETCONST: return "SETCONST";
- }
-
- // Token without name
- throw new IllegalStateException(String.valueOf(token));
- }
-}
diff --git a/src/org/mozilla/javascript/TokenStream.java b/src/org/mozilla/javascript/TokenStream.java
deleted file mode 100644
index 8a508fd5..00000000
--- a/src/org/mozilla/javascript/TokenStream.java
+++ /dev/null
@@ -1,1423 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
-*
-* Version: MPL 1.1
-*
-* 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 org/mozilla/javascript/TokenStream.java,
-* a component of the Rhino Library ( http://www.mozilla.org/rhino/ )
-* This file is a modification of the Original Code developed
-* for YUI Compressor.
-*
-* The Initial Developer of the Original Code is Mozilla Foundation
-*
-* Copyright (c) 2009 Mozilla Foundation. All Rights Reserved.
-*
-* Contributor(s): Yahoo! Inc. 2009
-*
-* ***** END LICENSE BLOCK ***** */
-
-package org.mozilla.javascript;
-
-import java.io.*;
-
-/**
- * This class implements the JavaScript scanner.
- *
- * It is based on the C source files jsscan.c and jsscan.h
- * in the jsref package.
- *
- * @see org.mozilla.javascript.Parser
- *
- * @author Mike McCabe
- * @author Brendan Eich
- */
-
-class TokenStream
-{
- /*
- * For chars - because we need something out-of-range
- * to check. (And checking EOF by exception is annoying.)
- * Note distinction from EOF token type!
- */
- private final static int
- EOF_CHAR = -1;
-
- TokenStream(Parser parser, Reader sourceReader, String sourceString,
- int lineno)
- {
- this.parser = parser;
- this.lineno = lineno;
- if (sourceReader != null) {
- if (sourceString != null) Kit.codeBug();
- this.sourceReader = sourceReader;
- this.sourceBuffer = new char[512];
- this.sourceEnd = 0;
- } else {
- if (sourceString == null) Kit.codeBug();
- this.sourceString = sourceString;
- this.sourceEnd = sourceString.length();
- }
- this.sourceCursor = 0;
- }
-
- /* This function uses the cached op, string and number fields in
- * TokenStream; if getToken has been called since the passed token
- * was scanned, the op or string printed may be incorrect.
- */
- String tokenToString(int token)
- {
- if (Token.printTrees) {
- String name = Token.name(token);
-
- switch (token) {
- case Token.STRING:
- case Token.REGEXP:
- case Token.NAME:
- return name + " `" + this.string + "'";
-
- case Token.NUMBER:
- return "NUMBER " + this.number;
- }
-
- return name;
- }
- return "";
- }
-
- static boolean isKeyword(String s)
- {
- return Token.EOF != stringToKeyword(s);
- }
-
- private static int stringToKeyword(String name)
- {
-// #string_id_map#
-// The following assumes that Token.EOF == 0
- final int
- Id_break = Token.BREAK,
- Id_case = Token.CASE,
- Id_continue = Token.CONTINUE,
- Id_default = Token.DEFAULT,
- Id_delete = Token.DELPROP,
- Id_do = Token.DO,
- Id_else = Token.ELSE,
- Id_export = Token.EXPORT,
- Id_false = Token.FALSE,
- Id_for = Token.FOR,
- Id_function = Token.FUNCTION,
- Id_if = Token.IF,
- Id_in = Token.IN,
- Id_let = Token.LET,
- Id_new = Token.NEW,
- Id_null = Token.NULL,
- Id_return = Token.RETURN,
- Id_switch = Token.SWITCH,
- Id_this = Token.THIS,
- Id_true = Token.TRUE,
- Id_typeof = Token.TYPEOF,
- Id_var = Token.VAR,
- Id_void = Token.VOID,
- Id_while = Token.WHILE,
- Id_with = Token.WITH,
- Id_yield = Token.YIELD,
-
- // the following are #ifdef RESERVE_JAVA_KEYWORDS in jsscan.c
- Id_abstract = Token.RESERVED,
- Id_boolean = Token.RESERVED,
- Id_byte = Token.RESERVED,
- Id_catch = Token.CATCH,
- Id_char = Token.RESERVED,
- Id_class = Token.RESERVED,
- Id_const = Token.CONST,
- Id_debugger = Token.DEBUGGER,
- Id_double = Token.RESERVED,
- Id_enum = Token.RESERVED,
- Id_extends = Token.RESERVED,
- Id_final = Token.RESERVED,
- Id_finally = Token.FINALLY,
- Id_float = Token.RESERVED,
- Id_goto = Token.RESERVED,
- Id_implements = Token.RESERVED,
- Id_import = Token.IMPORT,
- Id_instanceof = Token.INSTANCEOF,
- Id_int = Token.RESERVED,
- Id_interface = Token.RESERVED,
- Id_long = Token.RESERVED,
- Id_native = Token.RESERVED,
- Id_package = Token.RESERVED,
- Id_private = Token.RESERVED,
- Id_protected = Token.RESERVED,
- Id_public = Token.RESERVED,
- Id_short = Token.RESERVED,
- Id_static = Token.RESERVED,
- Id_super = Token.RESERVED,
- Id_synchronized = Token.RESERVED,
- Id_throw = Token.THROW,
- Id_throws = Token.RESERVED,
- Id_transient = Token.RESERVED,
- Id_try = Token.TRY,
- Id_volatile = Token.RESERVED;
-
- int id;
- String s = name;
-// #generated# Last update: 2001-06-01 17:45:01 CEST
- L0: { id = 0; String X = null; int c;
- L: switch (s.length()) {
- case 2: c=s.charAt(1);
- if (c=='f') { if (s.charAt(0)=='i') {id=Id_if; break L0;} }
- else if (c=='n') { if (s.charAt(0)=='i') {id=Id_in; break L0;} }
- else if (c=='o') { if (s.charAt(0)=='d') {id=Id_do; break L0;} }
- break L;
- case 3: switch (s.charAt(0)) {
- case 'f': if (s.charAt(2)=='r' && s.charAt(1)=='o') {id=Id_for; break L0;} break L;
-// case 'i': if (s.charAt(2)=='t' && s.charAt(1)=='n') {id=Id_int; break L0;} break L;
- case 'l': if (s.charAt(2)=='t' && s.charAt(1)=='e') {id=Id_let; break L0;} break L;
- case 'n': if (s.charAt(2)=='w' && s.charAt(1)=='e') {id=Id_new; break L0;} break L;
- case 't': if (s.charAt(2)=='y' && s.charAt(1)=='r') {id=Id_try; break L0;} break L;
- case 'v': if (s.charAt(2)=='r' && s.charAt(1)=='a') {id=Id_var; break L0;} break L;
- } break L;
- case 4: switch (s.charAt(0)) {
-// case 'b': X="byte";id=Id_byte; break L;
- case 'c': c=s.charAt(3);
- if (c=='e') { if (s.charAt(2)=='s' && s.charAt(1)=='a') {id=Id_case; break L0;} }
-// else if (c=='r') { if (s.charAt(2)=='a' && s.charAt(1)=='h') {id=Id_char; break L0;} }
- break L;
- case 'e': c=s.charAt(3);
- if (c=='e') { if (s.charAt(2)=='s' && s.charAt(1)=='l') {id=Id_else; break L0;} }
- else if (c=='m') { if (s.charAt(2)=='u' && s.charAt(1)=='n') {id=Id_enum; break L0;} }
- break L;
- case 'g': X="goto";id=Id_goto; break L;
-// case 'l': X="long";id=Id_long; break L;
- case 'n': X="null";id=Id_null; break L;
- case 't': c=s.charAt(3);
- if (c=='e') { if (s.charAt(2)=='u' && s.charAt(1)=='r') {id=Id_true; break L0;} }
- else if (c=='s') { if (s.charAt(2)=='i' && s.charAt(1)=='h') {id=Id_this; break L0;} }
- break L;
- case 'v': X="void";id=Id_void; break L;
- case 'w': X="with";id=Id_with; break L;
- } break L;
- case 5: switch (s.charAt(2)) {
- case 'a': X="class";id=Id_class; break L;
- case 'e': c=s.charAt(0);
- if (c=='b') { X="break";id=Id_break; }
- else if (c=='y') { X="yield";id=Id_yield; }
- break L;
- case 'i': X="while";id=Id_while; break L;
- case 'l': X="false";id=Id_false; break L;
- case 'n': c=s.charAt(0);
- if (c=='c') { X="const";id=Id_const; }
- else if (c=='f') { X="final";id=Id_final; }
- break L;
- case 'o': c=s.charAt(0);
-// if (c=='f') { X="float";id=Id_float; }
-// else if (c=='s') { X="short";id=Id_short; }
- break L;
- case 'p': X="super";id=Id_super; break L;
- case 'r': X="throw";id=Id_throw; break L;
- case 't': X="catch";id=Id_catch; break L;
- } break L;
- case 6: switch (s.charAt(1)) {
- case 'a': X="native";id=Id_native; break L;
- case 'e': c=s.charAt(0);
- if (c=='d') { X="delete";id=Id_delete; }
- else if (c=='r') { X="return";id=Id_return; }
- break L;
- case 'h': X="throws";id=Id_throws; break L;
- case 'm': X="import";id=Id_import; break L;
-// case 'o': X="double";id=Id_double; break L;
- case 't': X="static";id=Id_static; break L;
- case 'u': X="public";id=Id_public; break L;
- case 'w': X="switch";id=Id_switch; break L;
- case 'x': X="export";id=Id_export; break L;
- case 'y': X="typeof";id=Id_typeof; break L;
- } break L;
- case 7: switch (s.charAt(1)) {
- case 'a': X="package";id=Id_package; break L;
- case 'e': X="default";id=Id_default; break L;
- case 'i': X="finally";id=Id_finally; break L;
-// case 'o': X="boolean";id=Id_boolean; break L;
- case 'r': X="private";id=Id_private; break L;
- case 'x': X="extends";id=Id_extends; break L;
- } break L;
- case 8: switch (s.charAt(0)) {
- case 'a': X="abstract";id=Id_abstract; break L;
- case 'c': X="continue";id=Id_continue; break L;
- case 'd': X="debugger";id=Id_debugger; break L;
- case 'f': X="function";id=Id_function; break L;
- case 'v': X="volatile";id=Id_volatile; break L;
- } break L;
- case 9: c=s.charAt(0);
- if (c=='i') { X="interface";id=Id_interface; }
- else if (c=='p') { X="protected";id=Id_protected; }
- else if (c=='t') { X="transient";id=Id_transient; }
- break L;
- case 10: c=s.charAt(1);
- if (c=='m') { X="implements";id=Id_implements; }
- else if (c=='n') { X="instanceof";id=Id_instanceof; }
- break L;
- case 12: X="synchronized";id=Id_synchronized; break L;
- }
- if (X!=null && X!=s && !X.equals(s)) id = 0;
- }
-// #/generated#
-// #/string_id_map#
- if (id == 0) { return Token.EOF; }
- return id & 0xff;
- }
-
- final int getLineno() { return lineno; }
-
- final String getString() { return string; }
-
- final double getNumber() { return number; }
-
- final boolean eof() { return hitEOF; }
-
- final int getToken() throws IOException
- {
- int c;
-
- retry:
- for (;;) {
- // Eat whitespace, possibly sensitive to newlines.
- for (;;) {
- c = getChar();
- if (c == EOF_CHAR) {
- return Token.EOF;
- } else if (c == '\n') {
- dirtyLine = false;
- return Token.EOL;
- } else if (!isJSSpace(c)) {
- if (c != '-') {
- dirtyLine = true;
- }
- break;
- }
- }
-
- if (c == '@') return Token.XMLATTR;
-
- // identifier/keyword/instanceof?
- // watch out for starting with a
- boolean identifierStart;
- boolean isUnicodeEscapeStart = false;
- if (c == '\\') {
- c = getChar();
- if (c == 'u') {
- identifierStart = true;
- isUnicodeEscapeStart = true;
- stringBufferTop = 0;
- } else {
- identifierStart = false;
- ungetChar(c);
- c = '\\';
- }
- } else {
- identifierStart = Character.isJavaIdentifierStart((char)c);
- if (identifierStart) {
- stringBufferTop = 0;
- addToString(c);
- }
- }
-
- if (identifierStart) {
- boolean containsEscape = isUnicodeEscapeStart;
- for (;;) {
- if (isUnicodeEscapeStart) {
- // strictly speaking we should probably push-back
- // all the bad characters if the uXXXX
- // sequence is malformed. But since there isn't a
- // correct context(is there?) for a bad Unicode
- // escape sequence in an identifier, we can report
- // an error here.
- int escapeVal = 0;
- for (int i = 0; i != 4; ++i) {
- c = getChar();
- escapeVal = Kit.xDigitToInt(c, escapeVal);
- // Next check takes care about c < 0 and bad escape
- if (escapeVal < 0) { break; }
- }
- if (escapeVal < 0) {
- parser.addError("msg.invalid.escape");
- return Token.ERROR;
- }
- addToString(escapeVal);
- isUnicodeEscapeStart = false;
- } else {
- c = getChar();
- if (c == '\\') {
- c = getChar();
- if (c == 'u') {
- isUnicodeEscapeStart = true;
- containsEscape = true;
- } else {
- parser.addError("msg.illegal.character");
- return Token.ERROR;
- }
- } else {
- if (c == EOF_CHAR
- || !Character.isJavaIdentifierPart((char)c))
- {
- break;
- }
- addToString(c);
- }
- }
- }
- ungetChar(c);
-
- String str = getStringFromBuffer();
- if (!containsEscape) {
- // OPT we shouldn't have to make a string (object!) to
- // check if it's a keyword.
-
- // Return the corresponding token if it's a keyword
- int result = stringToKeyword(str);
- if (result != Token.EOF) {
- if ((result == Token.LET || result == Token.YIELD) &&
- parser.compilerEnv.getLanguageVersion()
- < Context.VERSION_1_7)
- {
- // LET and YIELD are tokens only in 1.7 and later
- string = result == Token.LET ? "let" : "yield";
- result = Token.NAME;
- }
- if (result != Token.RESERVED) {
- return result;
- } else if (!parser.compilerEnv.
- isReservedKeywordAsIdentifier())
- {
- return result;
- } else {
- // If implementation permits to use future reserved
- // keywords in violation with the EcmaScript,
- // treat it as name but issue warning
- parser.addWarning("msg.reserved.keyword", str);
- }
- }
- }
- this.string = (String)allStrings.intern(str);
- return Token.NAME;
- }
-
- // is it a number?
- if (isDigit(c) || (c == '.' && isDigit(peekChar()))) {
-
- stringBufferTop = 0;
- int base = 10;
-
- if (c == '0') {
- c = getChar();
- if (c == 'x' || c == 'X') {
- base = 16;
- c = getChar();
- } else if (isDigit(c)) {
- base = 8;
- } else {
- addToString('0');
- }
- }
-
- if (base == 16) {
- while (0 <= Kit.xDigitToInt(c, 0)) {
- addToString(c);
- c = getChar();
- }
- } else {
- while ('0' <= c && c <= '9') {
- /*
- * We permit 08 and 09 as decimal numbers, which
- * makes our behavior a superset of the ECMA
- * numeric grammar. We might not always be so
- * permissive, so we warn about it.
- */
- if (base == 8 && c >= '8') {
- parser.addWarning("msg.bad.octal.literal",
- c == '8' ? "8" : "9");
- base = 10;
- }
- addToString(c);
- c = getChar();
- }
- }
-
- boolean isInteger = true;
-
- if (base == 10 && (c == '.' || c == 'e' || c == 'E')) {
- isInteger = false;
- if (c == '.') {
- do {
- addToString(c);
- c = getChar();
- } while (isDigit(c));
- }
- if (c == 'e' || c == 'E') {
- addToString(c);
- c = getChar();
- if (c == '+' || c == '-') {
- addToString(c);
- c = getChar();
- }
- if (!isDigit(c)) {
- parser.addError("msg.missing.exponent");
- return Token.ERROR;
- }
- do {
- addToString(c);
- c = getChar();
- } while (isDigit(c));
- }
- }
- ungetChar(c);
- String numString = getStringFromBuffer();
-
- double dval;
- if (base == 10 && !isInteger) {
- try {
- // Use Java conversion to number from string...
- dval = Double.valueOf(numString).doubleValue();
- }
- catch (NumberFormatException ex) {
- parser.addError("msg.caught.nfe");
- return Token.ERROR;
- }
- } else {
- dval = ScriptRuntime.stringToNumber(numString, 0, base);
- }
-
- this.number = dval;
- return Token.NUMBER;
- }
-
- // is it a string?
- if (c == '"' || c == '\'') {
- // We attempt to accumulate a string the fast way, by
- // building it directly out of the reader. But if there
- // are any escaped characters in the string, we revert to
- // building it out of a StringBuffer.
-
- int quoteChar = c;
- stringBufferTop = 0;
-
- c = getChar();
- while (c != quoteChar) {
- if (c == '\n' || c == EOF_CHAR) {
- ungetChar(c);
- parser.addError("msg.unterminated.string.lit");
- return Token.ERROR;
- }
-
- if (c == '\\') {
- // We've hit an escaped character
-
- c = getChar();
-
- switch (c) {
-
- case '\\': // backslash
- case 'b': // backspace
- case 'f': // form feed
- case 'n': // line feed
- case 'r': // carriage return
- case 't': // horizontal tab
- case 'v': // vertical tab
- case 'd': // octal sequence
- case 'u': // unicode sequence
- case 'x': // hexadecimal sequence
- // Only keep the '\' character for those
- // characters that need to be escaped...
- // Don't escape quoting characters...
- addToString('\\');
- addToString(c);
- break;
-
- case '\n':
- // Remove line terminator after escape
- break;
-
- default:
- if (isDigit(c)) {
- // Octal representation of a character.
- // Preserve the escaping (see Y! bug #1637286)
- addToString('\\');
- }
- addToString(c);
- break;
- }
-
- } else {
-
- addToString(c);
- }
-
- c = getChar();
- }
-
- String str = getStringFromBuffer();
- this.string = (String)allStrings.intern(str);
- return Token.STRING;
- }
-
- switch (c) {
- case ';': return Token.SEMI;
- case '[': return Token.LB;
- case ']': return Token.RB;
- case '{': return Token.LC;
- case '}': return Token.RC;
- case '(': return Token.LP;
- case ')': return Token.RP;
- case ',': return Token.COMMA;
- case '?': return Token.HOOK;
- case ':':
- if (matchChar(':')) {
- return Token.COLONCOLON;
- } else {
- return Token.COLON;
- }
- case '.':
- if (matchChar('.')) {
- return Token.DOTDOT;
- } else if (matchChar('(')) {
- return Token.DOTQUERY;
- } else {
- return Token.DOT;
- }
-
- case '|':
- if (matchChar('|')) {
- return Token.OR;
- } else if (matchChar('=')) {
- return Token.ASSIGN_BITOR;
- } else {
- return Token.BITOR;
- }
-
- case '^':
- if (matchChar('=')) {
- return Token.ASSIGN_BITXOR;
- } else {
- return Token.BITXOR;
- }
-
- case '&':
- if (matchChar('&')) {
- return Token.AND;
- } else if (matchChar('=')) {
- return Token.ASSIGN_BITAND;
- } else {
- return Token.BITAND;
- }
-
- case '=':
- if (matchChar('=')) {
- if (matchChar('='))
- return Token.SHEQ;
- else
- return Token.EQ;
- } else {
- return Token.ASSIGN;
- }
-
- case '!':
- if (matchChar('=')) {
- if (matchChar('='))
- return Token.SHNE;
- else
- return Token.NE;
- } else {
- return Token.NOT;
- }
-
- case '<':
- /* NB:treat HTML begin-comment as comment-till-eol */
- if (matchChar('!')) {
- if (matchChar('-')) {
- if (matchChar('-')) {
- skipLine();
- continue retry;
- }
- ungetCharIgnoreLineEnd('-');
- }
- ungetCharIgnoreLineEnd('!');
- }
- if (matchChar('<')) {
- if (matchChar('=')) {
- return Token.ASSIGN_LSH;
- } else {
- return Token.LSH;
- }
- } else {
- if (matchChar('=')) {
- return Token.LE;
- } else {
- return Token.LT;
- }
- }
-
- case '>':
- if (matchChar('>')) {
- if (matchChar('>')) {
- if (matchChar('=')) {
- return Token.ASSIGN_URSH;
- } else {
- return Token.URSH;
- }
- } else {
- if (matchChar('=')) {
- return Token.ASSIGN_RSH;
- } else {
- return Token.RSH;
- }
- }
- } else {
- if (matchChar('=')) {
- return Token.GE;
- } else {
- return Token.GT;
- }
- }
-
- case '*':
- if (matchChar('=')) {
- return Token.ASSIGN_MUL;
- } else {
- return Token.MUL;
- }
-
- case '/':
- // is it a // comment?
- if (matchChar('/')) {
- skipLine();
- continue retry;
- }
- if (matchChar('*')) {
- boolean lookForSlash = false;
- StringBuffer sb = new StringBuffer();
- for (;;) {
- c = getChar();
- if (c == EOF_CHAR) {
- parser.addError("msg.unterminated.comment");
- return Token.ERROR;
- }
- sb.append((char) c);
- if (c == '*') {
- lookForSlash = true;
- } else if (c == '/') {
- if (lookForSlash) {
- sb.delete(sb.length()-2, sb.length());
- String s1 = sb.toString();
- String s2 = s1.trim();
- if (s1.startsWith("!")) {
- // Remove the leading '!'
- this.string = s1.substring(1);
- return Token.KEEPCOMMENT;
- } else if (s2.startsWith("@cc_on") ||
- s2.startsWith("@if") ||
- s2.startsWith("@elif") ||
- s2.startsWith("@else") ||
- s2.startsWith("@end")) {
- this.string = s1;
- return Token.CONDCOMMENT;
- } else {
- continue retry;
- }
- }
- } else {
- lookForSlash = false;
- }
- }
- }
-
- if (matchChar('=')) {
- return Token.ASSIGN_DIV;
- } else {
- return Token.DIV;
- }
-
- case '%':
- if (matchChar('=')) {
- return Token.ASSIGN_MOD;
- } else {
- return Token.MOD;
- }
-
- case '~':
- return Token.BITNOT;
-
- case '+':
- if (matchChar('=')) {
- return Token.ASSIGN_ADD;
- } else if (matchChar('+')) {
- return Token.INC;
- } else {
- return Token.ADD;
- }
-
- case '-':
- if (matchChar('=')) {
- c = Token.ASSIGN_SUB;
- } else if (matchChar('-')) {
- if (!dirtyLine) {
- // treat HTML end-comment after possible whitespace
- // after line start as comment-utill-eol
- if (matchChar('>')) {
- skipLine();
- continue retry;
- }
- }
- c = Token.DEC;
- } else {
- c = Token.SUB;
- }
- dirtyLine = true;
- return c;
-
- default:
- parser.addError("msg.illegal.character");
- return Token.ERROR;
- }
- }
- }
-
- private static boolean isAlpha(int c)
- {
- // Use 'Z' < 'a'
- if (c <= 'Z') {
- return 'A' <= c;
- } else {
- return 'a' <= c && c <= 'z';
- }
- }
-
- static boolean isDigit(int c)
- {
- return '0' <= c && c <= '9';
- }
-
- /* As defined in ECMA. jsscan.c uses C isspace() (which allows
- * \v, I think.) note that code in getChar() implicitly accepts
- * '\r' == \u000D as well.
- */
- static boolean isJSSpace(int c)
- {
- if (c <= 127) {
- return c == 0x20 || c == 0x9 || c == 0xC || c == 0xB;
- } else {
- return c == 0xA0
- || Character.getType((char)c) == Character.SPACE_SEPARATOR;
- }
- }
-
- private static boolean isJSFormatChar(int c)
- {
- return c > 127 && Character.getType((char)c) == Character.FORMAT;
- }
-
- /**
- * Parser calls the method when it gets / or /= in literal context.
- */
- void readRegExp(int startToken)
- throws IOException
- {
- stringBufferTop = 0;
- if (startToken == Token.ASSIGN_DIV) {
- // Miss-scanned /=
- addToString('=');
- } else {
- if (startToken != Token.DIV) Kit.codeBug();
- }
-
- int c;
- boolean inClass = false;
- while ((c = getChar()) != '/' || inClass) {
- if (c == '\n' || c == EOF_CHAR) {
- ungetChar(c);
- throw parser.reportError("msg.unterminated.re.lit");
- }
- if (c == '\\') {
- addToString(c);
- c = getChar();
- } else if (c == '[') {
- inClass = true;
- } else if (c == ']') {
- inClass = false;
- }
- addToString(c);
- }
- int reEnd = stringBufferTop;
-
- while (true) {
- if (matchChar('g'))
- addToString('g');
- else if (matchChar('i'))
- addToString('i');
- else if (matchChar('m'))
- addToString('m');
- else
- break;
- }
-
- if (isAlpha(peekChar())) {
- throw parser.reportError("msg.invalid.re.flag");
- }
-
- this.string = new String(stringBuffer, 0, reEnd);
- this.regExpFlags = new String(stringBuffer, reEnd,
- stringBufferTop - reEnd);
- }
-
- boolean isXMLAttribute()
- {
- return xmlIsAttribute;
- }
-
- int getFirstXMLToken() throws IOException
- {
- xmlOpenTagsCount = 0;
- xmlIsAttribute = false;
- xmlIsTagContent = false;
- ungetChar('<');
- return getNextXMLToken();
- }
-
- int getNextXMLToken() throws IOException
- {
- stringBufferTop = 0; // remember the XML
-
- for (int c = getChar(); c != EOF_CHAR; c = getChar()) {
- if (xmlIsTagContent) {
- switch (c) {
- case '>':
- addToString(c);
- xmlIsTagContent = false;
- xmlIsAttribute = false;
- break;
- case '/':
- addToString(c);
- if (peekChar() == '>') {
- c = getChar();
- addToString(c);
- xmlIsTagContent = false;
- xmlOpenTagsCount--;
- }
- break;
- case '{':
- ungetChar(c);
- this.string = getStringFromBuffer();
- return Token.XML;
- case '\'':
- case '"':
- addToString(c);
- if (!readQuotedString(c)) return Token.ERROR;
- break;
- case '=':
- addToString(c);
- xmlIsAttribute = true;
- break;
- case ' ':
- case '\t':
- case '\r':
- case '\n':
- addToString(c);
- break;
- default:
- addToString(c);
- xmlIsAttribute = false;
- break;
- }
-
- if (!xmlIsTagContent && xmlOpenTagsCount == 0) {
- this.string = getStringFromBuffer();
- return Token.XMLEND;
- }
- } else {
- switch (c) {
- case '<':
- addToString(c);
- c = peekChar();
- switch (c) {
- case '!':
- c = getChar(); // Skip !
- addToString(c);
- c = peekChar();
- switch (c) {
- case '-':
- c = getChar(); // Skip -
- addToString(c);
- c = getChar();
- if (c == '-') {
- addToString(c);
- if(!readXmlComment()) return Token.ERROR;
- } else {
- // throw away the string in progress
- stringBufferTop = 0;
- this.string = null;
- parser.addError("msg.XML.bad.form");
- return Token.ERROR;
- }
- break;
- case '[':
- c = getChar(); // Skip [
- addToString(c);
- if (getChar() == 'C' &&
- getChar() == 'D' &&
- getChar() == 'A' &&
- getChar() == 'T' &&
- getChar() == 'A' &&
- getChar() == '[')
- {
- addToString('C');
- addToString('D');
- addToString('A');
- addToString('T');
- addToString('A');
- addToString('[');
- if (!readCDATA()) return Token.ERROR;
-
- } else {
- // throw away the string in progress
- stringBufferTop = 0;
- this.string = null;
- parser.addError("msg.XML.bad.form");
- return Token.ERROR;
- }
- break;
- default:
- if(!readEntity()) return Token.ERROR;
- break;
- }
- break;
- case '?':
- c = getChar(); // Skip ?
- addToString(c);
- if (!readPI()) return Token.ERROR;
- break;
- case '/':
- // End tag
- c = getChar(); // Skip /
- addToString(c);
- if (xmlOpenTagsCount == 0) {
- // throw away the string in progress
- stringBufferTop = 0;
- this.string = null;
- parser.addError("msg.XML.bad.form");
- return Token.ERROR;
- }
- xmlIsTagContent = true;
- xmlOpenTagsCount--;
- break;
- default:
- // Start tag
- xmlIsTagContent = true;
- xmlOpenTagsCount++;
- break;
- }
- break;
- case '{':
- ungetChar(c);
- this.string = getStringFromBuffer();
- return Token.XML;
- default:
- addToString(c);
- break;
- }
- }
- }
-
- stringBufferTop = 0; // throw away the string in progress
- this.string = null;
- parser.addError("msg.XML.bad.form");
- return Token.ERROR;
- }
-
- /**
- *
- */
- private boolean readQuotedString(int quote) throws IOException
- {
- for (int c = getChar(); c != EOF_CHAR; c = getChar()) {
- addToString(c);
- if (c == quote) return true;
- }
-
- stringBufferTop = 0; // throw away the string in progress
- this.string = null;
- parser.addError("msg.XML.bad.form");
- return false;
- }
-
- /**
- *
- */
- private boolean readXmlComment() throws IOException
- {
- for (int c = getChar(); c != EOF_CHAR;) {
- addToString(c);
- if (c == '-' && peekChar() == '-') {
- c = getChar();
- addToString(c);
- if (peekChar() == '>') {
- c = getChar(); // Skip >
- addToString(c);
- return true;
- } else {
- continue;
- }
- }
- c = getChar();
- }
-
- stringBufferTop = 0; // throw away the string in progress
- this.string = null;
- parser.addError("msg.XML.bad.form");
- return false;
- }
-
- /**
- *
- */
- private boolean readCDATA() throws IOException
- {
- for (int c = getChar(); c != EOF_CHAR;) {
- addToString(c);
- if (c == ']' && peekChar() == ']') {
- c = getChar();
- addToString(c);
- if (peekChar() == '>') {
- c = getChar(); // Skip >
- addToString(c);
- return true;
- } else {
- continue;
- }
- }
- c = getChar();
- }
-
- stringBufferTop = 0; // throw away the string in progress
- this.string = null;
- parser.addError("msg.XML.bad.form");
- return false;
- }
-
- /**
- *
- */
- private boolean readEntity() throws IOException
- {
- int declTags = 1;
- for (int c = getChar(); c != EOF_CHAR; c = getChar()) {
- addToString(c);
- switch (c) {
- case '<':
- declTags++;
- break;
- case '>':
- declTags--;
- if (declTags == 0) return true;
- break;
- }
- }
-
- stringBufferTop = 0; // throw away the string in progress
- this.string = null;
- parser.addError("msg.XML.bad.form");
- return false;
- }
-
- /**
- *
- */
- private boolean readPI() throws IOException
- {
- for (int c = getChar(); c != EOF_CHAR; c = getChar()) {
- addToString(c);
- if (c == '?' && peekChar() == '>') {
- c = getChar(); // Skip >
- addToString(c);
- return true;
- }
- }
-
- stringBufferTop = 0; // throw away the string in progress
- this.string = null;
- parser.addError("msg.XML.bad.form");
- return false;
- }
-
- private String getStringFromBuffer()
- {
- return new String(stringBuffer, 0, stringBufferTop);
- }
-
- private void addToString(int c)
- {
- int N = stringBufferTop;
- if (N == stringBuffer.length) {
- char[] tmp = new char[stringBuffer.length * 2];
- System.arraycopy(stringBuffer, 0, tmp, 0, N);
- stringBuffer = tmp;
- }
- stringBuffer[N] = (char)c;
- stringBufferTop = N + 1;
- }
-
- private void ungetChar(int c)
- {
- // can not unread past across line boundary
- if (ungetCursor != 0 && ungetBuffer[ungetCursor - 1] == '\n')
- Kit.codeBug();
- ungetBuffer[ungetCursor++] = c;
- }
-
- private boolean matchChar(int test) throws IOException
- {
- int c = getCharIgnoreLineEnd();
- if (c == test) {
- return true;
- } else {
- ungetCharIgnoreLineEnd(c);
- return false;
- }
- }
-
- private int peekChar() throws IOException
- {
- int c = getChar();
- ungetChar(c);
- return c;
- }
-
- private int getChar() throws IOException
- {
- if (ungetCursor != 0) {
- return ungetBuffer[--ungetCursor];
- }
-
- for(;;) {
- int c;
- if (sourceString != null) {
- if (sourceCursor == sourceEnd) {
- hitEOF = true;
- return EOF_CHAR;
- }
- c = sourceString.charAt(sourceCursor++);
- } else {
- if (sourceCursor == sourceEnd) {
- if (!fillSourceBuffer()) {
- hitEOF = true;
- return EOF_CHAR;
- }
- }
- c = sourceBuffer[sourceCursor++];
- }
-
- if (lineEndChar >= 0) {
- if (lineEndChar == '\r' && c == '\n') {
- lineEndChar = '\n';
- continue;
- }
- lineEndChar = -1;
- lineStart = sourceCursor - 1;
- lineno++;
- }
-
- if (c <= 127) {
- if (c == '\n' || c == '\r') {
- lineEndChar = c;
- c = '\n';
- }
- } else {
- if (isJSFormatChar(c)) {
- continue;
- }
- if (ScriptRuntime.isJSLineTerminator(c)) {
- lineEndChar = c;
- c = '\n';
- }
- }
- return c;
- }
- }
-
- private int getCharIgnoreLineEnd() throws IOException
- {
- if (ungetCursor != 0) {
- return ungetBuffer[--ungetCursor];
- }
-
- for(;;) {
- int c;
- if (sourceString != null) {
- if (sourceCursor == sourceEnd) {
- hitEOF = true;
- return EOF_CHAR;
- }
- c = sourceString.charAt(sourceCursor++);
- } else {
- if (sourceCursor == sourceEnd) {
- if (!fillSourceBuffer()) {
- hitEOF = true;
- return EOF_CHAR;
- }
- }
- c = sourceBuffer[sourceCursor++];
- }
-
- if (c <= 127) {
- if (c == '\n' || c == '\r') {
- lineEndChar = c;
- c = '\n';
- }
- } else {
- if (isJSFormatChar(c)) {
- continue;
- }
- if (ScriptRuntime.isJSLineTerminator(c)) {
- lineEndChar = c;
- c = '\n';
- }
- }
- return c;
- }
- }
-
- private void ungetCharIgnoreLineEnd(int c)
- {
- ungetBuffer[ungetCursor++] = c;
- }
-
- private void skipLine() throws IOException
- {
- // skip to end of line
- int c;
- while ((c = getChar()) != EOF_CHAR && c != '\n') { }
- ungetChar(c);
- }
-
- final int getOffset()
- {
- int n = sourceCursor - lineStart;
- if (lineEndChar >= 0) { --n; }
- return n;
- }
-
- final String getLine()
- {
- if (sourceString != null) {
- // String case
- int lineEnd = sourceCursor;
- if (lineEndChar >= 0) {
- --lineEnd;
- } else {
- for (; lineEnd != sourceEnd; ++lineEnd) {
- int c = sourceString.charAt(lineEnd);
- if (ScriptRuntime.isJSLineTerminator(c)) {
- break;
- }
- }
- }
- return sourceString.substring(lineStart, lineEnd);
- } else {
- // Reader case
- int lineLength = sourceCursor - lineStart;
- if (lineEndChar >= 0) {
- --lineLength;
- } else {
- // Read until the end of line
- for (;; ++lineLength) {
- int i = lineStart + lineLength;
- if (i == sourceEnd) {
- try {
- if (!fillSourceBuffer()) { break; }
- } catch (IOException ioe) {
- // ignore it, we're already displaying an error...
- break;
- }
- // i recalculuation as fillSourceBuffer can move saved
- // line buffer and change lineStart
- i = lineStart + lineLength;
- }
- int c = sourceBuffer[i];
- if (ScriptRuntime.isJSLineTerminator(c)) {
- break;
- }
- }
- }
- return new String(sourceBuffer, lineStart, lineLength);
- }
- }
-
- private boolean fillSourceBuffer() throws IOException
- {
- if (sourceString != null) Kit.codeBug();
- if (sourceEnd == sourceBuffer.length) {
- if (lineStart != 0) {
- System.arraycopy(sourceBuffer, lineStart, sourceBuffer, 0,
- sourceEnd - lineStart);
- sourceEnd -= lineStart;
- sourceCursor -= lineStart;
- lineStart = 0;
- } else {
- char[] tmp = new char[sourceBuffer.length * 2];
- System.arraycopy(sourceBuffer, 0, tmp, 0, sourceEnd);
- sourceBuffer = tmp;
- }
- }
- int n = sourceReader.read(sourceBuffer, sourceEnd,
- sourceBuffer.length - sourceEnd);
- if (n < 0) {
- return false;
- }
- sourceEnd += n;
- return true;
- }
-
- // stuff other than whitespace since start of line
- private boolean dirtyLine;
-
- String regExpFlags;
-
- // Set this to an initial non-null value so that the Parser has
- // something to retrieve even if an error has occurred and no
- // string is found. Fosters one class of error, but saves lots of
- // code.
- private String string = "";
- private double number;
-
- private char[] stringBuffer = new char[128];
- private int stringBufferTop;
- private ObjToIntMap allStrings = new ObjToIntMap(50);
-
- // Room to backtrace from to < on failed match of the last - in