From 20a4d9d138f33c69ab329a6a86700f38c71dab79 Mon Sep 17 00:00:00 2001 From: Eric Vergnaud Date: Fri, 19 Mar 2021 00:06:02 +0800 Subject: [PATCH 1/2] always trigger enter/exit rules (same as Java/C#) --- runtime/JavaScript/src/antlr4/Parser.js | 31 +++++++++---------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/runtime/JavaScript/src/antlr4/Parser.js b/runtime/JavaScript/src/antlr4/Parser.js index 3ad684762..61bf99d95 100644 --- a/runtime/JavaScript/src/antlr4/Parser.js +++ b/runtime/JavaScript/src/antlr4/Parser.js @@ -224,16 +224,16 @@ class Parser extends Recognizer { } } -// Remove all parse listeners. + // Remove all parse listeners. removeParseListeners() { this._parseListeners = null; } -// Notify any parse listeners of an enter rule event. + // Notify any parse listeners of an enter rule event. triggerEnterRuleEvent() { if (this._parseListeners !== null) { const ctx = this._ctx; - this._parseListeners.map(function(listener) { + this._parseListeners.forEach(function(listener) { listener.enterEveryRule(ctx); ctx.enterRule(listener); }); @@ -248,7 +248,7 @@ class Parser extends Recognizer { if (this._parseListeners !== null) { // reverse order walk of listeners const ctx = this._ctx; - this._parseListeners.slice(0).reverse().map(function(listener) { + this._parseListeners.slice(0).reverse().forEach(function(listener) { ctx.exitRule(listener); listener.exitEveryRule(ctx); }); @@ -392,7 +392,7 @@ class Parser extends Recognizer { } node.invokingState = this.state; if (hasListener) { - this._parseListeners.map(function(listener) { + this._parseListeners.forEach(function(listener) { if (node instanceof ErrorNode || (node.isErrorNode !== undefined && node.isErrorNode())) { listener.visitErrorNode(node); } else if (node instanceof TerminalNode) { @@ -422,17 +422,13 @@ class Parser extends Recognizer { if (this.buildParseTrees) { this.addContextToParseTree(); } - if (this._parseListeners !== null) { - this.triggerEnterRuleEvent(); - } + this.triggerEnterRuleEvent(); } exitRule() { this._ctx.stop = this._input.LT(-1); // trigger event on _ctx, before it reverts to parent - if (this._parseListeners !== null) { - this.triggerExitRuleEvent(); - } + this.triggerExitRuleEvent(); this.state = this._ctx.invokingState; this._ctx = this._ctx.parentCtx; } @@ -469,10 +465,7 @@ class Parser extends Recognizer { this._precedenceStack.push(precedence); this._ctx = localctx; this._ctx.start = this._input.LT(1); - if (this._parseListeners !== null) { - this.triggerEnterRuleEvent(); // simulates rule entry for - // left-recursive rules - } + this.triggerEnterRuleEvent(); // simulates rule entry for left-recursive rules } // Like {@link //enterRule} but for recursive rules. @@ -487,10 +480,7 @@ class Parser extends Recognizer { if (this.buildParseTrees) { this._ctx.addChild(previous); } - if (this._parseListeners !== null) { - this.triggerEnterRuleEvent(); // simulates rule entry for - // left-recursive rules - } + this.triggerEnterRuleEvent(); // simulates rule entry for left-recursive rules } unrollRecursionContexts(parentCtx) { @@ -498,7 +488,8 @@ class Parser extends Recognizer { this._ctx.stop = this._input.LT(-1); const retCtx = this._ctx; // save current ctx (return value) // unroll so _ctx is as it was before call to recursive method - if (this._parseListeners !== null) { + const parseListeners = this.getParseListeners(); + if (parseListeners !== null && parseListeners.length > 0) { while (this._ctx !== parentCtx) { this.triggerExitRuleEvent(); this._ctx = this._ctx.parentCtx; From d82e8921a6ce5782caddf4b726f02bc4dd382c33 Mon Sep 17 00:00:00 2001 From: Eric Vergnaud Date: Fri, 19 Mar 2021 00:11:03 +0800 Subject: [PATCH 2/2] Fix issue where original ATN would be damaged by IntervalSet operations. Foxes #3216 --- runtime/JavaScript/src/antlr4/IntervalSet.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/runtime/JavaScript/src/antlr4/IntervalSet.js b/runtime/JavaScript/src/antlr4/IntervalSet.js index be7c8b3b8..8a711e301 100644 --- a/runtime/JavaScript/src/antlr4/IntervalSet.js +++ b/runtime/JavaScript/src/antlr4/IntervalSet.js @@ -7,11 +7,16 @@ const {Token} = require('./Token'); /* stop is not included! */ class Interval { + constructor(start, stop) { this.start = start; this.stop = stop; } + clone() { + return new Interval(this.start, this.stop); + } + contains(item) { return item >= this.start && item < this.stop; } @@ -55,7 +60,7 @@ class IntervalSet { addInterval(toAdd) { if (this.intervals === null) { this.intervals = []; - this.intervals.push(toAdd); + this.intervals.push(toAdd.clone()); } else { // find insert pos for (let pos = 0; pos < this.intervals.length; pos++) { @@ -78,7 +83,7 @@ class IntervalSet { } } // greater than any existing - this.intervals.push(toAdd); + this.intervals.push(toAdd.clone()); } }