JS parser: removed unused decompilation info

This commit is contained in:
Alexey Tsvetkov
2014-12-01 17:31:13 +03:00
parent 272788cb27
commit 0d6b4c6590
@@ -127,7 +127,7 @@ public class Parser {
}
Object pn = nf.createScript(tempBlock, ts.getSourceName(), baseLineno, ts
.getLineno(), sourceToString(0));
.getLineno(), null);
((Node) pn).setIsSyntheticBlock(true);
return pn;
}
@@ -178,7 +178,6 @@ public class Parser {
Context.FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME)) {
// Extension to ECMA: if 'function <name>' does not follow
// by '(', assume <name> starts memberExpr
sourceAddString(ts.NAME, name);
Object memberExprHead = nf.createName(name);
name = null;
memberExprNode = memberExprTail(ts, false, memberExprHead);
@@ -200,16 +199,6 @@ public class Parser {
mustMatchToken(ts, ts.LP, "msg.no.paren.parms");
}
if (memberExprNode != null) {
// transform 'function' <memberExpr> to <memberExpr> = function
// even in the decompilated source
sourceAdd((char) ts.ASSIGN);
sourceAdd((char) ts.NOP);
}
// save a reference to the function in the enclosing source.
sourceAdd((char) ts.FUNCTION);
sourceAdd((char) functionNumber);
++functionNumber;
// Save current source top to restore it on exit not to include
@@ -218,53 +207,32 @@ public class Parser {
int savedFunctionNumber = functionNumber;
Object args;
Object body;
String source;
try {
functionNumber = 0;
// FUNCTION as the first token in a Source means it's a function
// definition, and not a reference.
sourceAdd((char) ts.FUNCTION);
if (name != null) {
sourceAddString(ts.NAME, name);
}
sourceAdd((char) ts.LP);
args = nf.createLeaf(ts.LP);
if (!ts.matchToken(ts.GWT)) {
boolean first = true;
do {
if (!first)
sourceAdd((char) ts.COMMA);
first = false;
mustMatchToken(ts, ts.NAME, "msg.no.parm");
String s = ts.getString();
nf.addChildToBack(args, nf.createName(s));
sourceAddString(ts.NAME, s);
} while (ts.matchToken(ts.COMMA));
mustMatchToken(ts, ts.GWT, "msg.no.paren.after.parms");
}
sourceAdd((char) ts.GWT);
mustMatchToken(ts, ts.LC, "msg.no.brace.body");
sourceAdd((char) ts.LC);
sourceAdd((char) ts.EOL);
body = parseFunctionBody(ts);
mustMatchToken(ts, ts.RC, "msg.no.brace.after.body");
sourceAdd((char) ts.RC);
// skip the last EOL so nested functions work...
// name might be null;
source = sourceToString(savedSourceTop);
} finally {
sourceTop = savedSourceTop;
functionNumber = savedFunctionNumber;
}
Object pn = nf.createFunction(name, args, body, ts.getSourceName(),
baseLineno, ts.getLineno(), source, isExpr || memberExprNode != null);
baseLineno, ts.getLineno(), null, isExpr || memberExprNode != null);
if (memberExprNode != null) {
pn = nf.createBinary(ts.ASSIGN, ts.NOP, memberExprNode, pn);
}
@@ -272,12 +240,6 @@ public class Parser {
// Add EOL but only if function is not part of expression, in which
// case it gets SEMI + EOL from Statement.
if (!isExpr) {
if (memberExprNode != null) {
// Add ';' to make 'function x.f(){}' and 'x.f = function(){}'
// to print the same strings when decompiling
sourceAdd((char) ts.SEMI);
}
sourceAdd((char) ts.EOL);
wellTerminated(ts, ts.FUNCTION);
}
@@ -299,10 +261,8 @@ public class Parser {
JavaScriptException {
Object pn;
mustMatchToken(ts, ts.LP, "msg.no.paren.cond");
sourceAdd((char) ts.LP);
pn = expr(ts, false);
mustMatchToken(ts, ts.GWT, "msg.no.paren.after.cond");
sourceAdd((char) ts.GWT);
// there's a check here in jsparse.c that corrects = to ==
@@ -390,22 +350,13 @@ public class Parser {
case TokenStream.IF: {
skipsemi = true;
sourceAdd((char) ts.IF);
int lineno = ts.getLineno();
Object cond = condition(ts);
sourceAdd((char) ts.LC);
sourceAdd((char) ts.EOL);
Object ifTrue = statement(ts);
Object ifFalse = null;
if (ts.matchToken(ts.ELSE)) {
sourceAdd((char) ts.RC);
sourceAdd((char) ts.ELSE);
sourceAdd((char) ts.LC);
sourceAdd((char) ts.EOL);
ifFalse = statement(ts);
}
sourceAdd((char) ts.RC);
sourceAdd((char) ts.EOL);
pn = nf.createIf(cond, ifTrue, ifFalse, lineno);
break;
}
@@ -413,35 +364,24 @@ public class Parser {
case TokenStream.SWITCH: {
skipsemi = true;
sourceAdd((char) ts.SWITCH);
pn = nf.createSwitch(ts.getLineno());
Object cur_case = null; // to kill warning
Object case_statements;
mustMatchToken(ts, ts.LP, "msg.no.paren.switch");
sourceAdd((char) ts.LP);
nf.addChildToBack(pn, expr(ts, false));
mustMatchToken(ts, ts.GWT, "msg.no.paren.after.switch");
sourceAdd((char) ts.GWT);
mustMatchToken(ts, ts.LC, "msg.no.brace.switch");
sourceAdd((char) ts.LC);
sourceAdd((char) ts.EOL);
while ((tt = ts.getToken()) != ts.RC && tt != ts.EOF) {
switch (tt) {
case TokenStream.CASE:
sourceAdd((char) ts.CASE);
cur_case = nf.createUnary(ts.CASE, expr(ts, false));
sourceAdd((char) ts.COLON);
sourceAdd((char) ts.EOL);
break;
case TokenStream.DEFAULT:
cur_case = nf.createLeaf(ts.DEFAULT);
sourceAdd((char) ts.DEFAULT);
sourceAdd((char) ts.COLON);
sourceAdd((char) ts.EOL);
// XXX check that there isn't more than one default
break;
@@ -463,22 +403,15 @@ public class Parser {
nf.addChildToBack(pn, cur_case);
}
sourceAdd((char) ts.RC);
sourceAdd((char) ts.EOL);
break;
}
case TokenStream.WHILE: {
skipsemi = true;
sourceAdd((char) ts.WHILE);
int lineno = ts.getLineno();
Object cond = condition(ts);
sourceAdd((char) ts.LC);
sourceAdd((char) ts.EOL);
Object body = statement(ts);
sourceAdd((char) ts.RC);
sourceAdd((char) ts.EOL);
pn = nf.createWhile(cond, body, lineno);
break;
@@ -486,17 +419,11 @@ public class Parser {
}
case TokenStream.DO: {
sourceAdd((char) ts.DO);
sourceAdd((char) ts.LC);
sourceAdd((char) ts.EOL);
int lineno = ts.getLineno();
Object body = statement(ts);
sourceAdd((char) ts.RC);
mustMatchToken(ts, ts.WHILE, "msg.no.while.do");
sourceAdd((char) ts.WHILE);
Object cond = condition(ts);
pn = nf.createDoWhile(body, cond, lineno);
@@ -506,7 +433,6 @@ public class Parser {
case TokenStream.FOR: {
skipsemi = true;
sourceAdd((char) ts.FOR);
int lineno = ts.getLineno();
Object init; // Node init is also foo in 'foo in Object'
@@ -515,7 +441,6 @@ public class Parser {
Object body;
mustMatchToken(ts, ts.LP, "msg.no.paren.for");
sourceAdd((char) ts.LP);
tt = ts.peekToken();
if (tt == ts.SEMI) {
init = nf.createLeaf(ts.VOID);
@@ -532,12 +457,10 @@ public class Parser {
tt = ts.peekToken();
if (tt == ts.RELOP && ts.getOp() == ts.IN) {
ts.matchToken(ts.RELOP);
sourceAdd((char) ts.IN);
// 'cond' is the object over which we're iterating
cond = expr(ts, false);
} else { // ordinary for loop
mustMatchToken(ts, ts.SEMI, "msg.no.semi.for");
sourceAdd((char) ts.SEMI);
if (ts.peekToken() == ts.SEMI) {
// no loop condition
cond = nf.createLeaf(ts.VOID);
@@ -546,7 +469,6 @@ public class Parser {
}
mustMatchToken(ts, ts.SEMI, "msg.no.semi.for.cond");
sourceAdd((char) ts.SEMI);
if (ts.peekToken() == ts.GWT) {
incr = nf.createLeaf(ts.VOID);
} else {
@@ -555,12 +477,7 @@ public class Parser {
}
mustMatchToken(ts, ts.GWT, "msg.no.paren.for.ctrl");
sourceAdd((char) ts.GWT);
sourceAdd((char) ts.LC);
sourceAdd((char) ts.EOL);
body = statement(ts);
sourceAdd((char) ts.RC);
sourceAdd((char) ts.EOL);
if (incr == null) {
// cond could be null if 'in obj' got eaten by the init node.
@@ -579,12 +496,7 @@ public class Parser {
Object finallyblock = null;
skipsemi = true;
sourceAdd((char) ts.TRY);
sourceAdd((char) ts.LC);
sourceAdd((char) ts.EOL);
tryblock = statement(ts);
sourceAdd((char) ts.RC);
sourceAdd((char) ts.EOL);
catchblocks = nf.createLeaf(TokenStream.BLOCK);
@@ -595,47 +507,32 @@ public class Parser {
if (sawDefaultCatch) {
reportError(ts, "msg.catch.unreachable");
}
sourceAdd((char) ts.CATCH);
mustMatchToken(ts, ts.LP, "msg.no.paren.catch");
sourceAdd((char) ts.LP);
mustMatchToken(ts, ts.NAME, "msg.bad.catchcond");
String varName = ts.getString();
sourceAddString(ts.NAME, varName);
Object catchCond = null;
if (ts.matchToken(ts.IF)) {
sourceAdd((char) ts.IF);
catchCond = expr(ts, false);
} else {
sawDefaultCatch = true;
}
mustMatchToken(ts, ts.GWT, "msg.bad.catchcond");
sourceAdd((char) ts.GWT);
mustMatchToken(ts, ts.LC, "msg.no.brace.catchblock");
sourceAdd((char) ts.LC);
sourceAdd((char) ts.EOL);
nf.addChildToBack(catchblocks, nf.createCatch(varName, catchCond,
statements(ts), ts.getLineno()));
mustMatchToken(ts, ts.RC, "msg.no.brace.after.body");
sourceAdd((char) ts.RC);
sourceAdd((char) ts.EOL);
}
} else if (peek != ts.FINALLY) {
mustMatchToken(ts, ts.FINALLY, "msg.try.no.catchfinally");
}
if (ts.matchToken(ts.FINALLY)) {
sourceAdd((char) ts.FINALLY);
sourceAdd((char) ts.LC);
sourceAdd((char) ts.EOL);
finallyblock = statement(ts);
sourceAdd((char) ts.RC);
sourceAdd((char) ts.EOL);
}
pn = nf.createTryCatchFinally(tryblock, catchblocks, finallyblock,
@@ -645,7 +542,6 @@ public class Parser {
}
case TokenStream.THROW: {
int lineno = ts.getLineno();
sourceAdd((char) ts.THROW);
pn = nf.createThrow(expr(ts, false), lineno);
if (lineno == ts.getLineno())
wellTerminated(ts, ts.ERROR);
@@ -654,34 +550,21 @@ public class Parser {
case TokenStream.BREAK: {
int lineno = ts.getLineno();
sourceAdd((char) ts.BREAK);
// matchLabel only matches if there is one
String label = matchLabel(ts);
if (label != null) {
sourceAddString(ts.NAME, label);
}
pn = nf.createBreak(label, lineno);
break;
}
case TokenStream.CONTINUE: {
int lineno = ts.getLineno();
sourceAdd((char) ts.CONTINUE);
// matchLabel only matches if there is one
String label = matchLabel(ts);
if (label != null) {
sourceAddString(ts.NAME, label);
}
pn = nf.createContinue(label, lineno);
break;
}
case TokenStream.DEBUGGER: {
int lineno = ts.getLineno();
sourceAdd((char) ts.DEBUGGER);
pn = nf.createDebugger(lineno);
break;
}
@@ -694,21 +577,11 @@ public class Parser {
skipsemi = true;
sourceAdd((char) ts.WITH);
int lineno = ts.getLineno();
mustMatchToken(ts, ts.LP, "msg.no.paren.with");
sourceAdd((char) ts.LP);
Object obj = expr(ts, false);
mustMatchToken(ts, ts.GWT, "msg.no.paren.after.with");
sourceAdd((char) ts.GWT);
sourceAdd((char) ts.LC);
sourceAdd((char) ts.EOL);
Object body = statement(ts);
sourceAdd((char) ts.RC);
sourceAdd((char) ts.EOL);
pn = nf.createWith(obj, body, lineno);
break;
}
@@ -722,9 +595,6 @@ public class Parser {
case TokenStream.RETURN: {
Object retExpr = null;
int lineno = 0;
sourceAdd((char) ts.RETURN);
// bail if we're not in a (toplevel) function
if ((!insideFunction) && ((ts.flags & ts.TSF_FUNCTION) == 0)) {
reportError(ts, "msg.bad.return");
@@ -796,8 +666,6 @@ public class Parser {
// depend on decompiling lookahead to guess that that
// last name was a label.
sourceAdd((char) ts.COLON);
sourceAdd((char) ts.EOL);
return pn;
}
@@ -826,10 +694,6 @@ public class Parser {
}
}
ts.matchToken(ts.SEMI);
if (!skipsemi) {
sourceAdd((char) ts.SEMI);
sourceAdd((char) ts.EOL);
}
return pn;
}
@@ -837,21 +701,12 @@ public class Parser {
private Object variables(TokenStream ts, boolean inForInit)
throws IOException, JavaScriptException {
Object pn = nf.createVariables(ts.getLineno());
boolean first = true;
sourceAdd((char) ts.VAR);
for (;;) {
Object name;
Object init;
mustMatchToken(ts, ts.NAME, "msg.bad.var");
String s = ts.getString();
if (!first)
sourceAdd((char) ts.COMMA);
first = false;
sourceAddString(ts.NAME, s);
name = nf.createName(s);
// omitted check for argument hiding
@@ -860,9 +715,6 @@ public class Parser {
if (ts.getOp() != ts.NOP)
reportError(ts, "msg.bad.var.init");
sourceAdd((char) ts.ASSIGN);
sourceAdd((char) ts.NOP);
init = assignExpr(ts, inForInit);
nf.addChildToBack(name, init);
}
@@ -877,7 +729,6 @@ public class Parser {
JavaScriptException {
Object pn = assignExpr(ts, inForInit);
while (ts.matchToken(ts.COMMA)) {
sourceAdd((char) ts.COMMA);
pn = nf.createBinary(ts.COMMA, pn, assignExpr(ts, inForInit));
}
return pn;
@@ -889,8 +740,6 @@ public class Parser {
if (ts.matchToken(ts.ASSIGN)) {
// omitted: "invalid assignment left-hand side" check.
sourceAdd((char) ts.ASSIGN);
sourceAdd((char) ts.getOp());
pn = nf
.createBinary(ts.ASSIGN, ts.getOp(), pn, assignExpr(ts, inForInit));
}
@@ -906,10 +755,8 @@ public class Parser {
Object pn = orExpr(ts, inForInit);
if (ts.matchToken(ts.HOOK)) {
sourceAdd((char) ts.HOOK);
ifTrue = assignExpr(ts, false);
mustMatchToken(ts, ts.COLON, "msg.no.colon.cond");
sourceAdd((char) ts.COLON);
ifFalse = assignExpr(ts, inForInit);
return nf.createTernary(pn, ifTrue, ifFalse);
}
@@ -921,7 +768,6 @@ public class Parser {
JavaScriptException {
Object pn = andExpr(ts, inForInit);
if (ts.matchToken(ts.OR)) {
sourceAdd((char) ts.OR);
pn = nf.createBinary(ts.OR, pn, orExpr(ts, inForInit));
}
@@ -932,7 +778,6 @@ public class Parser {
JavaScriptException {
Object pn = bitOrExpr(ts, inForInit);
if (ts.matchToken(ts.AND)) {
sourceAdd((char) ts.AND);
pn = nf.createBinary(ts.AND, pn, andExpr(ts, inForInit));
}
@@ -943,7 +788,6 @@ public class Parser {
throws IOException, JavaScriptException {
Object pn = bitXorExpr(ts, inForInit);
while (ts.matchToken(ts.BITOR)) {
sourceAdd((char) ts.BITOR);
pn = nf.createBinary(ts.BITOR, pn, bitXorExpr(ts, inForInit));
}
return pn;
@@ -953,7 +797,6 @@ public class Parser {
throws IOException, JavaScriptException {
Object pn = bitAndExpr(ts, inForInit);
while (ts.matchToken(ts.BITXOR)) {
sourceAdd((char) ts.BITXOR);
pn = nf.createBinary(ts.BITXOR, pn, bitAndExpr(ts, inForInit));
}
return pn;
@@ -963,7 +806,6 @@ public class Parser {
throws IOException, JavaScriptException {
Object pn = eqExpr(ts, inForInit);
while (ts.matchToken(ts.BITAND)) {
sourceAdd((char) ts.BITAND);
pn = nf.createBinary(ts.BITAND, pn, eqExpr(ts, inForInit));
}
return pn;
@@ -973,8 +815,6 @@ public class Parser {
JavaScriptException {
Object pn = relExpr(ts, inForInit);
while (ts.matchToken(ts.EQOP)) {
sourceAdd((char) ts.EQOP);
sourceAdd((char) ts.getOp());
pn = nf.createBinary(ts.EQOP, ts.getOp(), pn, relExpr(ts, inForInit));
}
return pn;
@@ -989,8 +829,7 @@ public class Parser {
ts.ungetToken(ts.RELOP);
break;
}
sourceAdd((char) ts.RELOP);
sourceAdd((char) op);
pn = nf.createBinary(ts.RELOP, op, pn, shiftExpr(ts));
}
return pn;
@@ -1000,8 +839,6 @@ public class Parser {
JavaScriptException {
Object pn = addExpr(ts);
while (ts.matchToken(ts.SHOP)) {
sourceAdd((char) ts.SHOP);
sourceAdd((char) ts.getOp());
pn = nf.createBinary(ts.SHOP, ts.getOp(), pn, addExpr(ts));
}
return pn;
@@ -1013,7 +850,6 @@ public class Parser {
Object pn = mulExpr(ts);
while ((tt = ts.getToken()) == ts.ADD || tt == ts.SUB) {
sourceAdd((char) tt);
// flushNewLines
pn = nf.createBinary(tt, pn, mulExpr(ts));
}
@@ -1030,7 +866,6 @@ public class Parser {
while ((tt = ts.peekToken()) == ts.MUL || tt == ts.DIV || tt == ts.MOD) {
tt = ts.getToken();
sourceAdd((char) tt);
pn = nf.createBinary(tt, pn, unaryExpr(ts));
}
@@ -1047,23 +882,17 @@ public class Parser {
switch (tt) {
case TokenStream.UNARYOP:
sourceAdd((char) ts.UNARYOP);
sourceAdd((char) ts.getOp());
return nf.createUnary(ts.UNARYOP, ts.getOp(), unaryExpr(ts));
case TokenStream.ADD:
case TokenStream.SUB:
sourceAdd((char) ts.UNARYOP);
sourceAdd((char) tt);
return nf.createUnary(ts.UNARYOP, tt, unaryExpr(ts));
case TokenStream.INC:
case TokenStream.DEC:
sourceAdd((char) tt);
return nf.createUnary(tt, ts.PRE, memberExpr(ts, true));
case TokenStream.DELPROP:
sourceAdd((char) ts.DELPROP);
return nf.createUnary(ts.DELPROP, unaryExpr(ts));
case TokenStream.ERROR:
@@ -1087,7 +916,6 @@ public class Parser {
if (((peeked = ts.peekToken()) == ts.INC || peeked == ts.DEC)
&& ts.getLineno() == lineno) {
int pf = ts.getToken();
sourceAdd((char) pf);
return nf.createUnary(pf, ts.POST, pn);
}
return pn;
@@ -1103,17 +931,12 @@ public class Parser {
matched = ts.matchToken(ts.GWT);
ts.flags &= ~ts.TSF_REGEXP;
if (!matched) {
boolean first = true;
do {
if (!first)
sourceAdd((char) ts.COMMA);
first = false;
nf.addChildToBack(listNode, assignExpr(ts, false));
} while (ts.matchToken(ts.COMMA));
mustMatchToken(ts, ts.GWT, "msg.no.paren.arg");
}
sourceAdd((char) ts.GWT);
return listNode;
}
@@ -1130,14 +953,12 @@ public class Parser {
if (tt == ts.NEW) {
/* Eat the NEW token. */
ts.getToken();
sourceAdd((char) ts.NEW);
/* Make a NEW node to append to. */
pn = nf.createLeaf(ts.NEW);
nf.addChildToBack(pn, memberExpr(ts, false));
if (ts.matchToken(ts.LP)) {
sourceAdd((char) ts.LP);
/* Add the arguments to pn, if any are supplied. */
pn = argumentList(ts, pn);
}
@@ -1170,10 +991,8 @@ public class Parser {
int tt;
while ((tt = ts.getToken()) > ts.EOF) {
if (tt == ts.DOT) {
sourceAdd((char) ts.DOT);
mustMatchToken(ts, ts.NAME, "msg.no.name.after.dot");
String s = ts.getString();
sourceAddString(ts.NAME, s);
pn = nf.createBinary(ts.DOT, pn, nf.createName(ts.getString()));
/*
* pn = nf.createBinary(ts.DOT, pn, memberExpr(ts)) is the version in
@@ -1182,17 +1001,13 @@ public class Parser {
*/
lastExprEndLine = ts.getLineno();
} else if (tt == ts.LB) {
sourceAdd((char) ts.LB);
pn = nf.createBinary(ts.LB, pn, expr(ts, false));
mustMatchToken(ts, ts.RB, "msg.no.bracket.index");
sourceAdd((char) ts.RB);
lastExprEndLine = ts.getLineno();
} else if (allowCallSyntax && tt == ts.LP) {
/* make a call node */
pn = nf.createUnary(ts.CALL, pn);
sourceAdd((char) ts.LP);
/* Add the arguments to pn, if any are supplied. */
pn = argumentList(ts, pn);
@@ -1222,7 +1037,6 @@ public class Parser {
return function(ts, true);
case TokenStream.LB: {
sourceAdd((char) ts.LB);
pn = nf.createLeaf(ts.ARRAYLIT);
ts.flags |= ts.TSF_REGEXP;
@@ -1230,17 +1044,11 @@ public class Parser {
ts.flags &= ~ts.TSF_REGEXP;
if (!matched) {
boolean first = true;
do {
ts.flags |= ts.TSF_REGEXP;
tt = ts.peekToken();
ts.flags &= ~ts.TSF_REGEXP;
if (!first)
sourceAdd((char) ts.COMMA);
else
first = false;
if (tt == ts.RB) { // to fix [,,,].length behavior...
break;
}
@@ -1254,42 +1062,31 @@ public class Parser {
} while (ts.matchToken(ts.COMMA));
mustMatchToken(ts, ts.RB, "msg.no.bracket.arg");
}
sourceAdd((char) ts.RB);
return nf.createArrayLiteral(pn);
}
case TokenStream.LC: {
pn = nf.createLeaf(ts.OBJLIT);
sourceAdd((char) ts.LC);
if (!ts.matchToken(ts.RC)) {
boolean first = true;
commaloop : do {
Object property;
if (!first)
sourceAdd((char) ts.COMMA);
else
first = false;
tt = ts.getToken();
switch (tt) {
// map NAMEs to STRINGs in object literal context.
case TokenStream.NAME:
case TokenStream.STRING:
String s = ts.getString();
sourceAddString(ts.NAME, s);
property = nf.createString(ts.getString());
break;
case TokenStream.NUMBER_INT:
int n = (int) ts.getNumber();
sourceAddNumber(n);
property = nf.createNumber(n);
break;
case TokenStream.NUMBER:
double d = ts.getNumber();
sourceAddNumber(d);
property = nf.createNumber(d);
break;
case TokenStream.RC:
@@ -1304,7 +1101,6 @@ public class Parser {
// OBJLIT is used as ':' in object literal for
// decompilation to solve spacing ambiguity.
sourceAdd((char) ts.OBJLIT);
nf.addChildToBack(pn, property);
nf.addChildToBack(pn, assignExpr(ts, false));
@@ -1312,7 +1108,6 @@ public class Parser {
mustMatchToken(ts, ts.RC, "msg.no.brace.prop");
}
sourceAdd((char) ts.RC);
return nf.createObjectLiteral(pn);
}
@@ -1324,43 +1119,34 @@ public class Parser {
* the structure of the parse tree? also TOK_LP is already overloaded (I
* think) in the C IR as 'function call.'
*/
sourceAdd((char) ts.LP);
pn = expr(ts, false);
sourceAdd((char) ts.GWT);
mustMatchToken(ts, ts.GWT, "msg.no.paren");
return pn;
case TokenStream.NAME:
String name = ts.getString();
sourceAddString(ts.NAME, name);
return nf.createName(name);
case TokenStream.NUMBER_INT:
int n = (int)ts.getNumber();
sourceAddNumber(n);
return nf.createNumber(n);
case TokenStream.NUMBER:
double d = ts.getNumber();
sourceAddNumber(d);
return nf.createNumber(d);
case TokenStream.STRING:
String s = ts.getString();
sourceAddString(ts.STRING, s);
return nf.createString(s);
case TokenStream.REGEXP: {
String flags = ts.regExpFlags;
ts.regExpFlags = null;
String re = ts.getString();
sourceAddString(ts.REGEXP, '/' + re + '/' + flags);
return nf.createRegExp(re, flags);
}
case TokenStream.PRIMARY:
sourceAdd((char) ts.PRIMARY);
sourceAdd((char) ts.getOp());
return nf.createLeaf(ts.PRIMARY, ts.getOp());
case TokenStream.RESERVED:
@@ -1379,139 +1165,11 @@ public class Parser {
return null; // should never reach here
}
/**
* The following methods 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.) NativeFunction.decompile expands the tokens back into their
* string representations, using simple lookahead to correct spacing and
* indentation.
*
* Token types with associated ops (ASSIGN, SHOP, PRIMARY, etc.) are saved as
* two-token pairs. 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.
*
* Nested functions need a similar mechanism... fortunately the nested
* functions for a given function are generated in source order. Nested
* functions are encoded as FUNCTION followed by a function number (encoded as
* a character), which is enough information to find the proper generated
* NativeFunction instance.
*
*/
private void sourceAdd(char c) {
if (sourceTop == sourceBuffer.length) {
increaseSourceCapacity(sourceTop + 1);
}
sourceBuffer[sourceTop] = c;
++sourceTop;
}
private void sourceAddString(int type, String str) {
int L = str.length();
// java string length < 2^16?
if (Context.check && L > Character.MAX_VALUE)
Context.codeBug();
if (sourceTop + L + 2 > sourceBuffer.length) {
increaseSourceCapacity(sourceTop + L + 2);
}
sourceAdd((char) type);
sourceAdd((char) L);
str.getChars(0, L, sourceBuffer, sourceTop);
sourceTop += L;
}
private void sourceAddNumber(double n) {
sourceAdd((char) TokenStream.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 = Double.doubleToLongBits(n);
sourceAdd('D');
sourceAdd((char) (lbits >> 48));
sourceAdd((char) (lbits >> 32));
sourceAdd((char) (lbits >> 16));
sourceAdd((char) lbits);
}
private void sourceAddNumber(int n) {
sourceAdd((char) TokenStream.NUMBER_INT);
// we can ignore negative values, bc they're already prefixed
// by UNARYOP SUB
if (Context.check && (long) n < 0)
Context.codeBug();
// will it fit in a char?
// this gives a short encoding for integer values up to 2^16.
if ((long) n <= Character.MAX_VALUE) {
sourceAdd('S');
sourceAdd((char) (long) n);
} else { // Integral, but won't fit in a char. Store as a long.
sourceAdd('J');
sourceAdd((char) ((long) n >> 48));
sourceAdd((char) ((long) n >> 32));
sourceAdd((char) ((long) n >> 16));
sourceAdd((char) (long) n);
}
}
private void increaseSourceCapacity(int minimalCapacity) {
// Call this only when capacity increase is must
if (Context.check && minimalCapacity <= sourceBuffer.length)
Context.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 (Context.check && (offset < 0 || sourceTop < offset))
Context.codeBug();
return new String(sourceBuffer, offset, sourceTop - offset);
}
private int lastExprEndLine; // Hack to handle function expr termination.
private IRFactory nf;
private ErrorReporter er;
private boolean ok; // Did the parse encounter an error?
private char[] sourceBuffer = new char[128];
private int sourceTop;
private int functionNumber;
private final boolean insideFunction;