Do explicit parsing of function expression statements so a correct function type will be passed to IRFactory during node creation and fix incorrect code generation when FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME is true.

I also added explicit flags to Parser: languageVersion and allowMemberExprAsFunctionName and set them from Context. In this way Parser can be used without Context which is useful for debugging.
This commit is contained in:
igor%mir2.org 2003-02-15 23:30:02 +00:00
Родитель aab18156df
Коммит c62a606a26
4 изменённых файлов: 159 добавлений и 152 удалений

Просмотреть файл

@ -847,7 +847,7 @@ public class Context {
boolean errorseen = false; boolean errorseen = false;
try { try {
IRFactory irf = new IRFactory(ts, null); IRFactory irf = new IRFactory(ts, null);
Parser p = new Parser(irf); Parser p = createParser(irf);
p.parse(ts); p.parse(ts);
} catch (IOException ioe) { } catch (IOException ioe) {
errorseen = true; errorseen = true;
@ -2000,7 +2000,7 @@ public class Context {
errorCount = 0; errorCount = 0;
IRFactory irf = compiler.createIRFactory(this, ts, scope); IRFactory irf = compiler.createIRFactory(this, ts, scope);
Parser p = new Parser(irf); Parser p = createParser(irf);
Node tree = (Node) p.parse(ts); Node tree = (Node) p.parse(ts);
if (tree == null) if (tree == null)
return null; return null;
@ -2058,6 +2058,14 @@ public class Context {
return new Interpreter(); return new Interpreter();
} }
private Parser createParser(IRFactory irf) {
Parser parser = new Parser(irf);
parser.setLanguageVersion(getLanguageVersion());
parser.setAllowMemberExprAsFunctionName(
hasFeature(Context.FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME));
return parser;
}
static String getSourcePositionFromStack(int[] linep) { static String getSourcePositionFromStack(int[] linep) {
Context cx = getCurrentContext(); Context cx = getCurrentContext();
if (cx == null) if (cx == null)

Просмотреть файл

@ -210,15 +210,14 @@ public class IRFactory {
Object statements, Object statements,
String sourceName, int baseLineno, String sourceName, int baseLineno,
int endLineno, Object source, int endLineno, Object source,
boolean isExpr) int functionType)
{ {
if (name == null) { if (name == null) {
name = ""; name = "";
} }
FunctionNode f = (FunctionNode) createFunctionNode(name, statements); FunctionNode f = (FunctionNode) createFunctionNode(name, statements);
f.argNames = argNames; f.argNames = argNames;
f.setFunctionType(isExpr ? FunctionNode.FUNCTION_EXPRESSION f.setFunctionType(functionType);
: FunctionNode.FUNCTION_STATEMENT);
f.putProp(Node.SOURCENAME_PROP, sourceName); f.putProp(Node.SOURCENAME_PROP, sourceName);
f.putIntProp(Node.BASE_LINENO_PROP, baseLineno); f.putIntProp(Node.BASE_LINENO_PROP, baseLineno);
f.putIntProp(Node.END_LINENO_PROP, endLineno); f.putIntProp(Node.END_LINENO_PROP, endLineno);
@ -229,12 +228,6 @@ public class IRFactory {
return result; return result;
} }
public void setFunctionExpressionStatement(Object o) {
Node n = (Node) o;
FunctionNode f = (FunctionNode) n.getProp(Node.FUNCTION_PROP);
f.setFunctionType(FunctionNode.FUNCTION_EXPRESSION_STATEMENT);
}
/** /**
* Add a child to the back of the given node. This function * Add a child to the back of the given node. This function
* breaks the Factory abstraction, but it removes a requirement * breaks the Factory abstraction, but it removes a requirement

Просмотреть файл

@ -56,6 +56,14 @@ class Parser {
this.nf = nf; this.nf = nf;
} }
public void setLanguageVersion(int languageVersion) {
this.languageVersion = languageVersion;
}
public void setAllowMemberExprAsFunctionName(boolean flag) {
this.allowMemberExprAsFunctionName = flag;
}
private void mustMatchToken(TokenStream ts, int toMatch, String messageId) private void mustMatchToken(TokenStream ts, int toMatch, String messageId)
throws IOException, JavaScriptException throws IOException, JavaScriptException
{ {
@ -94,15 +102,15 @@ class Parser {
throws IOException throws IOException
{ {
this.ok = true; this.ok = true;
sourceTop = 0; fn_sourceTop = 0;
functionNumber = 0; fn_functionNumber = 0;
int tt; // last token from getToken(); int tt; // last token from getToken();
int baseLineno = ts.getLineno(); // line number where source starts int baseLineno = ts.getLineno(); // line number where source starts
/* so we have something to add nodes to until /* so we have something to add nodes to until
* we've collected all the source */ * we've collected all the source */
Object tempBlock = nf.createLeaf(TokenStream.BLOCK); Object pn = nf.createLeaf(TokenStream.BLOCK);
// Add script indicator // Add script indicator
sourceAdd((char)ts.SCRIPT); sourceAdd((char)ts.SCRIPT);
@ -116,17 +124,19 @@ class Parser {
break; break;
} }
Object n;
if (tt == ts.FUNCTION) { if (tt == ts.FUNCTION) {
try { try {
nf.addChildToBack(tempBlock, function(ts, false)); n = function(ts, FunctionNode.FUNCTION_STATEMENT);
} catch (JavaScriptException e) { } catch (JavaScriptException e) {
this.ok = false; this.ok = false;
break; break;
} }
} else { } else {
ts.ungetToken(tt); ts.ungetToken(tt);
nf.addChildToBack(tempBlock, statement(ts)); n = statement(ts);
} }
nf.addChildToBack(pn, n);
} }
if (!this.ok) { if (!this.ok) {
@ -136,9 +146,8 @@ class Parser {
String source = sourceToString(0); String source = sourceToString(0);
sourceBuffer = null; // To help GC sourceBuffer = null; // To help GC
Object pn = nf.createScript(tempBlock, ts.getSourceName(), pn = nf.createScript(pn, ts.getSourceName(),
baseLineno, ts.getLineno(), baseLineno, ts.getLineno(), source);
source);
return pn; return pn;
} }
@ -160,12 +169,14 @@ class Parser {
try { try {
int tt; int tt;
while((tt = ts.peekToken()) > ts.EOF && tt != ts.RC) { while((tt = ts.peekToken()) > ts.EOF && tt != ts.RC) {
Object n;
if (tt == TokenStream.FUNCTION) { if (tt == TokenStream.FUNCTION) {
ts.getToken(); ts.getToken();
nf.addChildToBack(pn, function(ts, false)); n = function(ts, FunctionNode.FUNCTION_STATEMENT);
} else { } else {
nf.addChildToBack(pn, statement(ts)); n = statement(ts);
} }
nf.addChildToBack(pn, n);
} }
} catch (JavaScriptException e) { } catch (JavaScriptException e) {
this.ok = false; this.ok = false;
@ -179,7 +190,7 @@ class Parser {
return pn; return pn;
} }
private Object function(TokenStream ts, boolean isExpr) private Object function(TokenStream ts, int functionType)
throws IOException, JavaScriptException throws IOException, JavaScriptException
{ {
int baseLineno = ts.getLineno(); // line number where source starts int baseLineno = ts.getLineno(); // line number where source starts
@ -189,9 +200,7 @@ class Parser {
if (ts.matchToken(ts.NAME)) { if (ts.matchToken(ts.NAME)) {
name = ts.getString(); name = ts.getString();
if (!ts.matchToken(ts.LP)) { if (!ts.matchToken(ts.LP)) {
if (Context.getContext().hasFeature if (allowMemberExprAsFunctionName) {
(Context.FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME))
{
// Extension to ECMA: if 'function <name>' does not follow // Extension to ECMA: if 'function <name>' does not follow
// by '(', assume <name> starts memberExpr // by '(', assume <name> starts memberExpr
sourceAddString(ts.NAME, name); sourceAddString(ts.NAME, name);
@ -201,18 +210,14 @@ class Parser {
} }
mustMatchToken(ts, ts.LP, "msg.no.paren.parms"); mustMatchToken(ts, ts.LP, "msg.no.paren.parms");
} }
} } else if (ts.matchToken(ts.LP)) {
else if (ts.matchToken(ts.LP)) {
// Anonymous function // Anonymous function
name = null; name = null;
} } else {
else {
name = null; name = null;
if (Context.getContext().hasFeature if (allowMemberExprAsFunctionName) {
(Context.FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME))
{
// Note that memberExpr can not start with '(' like // Note that memberExpr can not start with '(' like
// in (1+2).toString, because 'function (' already // in function (1+2).toString(), because 'function (' already
// processed as anonymous function // processed as anonymous function
memberExprNode = memberExpr(ts, false); memberExprNode = memberExpr(ts, false);
} }
@ -228,18 +233,18 @@ class Parser {
// save a reference to the function in the enclosing source. // save a reference to the function in the enclosing source.
sourceAdd((char) ts.FUNCTION); sourceAdd((char) ts.FUNCTION);
sourceAdd((char)functionNumber); sourceAdd((char)fn_functionNumber);
++functionNumber; ++fn_functionNumber;
// Save current source top to restore it on exit not to include // Save current source top to restore it on exit not to include
// function to parent source // function to parent source
int savedSourceTop = sourceTop; int saved_sourceTop = fn_sourceTop;
int savedFunctionNumber = functionNumber; int saved_functionNumber = fn_functionNumber;
ObjArray args = new ObjArray(); ObjArray args = new ObjArray();
Object body; Object body;
String source; String source;
try { try {
functionNumber = 0; fn_functionNumber = 0;
// FUNCTION as the first token in a Source means it's a function // FUNCTION as the first token in a Source means it's a function
// definition, and not a reference. // definition, and not a reference.
@ -272,34 +277,48 @@ class Parser {
// skip the last EOL so nested functions work... // skip the last EOL so nested functions work...
// name might be null; // name might be null;
source = sourceToString(savedSourceTop); source = sourceToString(saved_sourceTop);
} }
finally { finally {
sourceTop = savedSourceTop; fn_sourceTop = saved_sourceTop;
functionNumber = savedFunctionNumber; fn_functionNumber = saved_functionNumber;
} }
Object pn = nf.createFunction(name, args, body, Object pn;
ts.getSourceName(), if (memberExprNode == null) {
baseLineno, ts.getLineno(), pn = nf.createFunction(name, args, body,
source, ts.getSourceName(),
isExpr || memberExprNode != null); baseLineno, ts.getLineno(),
if (memberExprNode != null) { source,
functionType);
if (functionType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) {
// The following can be removed but then code generators should
// be modified not to push on the stack function expression
// statements
pn = nf.createExprStatement(pn, baseLineno);
}
// Add EOL but only if function is not part of expression, in which
// case it gets SEMI + EOL from Statement.
if (functionType != FunctionNode.FUNCTION_EXPRESSION) {
sourceAdd((char)ts.EOL);
checkWellTerminatedFunction(ts);
}
} else {
pn = nf.createFunction(name, args, body,
ts.getSourceName(),
baseLineno, ts.getLineno(),
source,
FunctionNode.FUNCTION_EXPRESSION);
pn = nf.createBinary(ts.ASSIGN, ts.NOP, memberExprNode, pn); pn = nf.createBinary(ts.ASSIGN, ts.NOP, memberExprNode, pn);
} if (functionType != FunctionNode.FUNCTION_EXPRESSION) {
pn = nf.createExprStatement(pn, baseLineno);
// 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(){}' // Add ';' to make 'function x.f(){}' and 'x.f = function(){}'
// to print the same strings when decompiling // to print the same strings when decompiling
sourceAdd((char)ts.SEMI); sourceAdd((char)ts.SEMI);
sourceAdd((char)ts.EOL);
checkWellTerminatedFunction(ts);
} }
sourceAdd((char)ts.EOL);
wellTerminated(ts, ts.FUNCTION);
} }
return pn; return pn;
} }
@ -331,31 +350,39 @@ class Parser {
return pn; return pn;
} }
private boolean wellTerminated(TokenStream ts, int lastExprType) private void checkWellTerminated(TokenStream ts)
throws IOException, JavaScriptException throws IOException, JavaScriptException
{ {
int tt = ts.peekTokenSameLine(); int tt = ts.peekTokenSameLine();
if (tt == ts.ERROR) { switch (tt) {
return false; case TokenStream.ERROR:
} case TokenStream.EOF:
case TokenStream.EOL:
case TokenStream.SEMI:
case TokenStream.RC:
return;
if (tt != ts.EOF && tt != ts.EOL case TokenStream.FUNCTION:
&& tt != ts.SEMI && tt != ts.RC) if (languageVersion < Context.VERSION_1_2) {
{ /*
int version = Context.getContext().getLanguageVersion(); * Checking against version < 1.2 and version >= 1.0
if ((tt == ts.FUNCTION || lastExprType == ts.FUNCTION) && * in the above line breaks old javascript, so we keep it
(version < Context.VERSION_1_2)) { * this way for now... XXX warning needed?
/* */
* Checking against version < 1.2 and version >= 1.0 return;
* in the above line breaks old javascript, so we keep it
* this way for now... XXX warning needed?
*/
return true;
} else {
reportError(ts, "msg.no.semi.stmt");
}
} }
return true; }
reportError(ts, "msg.no.semi.stmt");
}
private void checkWellTerminatedFunction(TokenStream ts)
throws IOException, JavaScriptException
{
if (languageVersion < Context.VERSION_1_2) {
// See comments in checkWellTerminated
return;
}
checkWellTerminated(ts);
} }
// match a NAME; return null if no match. // match a NAME; return null if no match.
@ -373,7 +400,7 @@ class Parser {
} }
if (lineno == ts.getLineno()) if (lineno == ts.getLineno())
wellTerminated(ts, ts.ERROR); checkWellTerminated(ts);
return label; return label;
} }
@ -411,8 +438,6 @@ class Parser {
int tt; int tt;
int lastExprType = 0; // For wellTerminated. 0 to avoid warning.
tt = ts.getToken(); tt = ts.getToken();
switch(tt) { switch(tt) {
@ -680,7 +705,7 @@ class Parser {
sourceAdd((char)ts.THROW); sourceAdd((char)ts.THROW);
pn = nf.createThrow(expr(ts, false), lineno); pn = nf.createThrow(expr(ts, false), lineno);
if (lineno == ts.getLineno()) if (lineno == ts.getLineno())
wellTerminated(ts, ts.ERROR); checkWellTerminated(ts);
break; break;
} }
case TokenStream.BREAK: { case TokenStream.BREAK: {
@ -734,7 +759,7 @@ class Parser {
int lineno = ts.getLineno(); int lineno = ts.getLineno();
pn = variables(ts, false); pn = variables(ts, false);
if (ts.getLineno() == lineno) if (ts.getLineno() == lineno)
wellTerminated(ts, ts.ERROR); checkWellTerminated(ts);
break; break;
} }
case TokenStream.RETURN: { case TokenStream.RETURN: {
@ -755,7 +780,7 @@ class Parser {
if (tt != ts.EOF && tt != ts.EOL && tt != ts.SEMI && tt != ts.RC) { if (tt != ts.EOF && tt != ts.EOL && tt != ts.SEMI && tt != ts.RC) {
retExpr = expr(ts, false); retExpr = expr(ts, false);
if (ts.getLineno() == lineno) if (ts.getLineno() == lineno)
wellTerminated(ts, ts.ERROR); checkWellTerminated(ts);
ts.flags |= ts.TSF_RETURN_EXPR; ts.flags |= ts.TSF_RETURN_EXPR;
} else { } else {
ts.flags |= ts.TSF_RETURN_VOID; ts.flags |= ts.TSF_RETURN_VOID;
@ -780,8 +805,13 @@ class Parser {
skipsemi = true; skipsemi = true;
break; break;
case TokenStream.FUNCTION: {
pn = function(ts, FunctionNode.FUNCTION_EXPRESSION_STATEMENT);
break;
}
default: { default: {
lastExprType = tt; int lastExprType = tt;
int tokenno = ts.getTokenno(); int tokenno = ts.getTokenno();
ts.ungetToken(tt); ts.ungetToken(tt);
int lineno = ts.getLineno(); int lineno = ts.getLineno();
@ -811,32 +841,10 @@ class Parser {
return pn; return pn;
} }
if (lastExprType == ts.FUNCTION) {
if (nf.getLeafType(pn) != ts.FUNCTION) {
reportError(ts, "msg.syntax");
}
nf.setFunctionExpressionStatement(pn);
}
pn = nf.createExprStatement(pn, lineno); pn = nf.createExprStatement(pn, lineno);
/* if (ts.getLineno() == lineno) {
* Check explicitly against (multi-line) function checkWellTerminated(ts);
* statement.
* lastExprEndLine is a hack to fix an
* automatic semicolon insertion problem with function
* expressions; the ts.getLineno() == lineno check was
* firing after a function definition even though the
* next statement was on a new line, because
* speculative getToken calls advanced the line number
* even when they didn't succeed.
*/
if (ts.getLineno() == lineno ||
(lastExprType == ts.FUNCTION &&
ts.getLineno() == lastExprEndLine))
{
wellTerminated(ts, lastExprType);
} }
break; break;
} }
@ -1206,7 +1214,6 @@ class Parser {
Object pn) Object pn)
throws IOException, JavaScriptException throws IOException, JavaScriptException
{ {
lastExprEndLine = ts.getLineno();
int tt; int tt;
while ((tt = ts.getToken()) > ts.EOF) { while ((tt = ts.getToken()) > ts.EOF) {
if (tt == ts.DOT) { if (tt == ts.DOT) {
@ -1220,14 +1227,12 @@ class Parser {
* is the version in Brendan's IR C version. Not in ECMA... * is the version in Brendan's IR C version. Not in ECMA...
* does it reflect the 'new' operator syntax he mentioned? * does it reflect the 'new' operator syntax he mentioned?
*/ */
lastExprEndLine = ts.getLineno();
} else if (tt == ts.LB) { } else if (tt == ts.LB) {
sourceAdd((char)ts.LB); sourceAdd((char)ts.LB);
pn = nf.createBinary(ts.LB, pn, expr(ts, false)); pn = nf.createBinary(ts.LB, pn, expr(ts, false));
mustMatchToken(ts, ts.RB, "msg.no.bracket.index"); mustMatchToken(ts, ts.RB, "msg.no.bracket.index");
sourceAdd((char)ts.RB); sourceAdd((char)ts.RB);
lastExprEndLine = ts.getLineno();
} else if (allowCallSyntax && tt == ts.LP) { } else if (allowCallSyntax && tt == ts.LP) {
/* make a call node */ /* make a call node */
@ -1236,7 +1241,6 @@ class Parser {
/* Add the arguments to pn, if any are supplied. */ /* Add the arguments to pn, if any are supplied. */
pn = argumentList(ts, pn); pn = argumentList(ts, pn);
lastExprEndLine = ts.getLineno();
} else { } else {
ts.ungetToken(tt); ts.ungetToken(tt);
@ -1260,7 +1264,7 @@ class Parser {
switch(tt) { switch(tt) {
case TokenStream.FUNCTION: case TokenStream.FUNCTION:
return function(ts, true); return function(ts, FunctionNode.FUNCTION_EXPRESSION);
case TokenStream.LB: case TokenStream.LB:
{ {
@ -1455,11 +1459,11 @@ class Parser {
*/ */
private void sourceAdd(char c) { private void sourceAdd(char c) {
if (sourceTop == sourceBuffer.length) { if (fn_sourceTop == sourceBuffer.length) {
increaseSourceCapacity(sourceTop + 1); increaseSourceCapacity(fn_sourceTop + 1);
} }
sourceBuffer[sourceTop] = c; sourceBuffer[fn_sourceTop] = c;
++sourceTop; ++fn_sourceTop;
} }
private void sourceAddString(int type, String str) { private void sourceAddString(int type, String str) {
@ -1473,20 +1477,20 @@ class Parser {
if (L >= 0x8000) { if (L >= 0x8000) {
lengthEncodingSize = 2; lengthEncodingSize = 2;
} }
int nextTop = sourceTop + lengthEncodingSize + L; int nextTop = fn_sourceTop + lengthEncodingSize + L;
if (nextTop > sourceBuffer.length) { if (nextTop > sourceBuffer.length) {
increaseSourceCapacity(nextTop); increaseSourceCapacity(nextTop);
} }
if (L >= 0x8000) { if (L >= 0x8000) {
// Use 2 chars to encode strings exceeding 32K, were the highest // Use 2 chars to encode strings exceeding 32K, were the highest
// bit in the first char indicates presence of the next byte // bit in the first char indicates presence of the next byte
sourceBuffer[sourceTop] = (char)(0x8000 | (L >>> 16)); sourceBuffer[fn_sourceTop] = (char)(0x8000 | (L >>> 16));
++sourceTop; ++fn_sourceTop;
} }
sourceBuffer[sourceTop] = (char)L; sourceBuffer[fn_sourceTop] = (char)L;
++sourceTop; ++fn_sourceTop;
str.getChars(0, L, sourceBuffer, sourceTop); str.getChars(0, L, sourceBuffer, fn_sourceTop);
sourceTop = nextTop; fn_sourceTop = nextTop;
} }
private void sourceAddNumber(double n) { private void sourceAddNumber(double n) {
@ -1523,7 +1527,7 @@ class Parser {
else { else {
// we can ignore negative values, bc they're already prefixed // we can ignore negative values, bc they're already prefixed
// by UNARYOP SUB // by UNARYOP SUB
if (Context.check && lbits < 0) Context.codeBug(); if (lbits < 0) Context.codeBug();
// will it fit in a char? // will it fit in a char?
// this gives a short encoding for integer values up to 2^16. // this gives a short encoding for integer values up to 2^16.
@ -1543,21 +1547,19 @@ class Parser {
private void increaseSourceCapacity(int minimalCapacity) { private void increaseSourceCapacity(int minimalCapacity) {
// Call this only when capacity increase is must // Call this only when capacity increase is must
if (Context.check && minimalCapacity <= sourceBuffer.length) if (minimalCapacity <= sourceBuffer.length) Context.codeBug();
Context.codeBug();
int newCapacity = sourceBuffer.length * 2; int newCapacity = sourceBuffer.length * 2;
if (newCapacity < minimalCapacity) { if (newCapacity < minimalCapacity) {
newCapacity = minimalCapacity; newCapacity = minimalCapacity;
} }
char[] tmp = new char[newCapacity]; char[] tmp = new char[newCapacity];
System.arraycopy(sourceBuffer, 0, tmp, 0, sourceTop); System.arraycopy(sourceBuffer, 0, tmp, 0, fn_sourceTop);
sourceBuffer = tmp; sourceBuffer = tmp;
} }
private String sourceToString(int offset) { private String sourceToString(int offset) {
if (Context.check && (offset < 0 || sourceTop < offset)) if (offset < 0 || fn_sourceTop < offset) Context.codeBug();
Context.codeBug(); return new String(sourceBuffer, offset, fn_sourceTop - offset);
return new String(sourceBuffer, offset, sourceTop - offset);
} }
/** /**
@ -1605,6 +1607,9 @@ class Parser {
int indent, int type, boolean justbody, int indent, int type, boolean justbody,
Object[] srcData, StringBuffer result) Object[] srcData, StringBuffer result)
{ {
final int OFFSET = 4; // how much to indent
final int SETBACK = 2; // less how much for case labels
String source; String source;
Object[] childNodes = null; Object[] childNodes = null;
if (encodedSourcesTree == null) { if (encodedSourcesTree == null) {
@ -2254,20 +2259,22 @@ class Parser {
return offset; return offset;
} }
private int lastExprEndLine; // Hack to handle function expr termination.
private IRFactory nf; private IRFactory nf;
private ErrorReporter er; private int languageVersion = Context.VERSION_DEFAULT;
private boolean allowMemberExprAsFunctionName = false;
private boolean ok; // Did the parse encounter an error? private boolean ok; // Did the parse encounter an error?
private char[] sourceBuffer = new char[128]; private char[] sourceBuffer = new char[128];
private int sourceTop;
private int functionNumber;
// how much to indent // fn_ prefix means per-function data that should be reset/restored in function
private final static int OFFSET = 4;
// less how much for case labels // Per function source buffer top: nested functions sources are not
private final static int SETBACK = 2; // included in parent.
private int fn_sourceTop;
// Nested function number
private int fn_functionNumber;
private static final int TOP_LEVEL_SCRIPT_OR_FUNCTION = 0; private static final int TOP_LEVEL_SCRIPT_OR_FUNCTION = 0;
private static final int CONSTRUCTED_FUNCTION = 1; private static final int CONSTRUCTED_FUNCTION = 1;

Просмотреть файл

@ -667,10 +667,6 @@ public class TokenStream {
return false; return false;
} }
public void clearPushback() {
this.pushbackToken = EOF;
}
public void ungetToken(int tt) { public void ungetToken(int tt) {
// Can not unread more then one token // Can not unread more then one token
if (this.pushbackToken != EOF && tt != ERROR) Context.codeBug(); if (this.pushbackToken != EOF && tt != ERROR) Context.codeBug();
@ -687,13 +683,15 @@ public class TokenStream {
} }
public int peekTokenSameLine() throws IOException { public int peekTokenSameLine() throws IOException {
int result;
flags |= TSF_NEWLINES; // SCAN_NEWLINES from jsscan.h flags |= TSF_NEWLINES; // SCAN_NEWLINES from jsscan.h
result = peekToken(); int result = getToken();
flags &= ~TSF_NEWLINES; // HIDE_NEWLINES from jsscan.h if (result == EOL) {
if (this.pushbackToken == EOL)
this.pushbackToken = EOF; this.pushbackToken = EOF;
} else {
this.pushbackToken = result;
}
tokenno--;
flags &= ~TSF_NEWLINES; // HIDE_NEWLINES from jsscan.h
return result; return result;
} }
@ -718,7 +716,7 @@ public class TokenStream {
} else if (c == '\n') { } else if (c == '\n') {
flags &= ~TSF_DIRTYLINE; flags &= ~TSF_DIRTYLINE;
if ((flags & TSF_NEWLINES) != 0) { if ((flags & TSF_NEWLINES) != 0) {
break; return EOL;
} }
} else if (!isJSSpace(c)) { } else if (!isJSSpace(c)) {
if (c != '-') { if (c != '-') {
@ -1024,7 +1022,6 @@ public class TokenStream {
} }
switch (c) { switch (c) {
case '\n': return EOL;
case ';': return SEMI; case ';': return SEMI;
case '[': return LB; case '[': return LB;
case ']': return RB; case ']': return RB;
@ -1331,12 +1328,14 @@ public class TokenStream {
} }
private void addToString(int c) { private void addToString(int c) {
if (stringBufferTop == stringBuffer.length) { int N = stringBufferTop;
if (N == stringBuffer.length) {
char[] tmp = new char[stringBuffer.length * 2]; char[] tmp = new char[stringBuffer.length * 2];
System.arraycopy(stringBuffer, 0, tmp, 0, stringBufferTop); System.arraycopy(stringBuffer, 0, tmp, 0, N);
stringBuffer = tmp; stringBuffer = tmp;
} }
stringBuffer[stringBufferTop++] = (char)c; stringBuffer[N] = (char)c;
stringBufferTop = N + 1;
} }
public void reportSyntaxError(String messageProperty, Object[] args) { public void reportSyntaxError(String messageProperty, Object[] args) {