Skip to content

Commit f03efdf

Browse files
committed
parser kernel: when parseError() produces a return value (i.e. return value is NOT undefined) while executing a parse error recovery, exit the parse process with that value anyway, even when the parse itself would otherwise be recoverable.
In other words: whn your custom `parseError()` handler DOES NOT check the `hash.recoverable` flag AND produces a non-`undefined` return value, you will always have the `parse()` call terminate the parse and return said return value to the caller. (This change also 'beautifies'/'shortens' the `yylloc` dump sections in any `yydebug()` debug lines.)
1 parent 726ed54 commit f03efdf

File tree

1 file changed

+18
-14
lines changed

1 file changed

+18
-14
lines changed

lib/jison-parser-kernel.js

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,11 @@ function parse(input, parseParams) {
165165
} else {
166166
re1 = new XRegExp(' \"([\\p{Alphabetic}_][\\p{Alphabetic}\\p{Number}_. ]*)\": ', 'g');
167167
}
168-
js = JSON.stringify(obj, null, 2).replace(re1, ' $1: ').replace(/[\n\s]+/g, ' ');
168+
js = JSON.stringify(obj, null, 2)
169+
.replace(re1, ' $1: ')
170+
.replace(/[\n\s]+/g, ' ')
171+
// shorten yylloc object dumps too:
172+
.replace(/\{ first_line: (\d+), first_column: (\d+), last_line: (\d+), last_column: (\d+)/g, '{L/C: ($1,$2)..($3,$4)');
169173
} catch (ex) {
170174
js = String(obj);
171175
}
@@ -233,8 +237,7 @@ function parse(input, parseParams) {
233237
hash.extra_error_attributes = args;
234238
}
235239

236-
var r = this.parseError(str, hash, this.JisonParserError);
237-
return r;
240+
return this.parseError(str, hash, this.JisonParserError);
238241
};
239242
}
240243

@@ -885,16 +888,18 @@ function parse(input, parseParams) {
885888
// invoke the parser's cleanup API!
886889
recoveringErrorInfo = this.shallowCopyErrorInfo(p);
887890

891+
if (yydebug) yydebug('error recovery rule detected: ', { error_rule_depth: error_rule_depth, error: p.errStr, error_hash: p });
892+
888893
r = this.parseError(p.errStr, p, this.JisonParserError);
894+
if (typeof r !== 'undefined') {
895+
retval = r;
896+
break;
897+
}
889898

890-
if (yydebug) yydebug('error recovery rule detected: ', { error_rule_depth: error_rule_depth, error: p.errStr, error_hash: p });
891899
// Protect against overly blunt userland `parseError` code which *sets*
892900
// the `recoverable` flag without properly checking first:
893901
// we always terminate the parse when there's no recovery rule available anyhow!
894902
if (!p.recoverable || error_rule_depth < 0) {
895-
if (typeof r !== 'undefined') {
896-
retval = r;
897-
}
898903
break;
899904
} else {
900905
// TODO: allow parseError callback to edit symbol and or state at the start of the error recovery process...
@@ -1470,13 +1475,12 @@ function parse(input, parseParams) {
14701475
else if (lexer && typeof lexer.JisonLexerError === 'function' && ex instanceof lexer.JisonLexerError) {
14711476
throw ex;
14721477
}
1473-
else {
1474-
p = this.constructParseErrorInfo('Parsing aborted due to exception.', ex, null, false);
1475-
retval = false;
1476-
r = this.parseError(p.errStr, p, this.JisonParserError);
1477-
if (typeof r !== 'undefined') {
1478-
retval = r;
1479-
}
1478+
1479+
p = this.constructParseErrorInfo('Parsing aborted due to exception.', ex, null, false);
1480+
retval = false;
1481+
r = this.parseError(p.errStr, p, this.JisonParserError);
1482+
if (typeof r !== 'undefined') {
1483+
retval = r;
14801484
}
14811485
} finally {
14821486
retval = this.cleanupAfterParse(retval, true, true);

0 commit comments

Comments
 (0)