104 lines
4.2 KiB
JavaScript
104 lines
4.2 KiB
JavaScript
"use strict";
|
|
/*!
|
|
* Copyright 2016 The ANTLR Project. All rights reserved.
|
|
* Licensed under the BSD-3-Clause license. See LICENSE file in the project root for license information.
|
|
*/
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.ParseTreeWalker = void 0;
|
|
const ErrorNode_1 = require("./ErrorNode");
|
|
const TerminalNode_1 = require("./TerminalNode");
|
|
const RuleNode_1 = require("./RuleNode");
|
|
class ParseTreeWalker {
|
|
/**
|
|
* Performs a walk on the given parse tree starting at the root and going down recursively
|
|
* with depth-first search. On each node, {@link ParseTreeWalker#enterRule} is called before
|
|
* recursively walking down into child nodes, then
|
|
* {@link ParseTreeWalker#exitRule} is called after the recursive call to wind up.
|
|
* @param listener The listener used by the walker to process grammar rules
|
|
* @param t The parse tree to be walked on
|
|
*/
|
|
walk(listener, t) {
|
|
let nodeStack = [];
|
|
let indexStack = [];
|
|
let currentNode = t;
|
|
let currentIndex = 0;
|
|
while (currentNode) {
|
|
// pre-order visit
|
|
if (currentNode instanceof ErrorNode_1.ErrorNode) {
|
|
if (listener.visitErrorNode) {
|
|
listener.visitErrorNode(currentNode);
|
|
}
|
|
}
|
|
else if (currentNode instanceof TerminalNode_1.TerminalNode) {
|
|
if (listener.visitTerminal) {
|
|
listener.visitTerminal(currentNode);
|
|
}
|
|
}
|
|
else {
|
|
this.enterRule(listener, currentNode);
|
|
}
|
|
// Move down to first child, if exists
|
|
if (currentNode.childCount > 0) {
|
|
nodeStack.push(currentNode);
|
|
indexStack.push(currentIndex);
|
|
currentIndex = 0;
|
|
currentNode = currentNode.getChild(0);
|
|
continue;
|
|
}
|
|
// No child nodes, so walk tree
|
|
do {
|
|
// post-order visit
|
|
if (currentNode instanceof RuleNode_1.RuleNode) {
|
|
this.exitRule(listener, currentNode);
|
|
}
|
|
// No parent, so no siblings
|
|
if (nodeStack.length === 0) {
|
|
currentNode = undefined;
|
|
currentIndex = 0;
|
|
break;
|
|
}
|
|
// Move to next sibling if possible
|
|
let last = nodeStack[nodeStack.length - 1];
|
|
currentIndex++;
|
|
currentNode = currentIndex < last.childCount ? last.getChild(currentIndex) : undefined;
|
|
if (currentNode) {
|
|
break;
|
|
}
|
|
// No next sibling, so move up
|
|
currentNode = nodeStack.pop();
|
|
currentIndex = indexStack.pop();
|
|
} while (currentNode);
|
|
}
|
|
}
|
|
/**
|
|
* Enters a grammar rule by first triggering the generic event {@link ParseTreeListener#enterEveryRule}
|
|
* then by triggering the event specific to the given parse tree node
|
|
* @param listener The listener responding to the trigger events
|
|
* @param r The grammar rule containing the rule context
|
|
*/
|
|
enterRule(listener, r) {
|
|
let ctx = r.ruleContext;
|
|
if (listener.enterEveryRule) {
|
|
listener.enterEveryRule(ctx);
|
|
}
|
|
ctx.enterRule(listener);
|
|
}
|
|
/**
|
|
* Exits a grammar rule by first triggering the event specific to the given parse tree node
|
|
* then by triggering the generic event {@link ParseTreeListener#exitEveryRule}
|
|
* @param listener The listener responding to the trigger events
|
|
* @param r The grammar rule containing the rule context
|
|
*/
|
|
exitRule(listener, r) {
|
|
let ctx = r.ruleContext;
|
|
ctx.exitRule(listener);
|
|
if (listener.exitEveryRule) {
|
|
listener.exitEveryRule(ctx);
|
|
}
|
|
}
|
|
}
|
|
exports.ParseTreeWalker = ParseTreeWalker;
|
|
(function (ParseTreeWalker) {
|
|
ParseTreeWalker.DEFAULT = new ParseTreeWalker();
|
|
})(ParseTreeWalker = exports.ParseTreeWalker || (exports.ParseTreeWalker = {}));
|
|
//# sourceMappingURL=ParseTreeWalker.js.map
|