add hw2
This commit is contained in:
16
node_modules/chevrotain-allstar/LICENSE
generated
vendored
Normal file
16
node_modules/chevrotain-allstar/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
Copyright 2022 TypeFox GmbH
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
22
node_modules/chevrotain-allstar/README.md
generated
vendored
Normal file
22
node_modules/chevrotain-allstar/README.md
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
# Chevrotain Allstar
|
||||
|
||||
This is a lookahead plugin package for the [Chevrotain parser library](https://chevrotain.io/).
|
||||
It implements the [ALL(*) lookahead algorithm](https://www.antlr.org/papers/allstar-techreport.pdf) introduced for ANTLR4.
|
||||
The algorithm features unbounded lookahead, compared to the normal LL(*k*) behavior of Chevrotain.
|
||||
|
||||
## Usage
|
||||
|
||||
When creating your parser, pass an instance of the `LLStarLookaheadStrategy` to the `lookaheadStrategy` property of the base parser constructor options.
|
||||
|
||||
```ts
|
||||
import { LLStarLookaheadStrategy } from "chevrotain-allstar";
|
||||
|
||||
class Parser extends EmbeddedActionsParser {
|
||||
constructor() {
|
||||
super(tokens, {
|
||||
lookaheadStrategy: new LLStarLookaheadStrategy()
|
||||
});
|
||||
this.performSelfAnalysis()
|
||||
}
|
||||
}
|
||||
```
|
||||
36
node_modules/chevrotain-allstar/lib/all-star-lookahead.d.ts
generated
vendored
Normal file
36
node_modules/chevrotain-allstar/lib/all-star-lookahead.d.ts
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2022 TypeFox GmbH
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License, which is available in the project root.
|
||||
******************************************************************************/
|
||||
import { Rule, BaseParser, LLkLookaheadStrategy, ILookaheadValidationError, IOrAlt, OptionalProductionType } from "chevrotain";
|
||||
export type AmbiguityReport = (message: string) => void;
|
||||
export interface LLStarLookaheadOptions {
|
||||
logging?: AmbiguityReport;
|
||||
}
|
||||
export declare class LLStarLookaheadStrategy extends LLkLookaheadStrategy {
|
||||
private atn;
|
||||
private dfas;
|
||||
private logging;
|
||||
constructor(options?: LLStarLookaheadOptions);
|
||||
initialize(options: {
|
||||
rules: Rule[];
|
||||
}): void;
|
||||
validateAmbiguousAlternationAlternatives(): ILookaheadValidationError[];
|
||||
validateEmptyOrAlternatives(): ILookaheadValidationError[];
|
||||
buildLookaheadForAlternation(options: {
|
||||
prodOccurrence: number;
|
||||
rule: Rule;
|
||||
maxLookahead: number;
|
||||
hasPredicates: boolean;
|
||||
dynamicTokensEnabled: boolean;
|
||||
}): (this: BaseParser, orAlts?: IOrAlt<any>[] | undefined) => number | undefined;
|
||||
buildLookaheadForOptional(options: {
|
||||
prodOccurrence: number;
|
||||
prodType: OptionalProductionType;
|
||||
rule: Rule;
|
||||
maxLookahead: number;
|
||||
dynamicTokensEnabled: boolean;
|
||||
}): (this: BaseParser) => boolean;
|
||||
}
|
||||
//# sourceMappingURL=all-star-lookahead.d.ts.map
|
||||
1
node_modules/chevrotain-allstar/lib/all-star-lookahead.d.ts.map
generated
vendored
Normal file
1
node_modules/chevrotain-allstar/lib/all-star-lookahead.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"all-star-lookahead.d.ts","sourceRoot":"","sources":["../src/all-star-lookahead.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,EAKH,IAAI,EAUJ,UAAU,EACV,oBAAoB,EACpB,yBAAyB,EACzB,MAAM,EAEN,sBAAsB,EACzB,MAAM,YAAY,CAAC;AAgCpB,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAkDxD,MAAM,WAAW,sBAAsB;IACnC,OAAO,CAAC,EAAE,eAAe,CAAA;CAC5B;AAED,qBAAa,uBAAwB,SAAQ,oBAAoB;IAE7D,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,OAAO,CAAkB;gBAErB,OAAO,CAAC,EAAE,sBAAsB;IAKnC,UAAU,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,IAAI,EAAE,CAAA;KAAE,GAAG,IAAI;IAK5C,wCAAwC,IAAI,yBAAyB,EAAE;IAIvE,2BAA2B,IAAI,yBAAyB,EAAE;IAI1D,4BAA4B,CAAC,OAAO,EAAE;QAC3C,cAAc,EAAE,MAAM,CAAC;QACvB,IAAI,EAAE,IAAI,CAAC;QACX,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,OAAO,CAAC;QACvB,oBAAoB,EAAE,OAAO,CAAA;KAChC,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,SAAS,KAAK,MAAM,GAAG,SAAS;IAuEvE,yBAAyB,CAAC,OAAO,EAAE;QACxC,cAAc,EAAE,MAAM,CAAC;QACvB,QAAQ,EAAE,sBAAsB,CAAC;QACjC,IAAI,EAAE,IAAI,CAAC;QACX,YAAY,EAAE,MAAM,CAAC;QACrB,oBAAoB,EAAE,OAAO,CAAA;KAChC,GAAG,CAAC,IAAI,EAAE,UAAU,KAAK,OAAO;CA4DpC"}
|
||||
556
node_modules/chevrotain-allstar/lib/all-star-lookahead.js
generated
vendored
Normal file
556
node_modules/chevrotain-allstar/lib/all-star-lookahead.js
generated
vendored
Normal file
@@ -0,0 +1,556 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2022 TypeFox GmbH
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License, which is available in the project root.
|
||||
******************************************************************************/
|
||||
import { tokenMatcher, tokenLabel, NonTerminal, Alternation, Option, RepetitionMandatory, RepetitionMandatoryWithSeparator, RepetitionWithSeparator, Repetition, Terminal, LLkLookaheadStrategy, getLookaheadPaths } from "chevrotain";
|
||||
import { ATN_RULE_STOP, AtomTransition, buildATNKey, createATN, EpsilonTransition, RuleTransition } from "./atn.js";
|
||||
import { ATNConfigSet, DFA_ERROR, getATNConfigKey } from "./dfa.js";
|
||||
import min from "lodash-es/min.js";
|
||||
import flatMap from "lodash-es/flatMap.js";
|
||||
import uniqBy from "lodash-es/uniqBy.js";
|
||||
import map from "lodash-es/map.js";
|
||||
import flatten from "lodash-es/flatten.js";
|
||||
import forEach from "lodash-es/forEach.js";
|
||||
import isEmpty from "lodash-es/isEmpty.js";
|
||||
import reduce from "lodash-es/reduce.js";
|
||||
function createDFACache(startState, decision) {
|
||||
const map = {};
|
||||
return (predicateSet) => {
|
||||
const key = predicateSet.toString();
|
||||
let existing = map[key];
|
||||
if (existing !== undefined) {
|
||||
return existing;
|
||||
}
|
||||
else {
|
||||
existing = {
|
||||
atnStartState: startState,
|
||||
decision,
|
||||
states: {}
|
||||
};
|
||||
map[key] = existing;
|
||||
return existing;
|
||||
}
|
||||
};
|
||||
}
|
||||
class PredicateSet {
|
||||
constructor() {
|
||||
this.predicates = [];
|
||||
}
|
||||
is(index) {
|
||||
return index >= this.predicates.length || this.predicates[index];
|
||||
}
|
||||
set(index, value) {
|
||||
this.predicates[index] = value;
|
||||
}
|
||||
toString() {
|
||||
let value = "";
|
||||
const size = this.predicates.length;
|
||||
for (let i = 0; i < size; i++) {
|
||||
value += this.predicates[i] === true ? "1" : "0";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
const EMPTY_PREDICATES = new PredicateSet();
|
||||
export class LLStarLookaheadStrategy extends LLkLookaheadStrategy {
|
||||
constructor(options) {
|
||||
var _a;
|
||||
super();
|
||||
this.logging = (_a = options === null || options === void 0 ? void 0 : options.logging) !== null && _a !== void 0 ? _a : ((message) => console.log(message));
|
||||
}
|
||||
initialize(options) {
|
||||
this.atn = createATN(options.rules);
|
||||
this.dfas = initATNSimulator(this.atn);
|
||||
}
|
||||
validateAmbiguousAlternationAlternatives() {
|
||||
return [];
|
||||
}
|
||||
validateEmptyOrAlternatives() {
|
||||
return [];
|
||||
}
|
||||
buildLookaheadForAlternation(options) {
|
||||
const { prodOccurrence, rule, hasPredicates, dynamicTokensEnabled } = options;
|
||||
const dfas = this.dfas;
|
||||
const logging = this.logging;
|
||||
const key = buildATNKey(rule, 'Alternation', prodOccurrence);
|
||||
const decisionState = this.atn.decisionMap[key];
|
||||
const decisionIndex = decisionState.decision;
|
||||
const partialAlts = map(getLookaheadPaths({
|
||||
maxLookahead: 1,
|
||||
occurrence: prodOccurrence,
|
||||
prodType: "Alternation",
|
||||
rule: rule
|
||||
}), (currAlt) => map(currAlt, (path) => path[0]));
|
||||
if (isLL1Sequence(partialAlts, false) && !dynamicTokensEnabled) {
|
||||
const choiceToAlt = reduce(partialAlts, (result, currAlt, idx) => {
|
||||
forEach(currAlt, (currTokType) => {
|
||||
if (currTokType) {
|
||||
result[currTokType.tokenTypeIdx] = idx;
|
||||
forEach(currTokType.categoryMatches, (currExtendingType) => {
|
||||
result[currExtendingType] = idx;
|
||||
});
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}, {});
|
||||
if (hasPredicates) {
|
||||
return function (orAlts) {
|
||||
var _a;
|
||||
const nextToken = this.LA(1);
|
||||
const prediction = choiceToAlt[nextToken.tokenTypeIdx];
|
||||
if (orAlts !== undefined && prediction !== undefined) {
|
||||
const gate = (_a = orAlts[prediction]) === null || _a === void 0 ? void 0 : _a.GATE;
|
||||
if (gate !== undefined && gate.call(this) === false) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
return prediction;
|
||||
};
|
||||
}
|
||||
else {
|
||||
return function () {
|
||||
const nextToken = this.LA(1);
|
||||
return choiceToAlt[nextToken.tokenTypeIdx];
|
||||
};
|
||||
}
|
||||
}
|
||||
else if (hasPredicates) {
|
||||
return function (orAlts) {
|
||||
const predicates = new PredicateSet();
|
||||
const length = orAlts === undefined ? 0 : orAlts.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const gate = orAlts === null || orAlts === void 0 ? void 0 : orAlts[i].GATE;
|
||||
predicates.set(i, gate === undefined || gate.call(this));
|
||||
}
|
||||
const result = adaptivePredict.call(this, dfas, decisionIndex, predicates, logging);
|
||||
return typeof result === 'number' ? result : undefined;
|
||||
};
|
||||
}
|
||||
else {
|
||||
return function () {
|
||||
const result = adaptivePredict.call(this, dfas, decisionIndex, EMPTY_PREDICATES, logging);
|
||||
return typeof result === 'number' ? result : undefined;
|
||||
};
|
||||
}
|
||||
}
|
||||
buildLookaheadForOptional(options) {
|
||||
const { prodOccurrence, rule, prodType, dynamicTokensEnabled } = options;
|
||||
const dfas = this.dfas;
|
||||
const logging = this.logging;
|
||||
const key = buildATNKey(rule, prodType, prodOccurrence);
|
||||
const decisionState = this.atn.decisionMap[key];
|
||||
const decisionIndex = decisionState.decision;
|
||||
const alts = map(getLookaheadPaths({
|
||||
maxLookahead: 1,
|
||||
occurrence: prodOccurrence,
|
||||
prodType,
|
||||
rule
|
||||
}), (e) => {
|
||||
return map(e, (g) => g[0]);
|
||||
});
|
||||
if (isLL1Sequence(alts) && alts[0][0] && !dynamicTokensEnabled) {
|
||||
const alt = alts[0];
|
||||
const singleTokensTypes = flatten(alt);
|
||||
if (singleTokensTypes.length === 1 &&
|
||||
isEmpty(singleTokensTypes[0].categoryMatches)) {
|
||||
const expectedTokenType = singleTokensTypes[0];
|
||||
const expectedTokenUniqueKey = expectedTokenType.tokenTypeIdx;
|
||||
return function () {
|
||||
return this.LA(1).tokenTypeIdx === expectedTokenUniqueKey;
|
||||
};
|
||||
}
|
||||
else {
|
||||
const choiceToAlt = reduce(singleTokensTypes, (result, currTokType) => {
|
||||
if (currTokType !== undefined) {
|
||||
result[currTokType.tokenTypeIdx] = true;
|
||||
forEach(currTokType.categoryMatches, (currExtendingType) => {
|
||||
result[currExtendingType] = true;
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}, {});
|
||||
return function () {
|
||||
const nextToken = this.LA(1);
|
||||
return choiceToAlt[nextToken.tokenTypeIdx] === true;
|
||||
};
|
||||
}
|
||||
}
|
||||
return function () {
|
||||
const result = adaptivePredict.call(this, dfas, decisionIndex, EMPTY_PREDICATES, logging);
|
||||
return typeof result === "object" ? false : result === 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
function isLL1Sequence(sequences, allowEmpty = true) {
|
||||
const fullSet = new Set();
|
||||
for (const alt of sequences) {
|
||||
const altSet = new Set();
|
||||
for (const tokType of alt) {
|
||||
if (tokType === undefined) {
|
||||
if (allowEmpty) {
|
||||
// Epsilon production encountered
|
||||
break;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const indices = [tokType.tokenTypeIdx].concat(tokType.categoryMatches);
|
||||
for (const index of indices) {
|
||||
if (fullSet.has(index)) {
|
||||
if (!altSet.has(index)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fullSet.add(index);
|
||||
altSet.add(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function initATNSimulator(atn) {
|
||||
const decisionLength = atn.decisionStates.length;
|
||||
const decisionToDFA = Array(decisionLength);
|
||||
for (let i = 0; i < decisionLength; i++) {
|
||||
decisionToDFA[i] = createDFACache(atn.decisionStates[i], i);
|
||||
}
|
||||
return decisionToDFA;
|
||||
}
|
||||
function adaptivePredict(dfaCaches, decision, predicateSet, logging) {
|
||||
const dfa = dfaCaches[decision](predicateSet);
|
||||
let start = dfa.start;
|
||||
if (start === undefined) {
|
||||
const closure = computeStartState(dfa.atnStartState);
|
||||
start = addDFAState(dfa, newDFAState(closure));
|
||||
dfa.start = start;
|
||||
}
|
||||
const alt = performLookahead.apply(this, [dfa, start, predicateSet, logging]);
|
||||
return alt;
|
||||
}
|
||||
function performLookahead(dfa, s0, predicateSet, logging) {
|
||||
let previousD = s0;
|
||||
let i = 1;
|
||||
const path = [];
|
||||
let t = this.LA(i++);
|
||||
while (true) {
|
||||
let d = getExistingTargetState(previousD, t);
|
||||
if (d === undefined) {
|
||||
d = computeLookaheadTarget.apply(this, [dfa, previousD, t, i, predicateSet, logging]);
|
||||
}
|
||||
if (d === DFA_ERROR) {
|
||||
return buildAdaptivePredictError(path, previousD, t);
|
||||
}
|
||||
if (d.isAcceptState === true) {
|
||||
return d.prediction;
|
||||
}
|
||||
previousD = d;
|
||||
path.push(t);
|
||||
t = this.LA(i++);
|
||||
}
|
||||
}
|
||||
function computeLookaheadTarget(dfa, previousD, token, lookahead, predicateSet, logging) {
|
||||
const reach = computeReachSet(previousD.configs, token, predicateSet);
|
||||
if (reach.size === 0) {
|
||||
addDFAEdge(dfa, previousD, token, DFA_ERROR);
|
||||
return DFA_ERROR;
|
||||
}
|
||||
let newState = newDFAState(reach);
|
||||
const predictedAlt = getUniqueAlt(reach, predicateSet);
|
||||
if (predictedAlt !== undefined) {
|
||||
newState.isAcceptState = true;
|
||||
newState.prediction = predictedAlt;
|
||||
newState.configs.uniqueAlt = predictedAlt;
|
||||
}
|
||||
else if (hasConflictTerminatingPrediction(reach)) {
|
||||
const prediction = min(reach.alts);
|
||||
newState.isAcceptState = true;
|
||||
newState.prediction = prediction;
|
||||
newState.configs.uniqueAlt = prediction;
|
||||
reportLookaheadAmbiguity.apply(this, [dfa, lookahead, reach.alts, logging]);
|
||||
}
|
||||
newState = addDFAEdge(dfa, previousD, token, newState);
|
||||
return newState;
|
||||
}
|
||||
function reportLookaheadAmbiguity(dfa, lookahead, ambiguityIndices, logging) {
|
||||
const prefixPath = [];
|
||||
for (let i = 1; i <= lookahead; i++) {
|
||||
prefixPath.push(this.LA(i).tokenType);
|
||||
}
|
||||
const atnState = dfa.atnStartState;
|
||||
const topLevelRule = atnState.rule;
|
||||
const production = atnState.production;
|
||||
const message = buildAmbiguityError({
|
||||
topLevelRule,
|
||||
ambiguityIndices,
|
||||
production,
|
||||
prefixPath
|
||||
});
|
||||
logging(message);
|
||||
}
|
||||
function buildAmbiguityError(options) {
|
||||
const pathMsg = map(options.prefixPath, (currtok) => tokenLabel(currtok)).join(", ");
|
||||
const occurrence = options.production.idx === 0 ? "" : options.production.idx;
|
||||
let currMessage = `Ambiguous Alternatives Detected: <${options.ambiguityIndices.join(", ")}> in <${getProductionDslName(options.production)}${occurrence}>` +
|
||||
` inside <${options.topLevelRule.name}> Rule,\n` +
|
||||
`<${pathMsg}> may appears as a prefix path in all these alternatives.\n`;
|
||||
currMessage =
|
||||
currMessage +
|
||||
`See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#AMBIGUOUS_ALTERNATIVES\n` +
|
||||
`For Further details.`;
|
||||
return currMessage;
|
||||
}
|
||||
function getProductionDslName(prod) {
|
||||
if (prod instanceof NonTerminal) {
|
||||
return "SUBRULE";
|
||||
}
|
||||
else if (prod instanceof Option) {
|
||||
return "OPTION";
|
||||
}
|
||||
else if (prod instanceof Alternation) {
|
||||
return "OR";
|
||||
}
|
||||
else if (prod instanceof RepetitionMandatory) {
|
||||
return "AT_LEAST_ONE";
|
||||
}
|
||||
else if (prod instanceof RepetitionMandatoryWithSeparator) {
|
||||
return "AT_LEAST_ONE_SEP";
|
||||
}
|
||||
else if (prod instanceof RepetitionWithSeparator) {
|
||||
return "MANY_SEP";
|
||||
}
|
||||
else if (prod instanceof Repetition) {
|
||||
return "MANY";
|
||||
}
|
||||
else if (prod instanceof Terminal) {
|
||||
return "CONSUME";
|
||||
}
|
||||
else {
|
||||
throw Error("non exhaustive match");
|
||||
}
|
||||
}
|
||||
function buildAdaptivePredictError(path, previous, current) {
|
||||
const nextTransitions = flatMap(previous.configs.elements, (e) => e.state.transitions);
|
||||
const nextTokenTypes = uniqBy(nextTransitions
|
||||
.filter((e) => e instanceof AtomTransition)
|
||||
.map((e) => e.tokenType), (e) => e.tokenTypeIdx);
|
||||
return {
|
||||
actualToken: current,
|
||||
possibleTokenTypes: nextTokenTypes,
|
||||
tokenPath: path
|
||||
};
|
||||
}
|
||||
function getExistingTargetState(state, token) {
|
||||
return state.edges[token.tokenTypeIdx];
|
||||
}
|
||||
function computeReachSet(configs, token, predicateSet) {
|
||||
const intermediate = new ATNConfigSet();
|
||||
const skippedStopStates = [];
|
||||
for (const c of configs.elements) {
|
||||
if (predicateSet.is(c.alt) === false) {
|
||||
continue;
|
||||
}
|
||||
if (c.state.type === ATN_RULE_STOP) {
|
||||
skippedStopStates.push(c);
|
||||
continue;
|
||||
}
|
||||
const transitionLength = c.state.transitions.length;
|
||||
for (let i = 0; i < transitionLength; i++) {
|
||||
const transition = c.state.transitions[i];
|
||||
const target = getReachableTarget(transition, token);
|
||||
if (target !== undefined) {
|
||||
intermediate.add({
|
||||
state: target,
|
||||
alt: c.alt,
|
||||
stack: c.stack
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
let reach;
|
||||
if (skippedStopStates.length === 0 && intermediate.size === 1) {
|
||||
reach = intermediate;
|
||||
}
|
||||
if (reach === undefined) {
|
||||
reach = new ATNConfigSet();
|
||||
for (const c of intermediate.elements) {
|
||||
closure(c, reach);
|
||||
}
|
||||
}
|
||||
if (skippedStopStates.length > 0 && !hasConfigInRuleStopState(reach)) {
|
||||
for (const c of skippedStopStates) {
|
||||
reach.add(c);
|
||||
}
|
||||
}
|
||||
return reach;
|
||||
}
|
||||
function getReachableTarget(transition, token) {
|
||||
if (transition instanceof AtomTransition &&
|
||||
tokenMatcher(token, transition.tokenType)) {
|
||||
return transition.target;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
function getUniqueAlt(configs, predicateSet) {
|
||||
let alt;
|
||||
for (const c of configs.elements) {
|
||||
if (predicateSet.is(c.alt) === true) {
|
||||
if (alt === undefined) {
|
||||
alt = c.alt;
|
||||
}
|
||||
else if (alt !== c.alt) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
return alt;
|
||||
}
|
||||
function newDFAState(closure) {
|
||||
return {
|
||||
configs: closure,
|
||||
edges: {},
|
||||
isAcceptState: false,
|
||||
prediction: -1
|
||||
};
|
||||
}
|
||||
function addDFAEdge(dfa, from, token, to) {
|
||||
to = addDFAState(dfa, to);
|
||||
from.edges[token.tokenTypeIdx] = to;
|
||||
return to;
|
||||
}
|
||||
function addDFAState(dfa, state) {
|
||||
if (state === DFA_ERROR) {
|
||||
return state;
|
||||
}
|
||||
// Repetitions have the same config set
|
||||
// Therefore, storing the key of the config in a map allows us to create a loop in our DFA
|
||||
const mapKey = state.configs.key;
|
||||
const existing = dfa.states[mapKey];
|
||||
if (existing !== undefined) {
|
||||
return existing;
|
||||
}
|
||||
state.configs.finalize();
|
||||
dfa.states[mapKey] = state;
|
||||
return state;
|
||||
}
|
||||
function computeStartState(atnState) {
|
||||
const configs = new ATNConfigSet();
|
||||
const numberOfTransitions = atnState.transitions.length;
|
||||
for (let i = 0; i < numberOfTransitions; i++) {
|
||||
const target = atnState.transitions[i].target;
|
||||
const config = {
|
||||
state: target,
|
||||
alt: i,
|
||||
stack: []
|
||||
};
|
||||
closure(config, configs);
|
||||
}
|
||||
return configs;
|
||||
}
|
||||
function closure(config, configs) {
|
||||
const p = config.state;
|
||||
if (p.type === ATN_RULE_STOP) {
|
||||
if (config.stack.length > 0) {
|
||||
const atnStack = [...config.stack];
|
||||
const followState = atnStack.pop();
|
||||
const followConfig = {
|
||||
state: followState,
|
||||
alt: config.alt,
|
||||
stack: atnStack
|
||||
};
|
||||
closure(followConfig, configs);
|
||||
}
|
||||
else {
|
||||
// Dipping into outer context, simply add the config
|
||||
// This will stop computation once every config is at the rule stop state
|
||||
configs.add(config);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!p.epsilonOnlyTransitions) {
|
||||
configs.add(config);
|
||||
}
|
||||
const transitionLength = p.transitions.length;
|
||||
for (let i = 0; i < transitionLength; i++) {
|
||||
const transition = p.transitions[i];
|
||||
const c = getEpsilonTarget(config, transition);
|
||||
if (c !== undefined) {
|
||||
closure(c, configs);
|
||||
}
|
||||
}
|
||||
}
|
||||
function getEpsilonTarget(config, transition) {
|
||||
if (transition instanceof EpsilonTransition) {
|
||||
return {
|
||||
state: transition.target,
|
||||
alt: config.alt,
|
||||
stack: config.stack
|
||||
};
|
||||
}
|
||||
else if (transition instanceof RuleTransition) {
|
||||
const stack = [...config.stack, transition.followState];
|
||||
return {
|
||||
state: transition.target,
|
||||
alt: config.alt,
|
||||
stack
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
function hasConfigInRuleStopState(configs) {
|
||||
for (const c of configs.elements) {
|
||||
if (c.state.type === ATN_RULE_STOP) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function allConfigsInRuleStopStates(configs) {
|
||||
for (const c of configs.elements) {
|
||||
if (c.state.type !== ATN_RULE_STOP) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function hasConflictTerminatingPrediction(configs) {
|
||||
if (allConfigsInRuleStopStates(configs)) {
|
||||
return true;
|
||||
}
|
||||
const altSets = getConflictingAltSets(configs.elements);
|
||||
const heuristic = hasConflictingAltSet(altSets) && !hasStateAssociatedWithOneAlt(altSets);
|
||||
return heuristic;
|
||||
}
|
||||
function getConflictingAltSets(configs) {
|
||||
const configToAlts = new Map();
|
||||
for (const c of configs) {
|
||||
const key = getATNConfigKey(c, false);
|
||||
let alts = configToAlts.get(key);
|
||||
if (alts === undefined) {
|
||||
alts = {};
|
||||
configToAlts.set(key, alts);
|
||||
}
|
||||
alts[c.alt] = true;
|
||||
}
|
||||
return configToAlts;
|
||||
}
|
||||
function hasConflictingAltSet(altSets) {
|
||||
for (const value of Array.from(altSets.values())) {
|
||||
if (Object.keys(value).length > 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function hasStateAssociatedWithOneAlt(altSets) {
|
||||
for (const value of Array.from(altSets.values())) {
|
||||
if (Object.keys(value).length === 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//# sourceMappingURL=all-star-lookahead.js.map
|
||||
1
node_modules/chevrotain-allstar/lib/all-star-lookahead.js.map
generated
vendored
Normal file
1
node_modules/chevrotain-allstar/lib/all-star-lookahead.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
105
node_modules/chevrotain-allstar/lib/atn.d.ts
generated
vendored
Normal file
105
node_modules/chevrotain-allstar/lib/atn.d.ts
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2022 TypeFox GmbH
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License, which is available in the project root.
|
||||
******************************************************************************/
|
||||
import { IProductionWithOccurrence, TokenType, Rule, LookaheadProductionType } from "chevrotain";
|
||||
export declare function buildATNKey(rule: Rule, type: LookaheadProductionType, occurrence: number): string;
|
||||
export interface ATN {
|
||||
decisionMap: Record<string, DecisionState>;
|
||||
states: ATNState[];
|
||||
decisionStates: DecisionState[];
|
||||
ruleToStartState: Map<Rule, RuleStartState>;
|
||||
ruleToStopState: Map<Rule, RuleStopState>;
|
||||
}
|
||||
export declare const ATN_INVALID_TYPE = 0;
|
||||
export declare const ATN_BASIC = 1;
|
||||
export declare const ATN_RULE_START = 2;
|
||||
export declare const ATN_PLUS_BLOCK_START = 4;
|
||||
export declare const ATN_STAR_BLOCK_START = 5;
|
||||
export declare const ATN_TOKEN_START = 6;
|
||||
export declare const ATN_RULE_STOP = 7;
|
||||
export declare const ATN_BLOCK_END = 8;
|
||||
export declare const ATN_STAR_LOOP_BACK = 9;
|
||||
export declare const ATN_STAR_LOOP_ENTRY = 10;
|
||||
export declare const ATN_PLUS_LOOP_BACK = 11;
|
||||
export declare const ATN_LOOP_END = 12;
|
||||
export type ATNState = BasicState | BasicBlockStartState | PlusBlockStartState | PlusLoopbackState | StarBlockStartState | StarLoopbackState | StarLoopEntryState | BlockEndState | RuleStartState | RuleStopState | LoopEndState;
|
||||
export interface ATNBaseState {
|
||||
atn: ATN;
|
||||
production: IProductionWithOccurrence;
|
||||
stateNumber: number;
|
||||
rule: Rule;
|
||||
epsilonOnlyTransitions: boolean;
|
||||
transitions: Transition[];
|
||||
nextTokenWithinRule: number[];
|
||||
}
|
||||
export interface BasicState extends ATNBaseState {
|
||||
type: typeof ATN_BASIC;
|
||||
}
|
||||
export interface BlockStartState extends DecisionState {
|
||||
end: BlockEndState;
|
||||
}
|
||||
export interface BasicBlockStartState extends BlockStartState {
|
||||
type: typeof ATN_BASIC;
|
||||
}
|
||||
export interface PlusBlockStartState extends BlockStartState {
|
||||
loopback: PlusLoopbackState;
|
||||
type: typeof ATN_PLUS_BLOCK_START;
|
||||
}
|
||||
export interface PlusLoopbackState extends DecisionState {
|
||||
type: typeof ATN_PLUS_LOOP_BACK;
|
||||
}
|
||||
export interface StarBlockStartState extends BlockStartState {
|
||||
type: typeof ATN_STAR_BLOCK_START;
|
||||
}
|
||||
export interface StarLoopbackState extends ATNBaseState {
|
||||
type: typeof ATN_STAR_LOOP_BACK;
|
||||
}
|
||||
export interface StarLoopEntryState extends DecisionState {
|
||||
loopback: StarLoopbackState;
|
||||
type: typeof ATN_STAR_LOOP_ENTRY;
|
||||
}
|
||||
export interface BlockEndState extends ATNBaseState {
|
||||
start: BlockStartState;
|
||||
type: typeof ATN_BLOCK_END;
|
||||
}
|
||||
export interface DecisionState extends ATNBaseState {
|
||||
decision: number;
|
||||
}
|
||||
export interface LoopEndState extends ATNBaseState {
|
||||
loopback: ATNState;
|
||||
type: typeof ATN_LOOP_END;
|
||||
}
|
||||
export interface RuleStartState extends ATNBaseState {
|
||||
stop: RuleStopState;
|
||||
type: typeof ATN_RULE_START;
|
||||
}
|
||||
export interface RuleStopState extends ATNBaseState {
|
||||
type: typeof ATN_RULE_STOP;
|
||||
}
|
||||
export interface Transition {
|
||||
target: ATNState;
|
||||
isEpsilon(): boolean;
|
||||
}
|
||||
export declare abstract class AbstractTransition implements Transition {
|
||||
target: ATNState;
|
||||
constructor(target: ATNState);
|
||||
isEpsilon(): boolean;
|
||||
}
|
||||
export declare class AtomTransition extends AbstractTransition {
|
||||
tokenType: TokenType;
|
||||
constructor(target: ATNState, tokenType: TokenType);
|
||||
}
|
||||
export declare class EpsilonTransition extends AbstractTransition {
|
||||
constructor(target: ATNState);
|
||||
isEpsilon(): boolean;
|
||||
}
|
||||
export declare class RuleTransition extends AbstractTransition {
|
||||
rule: Rule;
|
||||
followState: ATNState;
|
||||
constructor(ruleStart: RuleStartState, rule: Rule, followState: ATNState);
|
||||
isEpsilon(): boolean;
|
||||
}
|
||||
export declare function createATN(rules: Rule[]): ATN;
|
||||
//# sourceMappingURL=atn.d.ts.map
|
||||
1
node_modules/chevrotain-allstar/lib/atn.d.ts.map
generated
vendored
Normal file
1
node_modules/chevrotain-allstar/lib/atn.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"atn.d.ts","sourceRoot":"","sources":["../src/atn.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAIhF,OAAO,EAEH,yBAAyB,EACzB,SAAS,EAGT,IAAI,EAQJ,uBAAuB,EAC1B,MAAM,YAAY,CAAA;AAEnB,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,uBAAuB,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAEjG;AAED,MAAM,WAAW,GAAG;IAChB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;IAC1C,MAAM,EAAE,QAAQ,EAAE,CAAA;IAClB,cAAc,EAAE,aAAa,EAAE,CAAA;IAC/B,gBAAgB,EAAE,GAAG,CAAC,IAAI,EAAE,cAAc,CAAC,CAAA;IAC3C,eAAe,EAAE,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;CAC5C;AAED,eAAO,MAAM,gBAAgB,IAAI,CAAA;AACjC,eAAO,MAAM,SAAS,IAAI,CAAA;AAC1B,eAAO,MAAM,cAAc,IAAI,CAAA;AAC/B,eAAO,MAAM,oBAAoB,IAAI,CAAA;AACrC,eAAO,MAAM,oBAAoB,IAAI,CAAA;AAErC,eAAO,MAAM,eAAe,IAAI,CAAA;AAChC,eAAO,MAAM,aAAa,IAAI,CAAA;AAC9B,eAAO,MAAM,aAAa,IAAI,CAAA;AAC9B,eAAO,MAAM,kBAAkB,IAAI,CAAA;AACnC,eAAO,MAAM,mBAAmB,KAAK,CAAA;AACrC,eAAO,MAAM,kBAAkB,KAAK,CAAA;AACpC,eAAO,MAAM,YAAY,KAAK,CAAA;AAE9B,MAAM,MAAM,QAAQ,GACd,UAAU,GACV,oBAAoB,GACpB,mBAAmB,GACnB,iBAAiB,GACjB,mBAAmB,GACnB,iBAAiB,GACjB,kBAAkB,GAClB,aAAa,GACb,cAAc,GACd,aAAa,GACb,YAAY,CAAA;AAElB,MAAM,WAAW,YAAY;IACzB,GAAG,EAAE,GAAG,CAAA;IACR,UAAU,EAAE,yBAAyB,CAAA;IACrC,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,IAAI,CAAA;IACV,sBAAsB,EAAE,OAAO,CAAA;IAC/B,WAAW,EAAE,UAAU,EAAE,CAAA;IACzB,mBAAmB,EAAE,MAAM,EAAE,CAAA;CAChC;AAED,MAAM,WAAW,UAAW,SAAQ,YAAY;IAC5C,IAAI,EAAE,OAAO,SAAS,CAAA;CACzB;AAED,MAAM,WAAW,eAAgB,SAAQ,aAAa;IAClD,GAAG,EAAE,aAAa,CAAA;CACrB;AAED,MAAM,WAAW,oBAAqB,SAAQ,eAAe;IACzD,IAAI,EAAE,OAAO,SAAS,CAAA;CACzB;AAED,MAAM,WAAW,mBAAoB,SAAQ,eAAe;IACxD,QAAQ,EAAE,iBAAiB,CAAA;IAC3B,IAAI,EAAE,OAAO,oBAAoB,CAAA;CACpC;AAED,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACpD,IAAI,EAAE,OAAO,kBAAkB,CAAA;CAClC;AAED,MAAM,WAAW,mBAAoB,SAAQ,eAAe;IACxD,IAAI,EAAE,OAAO,oBAAoB,CAAA;CACpC;AAED,MAAM,WAAW,iBAAkB,SAAQ,YAAY;IACnD,IAAI,EAAE,OAAO,kBAAkB,CAAA;CAClC;AAED,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACrD,QAAQ,EAAE,iBAAiB,CAAA;IAC3B,IAAI,EAAE,OAAO,mBAAmB,CAAA;CACnC;AAED,MAAM,WAAW,aAAc,SAAQ,YAAY;IAC/C,KAAK,EAAE,eAAe,CAAA;IACtB,IAAI,EAAE,OAAO,aAAa,CAAA;CAC7B;AAED,MAAM,WAAW,aAAc,SAAQ,YAAY;IAC/C,QAAQ,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,YAAa,SAAQ,YAAY;IAC9C,QAAQ,EAAE,QAAQ,CAAA;IAClB,IAAI,EAAE,OAAO,YAAY,CAAA;CAC5B;AAED,MAAM,WAAW,cAAe,SAAQ,YAAY;IAChD,IAAI,EAAE,aAAa,CAAA;IACnB,IAAI,EAAE,OAAO,cAAc,CAAA;CAC9B;AAED,MAAM,WAAW,aAAc,SAAQ,YAAY;IAC/C,IAAI,EAAE,OAAO,aAAa,CAAA;CAC7B;AAED,MAAM,WAAW,UAAU;IACvB,MAAM,EAAE,QAAQ,CAAA;IAChB,SAAS,IAAI,OAAO,CAAA;CACvB;AAED,8BAAsB,kBAAmB,YAAW,UAAU;IAC1D,MAAM,EAAE,QAAQ,CAAA;gBAEJ,MAAM,EAAE,QAAQ;IAI5B,SAAS;CAGZ;AAED,qBAAa,cAAe,SAAQ,kBAAkB;IAClD,SAAS,EAAE,SAAS,CAAA;gBAER,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS;CAIrD;AAED,qBAAa,iBAAkB,SAAQ,kBAAkB;gBACzC,MAAM,EAAE,QAAQ;IAI5B,SAAS;CAGZ;AAED,qBAAa,cAAe,SAAQ,kBAAkB;IAClD,IAAI,EAAE,IAAI,CAAA;IACV,WAAW,EAAE,QAAQ,CAAA;gBAET,SAAS,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ;IAMxE,SAAS;CAGZ;AAOD,wBAAgB,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,GAAG,CAmB5C"}
|
||||
404
node_modules/chevrotain-allstar/lib/atn.js
generated
vendored
Normal file
404
node_modules/chevrotain-allstar/lib/atn.js
generated
vendored
Normal file
@@ -0,0 +1,404 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2022 TypeFox GmbH
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License, which is available in the project root.
|
||||
******************************************************************************/
|
||||
import map from "lodash-es/map.js";
|
||||
import filter from "lodash-es/filter.js";
|
||||
import { Alternation, NonTerminal, Option, RepetitionMandatory, Repetition, Terminal, RepetitionWithSeparator, RepetitionMandatoryWithSeparator } from "chevrotain";
|
||||
export function buildATNKey(rule, type, occurrence) {
|
||||
return `${rule.name}_${type}_${occurrence}`;
|
||||
}
|
||||
export const ATN_INVALID_TYPE = 0;
|
||||
export const ATN_BASIC = 1;
|
||||
export const ATN_RULE_START = 2;
|
||||
export const ATN_PLUS_BLOCK_START = 4;
|
||||
export const ATN_STAR_BLOCK_START = 5;
|
||||
// Currently unused as the ATN is not used for lexing
|
||||
export const ATN_TOKEN_START = 6;
|
||||
export const ATN_RULE_STOP = 7;
|
||||
export const ATN_BLOCK_END = 8;
|
||||
export const ATN_STAR_LOOP_BACK = 9;
|
||||
export const ATN_STAR_LOOP_ENTRY = 10;
|
||||
export const ATN_PLUS_LOOP_BACK = 11;
|
||||
export const ATN_LOOP_END = 12;
|
||||
export class AbstractTransition {
|
||||
constructor(target) {
|
||||
this.target = target;
|
||||
}
|
||||
isEpsilon() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
export class AtomTransition extends AbstractTransition {
|
||||
constructor(target, tokenType) {
|
||||
super(target);
|
||||
this.tokenType = tokenType;
|
||||
}
|
||||
}
|
||||
export class EpsilonTransition extends AbstractTransition {
|
||||
constructor(target) {
|
||||
super(target);
|
||||
}
|
||||
isEpsilon() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
export class RuleTransition extends AbstractTransition {
|
||||
constructor(ruleStart, rule, followState) {
|
||||
super(ruleStart);
|
||||
this.rule = rule;
|
||||
this.followState = followState;
|
||||
}
|
||||
isEpsilon() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
export function createATN(rules) {
|
||||
const atn = {
|
||||
decisionMap: {},
|
||||
decisionStates: [],
|
||||
ruleToStartState: new Map(),
|
||||
ruleToStopState: new Map(),
|
||||
states: []
|
||||
};
|
||||
createRuleStartAndStopATNStates(atn, rules);
|
||||
const ruleLength = rules.length;
|
||||
for (let i = 0; i < ruleLength; i++) {
|
||||
const rule = rules[i];
|
||||
const ruleBlock = block(atn, rule, rule);
|
||||
if (ruleBlock === undefined) {
|
||||
continue;
|
||||
}
|
||||
buildRuleHandle(atn, rule, ruleBlock);
|
||||
}
|
||||
return atn;
|
||||
}
|
||||
function createRuleStartAndStopATNStates(atn, rules) {
|
||||
const ruleLength = rules.length;
|
||||
for (let i = 0; i < ruleLength; i++) {
|
||||
const rule = rules[i];
|
||||
const start = newState(atn, rule, undefined, {
|
||||
type: ATN_RULE_START
|
||||
});
|
||||
const stop = newState(atn, rule, undefined, {
|
||||
type: ATN_RULE_STOP
|
||||
});
|
||||
start.stop = stop;
|
||||
atn.ruleToStartState.set(rule, start);
|
||||
atn.ruleToStopState.set(rule, stop);
|
||||
}
|
||||
}
|
||||
function atom(atn, rule, production) {
|
||||
if (production instanceof Terminal) {
|
||||
return tokenRef(atn, rule, production.terminalType, production);
|
||||
}
|
||||
else if (production instanceof NonTerminal) {
|
||||
return ruleRef(atn, rule, production);
|
||||
}
|
||||
else if (production instanceof Alternation) {
|
||||
return alternation(atn, rule, production);
|
||||
}
|
||||
else if (production instanceof Option) {
|
||||
return option(atn, rule, production);
|
||||
}
|
||||
else if (production instanceof Repetition) {
|
||||
return repetition(atn, rule, production);
|
||||
}
|
||||
else if (production instanceof RepetitionWithSeparator) {
|
||||
return repetitionSep(atn, rule, production);
|
||||
}
|
||||
else if (production instanceof RepetitionMandatory) {
|
||||
return repetitionMandatory(atn, rule, production);
|
||||
}
|
||||
else if (production instanceof RepetitionMandatoryWithSeparator) {
|
||||
return repetitionMandatorySep(atn, rule, production);
|
||||
}
|
||||
else {
|
||||
return block(atn, rule, production);
|
||||
}
|
||||
}
|
||||
function repetition(atn, rule, repetition) {
|
||||
const starState = newState(atn, rule, repetition, {
|
||||
type: ATN_STAR_BLOCK_START
|
||||
});
|
||||
defineDecisionState(atn, starState);
|
||||
const handle = makeAlts(atn, rule, starState, repetition, block(atn, rule, repetition));
|
||||
return star(atn, rule, repetition, handle);
|
||||
}
|
||||
function repetitionSep(atn, rule, repetition) {
|
||||
const starState = newState(atn, rule, repetition, {
|
||||
type: ATN_STAR_BLOCK_START
|
||||
});
|
||||
defineDecisionState(atn, starState);
|
||||
const handle = makeAlts(atn, rule, starState, repetition, block(atn, rule, repetition));
|
||||
const sep = tokenRef(atn, rule, repetition.separator, repetition);
|
||||
return star(atn, rule, repetition, handle, sep);
|
||||
}
|
||||
function repetitionMandatory(atn, rule, repetition) {
|
||||
const plusState = newState(atn, rule, repetition, {
|
||||
type: ATN_PLUS_BLOCK_START
|
||||
});
|
||||
defineDecisionState(atn, plusState);
|
||||
const handle = makeAlts(atn, rule, plusState, repetition, block(atn, rule, repetition));
|
||||
return plus(atn, rule, repetition, handle);
|
||||
}
|
||||
function repetitionMandatorySep(atn, rule, repetition) {
|
||||
const plusState = newState(atn, rule, repetition, {
|
||||
type: ATN_PLUS_BLOCK_START
|
||||
});
|
||||
defineDecisionState(atn, plusState);
|
||||
const handle = makeAlts(atn, rule, plusState, repetition, block(atn, rule, repetition));
|
||||
const sep = tokenRef(atn, rule, repetition.separator, repetition);
|
||||
return plus(atn, rule, repetition, handle, sep);
|
||||
}
|
||||
function alternation(atn, rule, alternation) {
|
||||
const start = newState(atn, rule, alternation, {
|
||||
type: ATN_BASIC
|
||||
});
|
||||
defineDecisionState(atn, start);
|
||||
const alts = map(alternation.definition, (e) => atom(atn, rule, e));
|
||||
const handle = makeAlts(atn, rule, start, alternation, ...alts);
|
||||
return handle;
|
||||
}
|
||||
function option(atn, rule, option) {
|
||||
const start = newState(atn, rule, option, {
|
||||
type: ATN_BASIC
|
||||
});
|
||||
defineDecisionState(atn, start);
|
||||
const handle = makeAlts(atn, rule, start, option, block(atn, rule, option));
|
||||
return optional(atn, rule, option, handle);
|
||||
}
|
||||
function block(atn, rule, block) {
|
||||
const handles = filter(map(block.definition, (e) => atom(atn, rule, e)), (e) => e !== undefined);
|
||||
if (handles.length === 1) {
|
||||
return handles[0];
|
||||
}
|
||||
else if (handles.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
else {
|
||||
return makeBlock(atn, handles);
|
||||
}
|
||||
}
|
||||
function plus(atn, rule, plus, handle, sep) {
|
||||
const blkStart = handle.left;
|
||||
const blkEnd = handle.right;
|
||||
const loop = newState(atn, rule, plus, {
|
||||
type: ATN_PLUS_LOOP_BACK
|
||||
});
|
||||
defineDecisionState(atn, loop);
|
||||
const end = newState(atn, rule, plus, {
|
||||
type: ATN_LOOP_END
|
||||
});
|
||||
blkStart.loopback = loop;
|
||||
end.loopback = loop;
|
||||
atn.decisionMap[buildATNKey(rule, sep ? 'RepetitionMandatoryWithSeparator' : 'RepetitionMandatory', plus.idx)] = loop;
|
||||
epsilon(blkEnd, loop); // block can see loop back
|
||||
// Depending on whether we have a separator we put the exit transition at index 1 or 0
|
||||
// This influences the chosen option in the lookahead DFA
|
||||
if (sep === undefined) {
|
||||
epsilon(loop, blkStart); // loop back to start
|
||||
epsilon(loop, end); // exit
|
||||
}
|
||||
else {
|
||||
epsilon(loop, end); // exit
|
||||
// loop back to start with separator
|
||||
epsilon(loop, sep.left);
|
||||
epsilon(sep.right, blkStart);
|
||||
}
|
||||
return {
|
||||
left: blkStart,
|
||||
right: end
|
||||
};
|
||||
}
|
||||
function star(atn, rule, star, handle, sep) {
|
||||
const start = handle.left;
|
||||
const end = handle.right;
|
||||
const entry = newState(atn, rule, star, {
|
||||
type: ATN_STAR_LOOP_ENTRY
|
||||
});
|
||||
defineDecisionState(atn, entry);
|
||||
const loopEnd = newState(atn, rule, star, {
|
||||
type: ATN_LOOP_END
|
||||
});
|
||||
const loop = newState(atn, rule, star, {
|
||||
type: ATN_STAR_LOOP_BACK
|
||||
});
|
||||
entry.loopback = loop;
|
||||
loopEnd.loopback = loop;
|
||||
epsilon(entry, start); // loop enter edge (alt 2)
|
||||
epsilon(entry, loopEnd); // bypass loop edge (alt 1)
|
||||
epsilon(end, loop); // block end hits loop back
|
||||
if (sep !== undefined) {
|
||||
epsilon(loop, loopEnd); // end loop
|
||||
// loop back to start of handle using separator
|
||||
epsilon(loop, sep.left);
|
||||
epsilon(sep.right, start);
|
||||
}
|
||||
else {
|
||||
epsilon(loop, entry); // loop back to entry/exit decision
|
||||
}
|
||||
atn.decisionMap[buildATNKey(rule, sep ? 'RepetitionWithSeparator' : 'Repetition', star.idx)] = entry;
|
||||
return {
|
||||
left: entry,
|
||||
right: loopEnd
|
||||
};
|
||||
}
|
||||
function optional(atn, rule, optional, handle) {
|
||||
const start = handle.left;
|
||||
const end = handle.right;
|
||||
epsilon(start, end);
|
||||
atn.decisionMap[buildATNKey(rule, 'Option', optional.idx)] = start;
|
||||
return handle;
|
||||
}
|
||||
function defineDecisionState(atn, state) {
|
||||
atn.decisionStates.push(state);
|
||||
state.decision = atn.decisionStates.length - 1;
|
||||
return state.decision;
|
||||
}
|
||||
function makeAlts(atn, rule, start, production, ...alts) {
|
||||
const end = newState(atn, rule, production, {
|
||||
type: ATN_BLOCK_END,
|
||||
start
|
||||
});
|
||||
start.end = end;
|
||||
for (const alt of alts) {
|
||||
if (alt !== undefined) {
|
||||
// hook alts up to decision block
|
||||
epsilon(start, alt.left);
|
||||
epsilon(alt.right, end);
|
||||
}
|
||||
else {
|
||||
epsilon(start, end);
|
||||
}
|
||||
}
|
||||
const handle = {
|
||||
left: start,
|
||||
right: end
|
||||
};
|
||||
atn.decisionMap[buildATNKey(rule, getProdType(production), production.idx)] = start;
|
||||
return handle;
|
||||
}
|
||||
function getProdType(production) {
|
||||
if (production instanceof Alternation) {
|
||||
return 'Alternation';
|
||||
}
|
||||
else if (production instanceof Option) {
|
||||
return 'Option';
|
||||
}
|
||||
else if (production instanceof Repetition) {
|
||||
return 'Repetition';
|
||||
}
|
||||
else if (production instanceof RepetitionWithSeparator) {
|
||||
return 'RepetitionWithSeparator';
|
||||
}
|
||||
else if (production instanceof RepetitionMandatory) {
|
||||
return 'RepetitionMandatory';
|
||||
}
|
||||
else if (production instanceof RepetitionMandatoryWithSeparator) {
|
||||
return 'RepetitionMandatoryWithSeparator';
|
||||
}
|
||||
else {
|
||||
throw new Error('Invalid production type encountered');
|
||||
}
|
||||
}
|
||||
function makeBlock(atn, alts) {
|
||||
const altsLength = alts.length;
|
||||
for (let i = 0; i < altsLength - 1; i++) {
|
||||
const handle = alts[i];
|
||||
let transition;
|
||||
if (handle.left.transitions.length === 1) {
|
||||
transition = handle.left.transitions[0];
|
||||
}
|
||||
const isRuleTransition = transition instanceof RuleTransition;
|
||||
const ruleTransition = transition;
|
||||
const next = alts[i + 1].left;
|
||||
if (handle.left.type === ATN_BASIC &&
|
||||
handle.right.type === ATN_BASIC &&
|
||||
transition !== undefined &&
|
||||
((isRuleTransition && ruleTransition.followState === handle.right) ||
|
||||
transition.target === handle.right)) {
|
||||
// we can avoid epsilon edge to next element
|
||||
if (isRuleTransition) {
|
||||
ruleTransition.followState = next;
|
||||
}
|
||||
else {
|
||||
transition.target = next;
|
||||
}
|
||||
removeState(atn, handle.right); // we skipped over this state
|
||||
}
|
||||
else {
|
||||
// need epsilon if previous block's right end node is complex
|
||||
epsilon(handle.right, next);
|
||||
}
|
||||
}
|
||||
const first = alts[0];
|
||||
const last = alts[altsLength - 1];
|
||||
return {
|
||||
left: first.left,
|
||||
right: last.right
|
||||
};
|
||||
}
|
||||
function tokenRef(atn, rule, tokenType, production) {
|
||||
const left = newState(atn, rule, production, {
|
||||
type: ATN_BASIC
|
||||
});
|
||||
const right = newState(atn, rule, production, {
|
||||
type: ATN_BASIC
|
||||
});
|
||||
addTransition(left, new AtomTransition(right, tokenType));
|
||||
return {
|
||||
left,
|
||||
right
|
||||
};
|
||||
}
|
||||
function ruleRef(atn, currentRule, nonTerminal) {
|
||||
const rule = nonTerminal.referencedRule;
|
||||
const start = atn.ruleToStartState.get(rule);
|
||||
const left = newState(atn, currentRule, nonTerminal, {
|
||||
type: ATN_BASIC
|
||||
});
|
||||
const right = newState(atn, currentRule, nonTerminal, {
|
||||
type: ATN_BASIC
|
||||
});
|
||||
const call = new RuleTransition(start, rule, right);
|
||||
addTransition(left, call);
|
||||
return {
|
||||
left,
|
||||
right
|
||||
};
|
||||
}
|
||||
function buildRuleHandle(atn, rule, block) {
|
||||
const start = atn.ruleToStartState.get(rule);
|
||||
epsilon(start, block.left);
|
||||
const stop = atn.ruleToStopState.get(rule);
|
||||
epsilon(block.right, stop);
|
||||
const handle = {
|
||||
left: start,
|
||||
right: stop
|
||||
};
|
||||
return handle;
|
||||
}
|
||||
function epsilon(a, b) {
|
||||
const transition = new EpsilonTransition(b);
|
||||
addTransition(a, transition);
|
||||
}
|
||||
function newState(atn, rule, production, partial) {
|
||||
const t = Object.assign({ atn,
|
||||
production, epsilonOnlyTransitions: false, rule, transitions: [], nextTokenWithinRule: [], stateNumber: atn.states.length }, partial);
|
||||
atn.states.push(t);
|
||||
return t;
|
||||
}
|
||||
function addTransition(state, transition) {
|
||||
// A single ATN state can only contain epsilon transitions or non-epsilon transitions
|
||||
// Because they are never mixed, only setting the property for the first transition is fine
|
||||
if (state.transitions.length === 0) {
|
||||
state.epsilonOnlyTransitions = transition.isEpsilon();
|
||||
}
|
||||
state.transitions.push(transition);
|
||||
}
|
||||
function removeState(atn, state) {
|
||||
atn.states.splice(atn.states.indexOf(state), 1);
|
||||
}
|
||||
//# sourceMappingURL=atn.js.map
|
||||
1
node_modules/chevrotain-allstar/lib/atn.js.map
generated
vendored
Normal file
1
node_modules/chevrotain-allstar/lib/atn.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
37
node_modules/chevrotain-allstar/lib/dfa.d.ts
generated
vendored
Normal file
37
node_modules/chevrotain-allstar/lib/dfa.d.ts
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2022 TypeFox GmbH
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License, which is available in the project root.
|
||||
******************************************************************************/
|
||||
import { ATNState, DecisionState } from "./atn.js";
|
||||
export interface DFA {
|
||||
start?: DFAState;
|
||||
states: Record<string, DFAState>;
|
||||
decision: number;
|
||||
atnStartState: DecisionState;
|
||||
}
|
||||
export interface DFAState {
|
||||
configs: ATNConfigSet;
|
||||
edges: Record<number, DFAState>;
|
||||
isAcceptState: boolean;
|
||||
prediction: number;
|
||||
}
|
||||
export declare const DFA_ERROR: DFAState;
|
||||
export interface ATNConfig {
|
||||
state: ATNState;
|
||||
alt: number;
|
||||
stack: ATNState[];
|
||||
}
|
||||
export declare class ATNConfigSet {
|
||||
private map;
|
||||
private configs;
|
||||
uniqueAlt: number | undefined;
|
||||
get size(): number;
|
||||
finalize(): void;
|
||||
add(config: ATNConfig): void;
|
||||
get elements(): readonly ATNConfig[];
|
||||
get alts(): number[];
|
||||
get key(): string;
|
||||
}
|
||||
export declare function getATNConfigKey(config: ATNConfig, alt?: boolean): string;
|
||||
//# sourceMappingURL=dfa.d.ts.map
|
||||
1
node_modules/chevrotain-allstar/lib/dfa.d.ts.map
generated
vendored
Normal file
1
node_modules/chevrotain-allstar/lib/dfa.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"dfa.d.ts","sourceRoot":"","sources":["../src/dfa.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAGhF,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAElD,MAAM,WAAW,GAAG;IAClB,KAAK,CAAC,EAAE,QAAQ,CAAA;IAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;IAChC,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,aAAa,CAAA;CAC7B;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,YAAY,CAAA;IACrB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;IAC/B,aAAa,EAAE,OAAO,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,eAAO,MAAM,SAAS,UAAiB,CAAA;AAEvC,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,QAAQ,CAAA;IACf,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,QAAQ,EAAE,CAAA;CAClB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,GAAG,CAA6B;IACxC,OAAO,CAAC,OAAO,CAAkB;IAEjC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IAE7B,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,QAAQ,IAAI,IAAI;IAKhB,GAAG,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IAU5B,IAAI,QAAQ,IAAI,SAAS,SAAS,EAAE,CAEnC;IAED,IAAI,IAAI,IAAI,MAAM,EAAE,CAEnB;IAED,IAAI,GAAG,IAAI,MAAM,CAMhB;CACF;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,UAAO,UAI5D"}
|
||||
46
node_modules/chevrotain-allstar/lib/dfa.js
generated
vendored
Normal file
46
node_modules/chevrotain-allstar/lib/dfa.js
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2022 TypeFox GmbH
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License, which is available in the project root.
|
||||
******************************************************************************/
|
||||
import map from "lodash-es/map.js";
|
||||
export const DFA_ERROR = {};
|
||||
export class ATNConfigSet {
|
||||
constructor() {
|
||||
this.map = {};
|
||||
this.configs = [];
|
||||
}
|
||||
get size() {
|
||||
return this.configs.length;
|
||||
}
|
||||
finalize() {
|
||||
// Empties the map to free up memory
|
||||
this.map = {};
|
||||
}
|
||||
add(config) {
|
||||
const key = getATNConfigKey(config);
|
||||
// Only add configs which don't exist in our map already
|
||||
// While this does not influence the actual algorithm, adding them anyway would massively increase memory consumption
|
||||
if (!(key in this.map)) {
|
||||
this.map[key] = this.configs.length;
|
||||
this.configs.push(config);
|
||||
}
|
||||
}
|
||||
get elements() {
|
||||
return this.configs;
|
||||
}
|
||||
get alts() {
|
||||
return map(this.configs, (e) => e.alt);
|
||||
}
|
||||
get key() {
|
||||
let value = "";
|
||||
for (const k in this.map) {
|
||||
value += k + ":";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
export function getATNConfigKey(config, alt = true) {
|
||||
return `${alt ? `a${config.alt}` : ""}s${config.state.stateNumber}:${config.stack.map((e) => e.stateNumber.toString()).join("_")}`;
|
||||
}
|
||||
//# sourceMappingURL=dfa.js.map
|
||||
1
node_modules/chevrotain-allstar/lib/dfa.js.map
generated
vendored
Normal file
1
node_modules/chevrotain-allstar/lib/dfa.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"dfa.js","sourceRoot":"","sources":["../src/dfa.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,GAAG,MAAM,kBAAkB,CAAA;AAiBlC,MAAM,CAAC,MAAM,SAAS,GAAG,EAAc,CAAA;AAQvC,MAAM,OAAO,YAAY;IAAzB;QACU,QAAG,GAA2B,EAAE,CAAA;QAChC,YAAO,GAAgB,EAAE,CAAA;IAsCnC,CAAC;IAlCC,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAA;IAC5B,CAAC;IAED,QAAQ;QACN,oCAAoC;QACpC,IAAI,CAAC,GAAG,GAAG,EAAE,CAAA;IACf,CAAC;IAED,GAAG,CAAC,MAAiB;QACnB,MAAM,GAAG,GAAG,eAAe,CAAC,MAAM,CAAC,CAAA;QACnC,wDAAwD;QACxD,qHAAqH;QACrH,IAAI,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE;YACtB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAA;YACnC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;SAC1B;IACH,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,OAAO,CAAA;IACrB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;IACxC,CAAC;IAED,IAAI,GAAG;QACL,IAAI,KAAK,GAAG,EAAE,CAAA;QACd,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE;YACxB,KAAK,IAAI,CAAC,GAAG,GAAG,CAAA;SACjB;QACD,OAAO,KAAK,CAAA;IACd,CAAC;CACF;AAED,MAAM,UAAU,eAAe,CAAC,MAAiB,EAAE,GAAG,GAAG,IAAI;IAC3D,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,IACnC,MAAM,CAAC,KAAK,CAAC,WACf,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAA;AACnE,CAAC"}
|
||||
7
node_modules/chevrotain-allstar/lib/index.d.ts
generated
vendored
Normal file
7
node_modules/chevrotain-allstar/lib/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2022 TypeFox GmbH
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License, which is available in the project root.
|
||||
******************************************************************************/
|
||||
export { AmbiguityReport, LLStarLookaheadOptions, LLStarLookaheadStrategy } from './all-star-lookahead.js';
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
1
node_modules/chevrotain-allstar/lib/index.d.ts.map
generated
vendored
Normal file
1
node_modules/chevrotain-allstar/lib/index.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,EACH,eAAe,EACf,sBAAsB,EACtB,uBAAuB,EAC1B,MAAM,yBAAyB,CAAC"}
|
||||
7
node_modules/chevrotain-allstar/lib/index.js
generated
vendored
Normal file
7
node_modules/chevrotain-allstar/lib/index.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2022 TypeFox GmbH
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License, which is available in the project root.
|
||||
******************************************************************************/
|
||||
export { LLStarLookaheadStrategy } from './all-star-lookahead.js';
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
node_modules/chevrotain-allstar/lib/index.js.map
generated
vendored
Normal file
1
node_modules/chevrotain-allstar/lib/index.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,EAGH,uBAAuB,EAC1B,MAAM,yBAAyB,CAAC"}
|
||||
52
node_modules/chevrotain-allstar/package.json
generated
vendored
Normal file
52
node_modules/chevrotain-allstar/package.json
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"name": "chevrotain-allstar",
|
||||
"version": "0.3.1",
|
||||
"description": "LL(*) lookahead strategy for the Chevrotain parser library",
|
||||
"keywords": [
|
||||
"parser",
|
||||
"lookahead",
|
||||
"chevrotain",
|
||||
"langium"
|
||||
],
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"types": "./lib/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./lib/index.d.ts",
|
||||
"default": "./lib/index.js"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "vitest",
|
||||
"build": "tsc",
|
||||
"watch": "tsc -w",
|
||||
"clean": "shx rm -rf lib tsconfig.tsbuildinfo"
|
||||
},
|
||||
"files": [
|
||||
"src",
|
||||
"lib"
|
||||
],
|
||||
"dependencies": {
|
||||
"lodash-es": "^4.17.21"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"chevrotain": "^11.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.2.1",
|
||||
"@types/lodash-es": "^4.17.8",
|
||||
"shx": "^0.3.4",
|
||||
"typescript": "^5.1.6",
|
||||
"vitest": "^0.33.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/langium/chevrotain-allstar"
|
||||
},
|
||||
"bugs": "https://github.com/langium/chevrotain-allstar/issues",
|
||||
"author": {
|
||||
"name": "TypeFox",
|
||||
"url": "https://www.typefox.io"
|
||||
}
|
||||
}
|
||||
763
node_modules/chevrotain-allstar/src/all-star-lookahead.ts
generated
vendored
Normal file
763
node_modules/chevrotain-allstar/src/all-star-lookahead.ts
generated
vendored
Normal file
@@ -0,0 +1,763 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2022 TypeFox GmbH
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License, which is available in the project root.
|
||||
******************************************************************************/
|
||||
|
||||
import {
|
||||
IToken,
|
||||
TokenType,
|
||||
tokenMatcher,
|
||||
tokenLabel,
|
||||
Rule,
|
||||
IProductionWithOccurrence,
|
||||
NonTerminal,
|
||||
Alternation,
|
||||
Option,
|
||||
RepetitionMandatory,
|
||||
RepetitionMandatoryWithSeparator,
|
||||
RepetitionWithSeparator,
|
||||
Repetition,
|
||||
Terminal,
|
||||
BaseParser,
|
||||
LLkLookaheadStrategy,
|
||||
ILookaheadValidationError,
|
||||
IOrAlt,
|
||||
getLookaheadPaths,
|
||||
OptionalProductionType
|
||||
} from "chevrotain";
|
||||
import {
|
||||
ATN,
|
||||
ATNState,
|
||||
ATN_RULE_STOP,
|
||||
AtomTransition,
|
||||
buildATNKey,
|
||||
createATN,
|
||||
DecisionState,
|
||||
EpsilonTransition,
|
||||
RuleTransition,
|
||||
Transition
|
||||
} from "./atn.js";
|
||||
import {
|
||||
ATNConfig,
|
||||
ATNConfigSet,
|
||||
DFA,
|
||||
DFAState,
|
||||
DFA_ERROR,
|
||||
getATNConfigKey
|
||||
} from "./dfa.js";
|
||||
import min from "lodash-es/min.js";
|
||||
import flatMap from "lodash-es/flatMap.js";
|
||||
import uniqBy from "lodash-es/uniqBy.js";
|
||||
import map from "lodash-es/map.js";
|
||||
import flatten from "lodash-es/flatten.js";
|
||||
import forEach from "lodash-es/forEach.js";
|
||||
import isEmpty from "lodash-es/isEmpty.js";
|
||||
import reduce from "lodash-es/reduce.js";
|
||||
|
||||
type DFACache = (predicateSet: PredicateSet) => DFA
|
||||
|
||||
export type AmbiguityReport = (message: string) => void;
|
||||
|
||||
function createDFACache(startState: DecisionState, decision: number): DFACache {
|
||||
const map: Record<string, DFA | undefined> = {}
|
||||
return (predicateSet) => {
|
||||
const key = predicateSet.toString()
|
||||
let existing = map[key]
|
||||
if (existing !== undefined) {
|
||||
return existing
|
||||
} else {
|
||||
existing = {
|
||||
atnStartState: startState,
|
||||
decision,
|
||||
states: {}
|
||||
}
|
||||
map[key] = existing
|
||||
return existing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PredicateSet {
|
||||
private predicates: boolean[] = []
|
||||
|
||||
is(index: number): boolean {
|
||||
return index >= this.predicates.length || this.predicates[index]
|
||||
}
|
||||
|
||||
set(index: number, value: boolean) {
|
||||
this.predicates[index] = value
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
let value = ""
|
||||
const size = this.predicates.length
|
||||
for (let i = 0; i < size; i++) {
|
||||
value += this.predicates[i] === true ? "1" : "0"
|
||||
}
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
interface AdaptivePredictError {
|
||||
tokenPath: IToken[]
|
||||
possibleTokenTypes: TokenType[]
|
||||
actualToken: IToken
|
||||
}
|
||||
|
||||
const EMPTY_PREDICATES = new PredicateSet()
|
||||
|
||||
export interface LLStarLookaheadOptions {
|
||||
logging?: AmbiguityReport
|
||||
}
|
||||
|
||||
export class LLStarLookaheadStrategy extends LLkLookaheadStrategy {
|
||||
|
||||
private atn: ATN;
|
||||
private dfas: DFACache[];
|
||||
private logging: AmbiguityReport;
|
||||
|
||||
constructor(options?: LLStarLookaheadOptions) {
|
||||
super();
|
||||
this.logging = options?.logging ?? ((message) => console.log(message));
|
||||
}
|
||||
|
||||
override initialize(options: { rules: Rule[] }): void {
|
||||
this.atn = createATN(options.rules);
|
||||
this.dfas = initATNSimulator(this.atn);
|
||||
}
|
||||
|
||||
override validateAmbiguousAlternationAlternatives(): ILookaheadValidationError[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
override validateEmptyOrAlternatives(): ILookaheadValidationError[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
override buildLookaheadForAlternation(options: {
|
||||
prodOccurrence: number;
|
||||
rule: Rule;
|
||||
maxLookahead: number;
|
||||
hasPredicates: boolean;
|
||||
dynamicTokensEnabled: boolean
|
||||
}): (this: BaseParser, orAlts?: IOrAlt<any>[] | undefined) => number | undefined {
|
||||
const { prodOccurrence, rule, hasPredicates, dynamicTokensEnabled } = options;
|
||||
const dfas = this.dfas;
|
||||
const logging = this.logging;
|
||||
const key = buildATNKey(rule, 'Alternation', prodOccurrence);
|
||||
const decisionState = this.atn.decisionMap[key];
|
||||
const decisionIndex = decisionState.decision;
|
||||
const partialAlts: (TokenType | undefined)[][] = map(
|
||||
getLookaheadPaths({
|
||||
maxLookahead: 1,
|
||||
occurrence: prodOccurrence,
|
||||
prodType: "Alternation",
|
||||
rule: rule
|
||||
}),
|
||||
(currAlt) => map(currAlt, (path) => path[0])
|
||||
)
|
||||
|
||||
if (isLL1Sequence(partialAlts, false) && !dynamicTokensEnabled) {
|
||||
const choiceToAlt = reduce(
|
||||
partialAlts,
|
||||
(result, currAlt, idx) => {
|
||||
forEach(currAlt, (currTokType) => {
|
||||
if (currTokType) {
|
||||
result[currTokType.tokenTypeIdx!] = idx
|
||||
forEach(currTokType.categoryMatches!, (currExtendingType) => {
|
||||
result[currExtendingType] = idx
|
||||
})
|
||||
}
|
||||
})
|
||||
return result
|
||||
},
|
||||
{} as Record<number, number>
|
||||
)
|
||||
|
||||
if (hasPredicates) {
|
||||
return function (this: BaseParser, orAlts) {
|
||||
const nextToken = this.LA(1)
|
||||
const prediction: number | undefined = choiceToAlt[nextToken.tokenTypeIdx]
|
||||
if (orAlts !== undefined && prediction !== undefined) {
|
||||
const gate = orAlts[prediction]?.GATE
|
||||
if (gate !== undefined && gate.call(this) === false) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
return prediction
|
||||
}
|
||||
} else {
|
||||
return function (this: BaseParser): number | undefined {
|
||||
const nextToken = this.LA(1)
|
||||
return choiceToAlt[nextToken.tokenTypeIdx];
|
||||
}
|
||||
}
|
||||
} else if (hasPredicates) {
|
||||
return function (this: BaseParser, orAlts) {
|
||||
const predicates = new PredicateSet()
|
||||
const length = orAlts === undefined ? 0 : orAlts.length
|
||||
for (let i = 0; i < length; i++) {
|
||||
const gate = orAlts?.[i].GATE
|
||||
predicates.set(i, gate === undefined || gate.call(this))
|
||||
}
|
||||
const result = adaptivePredict.call(this, dfas, decisionIndex, predicates, logging);
|
||||
return typeof result === 'number' ? result : undefined;
|
||||
}
|
||||
} else {
|
||||
return function (this: BaseParser) {
|
||||
const result = adaptivePredict.call(this, dfas, decisionIndex, EMPTY_PREDICATES, logging);
|
||||
return typeof result === 'number' ? result : undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override buildLookaheadForOptional(options: {
|
||||
prodOccurrence: number;
|
||||
prodType: OptionalProductionType;
|
||||
rule: Rule;
|
||||
maxLookahead: number;
|
||||
dynamicTokensEnabled: boolean
|
||||
}): (this: BaseParser) => boolean {
|
||||
const { prodOccurrence, rule, prodType, dynamicTokensEnabled } = options;
|
||||
const dfas = this.dfas;
|
||||
const logging = this.logging;
|
||||
const key = buildATNKey(rule, prodType, prodOccurrence);
|
||||
const decisionState = this.atn.decisionMap[key];
|
||||
const decisionIndex = decisionState.decision;
|
||||
const alts = map(
|
||||
getLookaheadPaths({
|
||||
maxLookahead: 1,
|
||||
occurrence: prodOccurrence,
|
||||
prodType,
|
||||
rule
|
||||
}),
|
||||
(e) => {
|
||||
return map(e, (g) => g[0])
|
||||
}
|
||||
)
|
||||
|
||||
if (isLL1Sequence(alts) && alts[0][0] && !dynamicTokensEnabled) {
|
||||
const alt = alts[0]
|
||||
const singleTokensTypes = flatten(alt)
|
||||
|
||||
if (
|
||||
singleTokensTypes.length === 1 &&
|
||||
isEmpty(singleTokensTypes[0].categoryMatches)
|
||||
) {
|
||||
const expectedTokenType = singleTokensTypes[0]
|
||||
const expectedTokenUniqueKey = expectedTokenType.tokenTypeIdx
|
||||
|
||||
return function (this: BaseParser): boolean {
|
||||
return this.LA(1).tokenTypeIdx === expectedTokenUniqueKey
|
||||
}
|
||||
} else {
|
||||
const choiceToAlt = reduce(
|
||||
singleTokensTypes,
|
||||
(result, currTokType) => {
|
||||
if (currTokType !== undefined) {
|
||||
result[currTokType.tokenTypeIdx!] = true
|
||||
forEach(currTokType.categoryMatches, (currExtendingType) => {
|
||||
result[currExtendingType] = true
|
||||
})
|
||||
}
|
||||
return result
|
||||
},
|
||||
{} as Record<number, boolean>
|
||||
)
|
||||
|
||||
return function (this: BaseParser): boolean {
|
||||
const nextToken = this.LA(1)
|
||||
return choiceToAlt[nextToken.tokenTypeIdx] === true
|
||||
}
|
||||
}
|
||||
}
|
||||
return function (this: BaseParser) {
|
||||
const result = adaptivePredict.call(this, dfas, decisionIndex, EMPTY_PREDICATES, logging)
|
||||
return typeof result === "object" ? false : result === 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function isLL1Sequence(sequences: (TokenType | undefined)[][], allowEmpty = true): boolean {
|
||||
const fullSet = new Set<number>()
|
||||
|
||||
for (const alt of sequences) {
|
||||
const altSet = new Set<number>()
|
||||
for (const tokType of alt) {
|
||||
if (tokType === undefined) {
|
||||
if (allowEmpty) {
|
||||
// Epsilon production encountered
|
||||
break
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const indices = [tokType.tokenTypeIdx!].concat(tokType.categoryMatches!)
|
||||
for (const index of indices) {
|
||||
if (fullSet.has(index)) {
|
||||
if (!altSet.has(index)) {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
fullSet.add(index)
|
||||
altSet.add(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function initATNSimulator(atn: ATN): DFACache[] {
|
||||
const decisionLength = atn.decisionStates.length
|
||||
const decisionToDFA: DFACache[] = Array(decisionLength)
|
||||
for (let i = 0; i < decisionLength; i++) {
|
||||
decisionToDFA[i] = createDFACache(atn.decisionStates[i], i)
|
||||
}
|
||||
return decisionToDFA;
|
||||
}
|
||||
|
||||
function adaptivePredict(
|
||||
this: BaseParser,
|
||||
dfaCaches: DFACache[],
|
||||
decision: number,
|
||||
predicateSet: PredicateSet,
|
||||
logging: AmbiguityReport
|
||||
): number | AdaptivePredictError {
|
||||
const dfa = dfaCaches[decision](predicateSet)
|
||||
let start = dfa.start
|
||||
if (start === undefined) {
|
||||
const closure = computeStartState(dfa.atnStartState as ATNState)
|
||||
start = addDFAState(dfa, newDFAState(closure))
|
||||
dfa.start = start
|
||||
}
|
||||
|
||||
const alt = performLookahead.apply(this, [dfa, start, predicateSet, logging])
|
||||
return alt
|
||||
}
|
||||
|
||||
function performLookahead(
|
||||
this: BaseParser,
|
||||
dfa: DFA,
|
||||
s0: DFAState,
|
||||
predicateSet: PredicateSet,
|
||||
logging: AmbiguityReport
|
||||
): number | AdaptivePredictError {
|
||||
let previousD = s0
|
||||
|
||||
let i = 1
|
||||
const path: IToken[] = []
|
||||
let t = this.LA(i++)
|
||||
|
||||
while (true) {
|
||||
let d = getExistingTargetState(previousD, t)
|
||||
if (d === undefined) {
|
||||
d = computeLookaheadTarget.apply(this, [dfa, previousD, t, i, predicateSet, logging])
|
||||
}
|
||||
|
||||
if (d === DFA_ERROR) {
|
||||
return buildAdaptivePredictError(path, previousD, t)
|
||||
}
|
||||
|
||||
if (d.isAcceptState === true) {
|
||||
return d.prediction
|
||||
}
|
||||
|
||||
previousD = d
|
||||
path.push(t)
|
||||
t = this.LA(i++)
|
||||
}
|
||||
}
|
||||
|
||||
function computeLookaheadTarget(
|
||||
this: BaseParser,
|
||||
dfa: DFA,
|
||||
previousD: DFAState,
|
||||
token: IToken,
|
||||
lookahead: number,
|
||||
predicateSet: PredicateSet,
|
||||
logging: AmbiguityReport
|
||||
): DFAState {
|
||||
const reach = computeReachSet(previousD.configs, token, predicateSet)
|
||||
if (reach.size === 0) {
|
||||
addDFAEdge(dfa, previousD, token, DFA_ERROR)
|
||||
return DFA_ERROR
|
||||
}
|
||||
|
||||
let newState = newDFAState(reach)
|
||||
const predictedAlt = getUniqueAlt(reach, predicateSet)
|
||||
|
||||
if (predictedAlt !== undefined) {
|
||||
newState.isAcceptState = true
|
||||
newState.prediction = predictedAlt
|
||||
newState.configs.uniqueAlt = predictedAlt
|
||||
} else if (hasConflictTerminatingPrediction(reach)) {
|
||||
const prediction = min(reach.alts)!
|
||||
newState.isAcceptState = true
|
||||
newState.prediction = prediction
|
||||
newState.configs.uniqueAlt = prediction
|
||||
reportLookaheadAmbiguity.apply(this, [dfa, lookahead, reach.alts, logging])
|
||||
}
|
||||
|
||||
newState = addDFAEdge(dfa, previousD, token, newState)
|
||||
return newState
|
||||
}
|
||||
|
||||
function reportLookaheadAmbiguity(
|
||||
this: BaseParser,
|
||||
dfa: DFA,
|
||||
lookahead: number,
|
||||
ambiguityIndices: number[],
|
||||
logging: AmbiguityReport
|
||||
) {
|
||||
const prefixPath: TokenType[] = []
|
||||
for (let i = 1; i <= lookahead; i++) {
|
||||
prefixPath.push(this.LA(i).tokenType)
|
||||
}
|
||||
const atnState = dfa.atnStartState
|
||||
const topLevelRule = atnState.rule
|
||||
const production = atnState.production
|
||||
const message = buildAmbiguityError({
|
||||
topLevelRule,
|
||||
ambiguityIndices,
|
||||
production,
|
||||
prefixPath
|
||||
})
|
||||
logging(message)
|
||||
}
|
||||
|
||||
function buildAmbiguityError(options: {
|
||||
topLevelRule: Rule
|
||||
prefixPath: TokenType[]
|
||||
ambiguityIndices: number[]
|
||||
production: IProductionWithOccurrence
|
||||
}): string {
|
||||
const pathMsg = map(options.prefixPath, (currtok) =>
|
||||
tokenLabel(currtok)
|
||||
).join(", ")
|
||||
const occurrence =
|
||||
options.production.idx === 0 ? "" : options.production.idx
|
||||
let currMessage =
|
||||
`Ambiguous Alternatives Detected: <${options.ambiguityIndices.join(
|
||||
", "
|
||||
)}> in <${getProductionDslName(options.production)}${occurrence}>` +
|
||||
` inside <${options.topLevelRule.name}> Rule,\n` +
|
||||
`<${pathMsg}> may appears as a prefix path in all these alternatives.\n`
|
||||
|
||||
currMessage =
|
||||
currMessage +
|
||||
`See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#AMBIGUOUS_ALTERNATIVES\n` +
|
||||
`For Further details.`
|
||||
return currMessage
|
||||
}
|
||||
|
||||
function getProductionDslName(prod: IProductionWithOccurrence): string {
|
||||
if (prod instanceof NonTerminal) {
|
||||
return "SUBRULE"
|
||||
} else if (prod instanceof Option) {
|
||||
return "OPTION"
|
||||
} else if (prod instanceof Alternation) {
|
||||
return "OR"
|
||||
} else if (prod instanceof RepetitionMandatory) {
|
||||
return "AT_LEAST_ONE"
|
||||
} else if (prod instanceof RepetitionMandatoryWithSeparator) {
|
||||
return "AT_LEAST_ONE_SEP"
|
||||
} else if (prod instanceof RepetitionWithSeparator) {
|
||||
return "MANY_SEP"
|
||||
} else if (prod instanceof Repetition) {
|
||||
return "MANY"
|
||||
} else if (prod instanceof Terminal) {
|
||||
return "CONSUME"
|
||||
} else {
|
||||
throw Error("non exhaustive match")
|
||||
}
|
||||
}
|
||||
|
||||
function buildAdaptivePredictError(
|
||||
path: IToken[],
|
||||
previous: DFAState,
|
||||
current: IToken
|
||||
): AdaptivePredictError {
|
||||
const nextTransitions = flatMap(
|
||||
previous.configs.elements,
|
||||
(e) => e.state.transitions
|
||||
)
|
||||
const nextTokenTypes = uniqBy(
|
||||
nextTransitions
|
||||
.filter((e): e is AtomTransition => e instanceof AtomTransition)
|
||||
.map((e) => e.tokenType),
|
||||
(e) => e.tokenTypeIdx
|
||||
)
|
||||
return {
|
||||
actualToken: current,
|
||||
possibleTokenTypes: nextTokenTypes,
|
||||
tokenPath: path
|
||||
}
|
||||
}
|
||||
|
||||
function getExistingTargetState(
|
||||
state: DFAState,
|
||||
token: IToken
|
||||
): DFAState | undefined {
|
||||
return state.edges[token.tokenTypeIdx]
|
||||
}
|
||||
|
||||
function computeReachSet(
|
||||
configs: ATNConfigSet,
|
||||
token: IToken,
|
||||
predicateSet: PredicateSet
|
||||
): ATNConfigSet {
|
||||
const intermediate = new ATNConfigSet()
|
||||
const skippedStopStates: ATNConfig[] = []
|
||||
|
||||
for (const c of configs.elements) {
|
||||
if (predicateSet.is(c.alt) === false) {
|
||||
continue
|
||||
}
|
||||
if (c.state.type === ATN_RULE_STOP) {
|
||||
skippedStopStates.push(c)
|
||||
continue
|
||||
}
|
||||
const transitionLength = c.state.transitions.length
|
||||
for (let i = 0; i < transitionLength; i++) {
|
||||
const transition = c.state.transitions[i]
|
||||
const target = getReachableTarget(transition, token)
|
||||
if (target !== undefined) {
|
||||
intermediate.add({
|
||||
state: target,
|
||||
alt: c.alt,
|
||||
stack: c.stack
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let reach: ATNConfigSet | undefined
|
||||
|
||||
if (skippedStopStates.length === 0 && intermediate.size === 1) {
|
||||
reach = intermediate
|
||||
}
|
||||
|
||||
if (reach === undefined) {
|
||||
reach = new ATNConfigSet()
|
||||
for (const c of intermediate.elements) {
|
||||
closure(c, reach)
|
||||
}
|
||||
}
|
||||
|
||||
if (skippedStopStates.length > 0 && !hasConfigInRuleStopState(reach)) {
|
||||
for (const c of skippedStopStates) {
|
||||
reach.add(c)
|
||||
}
|
||||
}
|
||||
|
||||
return reach
|
||||
}
|
||||
|
||||
function getReachableTarget(
|
||||
transition: Transition,
|
||||
token: IToken
|
||||
): ATNState | undefined {
|
||||
if (
|
||||
transition instanceof AtomTransition &&
|
||||
tokenMatcher(token, transition.tokenType)
|
||||
) {
|
||||
return transition.target
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
function getUniqueAlt(
|
||||
configs: ATNConfigSet,
|
||||
predicateSet: PredicateSet
|
||||
): number | undefined {
|
||||
let alt: number | undefined
|
||||
for (const c of configs.elements) {
|
||||
if (predicateSet.is(c.alt) === true) {
|
||||
if (alt === undefined) {
|
||||
alt = c.alt
|
||||
} else if (alt !== c.alt) {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
return alt
|
||||
}
|
||||
|
||||
function newDFAState(closure: ATNConfigSet): DFAState {
|
||||
return {
|
||||
configs: closure,
|
||||
edges: {},
|
||||
isAcceptState: false,
|
||||
prediction: -1
|
||||
}
|
||||
}
|
||||
|
||||
function addDFAEdge(
|
||||
dfa: DFA,
|
||||
from: DFAState,
|
||||
token: IToken,
|
||||
to: DFAState
|
||||
): DFAState {
|
||||
to = addDFAState(dfa, to)
|
||||
from.edges[token.tokenTypeIdx] = to
|
||||
return to
|
||||
}
|
||||
|
||||
function addDFAState(dfa: DFA, state: DFAState): DFAState {
|
||||
if (state === DFA_ERROR) {
|
||||
return state
|
||||
}
|
||||
// Repetitions have the same config set
|
||||
// Therefore, storing the key of the config in a map allows us to create a loop in our DFA
|
||||
const mapKey = state.configs.key
|
||||
const existing = dfa.states[mapKey]
|
||||
if (existing !== undefined) {
|
||||
return existing
|
||||
}
|
||||
state.configs.finalize()
|
||||
dfa.states[mapKey] = state
|
||||
return state
|
||||
}
|
||||
|
||||
function computeStartState(atnState: ATNState): ATNConfigSet {
|
||||
const configs = new ATNConfigSet()
|
||||
|
||||
const numberOfTransitions = atnState.transitions.length
|
||||
for (let i = 0; i < numberOfTransitions; i++) {
|
||||
const target = atnState.transitions[i].target
|
||||
const config: ATNConfig = {
|
||||
state: target,
|
||||
alt: i,
|
||||
stack: []
|
||||
}
|
||||
closure(config, configs)
|
||||
}
|
||||
|
||||
return configs
|
||||
}
|
||||
|
||||
function closure(config: ATNConfig, configs: ATNConfigSet): void {
|
||||
const p = config.state
|
||||
|
||||
if (p.type === ATN_RULE_STOP) {
|
||||
if (config.stack.length > 0) {
|
||||
const atnStack = [...config.stack]
|
||||
const followState = atnStack.pop()!
|
||||
const followConfig: ATNConfig = {
|
||||
state: followState,
|
||||
alt: config.alt,
|
||||
stack: atnStack
|
||||
}
|
||||
closure(followConfig, configs)
|
||||
} else {
|
||||
// Dipping into outer context, simply add the config
|
||||
// This will stop computation once every config is at the rule stop state
|
||||
configs.add(config)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (!p.epsilonOnlyTransitions) {
|
||||
configs.add(config)
|
||||
}
|
||||
|
||||
const transitionLength = p.transitions.length
|
||||
for (let i = 0; i < transitionLength; i++) {
|
||||
const transition = p.transitions[i]
|
||||
const c = getEpsilonTarget(config, transition)
|
||||
|
||||
if (c !== undefined) {
|
||||
closure(c, configs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getEpsilonTarget(
|
||||
config: ATNConfig,
|
||||
transition: Transition
|
||||
): ATNConfig | undefined {
|
||||
if (transition instanceof EpsilonTransition) {
|
||||
return {
|
||||
state: transition.target,
|
||||
alt: config.alt,
|
||||
stack: config.stack
|
||||
}
|
||||
} else if (transition instanceof RuleTransition) {
|
||||
const stack = [...config.stack, transition.followState]
|
||||
return {
|
||||
state: transition.target,
|
||||
alt: config.alt,
|
||||
stack
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
function hasConfigInRuleStopState(configs: ATNConfigSet): boolean {
|
||||
for (const c of configs.elements) {
|
||||
if (c.state.type === ATN_RULE_STOP) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function allConfigsInRuleStopStates(configs: ATNConfigSet): boolean {
|
||||
for (const c of configs.elements) {
|
||||
if (c.state.type !== ATN_RULE_STOP) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function hasConflictTerminatingPrediction(configs: ATNConfigSet): boolean {
|
||||
if (allConfigsInRuleStopStates(configs)) {
|
||||
return true
|
||||
}
|
||||
const altSets = getConflictingAltSets(configs.elements)
|
||||
const heuristic =
|
||||
hasConflictingAltSet(altSets) && !hasStateAssociatedWithOneAlt(altSets)
|
||||
return heuristic
|
||||
}
|
||||
|
||||
function getConflictingAltSets(
|
||||
configs: readonly ATNConfig[]
|
||||
): Map<string, Record<number, boolean>> {
|
||||
const configToAlts = new Map<string, Record<number, boolean>>()
|
||||
for (const c of configs) {
|
||||
const key = getATNConfigKey(c, false)
|
||||
let alts = configToAlts.get(key)
|
||||
if (alts === undefined) {
|
||||
alts = {}
|
||||
configToAlts.set(key, alts)
|
||||
}
|
||||
alts[c.alt] = true
|
||||
}
|
||||
return configToAlts
|
||||
}
|
||||
|
||||
function hasConflictingAltSet(
|
||||
altSets: Map<string, Record<number, boolean>>
|
||||
): boolean {
|
||||
for (const value of Array.from(altSets.values())) {
|
||||
if (Object.keys(value).length > 1) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function hasStateAssociatedWithOneAlt(
|
||||
altSets: Map<string, Record<number, boolean>>
|
||||
): boolean {
|
||||
for (const value of Array.from(altSets.values())) {
|
||||
if (Object.keys(value).length === 1) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
302
node_modules/chevrotain-allstar/src/atn.test.ts
generated
vendored
Normal file
302
node_modules/chevrotain-allstar/src/atn.test.ts
generated
vendored
Normal file
@@ -0,0 +1,302 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2022 TypeFox GmbH
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License, which is available in the project root.
|
||||
******************************************************************************/
|
||||
|
||||
import { createToken, EmbeddedActionsParser, EOF, IToken, TokenType } from "chevrotain"
|
||||
import { LLStarLookaheadStrategy } from "./all-star-lookahead"
|
||||
|
||||
describe("ATN Simulator", () => {
|
||||
describe("LL(*) lookahead", () => {
|
||||
const A = createToken({ name: "A", pattern: "a" })
|
||||
const B = createToken({ name: "B", pattern: "b" })
|
||||
|
||||
class UnboundedLookaheadParser extends EmbeddedActionsParser {
|
||||
constructor() {
|
||||
super([A, B], {
|
||||
lookaheadStrategy: new LLStarLookaheadStrategy()
|
||||
})
|
||||
this.performSelfAnalysis()
|
||||
}
|
||||
|
||||
LongRule = this.RULE("LongRule", () => {
|
||||
return this.OR([
|
||||
{
|
||||
ALT: () => {
|
||||
return 0
|
||||
}
|
||||
},
|
||||
{
|
||||
ALT: () => {
|
||||
this.AT_LEAST_ONE1(() => this.CONSUME1(A))
|
||||
return 1
|
||||
}
|
||||
},
|
||||
{
|
||||
ALT: () => {
|
||||
this.AT_LEAST_ONE2(() => this.CONSUME2(A))
|
||||
this.CONSUME(B)
|
||||
return 2
|
||||
}
|
||||
}
|
||||
])
|
||||
})
|
||||
}
|
||||
|
||||
it("Should pick longest alternative instead of first #1", () => {
|
||||
const parser = new UnboundedLookaheadParser()
|
||||
parser.input = [
|
||||
createRegularToken(A),
|
||||
createRegularToken(A),
|
||||
createRegularToken(A)
|
||||
]
|
||||
const result = parser.LongRule()
|
||||
expect(result).toBe(1);
|
||||
})
|
||||
|
||||
it("Should pick longest alternative instead of first #2", () => {
|
||||
const parser = new UnboundedLookaheadParser()
|
||||
parser.input = [
|
||||
createRegularToken(A),
|
||||
createRegularToken(A),
|
||||
createRegularToken(B)
|
||||
]
|
||||
const result = parser.LongRule()
|
||||
expect(result).toBe(2);
|
||||
})
|
||||
|
||||
it("Should pick shortest fitting alternative", () => {
|
||||
const parser = new UnboundedLookaheadParser()
|
||||
parser.input = []
|
||||
const result = parser.LongRule()
|
||||
expect(result).toBe(0);
|
||||
})
|
||||
})
|
||||
|
||||
describe("Ambiguity Detection", () => {
|
||||
const A = createToken({ name: "A" })
|
||||
const B = createToken({ name: "B" })
|
||||
|
||||
class AmbigiousParser extends EmbeddedActionsParser {
|
||||
ambiguityReports: string[] = []
|
||||
|
||||
constructor() {
|
||||
super([A, B], {
|
||||
lookaheadStrategy: new LLStarLookaheadStrategy({
|
||||
logging: (message) => this.ambiguityReports.push(message)
|
||||
})
|
||||
});
|
||||
this.performSelfAnalysis()
|
||||
}
|
||||
|
||||
OptionRule = this.RULE("OptionRule", () => {
|
||||
let usedOption = false
|
||||
this.OPTION(() => {
|
||||
this.AT_LEAST_ONE1(() => this.CONSUME1(A))
|
||||
usedOption = true
|
||||
})
|
||||
this.AT_LEAST_ONE2(() => this.CONSUME2(A))
|
||||
return usedOption
|
||||
})
|
||||
|
||||
AltRule = this.RULE("AltRule", () => {
|
||||
return this.OR([
|
||||
{
|
||||
ALT: () => {
|
||||
this.SUBRULE(this.RuleB)
|
||||
return 0
|
||||
}
|
||||
},
|
||||
{
|
||||
ALT: () => {
|
||||
this.SUBRULE(this.RuleC)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
])
|
||||
})
|
||||
|
||||
RuleB = this.RULE("RuleB", () => {
|
||||
this.MANY(() => this.CONSUME(A))
|
||||
})
|
||||
|
||||
RuleC = this.RULE("RuleC", () => {
|
||||
this.MANY(() => this.CONSUME(A))
|
||||
this.OPTION(() => this.CONSUME(B))
|
||||
})
|
||||
|
||||
AltRuleWithEOF = this.RULE("AltRuleWithEOF", () => {
|
||||
return this.OR([
|
||||
{
|
||||
ALT: () => {
|
||||
this.SUBRULE1(this.RuleEOF)
|
||||
return 0
|
||||
}
|
||||
},
|
||||
{
|
||||
ALT: () => {
|
||||
this.SUBRULE2(this.RuleEOF)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
])
|
||||
})
|
||||
|
||||
RuleEOF = this.RULE("RuleEOF", () => {
|
||||
this.MANY1(() => this.CONSUME(A))
|
||||
this.CONSUME(EOF)
|
||||
})
|
||||
|
||||
AltRuleWithPred = this.RULE("AltRuleWithPred", (pred?: boolean) => {
|
||||
return this.OR([
|
||||
{
|
||||
ALT: () => {
|
||||
this.CONSUME1(A)
|
||||
return 0
|
||||
},
|
||||
GATE: () => (pred === undefined ? true : pred)
|
||||
},
|
||||
{
|
||||
ALT: () => {
|
||||
this.CONSUME2(A)
|
||||
return 1
|
||||
},
|
||||
GATE: () => (pred === undefined ? true : !pred)
|
||||
},
|
||||
{
|
||||
ALT: () => {
|
||||
this.CONSUME(B)
|
||||
return 2
|
||||
}
|
||||
}
|
||||
])
|
||||
})
|
||||
|
||||
AltWithOption = this.RULE("AltWithOption", () => {
|
||||
const intermediate = this.OR([
|
||||
{
|
||||
ALT: () => {
|
||||
this.CONSUME1(A)
|
||||
return 2
|
||||
}
|
||||
},
|
||||
{
|
||||
ALT: () => {
|
||||
this.CONSUME2(B)
|
||||
return 4
|
||||
}
|
||||
}
|
||||
])
|
||||
const option = this.OPTION(() => {
|
||||
this.CONSUME3(A);
|
||||
return 1;
|
||||
})
|
||||
return (option ?? 0) + intermediate;
|
||||
})
|
||||
}
|
||||
|
||||
it("Should pick option on ambiguity", () => {
|
||||
const parser = new AmbigiousParser()
|
||||
parser.input = [
|
||||
createRegularToken(A),
|
||||
createRegularToken(A),
|
||||
createRegularToken(A)
|
||||
]
|
||||
const result = parser.OptionRule()
|
||||
expect(result).toBeTruthy();
|
||||
// The rule nests a `AT_LEAST_ONE` inside and outside the OPTION
|
||||
// Both productions produce lookahead ambiguities
|
||||
expect(parser.ambiguityReports[0]).toMatch("<0, 1> in <OPTION>")
|
||||
expect(parser.ambiguityReports[1]).toMatch("<0, 1> in <AT_LEAST_ONE1>")
|
||||
})
|
||||
|
||||
it("Should pick first alternative on ambiguity", () => {
|
||||
const parser = new AmbigiousParser()
|
||||
parser.input = [
|
||||
createRegularToken(A),
|
||||
createRegularToken(A),
|
||||
createRegularToken(A)
|
||||
]
|
||||
const result = parser.AltRule()
|
||||
expect(result).toBe(0);
|
||||
expect(parser.ambiguityReports[0]).toMatch("<0, 1> in <OR>")
|
||||
})
|
||||
|
||||
it("Should pick first alternative on EOF ambiguity", () => {
|
||||
const parser = new AmbigiousParser()
|
||||
parser.input = []
|
||||
const result = parser.AltRuleWithEOF()
|
||||
expect(result).toBe(0);
|
||||
expect(parser.ambiguityReports[0]).toMatch("<0, 1> in <OR>")
|
||||
})
|
||||
|
||||
it("Should pick correct alternative on long prefix", () => {
|
||||
const parser = new AmbigiousParser()
|
||||
parser.input = [
|
||||
createRegularToken(A),
|
||||
createRegularToken(A),
|
||||
createRegularToken(B)
|
||||
]
|
||||
const result = parser.AltRule()
|
||||
expect(result).toBe(1);
|
||||
expect(parser.ambiguityReports).toHaveLength(0);
|
||||
})
|
||||
|
||||
it("Should resolve ambiguity using predicate", () => {
|
||||
const parser = new AmbigiousParser()
|
||||
parser.input = [createRegularToken(A)]
|
||||
const resultAutomatic = parser.AltRuleWithPred(undefined)
|
||||
// Automatically resolving the ambiguity should return `0`
|
||||
expect(resultAutomatic).toBe(0);
|
||||
// It should also create an ambiguity report
|
||||
expect(parser.ambiguityReports[0]).toMatch("<0, 1> in <OR>")
|
||||
parser.ambiguityReports = []
|
||||
parser.input = [createRegularToken(A)]
|
||||
const resultTrue = parser.AltRuleWithPred(true)
|
||||
expect(resultTrue).toBe(0);
|
||||
parser.input = [createRegularToken(A)]
|
||||
const resultFalse = parser.AltRuleWithPred(false)
|
||||
expect(resultFalse).toBe(1),
|
||||
expect(parser.ambiguityReports).toHaveLength(0);
|
||||
})
|
||||
|
||||
it("Should pick non-ambigious alternative inside of ambigious, predicated alternation", () => {
|
||||
const parser = new AmbigiousParser()
|
||||
parser.input = [createRegularToken(B)]
|
||||
const result = parser.AltRuleWithPred(undefined)
|
||||
expect(result).toBe(2);
|
||||
expect(parser.ambiguityReports).toHaveLength(0);
|
||||
})
|
||||
|
||||
it("Should work with alternatives followed by optional elements", () => {
|
||||
const parser = new AmbigiousParser();
|
||||
parser.input = [createRegularToken(B), createRegularToken(A)];
|
||||
const result = parser.AltWithOption();
|
||||
expect(result).toBe(5);
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function createRegularToken(
|
||||
tokType: TokenType,
|
||||
image = "",
|
||||
startOffset = 1,
|
||||
startLine?: number,
|
||||
startColumn?: number,
|
||||
endOffset?: number,
|
||||
endLine?: number,
|
||||
endColumn?: number
|
||||
): IToken {
|
||||
return {
|
||||
image: image,
|
||||
startOffset: startOffset,
|
||||
startLine: startLine,
|
||||
startColumn: startColumn,
|
||||
endOffset: endOffset,
|
||||
endLine: endLine,
|
||||
endColumn: endColumn,
|
||||
tokenTypeIdx: tokType.tokenTypeIdx!,
|
||||
tokenType: tokType
|
||||
}
|
||||
}
|
||||
642
node_modules/chevrotain-allstar/src/atn.ts
generated
vendored
Normal file
642
node_modules/chevrotain-allstar/src/atn.ts
generated
vendored
Normal file
@@ -0,0 +1,642 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2022 TypeFox GmbH
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License, which is available in the project root.
|
||||
******************************************************************************/
|
||||
|
||||
import map from "lodash-es/map.js"
|
||||
import filter from "lodash-es/filter.js"
|
||||
import {
|
||||
IProduction,
|
||||
IProductionWithOccurrence,
|
||||
TokenType,
|
||||
Alternation,
|
||||
NonTerminal,
|
||||
Rule,
|
||||
Option,
|
||||
RepetitionMandatory,
|
||||
Repetition,
|
||||
Terminal,
|
||||
Alternative,
|
||||
RepetitionWithSeparator,
|
||||
RepetitionMandatoryWithSeparator,
|
||||
LookaheadProductionType
|
||||
} from "chevrotain"
|
||||
|
||||
export function buildATNKey(rule: Rule, type: LookaheadProductionType, occurrence: number): string {
|
||||
return `${rule.name}_${type}_${occurrence}`;
|
||||
}
|
||||
|
||||
export interface ATN {
|
||||
decisionMap: Record<string, DecisionState>
|
||||
states: ATNState[]
|
||||
decisionStates: DecisionState[]
|
||||
ruleToStartState: Map<Rule, RuleStartState>
|
||||
ruleToStopState: Map<Rule, RuleStopState>
|
||||
}
|
||||
|
||||
export const ATN_INVALID_TYPE = 0
|
||||
export const ATN_BASIC = 1
|
||||
export const ATN_RULE_START = 2
|
||||
export const ATN_PLUS_BLOCK_START = 4
|
||||
export const ATN_STAR_BLOCK_START = 5
|
||||
// Currently unused as the ATN is not used for lexing
|
||||
export const ATN_TOKEN_START = 6
|
||||
export const ATN_RULE_STOP = 7
|
||||
export const ATN_BLOCK_END = 8
|
||||
export const ATN_STAR_LOOP_BACK = 9
|
||||
export const ATN_STAR_LOOP_ENTRY = 10
|
||||
export const ATN_PLUS_LOOP_BACK = 11
|
||||
export const ATN_LOOP_END = 12
|
||||
|
||||
export type ATNState =
|
||||
| BasicState
|
||||
| BasicBlockStartState
|
||||
| PlusBlockStartState
|
||||
| PlusLoopbackState
|
||||
| StarBlockStartState
|
||||
| StarLoopbackState
|
||||
| StarLoopEntryState
|
||||
| BlockEndState
|
||||
| RuleStartState
|
||||
| RuleStopState
|
||||
| LoopEndState
|
||||
|
||||
export interface ATNBaseState {
|
||||
atn: ATN
|
||||
production: IProductionWithOccurrence
|
||||
stateNumber: number
|
||||
rule: Rule
|
||||
epsilonOnlyTransitions: boolean
|
||||
transitions: Transition[]
|
||||
nextTokenWithinRule: number[]
|
||||
}
|
||||
|
||||
export interface BasicState extends ATNBaseState {
|
||||
type: typeof ATN_BASIC
|
||||
}
|
||||
|
||||
export interface BlockStartState extends DecisionState {
|
||||
end: BlockEndState
|
||||
}
|
||||
|
||||
export interface BasicBlockStartState extends BlockStartState {
|
||||
type: typeof ATN_BASIC
|
||||
}
|
||||
|
||||
export interface PlusBlockStartState extends BlockStartState {
|
||||
loopback: PlusLoopbackState
|
||||
type: typeof ATN_PLUS_BLOCK_START
|
||||
}
|
||||
|
||||
export interface PlusLoopbackState extends DecisionState {
|
||||
type: typeof ATN_PLUS_LOOP_BACK
|
||||
}
|
||||
|
||||
export interface StarBlockStartState extends BlockStartState {
|
||||
type: typeof ATN_STAR_BLOCK_START
|
||||
}
|
||||
|
||||
export interface StarLoopbackState extends ATNBaseState {
|
||||
type: typeof ATN_STAR_LOOP_BACK
|
||||
}
|
||||
|
||||
export interface StarLoopEntryState extends DecisionState {
|
||||
loopback: StarLoopbackState
|
||||
type: typeof ATN_STAR_LOOP_ENTRY
|
||||
}
|
||||
|
||||
export interface BlockEndState extends ATNBaseState {
|
||||
start: BlockStartState
|
||||
type: typeof ATN_BLOCK_END
|
||||
}
|
||||
|
||||
export interface DecisionState extends ATNBaseState {
|
||||
decision: number
|
||||
}
|
||||
|
||||
export interface LoopEndState extends ATNBaseState {
|
||||
loopback: ATNState
|
||||
type: typeof ATN_LOOP_END
|
||||
}
|
||||
|
||||
export interface RuleStartState extends ATNBaseState {
|
||||
stop: RuleStopState
|
||||
type: typeof ATN_RULE_START
|
||||
}
|
||||
|
||||
export interface RuleStopState extends ATNBaseState {
|
||||
type: typeof ATN_RULE_STOP
|
||||
}
|
||||
|
||||
export interface Transition {
|
||||
target: ATNState
|
||||
isEpsilon(): boolean
|
||||
}
|
||||
|
||||
export abstract class AbstractTransition implements Transition {
|
||||
target: ATNState
|
||||
|
||||
constructor(target: ATNState) {
|
||||
this.target = target
|
||||
}
|
||||
|
||||
isEpsilon() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export class AtomTransition extends AbstractTransition {
|
||||
tokenType: TokenType
|
||||
|
||||
constructor(target: ATNState, tokenType: TokenType) {
|
||||
super(target)
|
||||
this.tokenType = tokenType
|
||||
}
|
||||
}
|
||||
|
||||
export class EpsilonTransition extends AbstractTransition {
|
||||
constructor(target: ATNState) {
|
||||
super(target)
|
||||
}
|
||||
|
||||
isEpsilon() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
export class RuleTransition extends AbstractTransition {
|
||||
rule: Rule
|
||||
followState: ATNState
|
||||
|
||||
constructor(ruleStart: RuleStartState, rule: Rule, followState: ATNState) {
|
||||
super(ruleStart)
|
||||
this.rule = rule
|
||||
this.followState = followState
|
||||
}
|
||||
|
||||
isEpsilon() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
interface ATNHandle {
|
||||
left: ATNState
|
||||
right: ATNState
|
||||
}
|
||||
|
||||
export function createATN(rules: Rule[]): ATN {
|
||||
const atn: ATN = {
|
||||
decisionMap: {},
|
||||
decisionStates: [],
|
||||
ruleToStartState: new Map(),
|
||||
ruleToStopState: new Map(),
|
||||
states: []
|
||||
}
|
||||
createRuleStartAndStopATNStates(atn, rules)
|
||||
const ruleLength = rules.length
|
||||
for (let i = 0; i < ruleLength; i++) {
|
||||
const rule = rules[i]
|
||||
const ruleBlock = block(atn, rule, rule)
|
||||
if (ruleBlock === undefined) {
|
||||
continue
|
||||
}
|
||||
buildRuleHandle(atn, rule, ruleBlock)
|
||||
}
|
||||
return atn
|
||||
}
|
||||
|
||||
function createRuleStartAndStopATNStates(atn: ATN, rules: Rule[]): void {
|
||||
const ruleLength = rules.length
|
||||
for (let i = 0; i < ruleLength; i++) {
|
||||
const rule = rules[i]
|
||||
const start = newState<RuleStartState>(atn, rule, undefined, {
|
||||
type: ATN_RULE_START
|
||||
})
|
||||
const stop = newState<RuleStopState>(atn, rule, undefined, {
|
||||
type: ATN_RULE_STOP
|
||||
})
|
||||
start.stop = stop
|
||||
atn.ruleToStartState.set(rule, start)
|
||||
atn.ruleToStopState.set(rule, stop)
|
||||
}
|
||||
}
|
||||
|
||||
function atom(
|
||||
atn: ATN,
|
||||
rule: Rule,
|
||||
production: IProduction
|
||||
): ATNHandle | undefined {
|
||||
if (production instanceof Terminal) {
|
||||
return tokenRef(atn, rule, production.terminalType, production)
|
||||
} else if (production instanceof NonTerminal) {
|
||||
return ruleRef(atn, rule, production)
|
||||
} else if (production instanceof Alternation) {
|
||||
return alternation(atn, rule, production)
|
||||
} else if (production instanceof Option) {
|
||||
return option(atn, rule, production)
|
||||
} else if (production instanceof Repetition) {
|
||||
return repetition(atn, rule, production)
|
||||
} else if (production instanceof RepetitionWithSeparator) {
|
||||
return repetitionSep(atn, rule, production)
|
||||
} else if (production instanceof RepetitionMandatory) {
|
||||
return repetitionMandatory(atn, rule, production)
|
||||
} else if (production instanceof RepetitionMandatoryWithSeparator) {
|
||||
return repetitionMandatorySep(atn, rule, production)
|
||||
} else {
|
||||
return block(atn, rule, production as Alternative)
|
||||
}
|
||||
}
|
||||
|
||||
function repetition(atn: ATN, rule: Rule, repetition: Repetition): ATNHandle {
|
||||
const starState = newState<StarBlockStartState>(atn, rule, repetition, {
|
||||
type: ATN_STAR_BLOCK_START
|
||||
})
|
||||
defineDecisionState(atn, starState)
|
||||
const handle = makeAlts(
|
||||
atn,
|
||||
rule,
|
||||
starState,
|
||||
repetition,
|
||||
block(atn, rule, repetition)
|
||||
)
|
||||
return star(atn, rule, repetition, handle)
|
||||
}
|
||||
|
||||
function repetitionSep(
|
||||
atn: ATN,
|
||||
rule: Rule,
|
||||
repetition: RepetitionWithSeparator
|
||||
): ATNHandle {
|
||||
const starState = newState<StarBlockStartState>(atn, rule, repetition, {
|
||||
type: ATN_STAR_BLOCK_START
|
||||
})
|
||||
defineDecisionState(atn, starState)
|
||||
const handle = makeAlts(
|
||||
atn,
|
||||
rule,
|
||||
starState,
|
||||
repetition,
|
||||
block(atn, rule, repetition)
|
||||
)
|
||||
const sep = tokenRef(atn, rule, repetition.separator, repetition)
|
||||
return star(atn, rule, repetition, handle, sep)
|
||||
}
|
||||
|
||||
function repetitionMandatory(
|
||||
atn: ATN,
|
||||
rule: Rule,
|
||||
repetition: RepetitionMandatory
|
||||
): ATNHandle {
|
||||
const plusState = newState<PlusBlockStartState>(atn, rule, repetition, {
|
||||
type: ATN_PLUS_BLOCK_START
|
||||
})
|
||||
defineDecisionState(atn, plusState)
|
||||
const handle = makeAlts(
|
||||
atn,
|
||||
rule,
|
||||
plusState,
|
||||
repetition,
|
||||
block(atn, rule, repetition)
|
||||
)
|
||||
return plus(atn, rule, repetition, handle)
|
||||
}
|
||||
|
||||
function repetitionMandatorySep(
|
||||
atn: ATN,
|
||||
rule: Rule,
|
||||
repetition: RepetitionMandatoryWithSeparator
|
||||
): ATNHandle {
|
||||
const plusState = newState<PlusBlockStartState>(atn, rule, repetition, {
|
||||
type: ATN_PLUS_BLOCK_START
|
||||
})
|
||||
defineDecisionState(atn, plusState)
|
||||
const handle = makeAlts(
|
||||
atn,
|
||||
rule,
|
||||
plusState,
|
||||
repetition,
|
||||
block(atn, rule, repetition)
|
||||
)
|
||||
const sep = tokenRef(atn, rule, repetition.separator, repetition)
|
||||
return plus(atn, rule, repetition, handle, sep)
|
||||
}
|
||||
|
||||
function alternation(
|
||||
atn: ATN,
|
||||
rule: Rule,
|
||||
alternation: Alternation
|
||||
): ATNHandle {
|
||||
const start = newState<BasicBlockStartState>(atn, rule, alternation, {
|
||||
type: ATN_BASIC
|
||||
})
|
||||
defineDecisionState(atn, start)
|
||||
const alts = map(alternation.definition, (e) => atom(atn, rule, e))
|
||||
const handle = makeAlts(atn, rule, start, alternation, ...alts)
|
||||
return handle
|
||||
}
|
||||
|
||||
function option(atn: ATN, rule: Rule, option: Option): ATNHandle {
|
||||
const start = newState<BasicBlockStartState>(atn, rule, option, {
|
||||
type: ATN_BASIC
|
||||
})
|
||||
defineDecisionState(atn, start)
|
||||
const handle = makeAlts(atn, rule, start, option, block(atn, rule, option))
|
||||
return optional(atn, rule, option, handle)
|
||||
}
|
||||
|
||||
function block(
|
||||
atn: ATN,
|
||||
rule: Rule,
|
||||
block: { definition: IProduction[] }
|
||||
): ATNHandle | undefined {
|
||||
const handles = filter(
|
||||
map(block.definition, (e) => atom(atn, rule, e)),
|
||||
(e) => e !== undefined
|
||||
) as ATNHandle[]
|
||||
if (handles.length === 1) {
|
||||
return handles[0]
|
||||
} else if (handles.length === 0) {
|
||||
return undefined
|
||||
} else {
|
||||
return makeBlock(atn, handles)
|
||||
}
|
||||
}
|
||||
|
||||
function plus(
|
||||
atn: ATN,
|
||||
rule: Rule,
|
||||
plus: IProductionWithOccurrence,
|
||||
handle: ATNHandle,
|
||||
sep?: ATNHandle
|
||||
): ATNHandle {
|
||||
const blkStart = handle.left as PlusBlockStartState
|
||||
const blkEnd = handle.right
|
||||
|
||||
const loop = newState<PlusLoopbackState>(atn, rule, plus, {
|
||||
type: ATN_PLUS_LOOP_BACK
|
||||
})
|
||||
defineDecisionState(atn, loop)
|
||||
const end = newState<LoopEndState>(atn, rule, plus, {
|
||||
type: ATN_LOOP_END
|
||||
})
|
||||
blkStart.loopback = loop
|
||||
end.loopback = loop
|
||||
atn.decisionMap[buildATNKey(rule, sep ? 'RepetitionMandatoryWithSeparator' : 'RepetitionMandatory', plus.idx)] = loop;
|
||||
epsilon(blkEnd, loop) // block can see loop back
|
||||
|
||||
// Depending on whether we have a separator we put the exit transition at index 1 or 0
|
||||
// This influences the chosen option in the lookahead DFA
|
||||
if (sep === undefined) {
|
||||
epsilon(loop, blkStart) // loop back to start
|
||||
epsilon(loop, end) // exit
|
||||
} else {
|
||||
epsilon(loop, end) // exit
|
||||
// loop back to start with separator
|
||||
epsilon(loop, sep.left)
|
||||
epsilon(sep.right, blkStart)
|
||||
}
|
||||
|
||||
return {
|
||||
left: blkStart,
|
||||
right: end
|
||||
}
|
||||
}
|
||||
|
||||
function star(
|
||||
atn: ATN,
|
||||
rule: Rule,
|
||||
star: IProductionWithOccurrence,
|
||||
handle: ATNHandle,
|
||||
sep?: ATNHandle
|
||||
): ATNHandle {
|
||||
const start = handle.left
|
||||
const end = handle.right
|
||||
|
||||
const entry = newState<StarLoopEntryState>(atn, rule, star, {
|
||||
type: ATN_STAR_LOOP_ENTRY
|
||||
})
|
||||
defineDecisionState(atn, entry)
|
||||
const loopEnd = newState<LoopEndState>(atn, rule, star, {
|
||||
type: ATN_LOOP_END
|
||||
})
|
||||
const loop = newState<StarLoopbackState>(atn, rule, star, {
|
||||
type: ATN_STAR_LOOP_BACK
|
||||
})
|
||||
entry.loopback = loop
|
||||
loopEnd.loopback = loop
|
||||
|
||||
epsilon(entry, start) // loop enter edge (alt 2)
|
||||
epsilon(entry, loopEnd) // bypass loop edge (alt 1)
|
||||
epsilon(end, loop) // block end hits loop back
|
||||
|
||||
if (sep !== undefined) {
|
||||
epsilon(loop, loopEnd) // end loop
|
||||
// loop back to start of handle using separator
|
||||
epsilon(loop, sep.left)
|
||||
epsilon(sep.right, start)
|
||||
} else {
|
||||
epsilon(loop, entry) // loop back to entry/exit decision
|
||||
}
|
||||
|
||||
atn.decisionMap[buildATNKey(rule, sep ? 'RepetitionWithSeparator' : 'Repetition', star.idx)] = entry;
|
||||
return {
|
||||
left: entry,
|
||||
right: loopEnd
|
||||
}
|
||||
}
|
||||
|
||||
function optional(atn: ATN, rule: Rule, optional: Option, handle: ATNHandle): ATNHandle {
|
||||
const start = handle.left as DecisionState
|
||||
const end = handle.right
|
||||
|
||||
epsilon(start, end)
|
||||
|
||||
atn.decisionMap[buildATNKey(rule, 'Option', optional.idx)] = start;
|
||||
return handle
|
||||
}
|
||||
|
||||
function defineDecisionState(atn: ATN, state: DecisionState): number {
|
||||
atn.decisionStates.push(state)
|
||||
state.decision = atn.decisionStates.length - 1
|
||||
return state.decision
|
||||
}
|
||||
|
||||
function makeAlts(
|
||||
atn: ATN,
|
||||
rule: Rule,
|
||||
start: BlockStartState,
|
||||
production: IProductionWithOccurrence,
|
||||
...alts: (ATNHandle | undefined)[]
|
||||
): ATNHandle {
|
||||
const end = newState<BlockEndState>(atn, rule, production, {
|
||||
type: ATN_BLOCK_END,
|
||||
start
|
||||
})
|
||||
start.end = end
|
||||
for (const alt of alts) {
|
||||
if (alt !== undefined) {
|
||||
// hook alts up to decision block
|
||||
epsilon(start, alt.left)
|
||||
epsilon(alt.right, end)
|
||||
} else {
|
||||
epsilon(start, end)
|
||||
}
|
||||
}
|
||||
|
||||
const handle: ATNHandle = {
|
||||
left: start as ATNState,
|
||||
right: end
|
||||
}
|
||||
atn.decisionMap[buildATNKey(rule, getProdType(production), production.idx)] = start
|
||||
return handle
|
||||
}
|
||||
|
||||
function getProdType(production: IProduction): LookaheadProductionType {
|
||||
if (production instanceof Alternation) {
|
||||
return 'Alternation';
|
||||
} else if (production instanceof Option) {
|
||||
return 'Option';
|
||||
} else if (production instanceof Repetition) {
|
||||
return 'Repetition';
|
||||
} else if (production instanceof RepetitionWithSeparator) {
|
||||
return 'RepetitionWithSeparator';
|
||||
} else if (production instanceof RepetitionMandatory) {
|
||||
return 'RepetitionMandatory';
|
||||
} else if (production instanceof RepetitionMandatoryWithSeparator) {
|
||||
return 'RepetitionMandatoryWithSeparator';
|
||||
} else {
|
||||
throw new Error('Invalid production type encountered');
|
||||
}
|
||||
}
|
||||
|
||||
function makeBlock(atn: ATN, alts: ATNHandle[]): ATNHandle {
|
||||
const altsLength = alts.length
|
||||
for (let i = 0; i < altsLength - 1; i++) {
|
||||
const handle = alts[i]
|
||||
let transition: Transition | undefined
|
||||
if (handle.left.transitions.length === 1) {
|
||||
transition = handle.left.transitions[0]
|
||||
}
|
||||
const isRuleTransition = transition instanceof RuleTransition
|
||||
const ruleTransition = transition as RuleTransition
|
||||
const next = alts[i + 1].left
|
||||
if (
|
||||
handle.left.type === ATN_BASIC &&
|
||||
handle.right.type === ATN_BASIC &&
|
||||
transition !== undefined &&
|
||||
((isRuleTransition && ruleTransition.followState === handle.right) ||
|
||||
transition.target === handle.right)
|
||||
) {
|
||||
// we can avoid epsilon edge to next element
|
||||
if (isRuleTransition) {
|
||||
ruleTransition.followState = next
|
||||
} else {
|
||||
transition.target = next
|
||||
}
|
||||
removeState(atn, handle.right) // we skipped over this state
|
||||
} else {
|
||||
// need epsilon if previous block's right end node is complex
|
||||
epsilon(handle.right, next)
|
||||
}
|
||||
}
|
||||
|
||||
const first = alts[0]
|
||||
const last = alts[altsLength - 1]
|
||||
return {
|
||||
left: first.left,
|
||||
right: last.right
|
||||
}
|
||||
}
|
||||
|
||||
function tokenRef(
|
||||
atn: ATN,
|
||||
rule: Rule,
|
||||
tokenType: TokenType,
|
||||
production: IProductionWithOccurrence
|
||||
): ATNHandle {
|
||||
const left = newState<BasicState>(atn, rule, production, {
|
||||
type: ATN_BASIC
|
||||
})
|
||||
const right = newState<BasicState>(atn, rule, production, {
|
||||
type: ATN_BASIC
|
||||
})
|
||||
addTransition(left, new AtomTransition(right, tokenType))
|
||||
return {
|
||||
left,
|
||||
right
|
||||
}
|
||||
}
|
||||
|
||||
function ruleRef(
|
||||
atn: ATN,
|
||||
currentRule: Rule,
|
||||
nonTerminal: NonTerminal
|
||||
): ATNHandle {
|
||||
const rule = nonTerminal.referencedRule
|
||||
const start = atn.ruleToStartState.get(rule)!
|
||||
const left = newState<BasicBlockStartState>(atn, currentRule, nonTerminal, {
|
||||
type: ATN_BASIC
|
||||
})
|
||||
const right = newState<BasicBlockStartState>(atn, currentRule, nonTerminal, {
|
||||
type: ATN_BASIC
|
||||
})
|
||||
|
||||
const call = new RuleTransition(start, rule, right)
|
||||
addTransition(left, call)
|
||||
|
||||
return {
|
||||
left,
|
||||
right
|
||||
}
|
||||
}
|
||||
|
||||
function buildRuleHandle(atn: ATN, rule: Rule, block: ATNHandle): ATNHandle {
|
||||
const start = atn.ruleToStartState.get(rule)!
|
||||
epsilon(start, block.left)
|
||||
const stop = atn.ruleToStopState.get(rule)!
|
||||
epsilon(block.right, stop)
|
||||
const handle: ATNHandle = {
|
||||
left: start,
|
||||
right: stop
|
||||
}
|
||||
return handle
|
||||
}
|
||||
|
||||
function epsilon(a: ATNBaseState, b: ATNBaseState): void {
|
||||
const transition = new EpsilonTransition(b as ATNState)
|
||||
addTransition(a, transition)
|
||||
}
|
||||
|
||||
function newState<T extends ATNState>(
|
||||
atn: ATN,
|
||||
rule: Rule,
|
||||
production: IProductionWithOccurrence | undefined,
|
||||
partial: Partial<T>
|
||||
): T {
|
||||
const t: T = {
|
||||
atn,
|
||||
production,
|
||||
epsilonOnlyTransitions: false,
|
||||
rule,
|
||||
transitions: [],
|
||||
nextTokenWithinRule: [],
|
||||
stateNumber: atn.states.length,
|
||||
...partial
|
||||
} as unknown as T
|
||||
atn.states.push(t)
|
||||
return t
|
||||
}
|
||||
|
||||
function addTransition(state: ATNBaseState, transition: Transition) {
|
||||
// A single ATN state can only contain epsilon transitions or non-epsilon transitions
|
||||
// Because they are never mixed, only setting the property for the first transition is fine
|
||||
if (state.transitions.length === 0) {
|
||||
state.epsilonOnlyTransitions = transition.isEpsilon()
|
||||
}
|
||||
state.transitions.push(transition)
|
||||
}
|
||||
|
||||
function removeState(atn: ATN, state: ATNState): void {
|
||||
atn.states.splice(atn.states.indexOf(state), 1)
|
||||
}
|
||||
78
node_modules/chevrotain-allstar/src/dfa.ts
generated
vendored
Normal file
78
node_modules/chevrotain-allstar/src/dfa.ts
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2022 TypeFox GmbH
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License, which is available in the project root.
|
||||
******************************************************************************/
|
||||
|
||||
import map from "lodash-es/map.js"
|
||||
import { ATNState, DecisionState } from "./atn.js"
|
||||
|
||||
export interface DFA {
|
||||
start?: DFAState
|
||||
states: Record<string, DFAState>
|
||||
decision: number
|
||||
atnStartState: DecisionState
|
||||
}
|
||||
|
||||
export interface DFAState {
|
||||
configs: ATNConfigSet
|
||||
edges: Record<number, DFAState>
|
||||
isAcceptState: boolean
|
||||
prediction: number
|
||||
}
|
||||
|
||||
export const DFA_ERROR = {} as DFAState
|
||||
|
||||
export interface ATNConfig {
|
||||
state: ATNState
|
||||
alt: number
|
||||
stack: ATNState[]
|
||||
}
|
||||
|
||||
export class ATNConfigSet {
|
||||
private map: Record<string, number> = {}
|
||||
private configs: ATNConfig[] = []
|
||||
|
||||
uniqueAlt: number | undefined
|
||||
|
||||
get size(): number {
|
||||
return this.configs.length
|
||||
}
|
||||
|
||||
finalize(): void {
|
||||
// Empties the map to free up memory
|
||||
this.map = {}
|
||||
}
|
||||
|
||||
add(config: ATNConfig): void {
|
||||
const key = getATNConfigKey(config)
|
||||
// Only add configs which don't exist in our map already
|
||||
// While this does not influence the actual algorithm, adding them anyway would massively increase memory consumption
|
||||
if (!(key in this.map)) {
|
||||
this.map[key] = this.configs.length
|
||||
this.configs.push(config)
|
||||
}
|
||||
}
|
||||
|
||||
get elements(): readonly ATNConfig[] {
|
||||
return this.configs
|
||||
}
|
||||
|
||||
get alts(): number[] {
|
||||
return map(this.configs, (e) => e.alt)
|
||||
}
|
||||
|
||||
get key(): string {
|
||||
let value = ""
|
||||
for (const k in this.map) {
|
||||
value += k + ":"
|
||||
}
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
export function getATNConfigKey(config: ATNConfig, alt = true) {
|
||||
return `${alt ? `a${config.alt}` : ""}s${
|
||||
config.state.stateNumber
|
||||
}:${config.stack.map((e) => e.stateNumber.toString()).join("_")}`
|
||||
}
|
||||
11
node_modules/chevrotain-allstar/src/index.ts
generated
vendored
Normal file
11
node_modules/chevrotain-allstar/src/index.ts
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2022 TypeFox GmbH
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License, which is available in the project root.
|
||||
******************************************************************************/
|
||||
|
||||
export {
|
||||
AmbiguityReport,
|
||||
LLStarLookaheadOptions,
|
||||
LLStarLookaheadStrategy
|
||||
} from './all-star-lookahead.js';
|
||||
Reference in New Issue
Block a user