forked from kevin.shehu/GGD
548 lines
24 KiB
JavaScript
548 lines
24 KiB
JavaScript
"use strict";
|
|
/* istanbul ignore next */ var __extends = (this && this.__extends) || (function () {
|
|
var extendStatics = function (d, b) {
|
|
extendStatics = Object.setPrototypeOf ||
|
|
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
|
return extendStatics(d, b);
|
|
};
|
|
return function (d, b) {
|
|
extendStatics(d, b);
|
|
function __() { this.constructor = d; }
|
|
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
};
|
|
})();
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
var rest_1 = require("./rest");
|
|
var utils_1 = require("../../utils/utils");
|
|
var first_1 = require("./first");
|
|
var gast_public_1 = require("./gast/gast_public");
|
|
var AbstractNextPossibleTokensWalker = /** @class */ (function (_super) {
|
|
__extends(AbstractNextPossibleTokensWalker, _super);
|
|
function AbstractNextPossibleTokensWalker(topProd, path) {
|
|
var _this = _super.call(this) /* istanbul ignore next */ || this;
|
|
_this.topProd = topProd;
|
|
_this.path = path;
|
|
_this.possibleTokTypes = [];
|
|
_this.nextProductionName = "";
|
|
_this.nextProductionOccurrence = 0;
|
|
_this.found = false;
|
|
_this.isAtEndOfPath = false;
|
|
return _this;
|
|
}
|
|
AbstractNextPossibleTokensWalker.prototype.startWalking = function () {
|
|
this.found = false;
|
|
if (this.path.ruleStack[0] !== this.topProd.name) {
|
|
throw Error("The path does not start with the walker's top Rule!");
|
|
}
|
|
// immutable for the win
|
|
this.ruleStack = utils_1.cloneArr(this.path.ruleStack).reverse(); // intelij bug requires assertion
|
|
this.occurrenceStack = utils_1.cloneArr(this.path.occurrenceStack).reverse(); // intelij bug requires assertion
|
|
// already verified that the first production is valid, we now seek the 2nd production
|
|
this.ruleStack.pop();
|
|
this.occurrenceStack.pop();
|
|
this.updateExpectedNext();
|
|
this.walk(this.topProd);
|
|
return this.possibleTokTypes;
|
|
};
|
|
AbstractNextPossibleTokensWalker.prototype.walk = function (prod, prevRest) {
|
|
if (prevRest === void 0) { prevRest = []; }
|
|
// stop scanning once we found the path
|
|
if (!this.found) {
|
|
_super.prototype.walk.call(this, prod, prevRest);
|
|
}
|
|
};
|
|
AbstractNextPossibleTokensWalker.prototype.walkProdRef = function (refProd, currRest, prevRest) {
|
|
// found the next production, need to keep walking in it
|
|
if (refProd.referencedRule.name === this.nextProductionName &&
|
|
refProd.idx === this.nextProductionOccurrence) {
|
|
var fullRest = currRest.concat(prevRest);
|
|
this.updateExpectedNext();
|
|
this.walk(refProd.referencedRule, fullRest);
|
|
}
|
|
};
|
|
AbstractNextPossibleTokensWalker.prototype.updateExpectedNext = function () {
|
|
// need to consume the Terminal
|
|
if (utils_1.isEmpty(this.ruleStack)) {
|
|
// must reset nextProductionXXX to avoid walking down another Top Level production while what we are
|
|
// really seeking is the last Terminal...
|
|
this.nextProductionName = "";
|
|
this.nextProductionOccurrence = 0;
|
|
this.isAtEndOfPath = true;
|
|
}
|
|
else {
|
|
this.nextProductionName = this.ruleStack.pop();
|
|
this.nextProductionOccurrence = this.occurrenceStack.pop();
|
|
}
|
|
};
|
|
return AbstractNextPossibleTokensWalker;
|
|
}(rest_1.RestWalker));
|
|
exports.AbstractNextPossibleTokensWalker = AbstractNextPossibleTokensWalker;
|
|
var NextAfterTokenWalker = /** @class */ (function (_super) {
|
|
__extends(NextAfterTokenWalker, _super);
|
|
function NextAfterTokenWalker(topProd, path) {
|
|
var _this = _super.call(this, topProd, path) /* istanbul ignore next */ || this;
|
|
_this.path = path;
|
|
_this.nextTerminalName = "";
|
|
_this.nextTerminalOccurrence = 0;
|
|
_this.nextTerminalName = _this.path.lastTok.name;
|
|
_this.nextTerminalOccurrence = _this.path.lastTokOccurrence;
|
|
return _this;
|
|
}
|
|
NextAfterTokenWalker.prototype.walkTerminal = function (terminal, currRest, prevRest) {
|
|
if (this.isAtEndOfPath &&
|
|
terminal.terminalType.name === this.nextTerminalName &&
|
|
terminal.idx === this.nextTerminalOccurrence &&
|
|
!this.found) {
|
|
var fullRest = currRest.concat(prevRest);
|
|
var restProd = new gast_public_1.Flat({ definition: fullRest });
|
|
this.possibleTokTypes = first_1.first(restProd);
|
|
this.found = true;
|
|
}
|
|
};
|
|
return NextAfterTokenWalker;
|
|
}(AbstractNextPossibleTokensWalker));
|
|
exports.NextAfterTokenWalker = NextAfterTokenWalker;
|
|
/**
|
|
* This walker only "walks" a single "TOP" level in the Grammar Ast, this means
|
|
* it never "follows" production refs
|
|
*/
|
|
var AbstractNextTerminalAfterProductionWalker = /** @class */ (function (_super) {
|
|
__extends(AbstractNextTerminalAfterProductionWalker, _super);
|
|
function AbstractNextTerminalAfterProductionWalker(topRule, occurrence) {
|
|
var _this = _super.call(this) /* istanbul ignore next */ || this;
|
|
_this.topRule = topRule;
|
|
_this.occurrence = occurrence;
|
|
_this.result = {
|
|
token: undefined,
|
|
occurrence: undefined,
|
|
isEndOfRule: undefined
|
|
};
|
|
return _this;
|
|
}
|
|
AbstractNextTerminalAfterProductionWalker.prototype.startWalking = function () {
|
|
this.walk(this.topRule);
|
|
return this.result;
|
|
};
|
|
return AbstractNextTerminalAfterProductionWalker;
|
|
}(rest_1.RestWalker));
|
|
exports.AbstractNextTerminalAfterProductionWalker = AbstractNextTerminalAfterProductionWalker;
|
|
var NextTerminalAfterManyWalker = /** @class */ (function (_super) {
|
|
__extends(NextTerminalAfterManyWalker, _super);
|
|
function NextTerminalAfterManyWalker() {
|
|
return _super !== null && _super.apply(this, arguments) /* istanbul ignore next */ || this;
|
|
}
|
|
NextTerminalAfterManyWalker.prototype.walkMany = function (manyProd, currRest, prevRest) {
|
|
if (manyProd.idx === this.occurrence) {
|
|
var firstAfterMany = utils_1.first(currRest.concat(prevRest));
|
|
this.result.isEndOfRule = firstAfterMany === undefined;
|
|
if (firstAfterMany instanceof gast_public_1.Terminal) {
|
|
this.result.token = firstAfterMany.terminalType;
|
|
this.result.occurrence = firstAfterMany.idx;
|
|
}
|
|
}
|
|
else {
|
|
_super.prototype.walkMany.call(this, manyProd, currRest, prevRest);
|
|
}
|
|
};
|
|
return NextTerminalAfterManyWalker;
|
|
}(AbstractNextTerminalAfterProductionWalker));
|
|
exports.NextTerminalAfterManyWalker = NextTerminalAfterManyWalker;
|
|
var NextTerminalAfterManySepWalker = /** @class */ (function (_super) {
|
|
__extends(NextTerminalAfterManySepWalker, _super);
|
|
function NextTerminalAfterManySepWalker() {
|
|
return _super !== null && _super.apply(this, arguments) /* istanbul ignore next */ || this;
|
|
}
|
|
NextTerminalAfterManySepWalker.prototype.walkManySep = function (manySepProd, currRest, prevRest) {
|
|
if (manySepProd.idx === this.occurrence) {
|
|
var firstAfterManySep = utils_1.first(currRest.concat(prevRest));
|
|
this.result.isEndOfRule = firstAfterManySep === undefined;
|
|
if (firstAfterManySep instanceof gast_public_1.Terminal) {
|
|
this.result.token = firstAfterManySep.terminalType;
|
|
this.result.occurrence = firstAfterManySep.idx;
|
|
}
|
|
}
|
|
else {
|
|
_super.prototype.walkManySep.call(this, manySepProd, currRest, prevRest);
|
|
}
|
|
};
|
|
return NextTerminalAfterManySepWalker;
|
|
}(AbstractNextTerminalAfterProductionWalker));
|
|
exports.NextTerminalAfterManySepWalker = NextTerminalAfterManySepWalker;
|
|
var NextTerminalAfterAtLeastOneWalker = /** @class */ (function (_super) {
|
|
__extends(NextTerminalAfterAtLeastOneWalker, _super);
|
|
function NextTerminalAfterAtLeastOneWalker() {
|
|
return _super !== null && _super.apply(this, arguments) /* istanbul ignore next */ || this;
|
|
}
|
|
NextTerminalAfterAtLeastOneWalker.prototype.walkAtLeastOne = function (atLeastOneProd, currRest, prevRest) {
|
|
if (atLeastOneProd.idx === this.occurrence) {
|
|
var firstAfterAtLeastOne = utils_1.first(currRest.concat(prevRest));
|
|
this.result.isEndOfRule = firstAfterAtLeastOne === undefined;
|
|
if (firstAfterAtLeastOne instanceof gast_public_1.Terminal) {
|
|
this.result.token = firstAfterAtLeastOne.terminalType;
|
|
this.result.occurrence = firstAfterAtLeastOne.idx;
|
|
}
|
|
}
|
|
else {
|
|
_super.prototype.walkAtLeastOne.call(this, atLeastOneProd, currRest, prevRest);
|
|
}
|
|
};
|
|
return NextTerminalAfterAtLeastOneWalker;
|
|
}(AbstractNextTerminalAfterProductionWalker));
|
|
exports.NextTerminalAfterAtLeastOneWalker = NextTerminalAfterAtLeastOneWalker;
|
|
// TODO: reduce code duplication in the AfterWalkers
|
|
var NextTerminalAfterAtLeastOneSepWalker = /** @class */ (function (_super) {
|
|
__extends(NextTerminalAfterAtLeastOneSepWalker, _super);
|
|
function NextTerminalAfterAtLeastOneSepWalker() {
|
|
return _super !== null && _super.apply(this, arguments) /* istanbul ignore next */ || this;
|
|
}
|
|
NextTerminalAfterAtLeastOneSepWalker.prototype.walkAtLeastOneSep = function (atleastOneSepProd, currRest, prevRest) {
|
|
if (atleastOneSepProd.idx === this.occurrence) {
|
|
var firstAfterfirstAfterAtLeastOneSep = utils_1.first(currRest.concat(prevRest));
|
|
this.result.isEndOfRule =
|
|
firstAfterfirstAfterAtLeastOneSep === undefined;
|
|
if (firstAfterfirstAfterAtLeastOneSep instanceof gast_public_1.Terminal) {
|
|
this.result.token =
|
|
firstAfterfirstAfterAtLeastOneSep.terminalType;
|
|
this.result.occurrence = firstAfterfirstAfterAtLeastOneSep.idx;
|
|
}
|
|
}
|
|
else {
|
|
_super.prototype.walkAtLeastOneSep.call(this, atleastOneSepProd, currRest, prevRest);
|
|
}
|
|
};
|
|
return NextTerminalAfterAtLeastOneSepWalker;
|
|
}(AbstractNextTerminalAfterProductionWalker));
|
|
exports.NextTerminalAfterAtLeastOneSepWalker = NextTerminalAfterAtLeastOneSepWalker;
|
|
function possiblePathsFrom(targetDef, maxLength, currPath) {
|
|
if (currPath === void 0) { currPath = []; }
|
|
// avoid side effects
|
|
currPath = utils_1.cloneArr(currPath);
|
|
var result = [];
|
|
var i = 0;
|
|
// TODO: avoid inner funcs
|
|
function remainingPathWith(nextDef) {
|
|
return nextDef.concat(utils_1.drop(targetDef, i + 1));
|
|
}
|
|
// TODO: avoid inner funcs
|
|
function getAlternativesForProd(definition) {
|
|
var alternatives = possiblePathsFrom(remainingPathWith(definition), maxLength, currPath);
|
|
return result.concat(alternatives);
|
|
}
|
|
/**
|
|
* Mandatory productions will halt the loop as the paths computed from their recursive calls will already contain the
|
|
* following (rest) of the targetDef.
|
|
*
|
|
* For optional productions (Option/Repetition/...) the loop will continue to represent the paths that do not include the
|
|
* the optional production.
|
|
*/
|
|
while (currPath.length < maxLength && i < targetDef.length) {
|
|
var prod = targetDef[i];
|
|
/* istanbul ignore else */
|
|
if (prod instanceof gast_public_1.Flat) {
|
|
return getAlternativesForProd(prod.definition);
|
|
}
|
|
else if (prod instanceof gast_public_1.NonTerminal) {
|
|
return getAlternativesForProd(prod.definition);
|
|
}
|
|
else if (prod instanceof gast_public_1.Option) {
|
|
result = getAlternativesForProd(prod.definition);
|
|
}
|
|
else if (prod instanceof gast_public_1.RepetitionMandatory) {
|
|
var newDef = prod.definition.concat([
|
|
new gast_public_1.Repetition({
|
|
definition: prod.definition
|
|
})
|
|
]);
|
|
return getAlternativesForProd(newDef);
|
|
}
|
|
else if (prod instanceof gast_public_1.RepetitionMandatoryWithSeparator) {
|
|
var newDef = [
|
|
new gast_public_1.Flat({ definition: prod.definition }),
|
|
new gast_public_1.Repetition({
|
|
definition: [
|
|
new gast_public_1.Terminal({ terminalType: prod.separator })
|
|
].concat(prod.definition)
|
|
})
|
|
];
|
|
return getAlternativesForProd(newDef);
|
|
}
|
|
else if (prod instanceof gast_public_1.RepetitionWithSeparator) {
|
|
var newDef = prod.definition.concat([
|
|
new gast_public_1.Repetition({
|
|
definition: [
|
|
new gast_public_1.Terminal({ terminalType: prod.separator })
|
|
].concat(prod.definition)
|
|
})
|
|
]);
|
|
result = getAlternativesForProd(newDef);
|
|
}
|
|
else if (prod instanceof gast_public_1.Repetition) {
|
|
var newDef = prod.definition.concat([
|
|
new gast_public_1.Repetition({
|
|
definition: prod.definition
|
|
})
|
|
]);
|
|
result = getAlternativesForProd(newDef);
|
|
}
|
|
else if (prod instanceof gast_public_1.Alternation) {
|
|
utils_1.forEach(prod.definition, function (currAlt) {
|
|
result = getAlternativesForProd(currAlt.definition);
|
|
});
|
|
return result;
|
|
}
|
|
else if (prod instanceof gast_public_1.Terminal) {
|
|
currPath.push(prod.terminalType);
|
|
}
|
|
else {
|
|
throw Error("non exhaustive match");
|
|
}
|
|
i++;
|
|
}
|
|
result.push({
|
|
partialPath: currPath,
|
|
suffixDef: utils_1.drop(targetDef, i)
|
|
});
|
|
return result;
|
|
}
|
|
exports.possiblePathsFrom = possiblePathsFrom;
|
|
function nextPossibleTokensAfter(initialDef, tokenVector, tokMatcher, maxLookAhead) {
|
|
var EXIT_NON_TERMINAL = "EXIT_NONE_TERMINAL";
|
|
// to avoid creating a new Array each time.
|
|
var EXIT_NON_TERMINAL_ARR = [EXIT_NON_TERMINAL];
|
|
var EXIT_ALTERNATIVE = "EXIT_ALTERNATIVE";
|
|
var foundCompletePath = false;
|
|
var tokenVectorLength = tokenVector.length;
|
|
var minimalAlternativesIndex = tokenVectorLength - maxLookAhead - 1;
|
|
var result = [];
|
|
var possiblePaths = [];
|
|
possiblePaths.push({
|
|
idx: -1,
|
|
def: initialDef,
|
|
ruleStack: [],
|
|
occurrenceStack: []
|
|
});
|
|
while (!utils_1.isEmpty(possiblePaths)) {
|
|
var currPath = possiblePaths.pop();
|
|
// skip alternatives if no more results can be found (assuming deterministic grammar with fixed lookahead)
|
|
if (currPath === EXIT_ALTERNATIVE) {
|
|
if (foundCompletePath &&
|
|
utils_1.last(possiblePaths).idx <= minimalAlternativesIndex) {
|
|
// remove irrelevant alternative
|
|
possiblePaths.pop();
|
|
}
|
|
continue;
|
|
}
|
|
var currDef = currPath.def;
|
|
var currIdx = currPath.idx;
|
|
var currRuleStack = currPath.ruleStack;
|
|
var currOccurrenceStack = currPath.occurrenceStack;
|
|
// For Example: an empty path could exist in a valid grammar in the case of an EMPTY_ALT
|
|
if (utils_1.isEmpty(currDef)) {
|
|
continue;
|
|
}
|
|
var prod = currDef[0];
|
|
/* istanbul ignore else */
|
|
if (prod === EXIT_NON_TERMINAL) {
|
|
var nextPath = {
|
|
idx: currIdx,
|
|
def: utils_1.drop(currDef),
|
|
ruleStack: utils_1.dropRight(currRuleStack),
|
|
occurrenceStack: utils_1.dropRight(currOccurrenceStack)
|
|
};
|
|
possiblePaths.push(nextPath);
|
|
}
|
|
else if (prod instanceof gast_public_1.Terminal) {
|
|
/* istanbul ignore else */
|
|
if (currIdx < tokenVectorLength - 1) {
|
|
var nextIdx = currIdx + 1;
|
|
var actualToken = tokenVector[nextIdx];
|
|
if (tokMatcher(actualToken, prod.terminalType)) {
|
|
var nextPath = {
|
|
idx: nextIdx,
|
|
def: utils_1.drop(currDef),
|
|
ruleStack: currRuleStack,
|
|
occurrenceStack: currOccurrenceStack
|
|
};
|
|
possiblePaths.push(nextPath);
|
|
}
|
|
// end of the line
|
|
}
|
|
else if (currIdx === tokenVectorLength - 1) {
|
|
// IGNORE ABOVE ELSE
|
|
result.push({
|
|
nextTokenType: prod.terminalType,
|
|
nextTokenOccurrence: prod.idx,
|
|
ruleStack: currRuleStack,
|
|
occurrenceStack: currOccurrenceStack
|
|
});
|
|
foundCompletePath = true;
|
|
}
|
|
else {
|
|
throw Error("non exhaustive match");
|
|
}
|
|
}
|
|
else if (prod instanceof gast_public_1.NonTerminal) {
|
|
var newRuleStack = utils_1.cloneArr(currRuleStack);
|
|
newRuleStack.push(prod.nonTerminalName);
|
|
var newOccurrenceStack = utils_1.cloneArr(currOccurrenceStack);
|
|
newOccurrenceStack.push(prod.idx);
|
|
var nextPath = {
|
|
idx: currIdx,
|
|
def: prod.definition.concat(EXIT_NON_TERMINAL_ARR, utils_1.drop(currDef)),
|
|
ruleStack: newRuleStack,
|
|
occurrenceStack: newOccurrenceStack
|
|
};
|
|
possiblePaths.push(nextPath);
|
|
}
|
|
else if (prod instanceof gast_public_1.Option) {
|
|
// the order of alternatives is meaningful, FILO (Last path will be traversed first).
|
|
var nextPathWithout = {
|
|
idx: currIdx,
|
|
def: utils_1.drop(currDef),
|
|
ruleStack: currRuleStack,
|
|
occurrenceStack: currOccurrenceStack
|
|
};
|
|
possiblePaths.push(nextPathWithout);
|
|
// required marker to avoid backtracking paths whose higher priority alternatives already matched
|
|
possiblePaths.push(EXIT_ALTERNATIVE);
|
|
var nextPathWith = {
|
|
idx: currIdx,
|
|
def: prod.definition.concat(utils_1.drop(currDef)),
|
|
ruleStack: currRuleStack,
|
|
occurrenceStack: currOccurrenceStack
|
|
};
|
|
possiblePaths.push(nextPathWith);
|
|
}
|
|
else if (prod instanceof gast_public_1.RepetitionMandatory) {
|
|
// TODO:(THE NEW operators here take a while...) (convert once?)
|
|
var secondIteration = new gast_public_1.Repetition({
|
|
definition: prod.definition,
|
|
idx: prod.idx
|
|
});
|
|
var nextDef = prod.definition.concat([secondIteration], utils_1.drop(currDef));
|
|
var nextPath = {
|
|
idx: currIdx,
|
|
def: nextDef,
|
|
ruleStack: currRuleStack,
|
|
occurrenceStack: currOccurrenceStack
|
|
};
|
|
possiblePaths.push(nextPath);
|
|
}
|
|
else if (prod instanceof gast_public_1.RepetitionMandatoryWithSeparator) {
|
|
// TODO:(THE NEW operators here take a while...) (convert once?)
|
|
var separatorGast = new gast_public_1.Terminal({
|
|
terminalType: prod.separator
|
|
});
|
|
var secondIteration = new gast_public_1.Repetition({
|
|
definition: [separatorGast].concat(prod.definition),
|
|
idx: prod.idx
|
|
});
|
|
var nextDef = prod.definition.concat([secondIteration], utils_1.drop(currDef));
|
|
var nextPath = {
|
|
idx: currIdx,
|
|
def: nextDef,
|
|
ruleStack: currRuleStack,
|
|
occurrenceStack: currOccurrenceStack
|
|
};
|
|
possiblePaths.push(nextPath);
|
|
}
|
|
else if (prod instanceof gast_public_1.RepetitionWithSeparator) {
|
|
// the order of alternatives is meaningful, FILO (Last path will be traversed first).
|
|
var nextPathWithout = {
|
|
idx: currIdx,
|
|
def: utils_1.drop(currDef),
|
|
ruleStack: currRuleStack,
|
|
occurrenceStack: currOccurrenceStack
|
|
};
|
|
possiblePaths.push(nextPathWithout);
|
|
// required marker to avoid backtracking paths whose higher priority alternatives already matched
|
|
possiblePaths.push(EXIT_ALTERNATIVE);
|
|
var separatorGast = new gast_public_1.Terminal({
|
|
terminalType: prod.separator
|
|
});
|
|
var nthRepetition = new gast_public_1.Repetition({
|
|
definition: [separatorGast].concat(prod.definition),
|
|
idx: prod.idx
|
|
});
|
|
var nextDef = prod.definition.concat([nthRepetition], utils_1.drop(currDef));
|
|
var nextPathWith = {
|
|
idx: currIdx,
|
|
def: nextDef,
|
|
ruleStack: currRuleStack,
|
|
occurrenceStack: currOccurrenceStack
|
|
};
|
|
possiblePaths.push(nextPathWith);
|
|
}
|
|
else if (prod instanceof gast_public_1.Repetition) {
|
|
// the order of alternatives is meaningful, FILO (Last path will be traversed first).
|
|
var nextPathWithout = {
|
|
idx: currIdx,
|
|
def: utils_1.drop(currDef),
|
|
ruleStack: currRuleStack,
|
|
occurrenceStack: currOccurrenceStack
|
|
};
|
|
possiblePaths.push(nextPathWithout);
|
|
// required marker to avoid backtracking paths whose higher priority alternatives already matched
|
|
possiblePaths.push(EXIT_ALTERNATIVE);
|
|
// TODO: an empty repetition will cause infinite loops here, will the parser detect this in selfAnalysis?
|
|
var nthRepetition = new gast_public_1.Repetition({
|
|
definition: prod.definition,
|
|
idx: prod.idx
|
|
});
|
|
var nextDef = prod.definition.concat([nthRepetition], utils_1.drop(currDef));
|
|
var nextPathWith = {
|
|
idx: currIdx,
|
|
def: nextDef,
|
|
ruleStack: currRuleStack,
|
|
occurrenceStack: currOccurrenceStack
|
|
};
|
|
possiblePaths.push(nextPathWith);
|
|
}
|
|
else if (prod instanceof gast_public_1.Alternation) {
|
|
// the order of alternatives is meaningful, FILO (Last path will be traversed first).
|
|
for (var i = prod.definition.length - 1; i >= 0; i--) {
|
|
var currAlt = prod.definition[i];
|
|
var currAltPath = {
|
|
idx: currIdx,
|
|
def: currAlt.definition.concat(utils_1.drop(currDef)),
|
|
ruleStack: currRuleStack,
|
|
occurrenceStack: currOccurrenceStack
|
|
};
|
|
possiblePaths.push(currAltPath);
|
|
possiblePaths.push(EXIT_ALTERNATIVE);
|
|
}
|
|
}
|
|
else if (prod instanceof gast_public_1.Flat) {
|
|
possiblePaths.push({
|
|
idx: currIdx,
|
|
def: prod.definition.concat(utils_1.drop(currDef)),
|
|
ruleStack: currRuleStack,
|
|
occurrenceStack: currOccurrenceStack
|
|
});
|
|
}
|
|
else if (prod instanceof gast_public_1.Rule) {
|
|
// last because we should only encounter at most a single one of these per invocation.
|
|
possiblePaths.push(expandTopLevelRule(prod, currIdx, currRuleStack, currOccurrenceStack));
|
|
}
|
|
else {
|
|
throw Error("non exhaustive match");
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
exports.nextPossibleTokensAfter = nextPossibleTokensAfter;
|
|
function expandTopLevelRule(topRule, currIdx, currRuleStack, currOccurrenceStack) {
|
|
var newRuleStack = utils_1.cloneArr(currRuleStack);
|
|
newRuleStack.push(topRule.name);
|
|
var newCurrOccurrenceStack = utils_1.cloneArr(currOccurrenceStack);
|
|
// top rule is always assumed to have been called with occurrence index 1
|
|
newCurrOccurrenceStack.push(1);
|
|
return {
|
|
idx: currIdx,
|
|
def: topRule.definition,
|
|
ruleStack: newRuleStack,
|
|
occurrenceStack: newCurrOccurrenceStack
|
|
};
|
|
}
|
|
//# sourceMappingURL=interpreter.js.map
|