diff --git a/src/org/mozilla/javascript/Parser.java b/src/org/mozilla/javascript/Parser.java index f8b64d14f0..7aa5f96302 100644 --- a/src/org/mozilla/javascript/Parser.java +++ b/src/org/mozilla/javascript/Parser.java @@ -3064,9 +3064,6 @@ private AstNode primaryExpr() pos = ts.tokenBeg; end = ts.tokenEnd; return new KeywordLiteral(pos, end - pos, tt); - case Token.RP: - return new EmptyExpression(); - case Token.RESERVED: consumeToken(); reportError("msg.reserved.id"); @@ -3099,7 +3096,7 @@ private AstNode parenExpr() throws IOException { Comment jsdocNode = getAndResetJsDoc(); int lineno = ts.lineno; int begin = ts.tokenBeg; - AstNode e = expr(); + AstNode e = (peekToken() == Token.RP ? new EmptyExpression() : expr()); if (peekToken() == Token.FOR) { return generatorExpression(e, begin); } diff --git a/testsrc/org/mozilla/javascript/tests/ParserTest.java b/testsrc/org/mozilla/javascript/tests/ParserTest.java index 507e41f891..1c398536be 100644 --- a/testsrc/org/mozilla/javascript/tests/ParserTest.java +++ b/testsrc/org/mozilla/javascript/tests/ParserTest.java @@ -4,6 +4,7 @@ package org.mozilla.javascript.tests; +import org.mozilla.javascript.ErrorReporter; import org.mozilla.javascript.ast.*; import org.mozilla.javascript.CompilerEnvirons; @@ -1183,6 +1184,56 @@ public void testParseKeywordPropertyAccess() { parse("({import:1}).import;"); } + public void testParseErrorRecovery() { + expectErrorWithRecovery(")", 1); + } + + public void testParseErrorRecovery2() { + expectErrorWithRecovery("print('Hi');)foo('bar');Silly", 2); + } + + public void testParseErrorRecovery3() { + expectErrorWithRecovery(")))", 5); + } + + // Check that error recovery is working by returning a parsing exception, but only + // when thrown by runtimeError. This is testing a regression in which the error recovery in + // certain cases would trigger an infinite loop. We do this by counting the number + // of parsing errors that are expected. + private void expectErrorWithRecovery(String code, int maxErrors) { + environment.setRecoverFromErrors(true); + environment.setErrorReporter(new ErrorReporter() + { + private int errorCount = 0; + + @Override + public void warning(String msg, String name, int line, String str, int col) + { + throw new AssertionError("Not expecting a warning"); + } + + @Override + public EvaluatorException runtimeError(String msg, String name, int line, String str, int col) + { + return new EvaluatorException(msg, name, line, str, col); + } + + @Override + public void error(String msg, String name, int line, String str, int col) + { + assertTrue(++errorCount <= maxErrors); + } + }); + + Parser p = new Parser(environment); + try { + p.parse(code, code, 0); + assertFalse("Expected an EvaluatorException", true); + } catch (EvaluatorException ee) { + // Normal failure + } + } + public void testReportError() { expectParseErrors("'use strict';(function(eval) {})();", new String[] { "\"eval\" is not a valid identifier for this use in strict mode." });