完成世界书、骰子、apiconfig页面处理
This commit is contained in:
1
frontend/node_modules/chevrotain/BREAKING_CHANGES.md
generated
vendored
Normal file
1
frontend/node_modules/chevrotain/BREAKING_CHANGES.md
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
See: https://chevrotain.io/docs/changes/BREAKING_CHANGES.html
|
||||
1
frontend/node_modules/chevrotain/diagrams/README.md
generated
vendored
Normal file
1
frontend/node_modules/chevrotain/diagrams/README.md
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
See [online docs](https://chevrotain.io/docs/guide/generating_syntax_diagrams.html).
|
||||
85
frontend/node_modules/chevrotain/diagrams/diagrams.css
generated
vendored
Normal file
85
frontend/node_modules/chevrotain/diagrams/diagrams.css
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
svg.railroad-diagram path {
|
||||
stroke-width: 3;
|
||||
stroke: black;
|
||||
fill: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
svg.railroad-diagram text {
|
||||
font: bold 14px monospace;
|
||||
text-anchor: middle;
|
||||
}
|
||||
|
||||
svg.railroad-diagram text.label {
|
||||
text-anchor: start;
|
||||
}
|
||||
|
||||
svg.railroad-diagram text.comment {
|
||||
font: italic 12px monospace;
|
||||
}
|
||||
|
||||
svg.railroad-diagram g.non-terminal rect {
|
||||
fill: hsl(223, 100%, 83%);
|
||||
}
|
||||
|
||||
svg.railroad-diagram rect {
|
||||
stroke-width: 3;
|
||||
stroke: black;
|
||||
fill: hsl(190, 100%, 83%);
|
||||
}
|
||||
|
||||
.diagramHeader {
|
||||
display: inline-block;
|
||||
-webkit-touch-callout: default;
|
||||
-webkit-user-select: text;
|
||||
-khtml-user-select: text;
|
||||
-moz-user-select: text;
|
||||
-ms-user-select: text;
|
||||
user-select: text;
|
||||
font-weight: bold;
|
||||
font-family: monospace;
|
||||
font-size: 18px;
|
||||
margin-bottom: -8px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.diagramHeaderDef {
|
||||
background-color: lightgreen;
|
||||
}
|
||||
|
||||
svg.railroad-diagram text {
|
||||
-webkit-touch-callout: default;
|
||||
-webkit-user-select: text;
|
||||
-khtml-user-select: text;
|
||||
-moz-user-select: text;
|
||||
-ms-user-select: text;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
svg.railroad-diagram g.non-terminal rect.diagramRectUsage {
|
||||
color: green;
|
||||
fill: yellow;
|
||||
stroke: 5;
|
||||
}
|
||||
|
||||
svg.railroad-diagram g.terminal rect.diagramRectUsage {
|
||||
color: green;
|
||||
fill: yellow;
|
||||
stroke: 5;
|
||||
}
|
||||
|
||||
div {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
svg.railroad-diagram g.non-terminal text {
|
||||
cursor: pointer;
|
||||
}
|
||||
968
frontend/node_modules/chevrotain/diagrams/vendor/railroad-diagrams.js
generated
vendored
Normal file
968
frontend/node_modules/chevrotain/diagrams/vendor/railroad-diagrams.js
generated
vendored
Normal file
@@ -0,0 +1,968 @@
|
||||
/*
|
||||
Railroad Diagrams
|
||||
by Tab Atkins Jr. (and others)
|
||||
http://xanthir.com
|
||||
http://twitter.com/tabatkins
|
||||
http://github.com/tabatkins/railroad-diagrams
|
||||
|
||||
This document and all associated files in the github project are licensed under CC0: http://creativecommons.org/publicdomain/zero/1.0/
|
||||
This means you can reuse, remix, or otherwise appropriate this project for your own use WITHOUT RESTRICTION.
|
||||
(The actual legal meaning can be found at the above link.)
|
||||
Don't ask me for permission to use any part of this project, JUST USE IT.
|
||||
I would appreciate attribution, but that is not required by the license.
|
||||
*/
|
||||
|
||||
/*
|
||||
This file uses a module pattern to avoid leaking names into the global scope.
|
||||
The only accidental leakage is the name "temp".
|
||||
The exported names can be found at the bottom of this file;
|
||||
simply change the names in the array of strings to change what they are called in your application.
|
||||
|
||||
As well, several configuration constants are passed into the module function at the bottom of this file.
|
||||
At runtime, these constants can be found on the Diagram class.
|
||||
*/
|
||||
|
||||
(function (options) {
|
||||
function subclassOf(baseClass, superClass) {
|
||||
baseClass.prototype = Object.create(superClass.prototype);
|
||||
baseClass.prototype.$super = superClass.prototype;
|
||||
}
|
||||
|
||||
function unnull(/* children */) {
|
||||
return [].slice.call(arguments).reduce(function (sofar, x) {
|
||||
return sofar !== undefined ? sofar : x;
|
||||
});
|
||||
}
|
||||
|
||||
function determineGaps(outer, inner) {
|
||||
var diff = outer - inner;
|
||||
switch (Diagram.INTERNAL_ALIGNMENT) {
|
||||
case "left":
|
||||
return [0, diff];
|
||||
break;
|
||||
case "right":
|
||||
return [diff, 0];
|
||||
break;
|
||||
case "center":
|
||||
default:
|
||||
return [diff / 2, diff / 2];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function wrapString(value) {
|
||||
return typeof value == "string" ? new Terminal(value) : value;
|
||||
}
|
||||
|
||||
function stackAtIllegalPosition(items) {
|
||||
/* The height of the last line of the Stack is determined by the last child and
|
||||
therefore any element outside the Stack could overlap with other elements.
|
||||
If the Stack is the last element no overlap can occur. */
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (items[i] instanceof Stack && i !== items.length - 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function SVG(name, attrs, text) {
|
||||
attrs = attrs || {};
|
||||
text = text || "";
|
||||
var el = document.createElementNS("http://www.w3.org/2000/svg", name);
|
||||
for (var attr in attrs) {
|
||||
if (attr === "xlink:href")
|
||||
el.setAttributeNS("http://www.w3.org/1999/xlink", "href", attrs[attr]);
|
||||
else el.setAttribute(attr, attrs[attr]);
|
||||
}
|
||||
el.textContent = text;
|
||||
return el;
|
||||
}
|
||||
|
||||
function FakeSVG(tagName, attrs, text) {
|
||||
if (!(this instanceof FakeSVG)) return new FakeSVG(tagName, attrs, text);
|
||||
if (text) this.children = text;
|
||||
else this.children = [];
|
||||
this.tagName = tagName;
|
||||
this.attrs = unnull(attrs, {});
|
||||
return this;
|
||||
}
|
||||
FakeSVG.prototype.format = function (x, y, width) {
|
||||
// Virtual
|
||||
};
|
||||
FakeSVG.prototype.addTo = function (parent) {
|
||||
if (parent instanceof FakeSVG) {
|
||||
parent.children.push(this);
|
||||
return this;
|
||||
} else {
|
||||
var svg = this.toSVG();
|
||||
parent.appendChild(svg);
|
||||
return svg;
|
||||
}
|
||||
};
|
||||
FakeSVG.prototype.escapeString = function (string) {
|
||||
// Escape markdown and HTML special characters
|
||||
return string.replace(/[*_\`\[\]<&]/g, function (charString) {
|
||||
return "&#" + charString.charCodeAt(0) + ";";
|
||||
});
|
||||
};
|
||||
FakeSVG.prototype.toSVG = function () {
|
||||
var el = SVG(this.tagName, this.attrs);
|
||||
if (typeof this.children == "string") {
|
||||
el.textContent = this.children;
|
||||
} else {
|
||||
this.children.forEach(function (e) {
|
||||
el.appendChild(e.toSVG());
|
||||
});
|
||||
}
|
||||
return el;
|
||||
};
|
||||
FakeSVG.prototype.toString = function () {
|
||||
var str = "<" + this.tagName;
|
||||
var group = this.tagName == "g" || this.tagName == "svg";
|
||||
for (var attr in this.attrs) {
|
||||
str +=
|
||||
" " +
|
||||
attr +
|
||||
'="' +
|
||||
(this.attrs[attr] + "").replace(/&/g, "&").replace(/"/g, """) +
|
||||
'"';
|
||||
}
|
||||
str += ">";
|
||||
if (group) str += "\n";
|
||||
if (typeof this.children == "string") {
|
||||
str += FakeSVG.prototype.escapeString(this.children);
|
||||
} else {
|
||||
this.children.forEach(function (e) {
|
||||
str += e;
|
||||
});
|
||||
}
|
||||
str += "</" + this.tagName + ">\n";
|
||||
return str;
|
||||
};
|
||||
|
||||
function Path(x, y) {
|
||||
if (!(this instanceof Path)) return new Path(x, y);
|
||||
FakeSVG.call(this, "path");
|
||||
this.attrs.d = "M" + x + " " + y;
|
||||
}
|
||||
subclassOf(Path, FakeSVG);
|
||||
Path.prototype.m = function (x, y) {
|
||||
this.attrs.d += "m" + x + " " + y;
|
||||
return this;
|
||||
};
|
||||
Path.prototype.h = function (val) {
|
||||
this.attrs.d += "h" + val;
|
||||
return this;
|
||||
};
|
||||
Path.prototype.right = Path.prototype.h;
|
||||
Path.prototype.left = function (val) {
|
||||
return this.h(-val);
|
||||
};
|
||||
Path.prototype.v = function (val) {
|
||||
this.attrs.d += "v" + val;
|
||||
return this;
|
||||
};
|
||||
Path.prototype.down = Path.prototype.v;
|
||||
Path.prototype.up = function (val) {
|
||||
return this.v(-val);
|
||||
};
|
||||
Path.prototype.arc = function (sweep) {
|
||||
var x = Diagram.ARC_RADIUS;
|
||||
var y = Diagram.ARC_RADIUS;
|
||||
if (sweep[0] == "e" || sweep[1] == "w") {
|
||||
x *= -1;
|
||||
}
|
||||
if (sweep[0] == "s" || sweep[1] == "n") {
|
||||
y *= -1;
|
||||
}
|
||||
if (sweep == "ne" || sweep == "es" || sweep == "sw" || sweep == "wn") {
|
||||
var cw = 1;
|
||||
} else {
|
||||
var cw = 0;
|
||||
}
|
||||
this.attrs.d +=
|
||||
"a" +
|
||||
Diagram.ARC_RADIUS +
|
||||
" " +
|
||||
Diagram.ARC_RADIUS +
|
||||
" 0 0 " +
|
||||
cw +
|
||||
" " +
|
||||
x +
|
||||
" " +
|
||||
y;
|
||||
return this;
|
||||
};
|
||||
Path.prototype.format = function () {
|
||||
// All paths in this library start/end horizontally.
|
||||
// The extra .5 ensures a minor overlap, so there's no seams in bad rasterizers.
|
||||
this.attrs.d += "h.5";
|
||||
return this;
|
||||
};
|
||||
|
||||
function Diagram(items) {
|
||||
if (!(this instanceof Diagram))
|
||||
return new Diagram([].slice.call(arguments));
|
||||
FakeSVG.call(this, "svg", { class: Diagram.DIAGRAM_CLASS });
|
||||
if (stackAtIllegalPosition(items)) {
|
||||
throw new RangeError(
|
||||
"Stack() must only occur at the very last position of Diagram().",
|
||||
);
|
||||
}
|
||||
this.items = items.map(wrapString);
|
||||
this.items.unshift(new Start());
|
||||
this.items.push(new End());
|
||||
this.width =
|
||||
this.items.reduce(function (sofar, el) {
|
||||
return sofar + el.width + (el.needsSpace ? 20 : 0);
|
||||
}, 0) + 1;
|
||||
this.height = this.items.reduce(function (sofar, el) {
|
||||
return sofar + el.height;
|
||||
}, 0);
|
||||
this.up = Math.max.apply(
|
||||
null,
|
||||
this.items.map(function (x) {
|
||||
return x.up;
|
||||
}),
|
||||
);
|
||||
this.down = Math.max.apply(
|
||||
null,
|
||||
this.items.map(function (x) {
|
||||
return x.down;
|
||||
}),
|
||||
);
|
||||
this.formatted = false;
|
||||
}
|
||||
subclassOf(Diagram, FakeSVG);
|
||||
for (var option in options) {
|
||||
Diagram[option] = options[option];
|
||||
}
|
||||
Diagram.prototype.format = function (paddingt, paddingr, paddingb, paddingl) {
|
||||
paddingt = unnull(paddingt, 20);
|
||||
paddingr = unnull(paddingr, paddingt, 20);
|
||||
paddingb = unnull(paddingb, paddingt, 20);
|
||||
paddingl = unnull(paddingl, paddingr, 20);
|
||||
var x = paddingl;
|
||||
var y = paddingt;
|
||||
y += this.up;
|
||||
var g = FakeSVG(
|
||||
"g",
|
||||
Diagram.STROKE_ODD_PIXEL_LENGTH ? { transform: "translate(.5 .5)" } : {},
|
||||
);
|
||||
for (var i = 0; i < this.items.length; i++) {
|
||||
var item = this.items[i];
|
||||
if (item.needsSpace) {
|
||||
Path(x, y).h(10).addTo(g);
|
||||
x += 10;
|
||||
}
|
||||
item.format(x, y, item.width + item.offsetX).addTo(g);
|
||||
x += item.width + item.offsetX;
|
||||
y += item.height;
|
||||
if (item.needsSpace) {
|
||||
Path(x, y).h(10).addTo(g);
|
||||
x += 10;
|
||||
}
|
||||
}
|
||||
this.attrs.width = this.width + paddingl + paddingr;
|
||||
this.attrs.height = this.up + this.height + this.down + paddingt + paddingb;
|
||||
this.attrs.viewBox = "0 0 " + this.attrs.width + " " + this.attrs.height;
|
||||
g.addTo(this);
|
||||
this.formatted = true;
|
||||
return this;
|
||||
};
|
||||
Diagram.prototype.addTo = function (parent) {
|
||||
var scriptTag = document.getElementsByTagName("script");
|
||||
scriptTag = scriptTag[scriptTag.length - 1];
|
||||
var parentTag = scriptTag.parentNode;
|
||||
parent = parent || parentTag;
|
||||
return this.$super.addTo.call(this, parent);
|
||||
};
|
||||
Diagram.prototype.toSVG = function () {
|
||||
if (!this.formatted) {
|
||||
this.format();
|
||||
}
|
||||
return this.$super.toSVG.call(this);
|
||||
};
|
||||
Diagram.prototype.toString = function () {
|
||||
if (!this.formatted) {
|
||||
this.format();
|
||||
}
|
||||
return this.$super.toString.call(this);
|
||||
};
|
||||
|
||||
function ComplexDiagram() {
|
||||
var diagram = new Diagram([].slice.call(arguments));
|
||||
var items = diagram.items;
|
||||
items.shift();
|
||||
items.pop();
|
||||
items.unshift(new Start(false));
|
||||
items.push(new End(false));
|
||||
diagram.items = items;
|
||||
return diagram;
|
||||
}
|
||||
|
||||
function Sequence(items) {
|
||||
if (!(this instanceof Sequence))
|
||||
return new Sequence([].slice.call(arguments));
|
||||
FakeSVG.call(this, "g");
|
||||
if (stackAtIllegalPosition(items)) {
|
||||
throw new RangeError(
|
||||
"Stack() must only occur at the very last position of Sequence().",
|
||||
);
|
||||
}
|
||||
this.items = items.map(wrapString);
|
||||
this.width = this.items.reduce(function (sofar, el) {
|
||||
return sofar + el.width + (el.needsSpace ? 20 : 0);
|
||||
}, 0);
|
||||
this.offsetX = 0;
|
||||
this.height = this.items.reduce(function (sofar, el) {
|
||||
return sofar + el.height;
|
||||
}, 0);
|
||||
this.up = this.items.reduce(function (sofar, el) {
|
||||
return Math.max(sofar, el.up);
|
||||
}, 0);
|
||||
this.down = this.items.reduce(function (sofar, el) {
|
||||
return Math.max(sofar, el.down);
|
||||
}, 0);
|
||||
}
|
||||
subclassOf(Sequence, FakeSVG);
|
||||
Sequence.prototype.format = function (x, y, width) {
|
||||
// Hook up the two sides if this is narrower than its stated width.
|
||||
var gaps = determineGaps(width, this.width);
|
||||
Path(x, y).h(gaps[0]).addTo(this);
|
||||
Path(x + gaps[0] + this.width, y + this.height)
|
||||
.h(gaps[1])
|
||||
.addTo(this);
|
||||
x += gaps[0];
|
||||
|
||||
for (var i = 0; i < this.items.length; i++) {
|
||||
var item = this.items[i];
|
||||
if (item.needsSpace) {
|
||||
Path(x, y).h(10).addTo(this);
|
||||
x += 10;
|
||||
}
|
||||
item.format(x, y, item.width).addTo(this);
|
||||
x += item.width;
|
||||
y += item.height;
|
||||
if (item.needsSpace) {
|
||||
Path(x, y).h(10).addTo(this);
|
||||
x += 10;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
function Stack(items) {
|
||||
if (!(this instanceof Stack)) return new Stack([].slice.call(arguments));
|
||||
FakeSVG.call(this, "g");
|
||||
if (stackAtIllegalPosition(items)) {
|
||||
throw new RangeError(
|
||||
"Stack() must only occur at the very last position of Stack().",
|
||||
);
|
||||
}
|
||||
if (items.length === 0) {
|
||||
throw new RangeError("Stack() must have at least one child.");
|
||||
}
|
||||
this.items = items.map(wrapString);
|
||||
this.width = this.items.reduce(function (sofar, el) {
|
||||
return Math.max(sofar, el.width + (el.needsSpace ? 20 : 0));
|
||||
}, 0);
|
||||
if (this.items.length > 1) {
|
||||
this.width += Diagram.ARC_RADIUS * 2;
|
||||
}
|
||||
|
||||
this.up = this.items[0].up;
|
||||
this.down = this.items[this.items.length - 1].down;
|
||||
|
||||
this.height = 0;
|
||||
for (var i = 0; i < this.items.length; i++) {
|
||||
this.height += this.items[i].height;
|
||||
if (i !== this.items.length - 1) {
|
||||
this.height +=
|
||||
Math.max(this.items[i].down, Diagram.VERTICAL_SEPARATION) +
|
||||
Math.max(this.items[i + 1].up, Diagram.VERTICAL_SEPARATION) +
|
||||
Diagram.ARC_RADIUS * 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.items.length === 0) {
|
||||
this.offsetX = 0;
|
||||
} else {
|
||||
// the value is usually negative because the linebreak resets the x value for the next element
|
||||
this.offsetX = -(
|
||||
this.width -
|
||||
this.items[this.items.length - 1].width -
|
||||
this.items[this.items.length - 1].offsetX -
|
||||
(this.items[this.items.length - 1].needsSpace ? 20 : 0)
|
||||
);
|
||||
if (this.items.length > 1) {
|
||||
this.offsetX += Diagram.ARC_RADIUS * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
subclassOf(Stack, FakeSVG);
|
||||
Stack.prototype.format = function (x, y, width) {
|
||||
var xIntitial = x;
|
||||
|
||||
for (var i = 0; i < this.items.length; i++) {
|
||||
var item = this.items[i];
|
||||
if (item.needsSpace) {
|
||||
Path(x, y).h(10).addTo(this);
|
||||
x += 10;
|
||||
}
|
||||
item
|
||||
.format(
|
||||
x,
|
||||
y,
|
||||
Math.max(item.width + item.offsetX, Diagram.ARC_RADIUS * 2),
|
||||
)
|
||||
.addTo(this);
|
||||
x += Math.max(item.width + item.offsetX, Diagram.ARC_RADIUS * 2);
|
||||
y += item.height;
|
||||
if (item.needsSpace) {
|
||||
Path(x, y).h(10).addTo(this);
|
||||
x += 10;
|
||||
}
|
||||
|
||||
if (i !== this.items.length - 1) {
|
||||
Path(x, y)
|
||||
.arc("ne")
|
||||
.down(Math.max(item.down, Diagram.VERTICAL_SEPARATION))
|
||||
.arc("es")
|
||||
.left(x - xIntitial - Diagram.ARC_RADIUS * 2)
|
||||
.arc("nw")
|
||||
.down(Math.max(this.items[i + 1].up, Diagram.VERTICAL_SEPARATION))
|
||||
.arc("ws")
|
||||
.addTo(this);
|
||||
|
||||
y +=
|
||||
Math.max(item.down, Diagram.VERTICAL_SEPARATION) +
|
||||
Math.max(this.items[i + 1].up, Diagram.VERTICAL_SEPARATION) +
|
||||
Diagram.ARC_RADIUS * 4;
|
||||
x = xIntitial + Diagram.ARC_RADIUS * 2;
|
||||
}
|
||||
}
|
||||
|
||||
Path(x, y)
|
||||
.h(width - (this.width + this.offsetX))
|
||||
.addTo(this);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
function Choice(normal, items) {
|
||||
if (!(this instanceof Choice))
|
||||
return new Choice(normal, [].slice.call(arguments, 1));
|
||||
FakeSVG.call(this, "g");
|
||||
if (typeof normal !== "number" || normal !== Math.floor(normal)) {
|
||||
throw new TypeError("The first argument of Choice() must be an integer.");
|
||||
} else if (normal < 0 || normal >= items.length) {
|
||||
throw new RangeError(
|
||||
"The first argument of Choice() must be an index for one of the items.",
|
||||
);
|
||||
} else {
|
||||
this.normal = normal;
|
||||
}
|
||||
this.items = items.map(wrapString);
|
||||
this.width =
|
||||
this.items.reduce(function (sofar, el) {
|
||||
return Math.max(sofar, el.width);
|
||||
}, 0) +
|
||||
Diagram.ARC_RADIUS * 4;
|
||||
this.offsetX = 0;
|
||||
this.height = this.items[normal].height;
|
||||
this.up = this.down = 0;
|
||||
for (var i = 0; i < this.items.length; i++) {
|
||||
var item = this.items[i];
|
||||
if (i < normal) {
|
||||
this.up += Math.max(
|
||||
Diagram.ARC_RADIUS,
|
||||
item.up + item.height + item.down + Diagram.VERTICAL_SEPARATION,
|
||||
);
|
||||
}
|
||||
if (i == normal) {
|
||||
this.up += Math.max(Diagram.ARC_RADIUS, item.up);
|
||||
this.down += Math.max(Diagram.ARC_RADIUS, item.down);
|
||||
}
|
||||
if (i > normal) {
|
||||
this.down += Math.max(
|
||||
Diagram.ARC_RADIUS,
|
||||
Diagram.VERTICAL_SEPARATION + item.up + item.down + item.height,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
subclassOf(Choice, FakeSVG);
|
||||
Choice.prototype.format = function (x, y, width) {
|
||||
// Hook up the two sides if this is narrower than its stated width.
|
||||
var gaps = determineGaps(width, this.width);
|
||||
Path(x, y).h(gaps[0]).addTo(this);
|
||||
Path(x + gaps[0] + this.width, y + this.height)
|
||||
.h(gaps[1])
|
||||
.addTo(this);
|
||||
x += gaps[0];
|
||||
|
||||
var last = this.items.length - 1;
|
||||
var innerWidth = this.width - Diagram.ARC_RADIUS * 4;
|
||||
|
||||
// Do the elements that curve above
|
||||
for (var i = this.normal - 1; i >= 0; i--) {
|
||||
var item = this.items[i];
|
||||
if (i == this.normal - 1) {
|
||||
var distanceFromY = Math.max(
|
||||
Diagram.ARC_RADIUS * 2,
|
||||
this.items[i + 1].up +
|
||||
Diagram.VERTICAL_SEPARATION +
|
||||
item.height +
|
||||
item.down,
|
||||
);
|
||||
}
|
||||
Path(x, y)
|
||||
.arc("se")
|
||||
.up(distanceFromY - Diagram.ARC_RADIUS * 2)
|
||||
.arc("wn")
|
||||
.addTo(this);
|
||||
item
|
||||
.format(x + Diagram.ARC_RADIUS * 2, y - distanceFromY, innerWidth)
|
||||
.addTo(this);
|
||||
Path(
|
||||
x + Diagram.ARC_RADIUS * 2 + innerWidth,
|
||||
y - distanceFromY + item.height,
|
||||
)
|
||||
.arc("ne")
|
||||
.down(
|
||||
distanceFromY -
|
||||
item.height +
|
||||
this.items[this.normal].height -
|
||||
Diagram.ARC_RADIUS * 2,
|
||||
)
|
||||
.arc("ws")
|
||||
.addTo(this);
|
||||
distanceFromY += Math.max(
|
||||
Diagram.ARC_RADIUS,
|
||||
item.up +
|
||||
Diagram.VERTICAL_SEPARATION +
|
||||
(i == 0 ? 0 : this.items[i - 1].down + this.items[i - 1].height),
|
||||
);
|
||||
}
|
||||
|
||||
// Do the straight-line path.
|
||||
Path(x, y)
|
||||
.right(Diagram.ARC_RADIUS * 2)
|
||||
.addTo(this);
|
||||
this.items[this.normal]
|
||||
.format(x + Diagram.ARC_RADIUS * 2, y, innerWidth)
|
||||
.addTo(this);
|
||||
Path(x + Diagram.ARC_RADIUS * 2 + innerWidth, y + this.height)
|
||||
.right(Diagram.ARC_RADIUS * 2)
|
||||
.addTo(this);
|
||||
|
||||
// Do the elements that curve below
|
||||
for (var i = this.normal + 1; i <= last; i++) {
|
||||
var item = this.items[i];
|
||||
if (i == this.normal + 1) {
|
||||
var distanceFromY = Math.max(
|
||||
Diagram.ARC_RADIUS * 2,
|
||||
this.items[i - 1].height +
|
||||
this.items[i - 1].down +
|
||||
Diagram.VERTICAL_SEPARATION +
|
||||
item.up,
|
||||
);
|
||||
}
|
||||
Path(x, y)
|
||||
.arc("ne")
|
||||
.down(distanceFromY - Diagram.ARC_RADIUS * 2)
|
||||
.arc("ws")
|
||||
.addTo(this);
|
||||
item
|
||||
.format(x + Diagram.ARC_RADIUS * 2, y + distanceFromY, innerWidth)
|
||||
.addTo(this);
|
||||
Path(
|
||||
x + Diagram.ARC_RADIUS * 2 + innerWidth,
|
||||
y + distanceFromY + item.height,
|
||||
)
|
||||
.arc("se")
|
||||
.up(
|
||||
distanceFromY -
|
||||
Diagram.ARC_RADIUS * 2 +
|
||||
item.height -
|
||||
this.items[this.normal].height,
|
||||
)
|
||||
.arc("wn")
|
||||
.addTo(this);
|
||||
distanceFromY += Math.max(
|
||||
Diagram.ARC_RADIUS,
|
||||
item.height +
|
||||
item.down +
|
||||
Diagram.VERTICAL_SEPARATION +
|
||||
(i == last ? 0 : this.items[i + 1].up),
|
||||
);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
function Optional(item, skip) {
|
||||
if (skip === undefined) return Choice(1, Skip(), item);
|
||||
else if (skip === "skip") return Choice(0, Skip(), item);
|
||||
else throw "Unknown value for Optional()'s 'skip' argument.";
|
||||
}
|
||||
|
||||
function OneOrMore(item, rep) {
|
||||
if (!(this instanceof OneOrMore)) return new OneOrMore(item, rep);
|
||||
FakeSVG.call(this, "g");
|
||||
rep = rep || new Skip();
|
||||
this.item = wrapString(item);
|
||||
this.rep = wrapString(rep);
|
||||
this.width =
|
||||
Math.max(this.item.width, this.rep.width) + Diagram.ARC_RADIUS * 2;
|
||||
this.offsetX = 0;
|
||||
this.height = this.item.height;
|
||||
this.up = this.item.up;
|
||||
this.down = Math.max(
|
||||
Diagram.ARC_RADIUS * 2,
|
||||
this.item.down +
|
||||
Diagram.VERTICAL_SEPARATION +
|
||||
this.rep.up +
|
||||
this.rep.height +
|
||||
this.rep.down,
|
||||
);
|
||||
}
|
||||
subclassOf(OneOrMore, FakeSVG);
|
||||
OneOrMore.prototype.needsSpace = true;
|
||||
OneOrMore.prototype.format = function (x, y, width) {
|
||||
// Hook up the two sides if this is narrower than its stated width.
|
||||
var gaps = determineGaps(width, this.width);
|
||||
Path(x, y).h(gaps[0]).addTo(this);
|
||||
Path(x + gaps[0] + this.width, y + this.height)
|
||||
.h(gaps[1])
|
||||
.addTo(this);
|
||||
x += gaps[0];
|
||||
|
||||
// Draw item
|
||||
Path(x, y).right(Diagram.ARC_RADIUS).addTo(this);
|
||||
this.item
|
||||
.format(x + Diagram.ARC_RADIUS, y, this.width - Diagram.ARC_RADIUS * 2)
|
||||
.addTo(this);
|
||||
Path(x + this.width - Diagram.ARC_RADIUS, y + this.height)
|
||||
.right(Diagram.ARC_RADIUS)
|
||||
.addTo(this);
|
||||
|
||||
// Draw repeat arc
|
||||
var distanceFromY = Math.max(
|
||||
Diagram.ARC_RADIUS * 2,
|
||||
this.item.height +
|
||||
this.item.down +
|
||||
Diagram.VERTICAL_SEPARATION +
|
||||
this.rep.up,
|
||||
);
|
||||
Path(x + Diagram.ARC_RADIUS, y)
|
||||
.arc("nw")
|
||||
.down(distanceFromY - Diagram.ARC_RADIUS * 2)
|
||||
.arc("ws")
|
||||
.addTo(this);
|
||||
this.rep
|
||||
.format(
|
||||
x + Diagram.ARC_RADIUS,
|
||||
y + distanceFromY,
|
||||
this.width - Diagram.ARC_RADIUS * 2,
|
||||
)
|
||||
.addTo(this);
|
||||
Path(
|
||||
x + this.width - Diagram.ARC_RADIUS,
|
||||
y + distanceFromY + this.rep.height,
|
||||
)
|
||||
.arc("se")
|
||||
.up(
|
||||
distanceFromY -
|
||||
Diagram.ARC_RADIUS * 2 +
|
||||
this.rep.height -
|
||||
this.item.height,
|
||||
)
|
||||
.arc("en")
|
||||
.addTo(this);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
function ZeroOrMore(item, rep, skip) {
|
||||
return Optional(OneOrMore(item, rep), skip);
|
||||
}
|
||||
|
||||
function Start(simpleType) {
|
||||
if (!(this instanceof Start)) return new Start();
|
||||
FakeSVG.call(this, "path");
|
||||
this.width = 20;
|
||||
this.height = 0;
|
||||
this.offsetX = 0;
|
||||
this.up = 10;
|
||||
this.down = 10;
|
||||
this.simpleType = simpleType;
|
||||
}
|
||||
subclassOf(Start, FakeSVG);
|
||||
Start.prototype.format = function (x, y) {
|
||||
if (this.simpleType === false) {
|
||||
this.attrs.d = "M " + x + " " + (y - 10) + " v 20 m 0 -10 h 20.5";
|
||||
} else {
|
||||
this.attrs.d =
|
||||
"M " + x + " " + (y - 10) + " v 20 m 10 -20 v 20 m -10 -10 h 20.5";
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
function End(simpleType) {
|
||||
if (!(this instanceof End)) return new End();
|
||||
FakeSVG.call(this, "path");
|
||||
this.width = 20;
|
||||
this.height = 0;
|
||||
this.offsetX = 0;
|
||||
this.up = 10;
|
||||
this.down = 10;
|
||||
this.simpleType = simpleType;
|
||||
}
|
||||
subclassOf(End, FakeSVG);
|
||||
End.prototype.format = function (x, y) {
|
||||
if (this.simpleType === false) {
|
||||
this.attrs.d = "M " + x + " " + y + " h 20 m 0 -10 v 20";
|
||||
} else {
|
||||
this.attrs.d = "M " + x + " " + y + " h 20 m -10 -10 v 20 m 10 -20 v 20";
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
function Terminal(
|
||||
text,
|
||||
href,
|
||||
title,
|
||||
occurrenceIdx,
|
||||
topRuleName,
|
||||
dslRuleName,
|
||||
tokenName,
|
||||
) {
|
||||
if (!(this instanceof Terminal))
|
||||
return new Terminal(
|
||||
text,
|
||||
href,
|
||||
title,
|
||||
occurrenceIdx,
|
||||
topRuleName,
|
||||
dslRuleName,
|
||||
tokenName,
|
||||
);
|
||||
FakeSVG.call(this, "g", { class: "terminal" });
|
||||
this.text = text;
|
||||
this.label = text;
|
||||
this.href = href;
|
||||
this.title = title;
|
||||
this.occurrenceIdx = occurrenceIdx;
|
||||
this.topRuleName = topRuleName;
|
||||
this.dslRuleName = dslRuleName;
|
||||
this.tokenName = tokenName;
|
||||
this.width =
|
||||
text.length * 8 +
|
||||
20; /* Assume that each char is .5em, and that the em is 16px */
|
||||
this.height = 0;
|
||||
this.offsetX = 0;
|
||||
this.up = 11;
|
||||
this.down = 11;
|
||||
}
|
||||
subclassOf(Terminal, FakeSVG);
|
||||
Terminal.prototype.needsSpace = true;
|
||||
Terminal.prototype.format = function (x, y, width) {
|
||||
// Hook up the two sides if this is narrower than its stated width.
|
||||
var gaps = determineGaps(width, this.width);
|
||||
Path(x, y).h(gaps[0]).addTo(this);
|
||||
Path(x + gaps[0] + this.width, y)
|
||||
.h(gaps[1])
|
||||
.addTo(this);
|
||||
x += gaps[0];
|
||||
|
||||
FakeSVG("rect", {
|
||||
x: x,
|
||||
y: y - 11,
|
||||
width: this.width,
|
||||
height: this.up + this.down,
|
||||
rx: 10,
|
||||
ry: 10,
|
||||
}).addTo(this);
|
||||
|
||||
var text = FakeSVG(
|
||||
"text",
|
||||
{
|
||||
x: x + this.width / 2,
|
||||
y: y + 4,
|
||||
occurrenceIdx: this.occurrenceIdx,
|
||||
topRuleName: this.topRuleName,
|
||||
dslRuleName: this.dslRuleName,
|
||||
tokenName: this.tokenName,
|
||||
label: this.label,
|
||||
},
|
||||
this.text,
|
||||
);
|
||||
var title = FakeSVG("title", {}, this.title);
|
||||
if (this.href)
|
||||
FakeSVG("a", { "xlink:href": this.href }, [text]).addTo(this);
|
||||
else {
|
||||
text.addTo(this);
|
||||
if (this.title !== undefined) {
|
||||
title.addTo(this);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
function NonTerminal(text, href, occurrenceIdx, topRuleName) {
|
||||
if (!(this instanceof NonTerminal))
|
||||
return new NonTerminal(text, href, occurrenceIdx, topRuleName);
|
||||
FakeSVG.call(this, "g", { class: "non-terminal" });
|
||||
this.text = text;
|
||||
this.ruleName = text;
|
||||
this.href = href;
|
||||
this.occurrenceIdx = occurrenceIdx;
|
||||
this.topRuleName = topRuleName;
|
||||
this.width = text.length * 8 + 20;
|
||||
this.height = 0;
|
||||
this.offsetX = 0;
|
||||
this.up = 11;
|
||||
this.down = 11;
|
||||
}
|
||||
subclassOf(NonTerminal, FakeSVG);
|
||||
NonTerminal.prototype.needsSpace = true;
|
||||
NonTerminal.prototype.format = function (x, y, width) {
|
||||
// Hook up the two sides if this is narrower than its stated width.
|
||||
var gaps = determineGaps(width, this.width);
|
||||
Path(x, y).h(gaps[0]).addTo(this);
|
||||
Path(x + gaps[0] + this.width, y)
|
||||
.h(gaps[1])
|
||||
.addTo(this);
|
||||
x += gaps[0];
|
||||
|
||||
FakeSVG("rect", {
|
||||
x: x,
|
||||
y: y - 11,
|
||||
width: this.width,
|
||||
height: this.up + this.down,
|
||||
}).addTo(this);
|
||||
var text = FakeSVG(
|
||||
"text",
|
||||
{
|
||||
x: x + this.width / 2,
|
||||
y: y + 4,
|
||||
occurrenceIdx: this.occurrenceIdx,
|
||||
topRuleName: this.topRuleName,
|
||||
ruleName: this.ruleName,
|
||||
},
|
||||
this.text,
|
||||
);
|
||||
if (this.href)
|
||||
FakeSVG("a", { "xlink:href": this.href }, [text]).addTo(this);
|
||||
else text.addTo(this);
|
||||
return this;
|
||||
};
|
||||
|
||||
function Comment(text) {
|
||||
if (!(this instanceof Comment)) return new Comment(text);
|
||||
FakeSVG.call(this, "g");
|
||||
this.text = text;
|
||||
this.width = text.length * 7 + 10;
|
||||
this.height = 0;
|
||||
this.offsetX = 0;
|
||||
this.up = 11;
|
||||
this.down = 11;
|
||||
}
|
||||
subclassOf(Comment, FakeSVG);
|
||||
Comment.prototype.needsSpace = true;
|
||||
Comment.prototype.format = function (x, y, width) {
|
||||
// Hook up the two sides if this is narrower than its stated width.
|
||||
var gaps = determineGaps(width, this.width);
|
||||
Path(x, y).h(gaps[0]).addTo(this);
|
||||
Path(x + gaps[0] + this.width, y + this.height)
|
||||
.h(gaps[1])
|
||||
.addTo(this);
|
||||
x += gaps[0];
|
||||
|
||||
FakeSVG(
|
||||
"text",
|
||||
{
|
||||
x: x + this.width / 2,
|
||||
y: y + 5,
|
||||
class: "comment",
|
||||
},
|
||||
this.text,
|
||||
).addTo(this);
|
||||
return this;
|
||||
};
|
||||
|
||||
function Skip() {
|
||||
if (!(this instanceof Skip)) return new Skip();
|
||||
FakeSVG.call(this, "g");
|
||||
this.width = 0;
|
||||
this.height = 0;
|
||||
this.offsetX = 0;
|
||||
this.up = 0;
|
||||
this.down = 0;
|
||||
}
|
||||
subclassOf(Skip, FakeSVG);
|
||||
Skip.prototype.format = function (x, y, width) {
|
||||
Path(x, y).right(width).addTo(this);
|
||||
return this;
|
||||
};
|
||||
|
||||
var root;
|
||||
if (typeof define === "function" && define.amd) {
|
||||
// AMD. Register as an anonymous module.
|
||||
root = {};
|
||||
define([], function () {
|
||||
return root;
|
||||
});
|
||||
} else if (typeof exports === "object") {
|
||||
// CommonJS for node
|
||||
root = exports;
|
||||
} else {
|
||||
// Browser globals (root is window.railroad)
|
||||
this.railroad = {};
|
||||
root = this.railroad;
|
||||
}
|
||||
|
||||
var temp = [
|
||||
Diagram,
|
||||
ComplexDiagram,
|
||||
Sequence,
|
||||
Stack,
|
||||
Choice,
|
||||
Optional,
|
||||
OneOrMore,
|
||||
ZeroOrMore,
|
||||
Terminal,
|
||||
NonTerminal,
|
||||
Comment,
|
||||
Skip,
|
||||
];
|
||||
/*
|
||||
These are the names that the internal classes are exported as.
|
||||
If you would like different names, adjust them here.
|
||||
*/
|
||||
[
|
||||
"Diagram",
|
||||
"ComplexDiagram",
|
||||
"Sequence",
|
||||
"Stack",
|
||||
"Choice",
|
||||
"Optional",
|
||||
"OneOrMore",
|
||||
"ZeroOrMore",
|
||||
"Terminal",
|
||||
"NonTerminal",
|
||||
"Comment",
|
||||
"Skip",
|
||||
].forEach(function (e, i) {
|
||||
root[e] = temp[i];
|
||||
});
|
||||
}).call(this, {
|
||||
VERTICAL_SEPARATION: 8,
|
||||
ARC_RADIUS: 10,
|
||||
DIAGRAM_CLASS: "railroad-diagram",
|
||||
STROKE_ODD_PIXEL_LENGTH: true,
|
||||
INTERNAL_ALIGNMENT: "center",
|
||||
});
|
||||
9620
frontend/node_modules/chevrotain/lib/chevrotain.mjs
generated
vendored
Normal file
9620
frontend/node_modules/chevrotain/lib/chevrotain.mjs
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
10
frontend/node_modules/chevrotain/lib/src/lang/lang_extensions.js
generated
vendored
Normal file
10
frontend/node_modules/chevrotain/lib/src/lang/lang_extensions.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
const NAME = "name";
|
||||
export function defineNameProp(obj, nameValue) {
|
||||
Object.defineProperty(obj, NAME, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: false,
|
||||
value: nameValue,
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=lang_extensions.js.map
|
||||
1
frontend/node_modules/chevrotain/lib/src/parse/constants.js.map
generated
vendored
Normal file
1
frontend/node_modules/chevrotain/lib/src/parse/constants.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/parse/constants.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,MAAM,CAAC,MAAM,EAAE,GAAG,QAAQ,CAAC"}
|
||||
56
frontend/node_modules/chevrotain/lib/src/parse/grammar/first.js
generated
vendored
Normal file
56
frontend/node_modules/chevrotain/lib/src/parse/grammar/first.js
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
import { flatten, map, uniq } from "lodash-es";
|
||||
import { isBranchingProd, isOptionalProd, isSequenceProd, NonTerminal, Terminal, } from "@chevrotain/gast";
|
||||
export function first(prod) {
|
||||
/* istanbul ignore else */
|
||||
if (prod instanceof NonTerminal) {
|
||||
// this could in theory cause infinite loops if
|
||||
// (1) prod A refs prod B.
|
||||
// (2) prod B refs prod A
|
||||
// (3) AB can match the empty set
|
||||
// in other words a cycle where everything is optional so the first will keep
|
||||
// looking ahead for the next optional part and will never exit
|
||||
// currently there is no safeguard for this unique edge case because
|
||||
// (1) not sure a grammar in which this can happen is useful for anything (productive)
|
||||
return first(prod.referencedRule);
|
||||
}
|
||||
else if (prod instanceof Terminal) {
|
||||
return firstForTerminal(prod);
|
||||
}
|
||||
else if (isSequenceProd(prod)) {
|
||||
return firstForSequence(prod);
|
||||
}
|
||||
else if (isBranchingProd(prod)) {
|
||||
return firstForBranching(prod);
|
||||
}
|
||||
else {
|
||||
throw Error("non exhaustive match");
|
||||
}
|
||||
}
|
||||
export function firstForSequence(prod) {
|
||||
let firstSet = [];
|
||||
const seq = prod.definition;
|
||||
let nextSubProdIdx = 0;
|
||||
let hasInnerProdsRemaining = seq.length > nextSubProdIdx;
|
||||
let currSubProd;
|
||||
// so we enter the loop at least once (if the definition is not empty
|
||||
let isLastInnerProdOptional = true;
|
||||
// scan a sequence until it's end or until we have found a NONE optional production in it
|
||||
while (hasInnerProdsRemaining && isLastInnerProdOptional) {
|
||||
currSubProd = seq[nextSubProdIdx];
|
||||
isLastInnerProdOptional = isOptionalProd(currSubProd);
|
||||
firstSet = firstSet.concat(first(currSubProd));
|
||||
nextSubProdIdx = nextSubProdIdx + 1;
|
||||
hasInnerProdsRemaining = seq.length > nextSubProdIdx;
|
||||
}
|
||||
return uniq(firstSet);
|
||||
}
|
||||
export function firstForBranching(prod) {
|
||||
const allAlternativesFirsts = map(prod.definition, (innerProd) => {
|
||||
return first(innerProd);
|
||||
});
|
||||
return uniq(flatten(allAlternativesFirsts));
|
||||
}
|
||||
export function firstForTerminal(terminal) {
|
||||
return [terminal.terminalType];
|
||||
}
|
||||
//# sourceMappingURL=first.js.map
|
||||
1
frontend/node_modules/chevrotain/lib/src/parse/grammar/first.js.map
generated
vendored
Normal file
1
frontend/node_modules/chevrotain/lib/src/parse/grammar/first.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"first.js","sourceRoot":"","sources":["../../../../src/parse/grammar/first.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EACL,eAAe,EACf,cAAc,EACd,cAAc,EACd,WAAW,EACX,QAAQ,GACT,MAAM,kBAAkB,CAAC;AAG1B,MAAM,UAAU,KAAK,CAAC,IAAiB;IACrC,0BAA0B;IAC1B,IAAI,IAAI,YAAY,WAAW,EAAE,CAAC;QAChC,+CAA+C;QAC/C,0BAA0B;QAC1B,yBAAyB;QACzB,iCAAiC;QACjC,6EAA6E;QAC7E,+DAA+D;QAC/D,oEAAoE;QACpE,sFAAsF;QACtF,OAAO,KAAK,CAAe,IAAK,CAAC,cAAc,CAAC,CAAC;IACnD,CAAC;SAAM,IAAI,IAAI,YAAY,QAAQ,EAAE,CAAC;QACpC,OAAO,gBAAgB,CAAW,IAAI,CAAC,CAAC;IAC1C,CAAC;SAAM,IAAI,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;SAAM,IAAI,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;QACjC,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;SAAM,CAAC;QACN,MAAM,KAAK,CAAC,sBAAsB,CAAC,CAAC;IACtC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAEhC;IACC,IAAI,QAAQ,GAAgB,EAAE,CAAC;IAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC;IAC5B,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,IAAI,sBAAsB,GAAG,GAAG,CAAC,MAAM,GAAG,cAAc,CAAC;IACzD,IAAI,WAAW,CAAC;IAChB,qEAAqE;IACrE,IAAI,uBAAuB,GAAG,IAAI,CAAC;IACnC,yFAAyF;IACzF,OAAO,sBAAsB,IAAI,uBAAuB,EAAE,CAAC;QACzD,WAAW,GAAG,GAAG,CAAC,cAAc,CAAC,CAAC;QAClC,uBAAuB,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;QACtD,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;QAC/C,cAAc,GAAG,cAAc,GAAG,CAAC,CAAC;QACpC,sBAAsB,GAAG,GAAG,CAAC,MAAM,GAAG,cAAc,CAAC;IACvD,CAAC;IAED,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAEjC;IACC,MAAM,qBAAqB,GAAkB,GAAG,CAC9C,IAAI,CAAC,UAAU,EACf,CAAC,SAAS,EAAE,EAAE;QACZ,OAAO,KAAK,CAAC,SAAS,CAAC,CAAC;IAC1B,CAAC,CACF,CAAC;IACF,OAAO,IAAI,CAAC,OAAO,CAAY,qBAAqB,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,QAAkB;IACjD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AACjC,CAAC"}
|
||||
26
frontend/node_modules/chevrotain/lib/src/parse/grammar/keys.js
generated
vendored
Normal file
26
frontend/node_modules/chevrotain/lib/src/parse/grammar/keys.js
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
// Lookahead keys are 32Bit integers in the form
|
||||
// TTTTTTTT-ZZZZZZZZZZZZ-YYYY-XXXXXXXX
|
||||
// XXXX -> Occurrence Index bitmap.
|
||||
// YYYY -> DSL Method Type bitmap.
|
||||
// ZZZZZZZZZZZZZZZ -> Rule short Index bitmap.
|
||||
// TTTTTTTTT -> alternation alternative index bitmap
|
||||
export const BITS_FOR_METHOD_TYPE = 4;
|
||||
export const BITS_FOR_OCCURRENCE_IDX = 8;
|
||||
export const BITS_FOR_RULE_IDX = 12;
|
||||
// TODO: validation, this means that there may at most 2^8 --> 256 alternatives for an alternation.
|
||||
export const BITS_FOR_ALT_IDX = 8;
|
||||
// short string used as part of mapping keys.
|
||||
// being short improves the performance when composing KEYS for maps out of these
|
||||
// The 5 - 8 bits (16 possible values, are reserved for the DSL method indices)
|
||||
export const OR_IDX = 1 << BITS_FOR_OCCURRENCE_IDX;
|
||||
export const OPTION_IDX = 2 << BITS_FOR_OCCURRENCE_IDX;
|
||||
export const MANY_IDX = 3 << BITS_FOR_OCCURRENCE_IDX;
|
||||
export const AT_LEAST_ONE_IDX = 4 << BITS_FOR_OCCURRENCE_IDX;
|
||||
export const MANY_SEP_IDX = 5 << BITS_FOR_OCCURRENCE_IDX;
|
||||
export const AT_LEAST_ONE_SEP_IDX = 6 << BITS_FOR_OCCURRENCE_IDX;
|
||||
// this actually returns a number, but it is always used as a string (object prop key)
|
||||
export function getKeyForAutomaticLookahead(ruleIdx, dslMethodIdx, occurrence) {
|
||||
return occurrence | dslMethodIdx | ruleIdx;
|
||||
}
|
||||
const BITS_START_FOR_ALT_IDX = 32 - BITS_FOR_ALT_IDX;
|
||||
//# sourceMappingURL=keys.js.map
|
||||
471
frontend/node_modules/chevrotain/lib/src/parse/grammar/lookahead.js
generated
vendored
Normal file
471
frontend/node_modules/chevrotain/lib/src/parse/grammar/lookahead.js
generated
vendored
Normal file
@@ -0,0 +1,471 @@
|
||||
import { every, flatten, forEach, has, isEmpty, map, reduce } from "lodash-es";
|
||||
import { possiblePathsFrom } from "./interpreter.js";
|
||||
import { RestWalker } from "./rest.js";
|
||||
import { tokenStructuredMatcher, tokenStructuredMatcherNoCategories, } from "../../scan/tokens.js";
|
||||
import { Alternation, Alternative as AlternativeGAST, GAstVisitor, Option, Repetition, RepetitionMandatory, RepetitionMandatoryWithSeparator, RepetitionWithSeparator, } from "@chevrotain/gast";
|
||||
export var PROD_TYPE;
|
||||
(function (PROD_TYPE) {
|
||||
PROD_TYPE[PROD_TYPE["OPTION"] = 0] = "OPTION";
|
||||
PROD_TYPE[PROD_TYPE["REPETITION"] = 1] = "REPETITION";
|
||||
PROD_TYPE[PROD_TYPE["REPETITION_MANDATORY"] = 2] = "REPETITION_MANDATORY";
|
||||
PROD_TYPE[PROD_TYPE["REPETITION_MANDATORY_WITH_SEPARATOR"] = 3] = "REPETITION_MANDATORY_WITH_SEPARATOR";
|
||||
PROD_TYPE[PROD_TYPE["REPETITION_WITH_SEPARATOR"] = 4] = "REPETITION_WITH_SEPARATOR";
|
||||
PROD_TYPE[PROD_TYPE["ALTERNATION"] = 5] = "ALTERNATION";
|
||||
})(PROD_TYPE || (PROD_TYPE = {}));
|
||||
export function getProdType(prod) {
|
||||
/* istanbul ignore else */
|
||||
if (prod instanceof Option || prod === "Option") {
|
||||
return PROD_TYPE.OPTION;
|
||||
}
|
||||
else if (prod instanceof Repetition || prod === "Repetition") {
|
||||
return PROD_TYPE.REPETITION;
|
||||
}
|
||||
else if (prod instanceof RepetitionMandatory ||
|
||||
prod === "RepetitionMandatory") {
|
||||
return PROD_TYPE.REPETITION_MANDATORY;
|
||||
}
|
||||
else if (prod instanceof RepetitionMandatoryWithSeparator ||
|
||||
prod === "RepetitionMandatoryWithSeparator") {
|
||||
return PROD_TYPE.REPETITION_MANDATORY_WITH_SEPARATOR;
|
||||
}
|
||||
else if (prod instanceof RepetitionWithSeparator ||
|
||||
prod === "RepetitionWithSeparator") {
|
||||
return PROD_TYPE.REPETITION_WITH_SEPARATOR;
|
||||
}
|
||||
else if (prod instanceof Alternation || prod === "Alternation") {
|
||||
return PROD_TYPE.ALTERNATION;
|
||||
}
|
||||
else {
|
||||
throw Error("non exhaustive match");
|
||||
}
|
||||
}
|
||||
export function getLookaheadPaths(options) {
|
||||
const { occurrence, rule, prodType, maxLookahead } = options;
|
||||
const type = getProdType(prodType);
|
||||
if (type === PROD_TYPE.ALTERNATION) {
|
||||
return getLookaheadPathsForOr(occurrence, rule, maxLookahead);
|
||||
}
|
||||
else {
|
||||
return getLookaheadPathsForOptionalProd(occurrence, rule, type, maxLookahead);
|
||||
}
|
||||
}
|
||||
export function buildLookaheadFuncForOr(occurrence, ruleGrammar, maxLookahead, hasPredicates, dynamicTokensEnabled, laFuncBuilder) {
|
||||
const lookAheadPaths = getLookaheadPathsForOr(occurrence, ruleGrammar, maxLookahead);
|
||||
const tokenMatcher = areTokenCategoriesNotUsed(lookAheadPaths)
|
||||
? tokenStructuredMatcherNoCategories
|
||||
: tokenStructuredMatcher;
|
||||
return laFuncBuilder(lookAheadPaths, hasPredicates, tokenMatcher, dynamicTokensEnabled);
|
||||
}
|
||||
/**
|
||||
* When dealing with an Optional production (OPTION/MANY/2nd iteration of AT_LEAST_ONE/...) we need to compare
|
||||
* the lookahead "inside" the production and the lookahead immediately "after" it in the same top level rule (context free).
|
||||
*
|
||||
* Example: given a production:
|
||||
* ABC(DE)?DF
|
||||
*
|
||||
* The optional '(DE)?' should only be entered if we see 'DE'. a single Token 'D' is not sufficient to distinguish between the two
|
||||
* alternatives.
|
||||
*
|
||||
* @returns A Lookahead function which will return true IFF the parser should parse the Optional production.
|
||||
*/
|
||||
export function buildLookaheadFuncForOptionalProd(occurrence, ruleGrammar, k, dynamicTokensEnabled, prodType, lookaheadBuilder) {
|
||||
const lookAheadPaths = getLookaheadPathsForOptionalProd(occurrence, ruleGrammar, prodType, k);
|
||||
const tokenMatcher = areTokenCategoriesNotUsed(lookAheadPaths)
|
||||
? tokenStructuredMatcherNoCategories
|
||||
: tokenStructuredMatcher;
|
||||
return lookaheadBuilder(lookAheadPaths[0], tokenMatcher, dynamicTokensEnabled);
|
||||
}
|
||||
export function buildAlternativesLookAheadFunc(alts, hasPredicates, tokenMatcher, dynamicTokensEnabled) {
|
||||
const numOfAlts = alts.length;
|
||||
const areAllOneTokenLookahead = every(alts, (currAlt) => {
|
||||
return every(currAlt, (currPath) => {
|
||||
return currPath.length === 1;
|
||||
});
|
||||
});
|
||||
// This version takes into account the predicates as well.
|
||||
if (hasPredicates) {
|
||||
/**
|
||||
* @returns {number} - The chosen alternative index
|
||||
*/
|
||||
return function (orAlts) {
|
||||
// unfortunately the predicates must be extracted every single time
|
||||
// as they cannot be cached due to references to parameters(vars) which are no longer valid.
|
||||
// note that in the common case of no predicates, no cpu time will be wasted on this (see else block)
|
||||
const predicates = map(orAlts, (currAlt) => currAlt.GATE);
|
||||
for (let t = 0; t < numOfAlts; t++) {
|
||||
const currAlt = alts[t];
|
||||
const currNumOfPaths = currAlt.length;
|
||||
const currPredicate = predicates[t];
|
||||
if (currPredicate !== undefined && currPredicate.call(this) === false) {
|
||||
// if the predicate does not match there is no point in checking the paths
|
||||
continue;
|
||||
}
|
||||
nextPath: for (let j = 0; j < currNumOfPaths; j++) {
|
||||
const currPath = currAlt[j];
|
||||
const currPathLength = currPath.length;
|
||||
for (let i = 0; i < currPathLength; i++) {
|
||||
const nextToken = this.LA(i + 1);
|
||||
if (tokenMatcher(nextToken, currPath[i]) === false) {
|
||||
// mismatch in current path
|
||||
// try the next pth
|
||||
continue nextPath;
|
||||
}
|
||||
}
|
||||
// found a full path that matches.
|
||||
// this will also work for an empty ALT as the loop will be skipped
|
||||
return t;
|
||||
}
|
||||
// none of the paths for the current alternative matched
|
||||
// try the next alternative
|
||||
}
|
||||
// none of the alternatives could be matched
|
||||
return undefined;
|
||||
};
|
||||
}
|
||||
else if (areAllOneTokenLookahead && !dynamicTokensEnabled) {
|
||||
// optimized (common) case of all the lookaheads paths requiring only
|
||||
// a single token lookahead. These Optimizations cannot work if dynamically defined Tokens are used.
|
||||
const singleTokenAlts = map(alts, (currAlt) => {
|
||||
return flatten(currAlt);
|
||||
});
|
||||
const choiceToAlt = reduce(singleTokenAlts, (result, currAlt, idx) => {
|
||||
forEach(currAlt, (currTokType) => {
|
||||
if (!has(result, currTokType.tokenTypeIdx)) {
|
||||
result[currTokType.tokenTypeIdx] = idx;
|
||||
}
|
||||
forEach(currTokType.categoryMatches, (currExtendingType) => {
|
||||
if (!has(result, currExtendingType)) {
|
||||
result[currExtendingType] = idx;
|
||||
}
|
||||
});
|
||||
});
|
||||
return result;
|
||||
}, {});
|
||||
/**
|
||||
* @returns {number} - The chosen alternative index
|
||||
*/
|
||||
return function () {
|
||||
const nextToken = this.LA(1);
|
||||
return choiceToAlt[nextToken.tokenTypeIdx];
|
||||
};
|
||||
}
|
||||
else {
|
||||
// optimized lookahead without needing to check the predicates at all.
|
||||
// this causes code duplication which is intentional to improve performance.
|
||||
/**
|
||||
* @returns {number} - The chosen alternative index
|
||||
*/
|
||||
return function () {
|
||||
for (let t = 0; t < numOfAlts; t++) {
|
||||
const currAlt = alts[t];
|
||||
const currNumOfPaths = currAlt.length;
|
||||
nextPath: for (let j = 0; j < currNumOfPaths; j++) {
|
||||
const currPath = currAlt[j];
|
||||
const currPathLength = currPath.length;
|
||||
for (let i = 0; i < currPathLength; i++) {
|
||||
const nextToken = this.LA(i + 1);
|
||||
if (tokenMatcher(nextToken, currPath[i]) === false) {
|
||||
// mismatch in current path
|
||||
// try the next pth
|
||||
continue nextPath;
|
||||
}
|
||||
}
|
||||
// found a full path that matches.
|
||||
// this will also work for an empty ALT as the loop will be skipped
|
||||
return t;
|
||||
}
|
||||
// none of the paths for the current alternative matched
|
||||
// try the next alternative
|
||||
}
|
||||
// none of the alternatives could be matched
|
||||
return undefined;
|
||||
};
|
||||
}
|
||||
}
|
||||
export function buildSingleAlternativeLookaheadFunction(alt, tokenMatcher, dynamicTokensEnabled) {
|
||||
const areAllOneTokenLookahead = every(alt, (currPath) => {
|
||||
return currPath.length === 1;
|
||||
});
|
||||
const numOfPaths = alt.length;
|
||||
// optimized (common) case of all the lookaheads paths requiring only
|
||||
// a single token lookahead.
|
||||
if (areAllOneTokenLookahead && !dynamicTokensEnabled) {
|
||||
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, idx) => {
|
||||
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;
|
||||
};
|
||||
}
|
||||
}
|
||||
else {
|
||||
return function () {
|
||||
nextPath: for (let j = 0; j < numOfPaths; j++) {
|
||||
const currPath = alt[j];
|
||||
const currPathLength = currPath.length;
|
||||
for (let i = 0; i < currPathLength; i++) {
|
||||
const nextToken = this.LA(i + 1);
|
||||
if (tokenMatcher(nextToken, currPath[i]) === false) {
|
||||
// mismatch in current path
|
||||
// try the next pth
|
||||
continue nextPath;
|
||||
}
|
||||
}
|
||||
// found a full path that matches.
|
||||
return true;
|
||||
}
|
||||
// none of the paths matched
|
||||
return false;
|
||||
};
|
||||
}
|
||||
}
|
||||
class RestDefinitionFinderWalker extends RestWalker {
|
||||
constructor(topProd, targetOccurrence, targetProdType) {
|
||||
super();
|
||||
this.topProd = topProd;
|
||||
this.targetOccurrence = targetOccurrence;
|
||||
this.targetProdType = targetProdType;
|
||||
}
|
||||
startWalking() {
|
||||
this.walk(this.topProd);
|
||||
return this.restDef;
|
||||
}
|
||||
checkIsTarget(node, expectedProdType, currRest, prevRest) {
|
||||
if (node.idx === this.targetOccurrence &&
|
||||
this.targetProdType === expectedProdType) {
|
||||
this.restDef = currRest.concat(prevRest);
|
||||
return true;
|
||||
}
|
||||
// performance optimization, do not iterate over the entire Grammar ast after we have found the target
|
||||
return false;
|
||||
}
|
||||
walkOption(optionProd, currRest, prevRest) {
|
||||
if (!this.checkIsTarget(optionProd, PROD_TYPE.OPTION, currRest, prevRest)) {
|
||||
super.walkOption(optionProd, currRest, prevRest);
|
||||
}
|
||||
}
|
||||
walkAtLeastOne(atLeastOneProd, currRest, prevRest) {
|
||||
if (!this.checkIsTarget(atLeastOneProd, PROD_TYPE.REPETITION_MANDATORY, currRest, prevRest)) {
|
||||
super.walkOption(atLeastOneProd, currRest, prevRest);
|
||||
}
|
||||
}
|
||||
walkAtLeastOneSep(atLeastOneSepProd, currRest, prevRest) {
|
||||
if (!this.checkIsTarget(atLeastOneSepProd, PROD_TYPE.REPETITION_MANDATORY_WITH_SEPARATOR, currRest, prevRest)) {
|
||||
super.walkOption(atLeastOneSepProd, currRest, prevRest);
|
||||
}
|
||||
}
|
||||
walkMany(manyProd, currRest, prevRest) {
|
||||
if (!this.checkIsTarget(manyProd, PROD_TYPE.REPETITION, currRest, prevRest)) {
|
||||
super.walkOption(manyProd, currRest, prevRest);
|
||||
}
|
||||
}
|
||||
walkManySep(manySepProd, currRest, prevRest) {
|
||||
if (!this.checkIsTarget(manySepProd, PROD_TYPE.REPETITION_WITH_SEPARATOR, currRest, prevRest)) {
|
||||
super.walkOption(manySepProd, currRest, prevRest);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns the definition of a target production in a top level level rule.
|
||||
*/
|
||||
class InsideDefinitionFinderVisitor extends GAstVisitor {
|
||||
constructor(targetOccurrence, targetProdType, targetRef) {
|
||||
super();
|
||||
this.targetOccurrence = targetOccurrence;
|
||||
this.targetProdType = targetProdType;
|
||||
this.targetRef = targetRef;
|
||||
this.result = [];
|
||||
}
|
||||
checkIsTarget(node, expectedProdName) {
|
||||
if (node.idx === this.targetOccurrence &&
|
||||
this.targetProdType === expectedProdName &&
|
||||
(this.targetRef === undefined || node === this.targetRef)) {
|
||||
this.result = node.definition;
|
||||
}
|
||||
}
|
||||
visitOption(node) {
|
||||
this.checkIsTarget(node, PROD_TYPE.OPTION);
|
||||
}
|
||||
visitRepetition(node) {
|
||||
this.checkIsTarget(node, PROD_TYPE.REPETITION);
|
||||
}
|
||||
visitRepetitionMandatory(node) {
|
||||
this.checkIsTarget(node, PROD_TYPE.REPETITION_MANDATORY);
|
||||
}
|
||||
visitRepetitionMandatoryWithSeparator(node) {
|
||||
this.checkIsTarget(node, PROD_TYPE.REPETITION_MANDATORY_WITH_SEPARATOR);
|
||||
}
|
||||
visitRepetitionWithSeparator(node) {
|
||||
this.checkIsTarget(node, PROD_TYPE.REPETITION_WITH_SEPARATOR);
|
||||
}
|
||||
visitAlternation(node) {
|
||||
this.checkIsTarget(node, PROD_TYPE.ALTERNATION);
|
||||
}
|
||||
}
|
||||
function initializeArrayOfArrays(size) {
|
||||
const result = new Array(size);
|
||||
for (let i = 0; i < size; i++) {
|
||||
result[i] = [];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* A sort of hash function between a Path in the grammar and a string.
|
||||
* Note that this returns multiple "hashes" to support the scenario of token categories.
|
||||
* - A single path with categories may match multiple **actual** paths.
|
||||
*/
|
||||
function pathToHashKeys(path) {
|
||||
let keys = [""];
|
||||
for (let i = 0; i < path.length; i++) {
|
||||
const tokType = path[i];
|
||||
const longerKeys = [];
|
||||
for (let j = 0; j < keys.length; j++) {
|
||||
const currShorterKey = keys[j];
|
||||
longerKeys.push(currShorterKey + "_" + tokType.tokenTypeIdx);
|
||||
for (let t = 0; t < tokType.categoryMatches.length; t++) {
|
||||
const categoriesKeySuffix = "_" + tokType.categoryMatches[t];
|
||||
longerKeys.push(currShorterKey + categoriesKeySuffix);
|
||||
}
|
||||
}
|
||||
keys = longerKeys;
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
/**
|
||||
* Imperative style due to being called from a hot spot
|
||||
*/
|
||||
function isUniquePrefixHash(altKnownPathsKeys, searchPathKeys, idx) {
|
||||
for (let currAltIdx = 0; currAltIdx < altKnownPathsKeys.length; currAltIdx++) {
|
||||
// We only want to test vs the other alternatives
|
||||
if (currAltIdx === idx) {
|
||||
continue;
|
||||
}
|
||||
const otherAltKnownPathsKeys = altKnownPathsKeys[currAltIdx];
|
||||
for (let searchIdx = 0; searchIdx < searchPathKeys.length; searchIdx++) {
|
||||
const searchKey = searchPathKeys[searchIdx];
|
||||
if (otherAltKnownPathsKeys[searchKey] === true) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// None of the SearchPathKeys were found in any of the other alternatives
|
||||
return true;
|
||||
}
|
||||
export function lookAheadSequenceFromAlternatives(altsDefs, k) {
|
||||
const partialAlts = map(altsDefs, (currAlt) => possiblePathsFrom([currAlt], 1));
|
||||
const finalResult = initializeArrayOfArrays(partialAlts.length);
|
||||
const altsHashes = map(partialAlts, (currAltPaths) => {
|
||||
const dict = {};
|
||||
forEach(currAltPaths, (item) => {
|
||||
const keys = pathToHashKeys(item.partialPath);
|
||||
forEach(keys, (currKey) => {
|
||||
dict[currKey] = true;
|
||||
});
|
||||
});
|
||||
return dict;
|
||||
});
|
||||
let newData = partialAlts;
|
||||
// maxLookahead loop
|
||||
for (let pathLength = 1; pathLength <= k; pathLength++) {
|
||||
const currDataset = newData;
|
||||
newData = initializeArrayOfArrays(currDataset.length);
|
||||
// alternatives loop
|
||||
for (let altIdx = 0; altIdx < currDataset.length; altIdx++) {
|
||||
const currAltPathsAndSuffixes = currDataset[altIdx];
|
||||
// paths in current alternative loop
|
||||
for (let currPathIdx = 0; currPathIdx < currAltPathsAndSuffixes.length; currPathIdx++) {
|
||||
const currPathPrefix = currAltPathsAndSuffixes[currPathIdx].partialPath;
|
||||
const suffixDef = currAltPathsAndSuffixes[currPathIdx].suffixDef;
|
||||
const prefixKeys = pathToHashKeys(currPathPrefix);
|
||||
const isUnique = isUniquePrefixHash(altsHashes, prefixKeys, altIdx);
|
||||
// End of the line for this path.
|
||||
if (isUnique || isEmpty(suffixDef) || currPathPrefix.length === k) {
|
||||
const currAltResult = finalResult[altIdx];
|
||||
// TODO: Can we implement a containsPath using Maps/Dictionaries?
|
||||
if (containsPath(currAltResult, currPathPrefix) === false) {
|
||||
currAltResult.push(currPathPrefix);
|
||||
// Update all new keys for the current path.
|
||||
for (let j = 0; j < prefixKeys.length; j++) {
|
||||
const currKey = prefixKeys[j];
|
||||
altsHashes[altIdx][currKey] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Expand longer paths
|
||||
else {
|
||||
const newPartialPathsAndSuffixes = possiblePathsFrom(suffixDef, pathLength + 1, currPathPrefix);
|
||||
newData[altIdx] = newData[altIdx].concat(newPartialPathsAndSuffixes);
|
||||
// Update keys for new known paths
|
||||
forEach(newPartialPathsAndSuffixes, (item) => {
|
||||
const prefixKeys = pathToHashKeys(item.partialPath);
|
||||
forEach(prefixKeys, (key) => {
|
||||
altsHashes[altIdx][key] = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return finalResult;
|
||||
}
|
||||
export function getLookaheadPathsForOr(occurrence, ruleGrammar, k, orProd) {
|
||||
const visitor = new InsideDefinitionFinderVisitor(occurrence, PROD_TYPE.ALTERNATION, orProd);
|
||||
ruleGrammar.accept(visitor);
|
||||
return lookAheadSequenceFromAlternatives(visitor.result, k);
|
||||
}
|
||||
export function getLookaheadPathsForOptionalProd(occurrence, ruleGrammar, prodType, k) {
|
||||
const insideDefVisitor = new InsideDefinitionFinderVisitor(occurrence, prodType);
|
||||
ruleGrammar.accept(insideDefVisitor);
|
||||
const insideDef = insideDefVisitor.result;
|
||||
const afterDefWalker = new RestDefinitionFinderWalker(ruleGrammar, occurrence, prodType);
|
||||
const afterDef = afterDefWalker.startWalking();
|
||||
const insideFlat = new AlternativeGAST({ definition: insideDef });
|
||||
const afterFlat = new AlternativeGAST({ definition: afterDef });
|
||||
return lookAheadSequenceFromAlternatives([insideFlat, afterFlat], k);
|
||||
}
|
||||
export function containsPath(alternative, searchPath) {
|
||||
compareOtherPath: for (let i = 0; i < alternative.length; i++) {
|
||||
const otherPath = alternative[i];
|
||||
if (otherPath.length !== searchPath.length) {
|
||||
continue;
|
||||
}
|
||||
for (let j = 0; j < otherPath.length; j++) {
|
||||
const searchTok = searchPath[j];
|
||||
const otherTok = otherPath[j];
|
||||
const matchingTokens = searchTok === otherTok ||
|
||||
otherTok.categoryMatchesMap[searchTok.tokenTypeIdx] !== undefined;
|
||||
if (matchingTokens === false) {
|
||||
continue compareOtherPath;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
export function isStrictPrefixOfPath(prefix, other) {
|
||||
return (prefix.length < other.length &&
|
||||
every(prefix, (tokType, idx) => {
|
||||
const otherTokType = other[idx];
|
||||
return (tokType === otherTokType ||
|
||||
otherTokType.categoryMatchesMap[tokType.tokenTypeIdx]);
|
||||
}));
|
||||
}
|
||||
export function areTokenCategoriesNotUsed(lookAheadPaths) {
|
||||
return every(lookAheadPaths, (singleAltPaths) => every(singleAltPaths, (singlePath) => every(singlePath, (token) => isEmpty(token.categoryMatches))));
|
||||
}
|
||||
//# sourceMappingURL=lookahead.js.map
|
||||
1
frontend/node_modules/chevrotain/lib/src/parse/grammar/resolver.js.map
generated
vendored
Normal file
1
frontend/node_modules/chevrotain/lib/src/parse/grammar/resolver.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../../../src/parse/grammar/resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,yBAAyB,GAC1B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAqB,MAAM,kBAAkB,CAAC;AAMlE,MAAM,UAAU,cAAc,CAC5B,SAA+B,EAC/B,cAAoD;IAEpD,MAAM,WAAW,GAAG,IAAI,sBAAsB,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IAC1E,WAAW,CAAC,WAAW,EAAE,CAAC;IAC1B,OAAO,WAAW,CAAC,MAAM,CAAC;AAC5B,CAAC;AAED,MAAM,OAAO,sBAAuB,SAAQ,WAAW;IAIrD,YACU,aAAmC,EACnC,cAAoD;QAE5D,KAAK,EAAE,CAAC;QAHA,kBAAa,GAAb,aAAa,CAAsB;QACnC,mBAAc,GAAd,cAAc,CAAsC;QALvD,WAAM,GAA0C,EAAE,CAAC;IAQ1D,CAAC;IAEM,WAAW;QAChB,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE;YAC3C,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;YACzB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;IACL,CAAC;IAEM,gBAAgB,CAAC,IAAiB;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAErD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,GAAG,GAAG,IAAI,CAAC,cAAc,CAAC,sBAAsB,CACpD,IAAI,CAAC,YAAY,EACjB,IAAI,CACL,CAAC;YACF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;gBACf,OAAO,EAAE,GAAG;gBACZ,IAAI,EAAE,yBAAyB,CAAC,sBAAsB;gBACtD,QAAQ,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI;gBAChC,iBAAiB,EAAE,IAAI,CAAC,eAAe;aACxC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,cAAc,GAAG,GAAG,CAAC;QAC5B,CAAC;IACH,CAAC;CACF"}
|
||||
103
frontend/node_modules/chevrotain/lib/src/parse/grammar/rest.js
generated
vendored
Normal file
103
frontend/node_modules/chevrotain/lib/src/parse/grammar/rest.js
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
import { drop, forEach } from "lodash-es";
|
||||
import { Alternation, Alternative, NonTerminal, Option, Repetition, RepetitionMandatory, RepetitionMandatoryWithSeparator, RepetitionWithSeparator, Terminal, } from "@chevrotain/gast";
|
||||
/**
|
||||
* A Grammar Walker that computes the "remaining" grammar "after" a productions in the grammar.
|
||||
*/
|
||||
export class RestWalker {
|
||||
walk(prod, prevRest = []) {
|
||||
forEach(prod.definition, (subProd, index) => {
|
||||
const currRest = drop(prod.definition, index + 1);
|
||||
/* istanbul ignore else */
|
||||
if (subProd instanceof NonTerminal) {
|
||||
this.walkProdRef(subProd, currRest, prevRest);
|
||||
}
|
||||
else if (subProd instanceof Terminal) {
|
||||
this.walkTerminal(subProd, currRest, prevRest);
|
||||
}
|
||||
else if (subProd instanceof Alternative) {
|
||||
this.walkFlat(subProd, currRest, prevRest);
|
||||
}
|
||||
else if (subProd instanceof Option) {
|
||||
this.walkOption(subProd, currRest, prevRest);
|
||||
}
|
||||
else if (subProd instanceof RepetitionMandatory) {
|
||||
this.walkAtLeastOne(subProd, currRest, prevRest);
|
||||
}
|
||||
else if (subProd instanceof RepetitionMandatoryWithSeparator) {
|
||||
this.walkAtLeastOneSep(subProd, currRest, prevRest);
|
||||
}
|
||||
else if (subProd instanceof RepetitionWithSeparator) {
|
||||
this.walkManySep(subProd, currRest, prevRest);
|
||||
}
|
||||
else if (subProd instanceof Repetition) {
|
||||
this.walkMany(subProd, currRest, prevRest);
|
||||
}
|
||||
else if (subProd instanceof Alternation) {
|
||||
this.walkOr(subProd, currRest, prevRest);
|
||||
}
|
||||
else {
|
||||
throw Error("non exhaustive match");
|
||||
}
|
||||
});
|
||||
}
|
||||
walkTerminal(terminal, currRest, prevRest) { }
|
||||
walkProdRef(refProd, currRest, prevRest) { }
|
||||
walkFlat(flatProd, currRest, prevRest) {
|
||||
// ABCDEF => after the D the rest is EF
|
||||
const fullOrRest = currRest.concat(prevRest);
|
||||
this.walk(flatProd, fullOrRest);
|
||||
}
|
||||
walkOption(optionProd, currRest, prevRest) {
|
||||
// ABC(DE)?F => after the (DE)? the rest is F
|
||||
const fullOrRest = currRest.concat(prevRest);
|
||||
this.walk(optionProd, fullOrRest);
|
||||
}
|
||||
walkAtLeastOne(atLeastOneProd, currRest, prevRest) {
|
||||
// ABC(DE)+F => after the (DE)+ the rest is (DE)?F
|
||||
const fullAtLeastOneRest = [
|
||||
new Option({ definition: atLeastOneProd.definition }),
|
||||
].concat(currRest, prevRest);
|
||||
this.walk(atLeastOneProd, fullAtLeastOneRest);
|
||||
}
|
||||
walkAtLeastOneSep(atLeastOneSepProd, currRest, prevRest) {
|
||||
// ABC DE(,DE)* F => after the (,DE)+ the rest is (,DE)?F
|
||||
const fullAtLeastOneSepRest = restForRepetitionWithSeparator(atLeastOneSepProd, currRest, prevRest);
|
||||
this.walk(atLeastOneSepProd, fullAtLeastOneSepRest);
|
||||
}
|
||||
walkMany(manyProd, currRest, prevRest) {
|
||||
// ABC(DE)*F => after the (DE)* the rest is (DE)?F
|
||||
const fullManyRest = [
|
||||
new Option({ definition: manyProd.definition }),
|
||||
].concat(currRest, prevRest);
|
||||
this.walk(manyProd, fullManyRest);
|
||||
}
|
||||
walkManySep(manySepProd, currRest, prevRest) {
|
||||
// ABC (DE(,DE)*)? F => after the (,DE)* the rest is (,DE)?F
|
||||
const fullManySepRest = restForRepetitionWithSeparator(manySepProd, currRest, prevRest);
|
||||
this.walk(manySepProd, fullManySepRest);
|
||||
}
|
||||
walkOr(orProd, currRest, prevRest) {
|
||||
// ABC(D|E|F)G => when finding the (D|E|F) the rest is G
|
||||
const fullOrRest = currRest.concat(prevRest);
|
||||
// walk all different alternatives
|
||||
forEach(orProd.definition, (alt) => {
|
||||
// wrapping each alternative in a single definition wrapper
|
||||
// to avoid errors in computing the rest of that alternative in the invocation to computeInProdFollows
|
||||
// (otherwise for OR([alt1,alt2]) alt2 will be considered in 'rest' of alt1
|
||||
const prodWrapper = new Alternative({ definition: [alt] });
|
||||
this.walk(prodWrapper, fullOrRest);
|
||||
});
|
||||
}
|
||||
}
|
||||
function restForRepetitionWithSeparator(repSepProd, currRest, prevRest) {
|
||||
const repSepRest = [
|
||||
new Option({
|
||||
definition: [
|
||||
new Terminal({ terminalType: repSepProd.separator }),
|
||||
].concat(repSepProd.definition),
|
||||
}),
|
||||
];
|
||||
const fullRepSepRest = repSepRest.concat(currRest, prevRest);
|
||||
return fullRepSepRest;
|
||||
}
|
||||
//# sourceMappingURL=rest.js.map
|
||||
1
frontend/node_modules/chevrotain/lib/src/parse/grammar/rest.js.map
generated
vendored
Normal file
1
frontend/node_modules/chevrotain/lib/src/parse/grammar/rest.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"rest.js","sourceRoot":"","sources":["../../../../src/parse/grammar/rest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EACL,WAAW,EACX,WAAW,EACX,WAAW,EACX,MAAM,EACN,UAAU,EACV,mBAAmB,EACnB,gCAAgC,EAChC,uBAAuB,EACvB,QAAQ,GACT,MAAM,kBAAkB,CAAC;AAG1B;;GAEG;AACH,MAAM,OAAgB,UAAU;IAC9B,IAAI,CAAC,IAAmC,EAAE,WAAkB,EAAE;QAC5D,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,OAAoB,EAAE,KAAK,EAAE,EAAE;YACvD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;YAClD,0BAA0B;YAC1B,IAAI,OAAO,YAAY,WAAW,EAAE,CAAC;gBACnC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAChD,CAAC;iBAAM,IAAI,OAAO,YAAY,QAAQ,EAAE,CAAC;gBACvC,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACjD,CAAC;iBAAM,IAAI,OAAO,YAAY,WAAW,EAAE,CAAC;gBAC1C,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC7C,CAAC;iBAAM,IAAI,OAAO,YAAY,MAAM,EAAE,CAAC;gBACrC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC/C,CAAC;iBAAM,IAAI,OAAO,YAAY,mBAAmB,EAAE,CAAC;gBAClD,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACnD,CAAC;iBAAM,IAAI,OAAO,YAAY,gCAAgC,EAAE,CAAC;gBAC/D,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACtD,CAAC;iBAAM,IAAI,OAAO,YAAY,uBAAuB,EAAE,CAAC;gBACtD,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAChD,CAAC;iBAAM,IAAI,OAAO,YAAY,UAAU,EAAE,CAAC;gBACzC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC7C,CAAC;iBAAM,IAAI,OAAO,YAAY,WAAW,EAAE,CAAC;gBAC1C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC3C,CAAC;iBAAM,CAAC;gBACN,MAAM,KAAK,CAAC,sBAAsB,CAAC,CAAC;YACtC,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,YAAY,CACV,QAAkB,EAClB,QAAuB,EACvB,QAAuB,IAChB,CAAC;IAEV,WAAW,CACT,OAAoB,EACpB,QAAuB,EACvB,QAAuB,IAChB,CAAC;IAEV,QAAQ,CACN,QAAqB,EACrB,QAAuB,EACvB,QAAuB;QAEvB,uCAAuC;QACvC,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC7C,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAO,UAAU,CAAC,CAAC;IACvC,CAAC;IAED,UAAU,CACR,UAAkB,EAClB,QAAuB,EACvB,QAAuB;QAEvB,6CAA6C;QAC7C,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC7C,IAAI,CAAC,IAAI,CAAC,UAAU,EAAO,UAAU,CAAC,CAAC;IACzC,CAAC;IAED,cAAc,CACZ,cAAmC,EACnC,QAAuB,EACvB,QAAuB;QAEvB,kDAAkD;QAClD,MAAM,kBAAkB,GAAkB;YACxC,IAAI,MAAM,CAAC,EAAE,UAAU,EAAE,cAAc,CAAC,UAAU,EAAE,CAAC;SACtD,CAAC,MAAM,CAAM,QAAQ,EAAO,QAAQ,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;IAChD,CAAC;IAED,iBAAiB,CACf,iBAAmD,EACnD,QAAuB,EACvB,QAAuB;QAEvB,yDAAyD;QACzD,MAAM,qBAAqB,GAAG,8BAA8B,CAC1D,iBAAiB,EACjB,QAAQ,EACR,QAAQ,CACT,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,qBAAqB,CAAC,CAAC;IACtD,CAAC;IAED,QAAQ,CACN,QAAoB,EACpB,QAAuB,EACvB,QAAuB;QAEvB,kDAAkD;QAClD,MAAM,YAAY,GAAkB;YAClC,IAAI,MAAM,CAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,EAAE,CAAC;SAChD,CAAC,MAAM,CAAM,QAAQ,EAAO,QAAQ,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACpC,CAAC;IAED,WAAW,CACT,WAAoC,EACpC,QAAuB,EACvB,QAAuB;QAEvB,4DAA4D;QAC5D,MAAM,eAAe,GAAG,8BAA8B,CACpD,WAAW,EACX,QAAQ,EACR,QAAQ,CACT,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM,CACJ,MAAmB,EACnB,QAAuB,EACvB,QAAuB;QAEvB,wDAAwD;QACxD,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC7C,kCAAkC;QAClC,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE;YACjC,2DAA2D;YAC3D,sGAAsG;YACtG,2EAA2E;YAC3E,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC3D,IAAI,CAAC,IAAI,CAAC,WAAW,EAAO,UAAU,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAED,SAAS,8BAA8B,CACrC,UAAmC,EACnC,QAAuB,EACvB,QAAuB;IAEvB,MAAM,UAAU,GAAG;QACjB,IAAI,MAAM,CAAC;YACT,UAAU,EAAE;gBACV,IAAI,QAAQ,CAAC,EAAE,YAAY,EAAE,UAAU,CAAC,SAAS,EAAE,CAAgB;aACpE,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC;SAChC,CAAgB;KAClB,CAAC;IACF,MAAM,cAAc,GAAkB,UAAU,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC5E,OAAO,cAAc,CAAC;AACxB,CAAC"}
|
||||
295
frontend/node_modules/chevrotain/lib/src/parse/parser/traits/gast_recorder.js
generated
vendored
Normal file
295
frontend/node_modules/chevrotain/lib/src/parse/parser/traits/gast_recorder.js
generated
vendored
Normal file
@@ -0,0 +1,295 @@
|
||||
import { forEach, has, isArray, isFunction, last as peek, some, } from "lodash-es";
|
||||
import { Alternation, Alternative, NonTerminal, Option, Repetition, RepetitionMandatory, RepetitionMandatoryWithSeparator, RepetitionWithSeparator, Rule, Terminal, } from "@chevrotain/gast";
|
||||
import { Lexer } from "../../../scan/lexer_public.js";
|
||||
import { augmentTokenTypes, hasShortKeyProperty, } from "../../../scan/tokens.js";
|
||||
import { createToken, createTokenInstance, } from "../../../scan/tokens_public.js";
|
||||
import { END_OF_FILE } from "../parser.js";
|
||||
import { BITS_FOR_OCCURRENCE_IDX } from "../../grammar/keys.js";
|
||||
const RECORDING_NULL_OBJECT = {
|
||||
description: "This Object indicates the Parser is during Recording Phase",
|
||||
};
|
||||
Object.freeze(RECORDING_NULL_OBJECT);
|
||||
const HANDLE_SEPARATOR = true;
|
||||
const MAX_METHOD_IDX = Math.pow(2, BITS_FOR_OCCURRENCE_IDX) - 1;
|
||||
const RFT = createToken({ name: "RECORDING_PHASE_TOKEN", pattern: Lexer.NA });
|
||||
augmentTokenTypes([RFT]);
|
||||
const RECORDING_PHASE_TOKEN = createTokenInstance(RFT, "This IToken indicates the Parser is in Recording Phase\n\t" +
|
||||
"" +
|
||||
"See: https://chevrotain.io/docs/guide/internals.html#grammar-recording for details",
|
||||
// Using "-1" instead of NaN (as in EOF) because an actual number is less likely to
|
||||
// cause errors if the output of LA or CONSUME would be (incorrectly) used during the recording phase.
|
||||
-1, -1, -1, -1, -1, -1);
|
||||
Object.freeze(RECORDING_PHASE_TOKEN);
|
||||
const RECORDING_PHASE_CSTNODE = {
|
||||
name: "This CSTNode indicates the Parser is in Recording Phase\n\t" +
|
||||
"See: https://chevrotain.io/docs/guide/internals.html#grammar-recording for details",
|
||||
children: {},
|
||||
};
|
||||
/**
|
||||
* This trait handles the creation of the GAST structure for Chevrotain Grammars
|
||||
*/
|
||||
export class GastRecorder {
|
||||
initGastRecorder(config) {
|
||||
this.recordingProdStack = [];
|
||||
this.RECORDING_PHASE = false;
|
||||
}
|
||||
enableRecording() {
|
||||
this.RECORDING_PHASE = true;
|
||||
this.TRACE_INIT("Enable Recording", () => {
|
||||
/**
|
||||
* Warning Dark Voodoo Magic upcoming!
|
||||
* We are "replacing" the public parsing DSL methods API
|
||||
* With **new** alternative implementations on the Parser **instance**
|
||||
*
|
||||
* So far this is the only way I've found to avoid performance regressions during parsing time.
|
||||
* - Approx 30% performance regression was measured on Chrome 75 Canary when attempting to replace the "internal"
|
||||
* implementations directly instead.
|
||||
*/
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const idx = i > 0 ? i : "";
|
||||
this[`CONSUME${idx}`] = function (arg1, arg2) {
|
||||
return this.consumeInternalRecord(arg1, i, arg2);
|
||||
};
|
||||
this[`SUBRULE${idx}`] = function (arg1, arg2) {
|
||||
return this.subruleInternalRecord(arg1, i, arg2);
|
||||
};
|
||||
this[`OPTION${idx}`] = function (arg1) {
|
||||
return this.optionInternalRecord(arg1, i);
|
||||
};
|
||||
this[`OR${idx}`] = function (arg1) {
|
||||
return this.orInternalRecord(arg1, i);
|
||||
};
|
||||
this[`MANY${idx}`] = function (arg1) {
|
||||
this.manyInternalRecord(i, arg1);
|
||||
};
|
||||
this[`MANY_SEP${idx}`] = function (arg1) {
|
||||
this.manySepFirstInternalRecord(i, arg1);
|
||||
};
|
||||
this[`AT_LEAST_ONE${idx}`] = function (arg1) {
|
||||
this.atLeastOneInternalRecord(i, arg1);
|
||||
};
|
||||
this[`AT_LEAST_ONE_SEP${idx}`] = function (arg1) {
|
||||
this.atLeastOneSepFirstInternalRecord(i, arg1);
|
||||
};
|
||||
}
|
||||
// DSL methods with the idx(suffix) as an argument
|
||||
this[`consume`] = function (idx, arg1, arg2) {
|
||||
return this.consumeInternalRecord(arg1, idx, arg2);
|
||||
};
|
||||
this[`subrule`] = function (idx, arg1, arg2) {
|
||||
return this.subruleInternalRecord(arg1, idx, arg2);
|
||||
};
|
||||
this[`option`] = function (idx, arg1) {
|
||||
return this.optionInternalRecord(arg1, idx);
|
||||
};
|
||||
this[`or`] = function (idx, arg1) {
|
||||
return this.orInternalRecord(arg1, idx);
|
||||
};
|
||||
this[`many`] = function (idx, arg1) {
|
||||
this.manyInternalRecord(idx, arg1);
|
||||
};
|
||||
this[`atLeastOne`] = function (idx, arg1) {
|
||||
this.atLeastOneInternalRecord(idx, arg1);
|
||||
};
|
||||
this.ACTION = this.ACTION_RECORD;
|
||||
this.BACKTRACK = this.BACKTRACK_RECORD;
|
||||
this.LA = this.LA_RECORD;
|
||||
});
|
||||
}
|
||||
disableRecording() {
|
||||
this.RECORDING_PHASE = false;
|
||||
// By deleting these **instance** properties, any future invocation
|
||||
// will be deferred to the original methods on the **prototype** object
|
||||
// This seems to get rid of any incorrect optimizations that V8 may
|
||||
// do during the recording phase.
|
||||
this.TRACE_INIT("Deleting Recording methods", () => {
|
||||
const that = this;
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const idx = i > 0 ? i : "";
|
||||
delete that[`CONSUME${idx}`];
|
||||
delete that[`SUBRULE${idx}`];
|
||||
delete that[`OPTION${idx}`];
|
||||
delete that[`OR${idx}`];
|
||||
delete that[`MANY${idx}`];
|
||||
delete that[`MANY_SEP${idx}`];
|
||||
delete that[`AT_LEAST_ONE${idx}`];
|
||||
delete that[`AT_LEAST_ONE_SEP${idx}`];
|
||||
}
|
||||
delete that[`consume`];
|
||||
delete that[`subrule`];
|
||||
delete that[`option`];
|
||||
delete that[`or`];
|
||||
delete that[`many`];
|
||||
delete that[`atLeastOne`];
|
||||
delete that.ACTION;
|
||||
delete that.BACKTRACK;
|
||||
delete that.LA;
|
||||
});
|
||||
}
|
||||
// Parser methods are called inside an ACTION?
|
||||
// Maybe try/catch/finally on ACTIONS while disabling the recorders state changes?
|
||||
// @ts-expect-error -- noop place holder
|
||||
ACTION_RECORD(impl) {
|
||||
// NO-OP during recording
|
||||
}
|
||||
// Executing backtracking logic will break our recording logic assumptions
|
||||
BACKTRACK_RECORD(grammarRule, args) {
|
||||
return () => true;
|
||||
}
|
||||
// LA is part of the official API and may be used for custom lookahead logic
|
||||
// by end users who may forget to wrap it in ACTION or inside a GATE
|
||||
LA_RECORD(howMuch) {
|
||||
// We cannot use the RECORD_PHASE_TOKEN here because someone may depend
|
||||
// On LA return EOF at the end of the input so an infinite loop may occur.
|
||||
return END_OF_FILE;
|
||||
}
|
||||
topLevelRuleRecord(name, def) {
|
||||
try {
|
||||
const newTopLevelRule = new Rule({ definition: [], name: name });
|
||||
newTopLevelRule.name = name;
|
||||
this.recordingProdStack.push(newTopLevelRule);
|
||||
def.call(this);
|
||||
this.recordingProdStack.pop();
|
||||
return newTopLevelRule;
|
||||
}
|
||||
catch (originalError) {
|
||||
if (originalError.KNOWN_RECORDER_ERROR !== true) {
|
||||
try {
|
||||
originalError.message =
|
||||
originalError.message +
|
||||
'\n\t This error was thrown during the "grammar recording phase" For more info see:\n\t' +
|
||||
"https://chevrotain.io/docs/guide/internals.html#grammar-recording";
|
||||
}
|
||||
catch (mutabilityError) {
|
||||
// We may not be able to modify the original error object
|
||||
throw originalError;
|
||||
}
|
||||
}
|
||||
throw originalError;
|
||||
}
|
||||
}
|
||||
// Implementation of parsing DSL
|
||||
optionInternalRecord(actionORMethodDef, occurrence) {
|
||||
return recordProd.call(this, Option, actionORMethodDef, occurrence);
|
||||
}
|
||||
atLeastOneInternalRecord(occurrence, actionORMethodDef) {
|
||||
recordProd.call(this, RepetitionMandatory, actionORMethodDef, occurrence);
|
||||
}
|
||||
atLeastOneSepFirstInternalRecord(occurrence, options) {
|
||||
recordProd.call(this, RepetitionMandatoryWithSeparator, options, occurrence, HANDLE_SEPARATOR);
|
||||
}
|
||||
manyInternalRecord(occurrence, actionORMethodDef) {
|
||||
recordProd.call(this, Repetition, actionORMethodDef, occurrence);
|
||||
}
|
||||
manySepFirstInternalRecord(occurrence, options) {
|
||||
recordProd.call(this, RepetitionWithSeparator, options, occurrence, HANDLE_SEPARATOR);
|
||||
}
|
||||
orInternalRecord(altsOrOpts, occurrence) {
|
||||
return recordOrProd.call(this, altsOrOpts, occurrence);
|
||||
}
|
||||
subruleInternalRecord(ruleToCall, occurrence, options) {
|
||||
assertMethodIdxIsValid(occurrence);
|
||||
if (!ruleToCall || has(ruleToCall, "ruleName") === false) {
|
||||
const error = new Error(`<SUBRULE${getIdxSuffix(occurrence)}> argument is invalid` +
|
||||
` expecting a Parser method reference but got: <${JSON.stringify(ruleToCall)}>` +
|
||||
`\n inside top level rule: <${this.recordingProdStack[0].name}>`);
|
||||
error.KNOWN_RECORDER_ERROR = true;
|
||||
throw error;
|
||||
}
|
||||
const prevProd = peek(this.recordingProdStack);
|
||||
const ruleName = ruleToCall.ruleName;
|
||||
const newNoneTerminal = new NonTerminal({
|
||||
idx: occurrence,
|
||||
nonTerminalName: ruleName,
|
||||
label: options === null || options === void 0 ? void 0 : options.LABEL,
|
||||
// The resolving of the `referencedRule` property will be done once all the Rule's GASTs have been created
|
||||
referencedRule: undefined,
|
||||
});
|
||||
prevProd.definition.push(newNoneTerminal);
|
||||
return this.outputCst
|
||||
? RECORDING_PHASE_CSTNODE
|
||||
: RECORDING_NULL_OBJECT;
|
||||
}
|
||||
consumeInternalRecord(tokType, occurrence, options) {
|
||||
assertMethodIdxIsValid(occurrence);
|
||||
if (!hasShortKeyProperty(tokType)) {
|
||||
const error = new Error(`<CONSUME${getIdxSuffix(occurrence)}> argument is invalid` +
|
||||
` expecting a TokenType reference but got: <${JSON.stringify(tokType)}>` +
|
||||
`\n inside top level rule: <${this.recordingProdStack[0].name}>`);
|
||||
error.KNOWN_RECORDER_ERROR = true;
|
||||
throw error;
|
||||
}
|
||||
const prevProd = peek(this.recordingProdStack);
|
||||
const newNoneTerminal = new Terminal({
|
||||
idx: occurrence,
|
||||
terminalType: tokType,
|
||||
label: options === null || options === void 0 ? void 0 : options.LABEL,
|
||||
});
|
||||
prevProd.definition.push(newNoneTerminal);
|
||||
return RECORDING_PHASE_TOKEN;
|
||||
}
|
||||
}
|
||||
function recordProd(prodConstructor, mainProdArg, occurrence, handleSep = false) {
|
||||
assertMethodIdxIsValid(occurrence);
|
||||
const prevProd = peek(this.recordingProdStack);
|
||||
const grammarAction = isFunction(mainProdArg) ? mainProdArg : mainProdArg.DEF;
|
||||
const newProd = new prodConstructor({ definition: [], idx: occurrence });
|
||||
if (handleSep) {
|
||||
newProd.separator = mainProdArg.SEP;
|
||||
}
|
||||
if (has(mainProdArg, "MAX_LOOKAHEAD")) {
|
||||
newProd.maxLookahead = mainProdArg.MAX_LOOKAHEAD;
|
||||
}
|
||||
this.recordingProdStack.push(newProd);
|
||||
grammarAction.call(this);
|
||||
prevProd.definition.push(newProd);
|
||||
this.recordingProdStack.pop();
|
||||
return RECORDING_NULL_OBJECT;
|
||||
}
|
||||
function recordOrProd(mainProdArg, occurrence) {
|
||||
assertMethodIdxIsValid(occurrence);
|
||||
const prevProd = peek(this.recordingProdStack);
|
||||
// Only an array of alternatives
|
||||
const hasOptions = isArray(mainProdArg) === false;
|
||||
const alts = hasOptions === false ? mainProdArg : mainProdArg.DEF;
|
||||
const newOrProd = new Alternation({
|
||||
definition: [],
|
||||
idx: occurrence,
|
||||
ignoreAmbiguities: hasOptions && mainProdArg.IGNORE_AMBIGUITIES === true,
|
||||
});
|
||||
if (has(mainProdArg, "MAX_LOOKAHEAD")) {
|
||||
newOrProd.maxLookahead = mainProdArg.MAX_LOOKAHEAD;
|
||||
}
|
||||
const hasPredicates = some(alts, (currAlt) => isFunction(currAlt.GATE));
|
||||
newOrProd.hasPredicates = hasPredicates;
|
||||
prevProd.definition.push(newOrProd);
|
||||
forEach(alts, (currAlt) => {
|
||||
const currAltFlat = new Alternative({ definition: [] });
|
||||
newOrProd.definition.push(currAltFlat);
|
||||
if (has(currAlt, "IGNORE_AMBIGUITIES")) {
|
||||
currAltFlat.ignoreAmbiguities = currAlt.IGNORE_AMBIGUITIES; // assumes end user provides the correct config value/type
|
||||
}
|
||||
// **implicit** ignoreAmbiguities due to usage of gate
|
||||
else if (has(currAlt, "GATE")) {
|
||||
currAltFlat.ignoreAmbiguities = true;
|
||||
}
|
||||
this.recordingProdStack.push(currAltFlat);
|
||||
currAlt.ALT.call(this);
|
||||
this.recordingProdStack.pop();
|
||||
});
|
||||
return RECORDING_NULL_OBJECT;
|
||||
}
|
||||
function getIdxSuffix(idx) {
|
||||
return idx === 0 ? "" : `${idx}`;
|
||||
}
|
||||
function assertMethodIdxIsValid(idx) {
|
||||
if (idx < 0 || idx > MAX_METHOD_IDX) {
|
||||
const error = new Error(
|
||||
// The stack trace will contain all the needed details
|
||||
`Invalid DSL Method idx value: <${idx}>\n\t` +
|
||||
`Idx value must be a none negative value smaller than ${MAX_METHOD_IDX + 1}`);
|
||||
error.KNOWN_RECORDER_ERROR = true;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=gast_recorder.js.map
|
||||
1
frontend/node_modules/chevrotain/lib/src/parse/parser/traits/gast_recorder.js.map
generated
vendored
Normal file
1
frontend/node_modules/chevrotain/lib/src/parse/parser/traits/gast_recorder.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
70
frontend/node_modules/chevrotain/lib/src/parse/parser/traits/lexer_adapter.js
generated
vendored
Normal file
70
frontend/node_modules/chevrotain/lib/src/parse/parser/traits/lexer_adapter.js
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
import { END_OF_FILE } from "../parser.js";
|
||||
/**
|
||||
* Trait responsible abstracting over the interaction with Lexer output (Token vector).
|
||||
*
|
||||
* This could be generalized to support other kinds of lexers, e.g.
|
||||
* - Just in Time Lexing / Lexer-Less parsing.
|
||||
* - Streaming Lexer.
|
||||
*/
|
||||
export class LexerAdapter {
|
||||
initLexerAdapter() {
|
||||
this.tokVector = [];
|
||||
this.tokVectorLength = 0;
|
||||
this.currIdx = -1;
|
||||
}
|
||||
set input(newInput) {
|
||||
// @ts-ignore - `this parameter` not supported in setters/getters
|
||||
// - https://www.typescriptlang.org/docs/handbook/functions.html#this-parameters
|
||||
if (this.selfAnalysisDone !== true) {
|
||||
throw Error(`Missing <performSelfAnalysis> invocation at the end of the Parser's constructor.`);
|
||||
}
|
||||
// @ts-ignore - `this parameter` not supported in setters/getters
|
||||
// - https://www.typescriptlang.org/docs/handbook/functions.html#this-parameters
|
||||
this.reset();
|
||||
this.tokVector = newInput;
|
||||
this.tokVectorLength = newInput.length;
|
||||
}
|
||||
get input() {
|
||||
return this.tokVector;
|
||||
}
|
||||
// skips a token and returns the next token
|
||||
SKIP_TOKEN() {
|
||||
if (this.currIdx <= this.tokVector.length - 2) {
|
||||
this.consumeToken();
|
||||
return this.LA(1);
|
||||
}
|
||||
else {
|
||||
return END_OF_FILE;
|
||||
}
|
||||
}
|
||||
// Lexer (accessing Token vector) related methods which can be overridden to implement lazy lexers
|
||||
// or lexers dependent on parser context.
|
||||
LA(howMuch) {
|
||||
const soughtIdx = this.currIdx + howMuch;
|
||||
if (soughtIdx < 0 || this.tokVectorLength <= soughtIdx) {
|
||||
return END_OF_FILE;
|
||||
}
|
||||
else {
|
||||
return this.tokVector[soughtIdx];
|
||||
}
|
||||
}
|
||||
consumeToken() {
|
||||
this.currIdx++;
|
||||
}
|
||||
exportLexerState() {
|
||||
return this.currIdx;
|
||||
}
|
||||
importLexerState(newState) {
|
||||
this.currIdx = newState;
|
||||
}
|
||||
resetLexerState() {
|
||||
this.currIdx = -1;
|
||||
}
|
||||
moveToTerminatedState() {
|
||||
this.currIdx = this.tokVector.length - 1;
|
||||
}
|
||||
getLexerPosition() {
|
||||
return this.exportLexerState();
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=lexer_adapter.js.map
|
||||
4
frontend/node_modules/chevrotain/lib/src/parse/parser/traits/parser_traits.js
generated
vendored
Normal file
4
frontend/node_modules/chevrotain/lib/src/parse/parser/traits/parser_traits.js
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { CstParser as CstParserConstructorImpel, EmbeddedActionsParser as EmbeddedActionsParserConstructorImpl, } from "../parser.js";
|
||||
export const CstParser = (CstParserConstructorImpel);
|
||||
export const EmbeddedActionsParser = EmbeddedActionsParserConstructorImpl;
|
||||
//# sourceMappingURL=parser_traits.js.map
|
||||
334
frontend/node_modules/chevrotain/lib/src/parse/parser/traits/recognizer_api.js
generated
vendored
Normal file
334
frontend/node_modules/chevrotain/lib/src/parse/parser/traits/recognizer_api.js
generated
vendored
Normal file
@@ -0,0 +1,334 @@
|
||||
import { includes, values } from "lodash-es";
|
||||
import { isRecognitionException } from "../../exceptions_public.js";
|
||||
import { DEFAULT_RULE_CONFIG, ParserDefinitionErrorType } from "../parser.js";
|
||||
import { defaultGrammarValidatorErrorProvider } from "../../errors_public.js";
|
||||
import { validateRuleIsOverridden } from "../../grammar/checks.js";
|
||||
import { serializeGrammar } from "@chevrotain/gast";
|
||||
/**
|
||||
* This trait is responsible for implementing the public API
|
||||
* for defining Chevrotain parsers, i.e:
|
||||
* - CONSUME
|
||||
* - RULE
|
||||
* - OPTION
|
||||
* - ...
|
||||
*/
|
||||
export class RecognizerApi {
|
||||
ACTION(impl) {
|
||||
return impl.call(this);
|
||||
}
|
||||
consume(idx, tokType, options) {
|
||||
return this.consumeInternal(tokType, idx, options);
|
||||
}
|
||||
subrule(idx, ruleToCall, options) {
|
||||
return this.subruleInternal(ruleToCall, idx, options);
|
||||
}
|
||||
option(idx, actionORMethodDef) {
|
||||
return this.optionInternal(actionORMethodDef, idx);
|
||||
}
|
||||
or(idx, altsOrOpts) {
|
||||
return this.orInternal(altsOrOpts, idx);
|
||||
}
|
||||
many(idx, actionORMethodDef) {
|
||||
return this.manyInternal(idx, actionORMethodDef);
|
||||
}
|
||||
atLeastOne(idx, actionORMethodDef) {
|
||||
return this.atLeastOneInternal(idx, actionORMethodDef);
|
||||
}
|
||||
CONSUME(tokType, options) {
|
||||
return this.consumeInternal(tokType, 0, options);
|
||||
}
|
||||
CONSUME1(tokType, options) {
|
||||
return this.consumeInternal(tokType, 1, options);
|
||||
}
|
||||
CONSUME2(tokType, options) {
|
||||
return this.consumeInternal(tokType, 2, options);
|
||||
}
|
||||
CONSUME3(tokType, options) {
|
||||
return this.consumeInternal(tokType, 3, options);
|
||||
}
|
||||
CONSUME4(tokType, options) {
|
||||
return this.consumeInternal(tokType, 4, options);
|
||||
}
|
||||
CONSUME5(tokType, options) {
|
||||
return this.consumeInternal(tokType, 5, options);
|
||||
}
|
||||
CONSUME6(tokType, options) {
|
||||
return this.consumeInternal(tokType, 6, options);
|
||||
}
|
||||
CONSUME7(tokType, options) {
|
||||
return this.consumeInternal(tokType, 7, options);
|
||||
}
|
||||
CONSUME8(tokType, options) {
|
||||
return this.consumeInternal(tokType, 8, options);
|
||||
}
|
||||
CONSUME9(tokType, options) {
|
||||
return this.consumeInternal(tokType, 9, options);
|
||||
}
|
||||
SUBRULE(ruleToCall, options) {
|
||||
return this.subruleInternal(ruleToCall, 0, options);
|
||||
}
|
||||
SUBRULE1(ruleToCall, options) {
|
||||
return this.subruleInternal(ruleToCall, 1, options);
|
||||
}
|
||||
SUBRULE2(ruleToCall, options) {
|
||||
return this.subruleInternal(ruleToCall, 2, options);
|
||||
}
|
||||
SUBRULE3(ruleToCall, options) {
|
||||
return this.subruleInternal(ruleToCall, 3, options);
|
||||
}
|
||||
SUBRULE4(ruleToCall, options) {
|
||||
return this.subruleInternal(ruleToCall, 4, options);
|
||||
}
|
||||
SUBRULE5(ruleToCall, options) {
|
||||
return this.subruleInternal(ruleToCall, 5, options);
|
||||
}
|
||||
SUBRULE6(ruleToCall, options) {
|
||||
return this.subruleInternal(ruleToCall, 6, options);
|
||||
}
|
||||
SUBRULE7(ruleToCall, options) {
|
||||
return this.subruleInternal(ruleToCall, 7, options);
|
||||
}
|
||||
SUBRULE8(ruleToCall, options) {
|
||||
return this.subruleInternal(ruleToCall, 8, options);
|
||||
}
|
||||
SUBRULE9(ruleToCall, options) {
|
||||
return this.subruleInternal(ruleToCall, 9, options);
|
||||
}
|
||||
OPTION(actionORMethodDef) {
|
||||
return this.optionInternal(actionORMethodDef, 0);
|
||||
}
|
||||
OPTION1(actionORMethodDef) {
|
||||
return this.optionInternal(actionORMethodDef, 1);
|
||||
}
|
||||
OPTION2(actionORMethodDef) {
|
||||
return this.optionInternal(actionORMethodDef, 2);
|
||||
}
|
||||
OPTION3(actionORMethodDef) {
|
||||
return this.optionInternal(actionORMethodDef, 3);
|
||||
}
|
||||
OPTION4(actionORMethodDef) {
|
||||
return this.optionInternal(actionORMethodDef, 4);
|
||||
}
|
||||
OPTION5(actionORMethodDef) {
|
||||
return this.optionInternal(actionORMethodDef, 5);
|
||||
}
|
||||
OPTION6(actionORMethodDef) {
|
||||
return this.optionInternal(actionORMethodDef, 6);
|
||||
}
|
||||
OPTION7(actionORMethodDef) {
|
||||
return this.optionInternal(actionORMethodDef, 7);
|
||||
}
|
||||
OPTION8(actionORMethodDef) {
|
||||
return this.optionInternal(actionORMethodDef, 8);
|
||||
}
|
||||
OPTION9(actionORMethodDef) {
|
||||
return this.optionInternal(actionORMethodDef, 9);
|
||||
}
|
||||
OR(altsOrOpts) {
|
||||
return this.orInternal(altsOrOpts, 0);
|
||||
}
|
||||
OR1(altsOrOpts) {
|
||||
return this.orInternal(altsOrOpts, 1);
|
||||
}
|
||||
OR2(altsOrOpts) {
|
||||
return this.orInternal(altsOrOpts, 2);
|
||||
}
|
||||
OR3(altsOrOpts) {
|
||||
return this.orInternal(altsOrOpts, 3);
|
||||
}
|
||||
OR4(altsOrOpts) {
|
||||
return this.orInternal(altsOrOpts, 4);
|
||||
}
|
||||
OR5(altsOrOpts) {
|
||||
return this.orInternal(altsOrOpts, 5);
|
||||
}
|
||||
OR6(altsOrOpts) {
|
||||
return this.orInternal(altsOrOpts, 6);
|
||||
}
|
||||
OR7(altsOrOpts) {
|
||||
return this.orInternal(altsOrOpts, 7);
|
||||
}
|
||||
OR8(altsOrOpts) {
|
||||
return this.orInternal(altsOrOpts, 8);
|
||||
}
|
||||
OR9(altsOrOpts) {
|
||||
return this.orInternal(altsOrOpts, 9);
|
||||
}
|
||||
MANY(actionORMethodDef) {
|
||||
this.manyInternal(0, actionORMethodDef);
|
||||
}
|
||||
MANY1(actionORMethodDef) {
|
||||
this.manyInternal(1, actionORMethodDef);
|
||||
}
|
||||
MANY2(actionORMethodDef) {
|
||||
this.manyInternal(2, actionORMethodDef);
|
||||
}
|
||||
MANY3(actionORMethodDef) {
|
||||
this.manyInternal(3, actionORMethodDef);
|
||||
}
|
||||
MANY4(actionORMethodDef) {
|
||||
this.manyInternal(4, actionORMethodDef);
|
||||
}
|
||||
MANY5(actionORMethodDef) {
|
||||
this.manyInternal(5, actionORMethodDef);
|
||||
}
|
||||
MANY6(actionORMethodDef) {
|
||||
this.manyInternal(6, actionORMethodDef);
|
||||
}
|
||||
MANY7(actionORMethodDef) {
|
||||
this.manyInternal(7, actionORMethodDef);
|
||||
}
|
||||
MANY8(actionORMethodDef) {
|
||||
this.manyInternal(8, actionORMethodDef);
|
||||
}
|
||||
MANY9(actionORMethodDef) {
|
||||
this.manyInternal(9, actionORMethodDef);
|
||||
}
|
||||
MANY_SEP(options) {
|
||||
this.manySepFirstInternal(0, options);
|
||||
}
|
||||
MANY_SEP1(options) {
|
||||
this.manySepFirstInternal(1, options);
|
||||
}
|
||||
MANY_SEP2(options) {
|
||||
this.manySepFirstInternal(2, options);
|
||||
}
|
||||
MANY_SEP3(options) {
|
||||
this.manySepFirstInternal(3, options);
|
||||
}
|
||||
MANY_SEP4(options) {
|
||||
this.manySepFirstInternal(4, options);
|
||||
}
|
||||
MANY_SEP5(options) {
|
||||
this.manySepFirstInternal(5, options);
|
||||
}
|
||||
MANY_SEP6(options) {
|
||||
this.manySepFirstInternal(6, options);
|
||||
}
|
||||
MANY_SEP7(options) {
|
||||
this.manySepFirstInternal(7, options);
|
||||
}
|
||||
MANY_SEP8(options) {
|
||||
this.manySepFirstInternal(8, options);
|
||||
}
|
||||
MANY_SEP9(options) {
|
||||
this.manySepFirstInternal(9, options);
|
||||
}
|
||||
AT_LEAST_ONE(actionORMethodDef) {
|
||||
this.atLeastOneInternal(0, actionORMethodDef);
|
||||
}
|
||||
AT_LEAST_ONE1(actionORMethodDef) {
|
||||
return this.atLeastOneInternal(1, actionORMethodDef);
|
||||
}
|
||||
AT_LEAST_ONE2(actionORMethodDef) {
|
||||
this.atLeastOneInternal(2, actionORMethodDef);
|
||||
}
|
||||
AT_LEAST_ONE3(actionORMethodDef) {
|
||||
this.atLeastOneInternal(3, actionORMethodDef);
|
||||
}
|
||||
AT_LEAST_ONE4(actionORMethodDef) {
|
||||
this.atLeastOneInternal(4, actionORMethodDef);
|
||||
}
|
||||
AT_LEAST_ONE5(actionORMethodDef) {
|
||||
this.atLeastOneInternal(5, actionORMethodDef);
|
||||
}
|
||||
AT_LEAST_ONE6(actionORMethodDef) {
|
||||
this.atLeastOneInternal(6, actionORMethodDef);
|
||||
}
|
||||
AT_LEAST_ONE7(actionORMethodDef) {
|
||||
this.atLeastOneInternal(7, actionORMethodDef);
|
||||
}
|
||||
AT_LEAST_ONE8(actionORMethodDef) {
|
||||
this.atLeastOneInternal(8, actionORMethodDef);
|
||||
}
|
||||
AT_LEAST_ONE9(actionORMethodDef) {
|
||||
this.atLeastOneInternal(9, actionORMethodDef);
|
||||
}
|
||||
AT_LEAST_ONE_SEP(options) {
|
||||
this.atLeastOneSepFirstInternal(0, options);
|
||||
}
|
||||
AT_LEAST_ONE_SEP1(options) {
|
||||
this.atLeastOneSepFirstInternal(1, options);
|
||||
}
|
||||
AT_LEAST_ONE_SEP2(options) {
|
||||
this.atLeastOneSepFirstInternal(2, options);
|
||||
}
|
||||
AT_LEAST_ONE_SEP3(options) {
|
||||
this.atLeastOneSepFirstInternal(3, options);
|
||||
}
|
||||
AT_LEAST_ONE_SEP4(options) {
|
||||
this.atLeastOneSepFirstInternal(4, options);
|
||||
}
|
||||
AT_LEAST_ONE_SEP5(options) {
|
||||
this.atLeastOneSepFirstInternal(5, options);
|
||||
}
|
||||
AT_LEAST_ONE_SEP6(options) {
|
||||
this.atLeastOneSepFirstInternal(6, options);
|
||||
}
|
||||
AT_LEAST_ONE_SEP7(options) {
|
||||
this.atLeastOneSepFirstInternal(7, options);
|
||||
}
|
||||
AT_LEAST_ONE_SEP8(options) {
|
||||
this.atLeastOneSepFirstInternal(8, options);
|
||||
}
|
||||
AT_LEAST_ONE_SEP9(options) {
|
||||
this.atLeastOneSepFirstInternal(9, options);
|
||||
}
|
||||
RULE(name, implementation, config = DEFAULT_RULE_CONFIG) {
|
||||
if (includes(this.definedRulesNames, name)) {
|
||||
const errMsg = defaultGrammarValidatorErrorProvider.buildDuplicateRuleNameError({
|
||||
topLevelRule: name,
|
||||
grammarName: this.className,
|
||||
});
|
||||
const error = {
|
||||
message: errMsg,
|
||||
type: ParserDefinitionErrorType.DUPLICATE_RULE_NAME,
|
||||
ruleName: name,
|
||||
};
|
||||
this.definitionErrors.push(error);
|
||||
}
|
||||
this.definedRulesNames.push(name);
|
||||
const ruleImplementation = this.defineRule(name, implementation, config);
|
||||
this[name] = ruleImplementation;
|
||||
return ruleImplementation;
|
||||
}
|
||||
OVERRIDE_RULE(name, impl, config = DEFAULT_RULE_CONFIG) {
|
||||
const ruleErrors = validateRuleIsOverridden(name, this.definedRulesNames, this.className);
|
||||
this.definitionErrors = this.definitionErrors.concat(ruleErrors);
|
||||
const ruleImplementation = this.defineRule(name, impl, config);
|
||||
this[name] = ruleImplementation;
|
||||
return ruleImplementation;
|
||||
}
|
||||
BACKTRACK(grammarRule, args) {
|
||||
return function () {
|
||||
// save org state
|
||||
this.isBackTrackingStack.push(1);
|
||||
const orgState = this.saveRecogState();
|
||||
try {
|
||||
grammarRule.apply(this, args);
|
||||
// if no exception was thrown we have succeed parsing the rule.
|
||||
return true;
|
||||
}
|
||||
catch (e) {
|
||||
if (isRecognitionException(e)) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.reloadRecogState(orgState);
|
||||
this.isBackTrackingStack.pop();
|
||||
}
|
||||
};
|
||||
}
|
||||
// GAST export APIs
|
||||
getGAstProductions() {
|
||||
return this.gastProductionsCache;
|
||||
}
|
||||
getSerializedGastProductions() {
|
||||
return serializeGrammar(values(this.gastProductionsCache));
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=recognizer_api.js.map
|
||||
1
frontend/node_modules/chevrotain/lib/src/parse/parser/traits/recognizer_api.js.map
generated
vendored
Normal file
1
frontend/node_modules/chevrotain/lib/src/parse/parser/traits/recognizer_api.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend/node_modules/chevrotain/lib/src/parse/parser/traits/recognizer_engine.js.map
generated
vendored
Normal file
1
frontend/node_modules/chevrotain/lib/src/parse/parser/traits/recognizer_engine.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
191
frontend/node_modules/chevrotain/lib/src/parse/parser/traits/tree_builder.js
generated
vendored
Normal file
191
frontend/node_modules/chevrotain/lib/src/parse/parser/traits/tree_builder.js
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
import { addNoneTerminalToCst, addTerminalToCst, setNodeLocationFull, setNodeLocationOnlyOffset, } from "../../cst/cst.js";
|
||||
import { has, isUndefined, keys, noop } from "lodash-es";
|
||||
import { createBaseSemanticVisitorConstructor, createBaseVisitorConstructorWithDefaults, } from "../../cst/cst_visitor.js";
|
||||
import { DEFAULT_PARSER_CONFIG } from "../parser.js";
|
||||
/**
|
||||
* This trait is responsible for the CST building logic.
|
||||
*/
|
||||
export class TreeBuilder {
|
||||
initTreeBuilder(config) {
|
||||
this.CST_STACK = [];
|
||||
// outputCst is no longer exposed/defined in the pubic API
|
||||
this.outputCst = config.outputCst;
|
||||
this.nodeLocationTracking = has(config, "nodeLocationTracking")
|
||||
? config.nodeLocationTracking // assumes end user provides the correct config value/type
|
||||
: DEFAULT_PARSER_CONFIG.nodeLocationTracking;
|
||||
if (!this.outputCst) {
|
||||
this.cstInvocationStateUpdate = noop;
|
||||
this.cstFinallyStateUpdate = noop;
|
||||
this.cstPostTerminal = noop;
|
||||
this.cstPostNonTerminal = noop;
|
||||
this.cstPostRule = noop;
|
||||
}
|
||||
else {
|
||||
if (/full/i.test(this.nodeLocationTracking)) {
|
||||
if (this.recoveryEnabled) {
|
||||
this.setNodeLocationFromToken = setNodeLocationFull;
|
||||
this.setNodeLocationFromNode = setNodeLocationFull;
|
||||
this.cstPostRule = noop;
|
||||
this.setInitialNodeLocation = this.setInitialNodeLocationFullRecovery;
|
||||
}
|
||||
else {
|
||||
this.setNodeLocationFromToken = noop;
|
||||
this.setNodeLocationFromNode = noop;
|
||||
this.cstPostRule = this.cstPostRuleFull;
|
||||
this.setInitialNodeLocation = this.setInitialNodeLocationFullRegular;
|
||||
}
|
||||
}
|
||||
else if (/onlyOffset/i.test(this.nodeLocationTracking)) {
|
||||
if (this.recoveryEnabled) {
|
||||
this.setNodeLocationFromToken = setNodeLocationOnlyOffset;
|
||||
this.setNodeLocationFromNode = setNodeLocationOnlyOffset;
|
||||
this.cstPostRule = noop;
|
||||
this.setInitialNodeLocation =
|
||||
this.setInitialNodeLocationOnlyOffsetRecovery;
|
||||
}
|
||||
else {
|
||||
this.setNodeLocationFromToken = noop;
|
||||
this.setNodeLocationFromNode = noop;
|
||||
this.cstPostRule = this.cstPostRuleOnlyOffset;
|
||||
this.setInitialNodeLocation =
|
||||
this.setInitialNodeLocationOnlyOffsetRegular;
|
||||
}
|
||||
}
|
||||
else if (/none/i.test(this.nodeLocationTracking)) {
|
||||
this.setNodeLocationFromToken = noop;
|
||||
this.setNodeLocationFromNode = noop;
|
||||
this.cstPostRule = noop;
|
||||
this.setInitialNodeLocation = noop;
|
||||
}
|
||||
else {
|
||||
throw Error(`Invalid <nodeLocationTracking> config option: "${config.nodeLocationTracking}"`);
|
||||
}
|
||||
}
|
||||
}
|
||||
setInitialNodeLocationOnlyOffsetRecovery(cstNode) {
|
||||
cstNode.location = {
|
||||
startOffset: NaN,
|
||||
endOffset: NaN,
|
||||
};
|
||||
}
|
||||
setInitialNodeLocationOnlyOffsetRegular(cstNode) {
|
||||
cstNode.location = {
|
||||
// without error recovery the starting Location of a new CstNode is guaranteed
|
||||
// To be the next Token's startOffset (for valid inputs).
|
||||
// For invalid inputs there won't be any CSTOutput so this potential
|
||||
// inaccuracy does not matter
|
||||
startOffset: this.LA(1).startOffset,
|
||||
endOffset: NaN,
|
||||
};
|
||||
}
|
||||
setInitialNodeLocationFullRecovery(cstNode) {
|
||||
cstNode.location = {
|
||||
startOffset: NaN,
|
||||
startLine: NaN,
|
||||
startColumn: NaN,
|
||||
endOffset: NaN,
|
||||
endLine: NaN,
|
||||
endColumn: NaN,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @see setInitialNodeLocationOnlyOffsetRegular for explanation why this work
|
||||
|
||||
* @param cstNode
|
||||
*/
|
||||
setInitialNodeLocationFullRegular(cstNode) {
|
||||
const nextToken = this.LA(1);
|
||||
cstNode.location = {
|
||||
startOffset: nextToken.startOffset,
|
||||
startLine: nextToken.startLine,
|
||||
startColumn: nextToken.startColumn,
|
||||
endOffset: NaN,
|
||||
endLine: NaN,
|
||||
endColumn: NaN,
|
||||
};
|
||||
}
|
||||
cstInvocationStateUpdate(fullRuleName) {
|
||||
const cstNode = {
|
||||
name: fullRuleName,
|
||||
children: Object.create(null),
|
||||
};
|
||||
this.setInitialNodeLocation(cstNode);
|
||||
this.CST_STACK.push(cstNode);
|
||||
}
|
||||
cstFinallyStateUpdate() {
|
||||
this.CST_STACK.pop();
|
||||
}
|
||||
cstPostRuleFull(ruleCstNode) {
|
||||
// casts to `required<CstNodeLocation>` are safe because `cstPostRuleFull` should only be invoked when full location is enabled
|
||||
const prevToken = this.LA(0);
|
||||
const loc = ruleCstNode.location;
|
||||
// If this condition is true it means we consumed at least one Token
|
||||
// In this CstNode.
|
||||
if (loc.startOffset <= prevToken.startOffset === true) {
|
||||
loc.endOffset = prevToken.endOffset;
|
||||
loc.endLine = prevToken.endLine;
|
||||
loc.endColumn = prevToken.endColumn;
|
||||
}
|
||||
// "empty" CstNode edge case
|
||||
else {
|
||||
loc.startOffset = NaN;
|
||||
loc.startLine = NaN;
|
||||
loc.startColumn = NaN;
|
||||
}
|
||||
}
|
||||
cstPostRuleOnlyOffset(ruleCstNode) {
|
||||
const prevToken = this.LA(0);
|
||||
// `location' is not null because `cstPostRuleOnlyOffset` will only be invoked when location tracking is enabled.
|
||||
const loc = ruleCstNode.location;
|
||||
// If this condition is true it means we consumed at least one Token
|
||||
// In this CstNode.
|
||||
if (loc.startOffset <= prevToken.startOffset === true) {
|
||||
loc.endOffset = prevToken.endOffset;
|
||||
}
|
||||
// "empty" CstNode edge case
|
||||
else {
|
||||
loc.startOffset = NaN;
|
||||
}
|
||||
}
|
||||
cstPostTerminal(key, consumedToken) {
|
||||
const rootCst = this.CST_STACK[this.CST_STACK.length - 1];
|
||||
addTerminalToCst(rootCst, consumedToken, key);
|
||||
// This is only used when **both** error recovery and CST Output are enabled.
|
||||
this.setNodeLocationFromToken(rootCst.location, consumedToken);
|
||||
}
|
||||
cstPostNonTerminal(ruleCstResult, ruleName) {
|
||||
const preCstNode = this.CST_STACK[this.CST_STACK.length - 1];
|
||||
addNoneTerminalToCst(preCstNode, ruleName, ruleCstResult);
|
||||
// This is only used when **both** error recovery and CST Output are enabled.
|
||||
this.setNodeLocationFromNode(preCstNode.location, ruleCstResult.location);
|
||||
}
|
||||
getBaseCstVisitorConstructor() {
|
||||
if (isUndefined(this.baseCstVisitorConstructor)) {
|
||||
const newBaseCstVisitorConstructor = createBaseSemanticVisitorConstructor(this.className, keys(this.gastProductionsCache));
|
||||
this.baseCstVisitorConstructor = newBaseCstVisitorConstructor;
|
||||
return newBaseCstVisitorConstructor;
|
||||
}
|
||||
return this.baseCstVisitorConstructor;
|
||||
}
|
||||
getBaseCstVisitorConstructorWithDefaults() {
|
||||
if (isUndefined(this.baseCstVisitorWithDefaultsConstructor)) {
|
||||
const newConstructor = createBaseVisitorConstructorWithDefaults(this.className, keys(this.gastProductionsCache), this.getBaseCstVisitorConstructor());
|
||||
this.baseCstVisitorWithDefaultsConstructor = newConstructor;
|
||||
return newConstructor;
|
||||
}
|
||||
return this.baseCstVisitorWithDefaultsConstructor;
|
||||
}
|
||||
getLastExplicitRuleShortName() {
|
||||
const ruleStack = this.RULE_STACK;
|
||||
return ruleStack[ruleStack.length - 1];
|
||||
}
|
||||
getPreviousExplicitRuleShortName() {
|
||||
const ruleStack = this.RULE_STACK;
|
||||
return ruleStack[ruleStack.length - 2];
|
||||
}
|
||||
getLastExplicitRuleOccurrenceIndex() {
|
||||
const occurrenceStack = this.RULE_OCCURRENCE_STACK;
|
||||
return occurrenceStack[occurrenceStack.length - 1];
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=tree_builder.js.map
|
||||
1
frontend/node_modules/chevrotain/lib/src/parse/parser/traits/tree_builder.js.map
generated
vendored
Normal file
1
frontend/node_modules/chevrotain/lib/src/parse/parser/traits/tree_builder.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend/node_modules/chevrotain/lib/src/parse/parser/utils/apply_mixins.js.map
generated
vendored
Normal file
1
frontend/node_modules/chevrotain/lib/src/parse/parser/utils/apply_mixins.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"apply_mixins.js","sourceRoot":"","sources":["../../../../../src/parse/parser/utils/apply_mixins.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,WAAW,CAAC,WAAgB,EAAE,SAAgB;IAC5D,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;QAC7B,MAAM,SAAS,GAAG,QAAQ,CAAC,SAAS,CAAC;QACrC,MAAM,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;YACzD,IAAI,QAAQ,KAAK,aAAa,EAAE,CAAC;gBAC/B,OAAO;YACT,CAAC;YAED,MAAM,kBAAkB,GAAG,MAAM,CAAC,wBAAwB,CACxD,SAAS,EACT,QAAQ,CACT,CAAC;YACF,mBAAmB;YACnB,IACE,kBAAkB;gBAClB,CAAC,kBAAkB,CAAC,GAAG,IAAI,kBAAkB,CAAC,GAAG,CAAC,EAClD,CAAC;gBACD,MAAM,CAAC,cAAc,CACnB,WAAW,CAAC,SAAS,EACrB,QAAQ,EACR,kBAAkB,CACnB,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YACjE,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
||||
1
frontend/node_modules/chevrotain/lib/src/scan/lexer_public.js.map
generated
vendored
Normal file
1
frontend/node_modules/chevrotain/lib/src/scan/lexer_public.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
87
frontend/node_modules/chevrotain/lib/src/scan/tokens_public.js
generated
vendored
Normal file
87
frontend/node_modules/chevrotain/lib/src/scan/tokens_public.js
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
import { has, isString, isUndefined } from "lodash-es";
|
||||
import { Lexer } from "./lexer_public.js";
|
||||
import { augmentTokenTypes, tokenStructuredMatcher } from "./tokens.js";
|
||||
export function tokenLabel(tokType) {
|
||||
if (hasTokenLabel(tokType)) {
|
||||
return tokType.LABEL;
|
||||
}
|
||||
else {
|
||||
return tokType.name;
|
||||
}
|
||||
}
|
||||
export function tokenName(tokType) {
|
||||
return tokType.name;
|
||||
}
|
||||
export function hasTokenLabel(obj) {
|
||||
return isString(obj.LABEL) && obj.LABEL !== "";
|
||||
}
|
||||
const PARENT = "parent";
|
||||
const CATEGORIES = "categories";
|
||||
const LABEL = "label";
|
||||
const GROUP = "group";
|
||||
const PUSH_MODE = "push_mode";
|
||||
const POP_MODE = "pop_mode";
|
||||
const LONGER_ALT = "longer_alt";
|
||||
const LINE_BREAKS = "line_breaks";
|
||||
const START_CHARS_HINT = "start_chars_hint";
|
||||
export function createToken(config) {
|
||||
return createTokenInternal(config);
|
||||
}
|
||||
function createTokenInternal(config) {
|
||||
const pattern = config.pattern;
|
||||
const tokenType = {};
|
||||
tokenType.name = config.name;
|
||||
if (!isUndefined(pattern)) {
|
||||
tokenType.PATTERN = pattern;
|
||||
}
|
||||
if (has(config, PARENT)) {
|
||||
throw ("The parent property is no longer supported.\n" +
|
||||
"See: https://github.com/chevrotain/chevrotain/issues/564#issuecomment-349062346 for details.");
|
||||
}
|
||||
if (has(config, CATEGORIES)) {
|
||||
// casting to ANY as this will be fixed inside `augmentTokenTypes``
|
||||
tokenType.CATEGORIES = config[CATEGORIES];
|
||||
}
|
||||
augmentTokenTypes([tokenType]);
|
||||
if (has(config, LABEL)) {
|
||||
tokenType.LABEL = config[LABEL];
|
||||
}
|
||||
if (has(config, GROUP)) {
|
||||
tokenType.GROUP = config[GROUP];
|
||||
}
|
||||
if (has(config, POP_MODE)) {
|
||||
tokenType.POP_MODE = config[POP_MODE];
|
||||
}
|
||||
if (has(config, PUSH_MODE)) {
|
||||
tokenType.PUSH_MODE = config[PUSH_MODE];
|
||||
}
|
||||
if (has(config, LONGER_ALT)) {
|
||||
tokenType.LONGER_ALT = config[LONGER_ALT];
|
||||
}
|
||||
if (has(config, LINE_BREAKS)) {
|
||||
tokenType.LINE_BREAKS = config[LINE_BREAKS];
|
||||
}
|
||||
if (has(config, START_CHARS_HINT)) {
|
||||
tokenType.START_CHARS_HINT = config[START_CHARS_HINT];
|
||||
}
|
||||
return tokenType;
|
||||
}
|
||||
export const EOF = createToken({ name: "EOF", pattern: Lexer.NA });
|
||||
augmentTokenTypes([EOF]);
|
||||
export function createTokenInstance(tokType, image, startOffset, endOffset, startLine, endLine, startColumn, endColumn) {
|
||||
return {
|
||||
image,
|
||||
startOffset,
|
||||
endOffset,
|
||||
startLine,
|
||||
endLine,
|
||||
startColumn,
|
||||
endColumn,
|
||||
tokenTypeIdx: tokType.tokenTypeIdx,
|
||||
tokenType: tokType,
|
||||
};
|
||||
}
|
||||
export function tokenMatcher(token, tokType) {
|
||||
return tokenStructuredMatcher(token, tokType);
|
||||
}
|
||||
//# sourceMappingURL=tokens_public.js.map
|
||||
1
frontend/node_modules/chevrotain/lib/src/scan/tokens_public.js.map
generated
vendored
Normal file
1
frontend/node_modules/chevrotain/lib/src/scan/tokens_public.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"tokens_public.js","sourceRoot":"","sources":["../../../src/scan/tokens_public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAGxE,MAAM,UAAU,UAAU,CAAC,OAAkB;IAC3C,IAAI,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,OAAO,OAAO,CAAC,KAAK,CAAC;IACvB,CAAC;SAAM,CAAC;QACN,OAAO,OAAO,CAAC,IAAI,CAAC;IACtB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,OAAkB;IAC1C,OAAO,OAAO,CAAC,IAAI,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,GAAc;IAEd,OAAO,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC;AACjD,CAAC;AAED,MAAM,MAAM,GAAG,QAAQ,CAAC;AACxB,MAAM,UAAU,GAAG,YAAY,CAAC;AAChC,MAAM,KAAK,GAAG,OAAO,CAAC;AACtB,MAAM,KAAK,GAAG,OAAO,CAAC;AACtB,MAAM,SAAS,GAAG,WAAW,CAAC;AAC9B,MAAM,QAAQ,GAAG,UAAU,CAAC;AAC5B,MAAM,UAAU,GAAG,YAAY,CAAC;AAChC,MAAM,WAAW,GAAG,aAAa,CAAC;AAClC,MAAM,gBAAgB,GAAG,kBAAkB,CAAC;AAE5C,MAAM,UAAU,WAAW,CAAC,MAAoB;IAC9C,OAAO,mBAAmB,CAAC,MAAM,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,mBAAmB,CAAC,MAAoB;IAC/C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IAE/B,MAAM,SAAS,GAAmB,EAAE,CAAC;IACrC,SAAS,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IAE7B,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1B,SAAS,CAAC,OAAO,GAAG,OAAO,CAAC;IAC9B,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;QACxB,MAAM,CACJ,+CAA+C;YAC/C,8FAA8F,CAC/F,CAAC;IACJ,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC;QAC5B,mEAAmE;QACnE,SAAS,CAAC,UAAU,GAAQ,MAAM,CAAC,UAAU,CAAC,CAAC;IACjD,CAAC;IAED,iBAAiB,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAE/B,IAAI,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;QACvB,SAAS,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;QACvB,SAAS,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC;QAC1B,SAAS,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IACxC,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC;QAC3B,SAAS,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC;QAC5B,SAAS,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,CAAC;QAC7B,SAAS,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;IAC9C,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,EAAE,CAAC;QAClC,SAAS,CAAC,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,MAAM,GAAG,GAAG,WAAW,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;AACnE,iBAAiB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAEzB,MAAM,UAAU,mBAAmB,CACjC,OAAkB,EAClB,KAAa,EACb,WAAmB,EACnB,SAAiB,EACjB,SAAiB,EACjB,OAAe,EACf,WAAmB,EACnB,SAAiB;IAEjB,OAAO;QACL,KAAK;QACL,WAAW;QACX,SAAS;QACT,SAAS;QACT,OAAO;QACP,WAAW;QACX,SAAS;QACT,YAAY,EAAQ,OAAQ,CAAC,YAAY;QACzC,SAAS,EAAE,OAAO;KACnB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,OAAkB;IAC5D,OAAO,sBAAsB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AAChD,CAAC"}
|
||||
1
frontend/node_modules/chevrotain/lib/src/text/range.js.map
generated
vendored
Normal file
1
frontend/node_modules/chevrotain/lib/src/text/range.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"range.js","sourceRoot":"","sources":["../../../src/text/range.ts"],"names":[],"mappings":"AAeA,MAAM,OAAO,KAAK;IAChB,YACS,KAAa,EACb,GAAW;QADX,UAAK,GAAL,KAAK,CAAQ;QACb,QAAG,GAAH,GAAG,CAAQ;QAElB,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,GAAW;QAClB,OAAO,IAAI,CAAC,KAAK,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC;IAC9C,CAAC;IAED,aAAa,CAAC,KAAa;QACzB,OAAO,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,GAAG,CAAC;IAC5D,CAAC;IAED,kBAAkB,CAAC,KAAa;QAC9B,OAAO,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,qBAAqB,CAAC,KAAa;QACjC,OAAO,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC;IAC1D,CAAC;IAED,0BAA0B,CAAC,KAAa;QACtC,OAAO,KAAK,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC;CACF;AAED,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,GAAW;IACrD,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,GAAG,KAAK,CAAC,CAAC;AACrC,CAAC"}
|
||||
1
frontend/node_modules/chevrotain/lib/src/version.js.map
generated
vendored
Normal file
1
frontend/node_modules/chevrotain/lib/src/version.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,mDAAmD;AACnD,iEAAiE;AACjE,MAAM,CAAC,MAAM,OAAO,GAAG,QAAQ,CAAC"}
|
||||
95
frontend/node_modules/chevrotain/package.json
generated
vendored
Normal file
95
frontend/node_modules/chevrotain/package.json
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
{
|
||||
"name": "chevrotain",
|
||||
"version": "11.1.2",
|
||||
"description": "Chevrotain is a high performance fault tolerant javascript parsing DSL for building recursive decent parsers",
|
||||
"keywords": [
|
||||
"parser",
|
||||
"syntax",
|
||||
"lexical",
|
||||
"analysis",
|
||||
"grammar",
|
||||
"lexer",
|
||||
"tokenizer",
|
||||
"generator",
|
||||
"compiler",
|
||||
"fault",
|
||||
"tolerant"
|
||||
],
|
||||
"bugs": {
|
||||
"url": "https://github.com/Chevrotain/chevrotain/issues"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"author": {
|
||||
"name": "Shahar Soel"
|
||||
},
|
||||
"type": "module",
|
||||
"types": "./chevrotain.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./lib/src/api.js",
|
||||
"require": "./lib/src/api.js",
|
||||
"types": "./chevrotain.d.ts"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"chevrotain.d.ts",
|
||||
"lib/chevrotain.min.mjs",
|
||||
"lib/chevrotain.mjs",
|
||||
"lib/src/**/*.js",
|
||||
"lib/src/**/*.map",
|
||||
"src/**/*.ts",
|
||||
"diagrams/**/*.*",
|
||||
"BREAKING_CHANGES.md",
|
||||
"CHANGELOG.md"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/Chevrotain/chevrotain.git"
|
||||
},
|
||||
"homepage": "https://chevrotain.io/docs/",
|
||||
"scripts": {
|
||||
"---------- CI FLOWS --------": "",
|
||||
"ci": "pnpm run build test",
|
||||
"build": "npm-run-all clean compile bundle",
|
||||
"test": "npm-run-all coverage",
|
||||
"version": "node ./scripts/version-update.js",
|
||||
"---------- DEV FLOWS --------": "",
|
||||
"watch": "tsc -w",
|
||||
"unit-tests": "mocha --enable-source-maps",
|
||||
"quick-build": "tsc && npm-run-all run bundle",
|
||||
"---------- BUILD STEPS --------": "",
|
||||
"clean": "shx rm -rf coverage dev lib temp",
|
||||
"compile": "tsc",
|
||||
"compile:watch": "tsc -w",
|
||||
"coverage": "c8 mocha --enable-source-maps",
|
||||
"---------- BUNDLING --------": "",
|
||||
"bundle": "npm-run-all bundle:**",
|
||||
"bundle:esm:regular": "esbuild ./lib/src/api.js --bundle --sourcemap --format=esm --outfile=lib/chevrotain.mjs",
|
||||
"bundle:esm:min": "esbuild ./lib/src/api.js --bundle --minify --format=esm --sourcemap --outfile=lib/chevrotain.min.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@chevrotain/cst-dts-gen": "11.1.2",
|
||||
"@chevrotain/gast": "11.1.2",
|
||||
"@chevrotain/regexp-to-ast": "11.1.2",
|
||||
"@chevrotain/types": "11.1.2",
|
||||
"@chevrotain/utils": "11.1.2",
|
||||
"lodash-es": "4.17.23"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jsdom": "28.0.0",
|
||||
"@types/lodash-es": "4.17.12",
|
||||
"@types/sinon": "21.0.0",
|
||||
"@types/sinon-chai": "4.0.0",
|
||||
"error-stack-parser": "2.1.4",
|
||||
"esbuild": "0.27.3",
|
||||
"gen-esm-wrapper": "1.1.3",
|
||||
"gitty": "3.7.2",
|
||||
"jsdom": "28.1.0",
|
||||
"jsonfile": "6.2.0",
|
||||
"require-from-string": "2.0.2",
|
||||
"sinon": "21.0.1",
|
||||
"sinon-chai": "4.0.1",
|
||||
"xregexp": "5.1.2"
|
||||
},
|
||||
"gitHead": "3a0ee6abc9ef3b22448cc72ec54ec4987e44ab9b"
|
||||
}
|
||||
87
frontend/node_modules/chevrotain/src/api.ts
generated
vendored
Normal file
87
frontend/node_modules/chevrotain/src/api.ts
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
/* istanbul ignore file - tricky to import some things from this module during testing */
|
||||
|
||||
// semantic version
|
||||
export { VERSION } from "./version.js";
|
||||
|
||||
export {
|
||||
CstParser,
|
||||
EmbeddedActionsParser,
|
||||
ParserDefinitionErrorType,
|
||||
EMPTY_ALT,
|
||||
} from "./parse/parser/parser.js";
|
||||
|
||||
export { Lexer, LexerDefinitionErrorType } from "./scan/lexer_public.js";
|
||||
|
||||
// Tokens utilities
|
||||
export {
|
||||
createToken,
|
||||
createTokenInstance,
|
||||
EOF,
|
||||
tokenLabel,
|
||||
tokenMatcher,
|
||||
tokenName,
|
||||
} from "./scan/tokens_public.js";
|
||||
|
||||
// Lookahead
|
||||
|
||||
export { getLookaheadPaths } from "./parse/grammar/lookahead.js";
|
||||
|
||||
export { LLkLookaheadStrategy } from "./parse/grammar/llk_lookahead.js";
|
||||
|
||||
// Other Utilities
|
||||
|
||||
export { defaultParserErrorProvider } from "./parse/errors_public.js";
|
||||
|
||||
export {
|
||||
EarlyExitException,
|
||||
isRecognitionException,
|
||||
MismatchedTokenException,
|
||||
NotAllInputParsedException,
|
||||
NoViableAltException,
|
||||
} from "./parse/exceptions_public.js";
|
||||
|
||||
export { defaultLexerErrorProvider } from "./scan/lexer_errors_public.js";
|
||||
|
||||
// grammar reflection API
|
||||
export {
|
||||
Alternation,
|
||||
Alternative,
|
||||
NonTerminal,
|
||||
Option,
|
||||
Repetition,
|
||||
RepetitionMandatory,
|
||||
RepetitionMandatoryWithSeparator,
|
||||
RepetitionWithSeparator,
|
||||
Rule,
|
||||
Terminal,
|
||||
} from "@chevrotain/gast";
|
||||
|
||||
// GAST Utilities
|
||||
|
||||
export {
|
||||
serializeGrammar,
|
||||
serializeProduction,
|
||||
GAstVisitor,
|
||||
} from "@chevrotain/gast";
|
||||
|
||||
export { generateCstDts } from "@chevrotain/cst-dts-gen";
|
||||
|
||||
/* istanbul ignore next */
|
||||
export function clearCache() {
|
||||
console.warn(
|
||||
"The clearCache function was 'soft' removed from the Chevrotain API." +
|
||||
"\n\t It performs no action other than printing this message." +
|
||||
"\n\t Please avoid using it as it will be completely removed in the future",
|
||||
);
|
||||
}
|
||||
|
||||
export { createSyntaxDiagramsCode } from "./diagrams/render_public.js";
|
||||
|
||||
export class Parser {
|
||||
constructor() {
|
||||
throw new Error(
|
||||
"The Parser class has been deprecated, use CstParser or EmbeddedActionsParser instead.\t\n" +
|
||||
"See: https://chevrotain.io/docs/changes/BREAKING_CHANGES.html#_7-0-0",
|
||||
);
|
||||
}
|
||||
}
|
||||
2
frontend/node_modules/chevrotain/src/parse/constants.ts
generated
vendored
Normal file
2
frontend/node_modules/chevrotain/src/parse/constants.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
// TODO: can this be removed? where is it used?
|
||||
export const IN = "_~IN~_";
|
||||
70
frontend/node_modules/chevrotain/src/parse/grammar/first.ts
generated
vendored
Normal file
70
frontend/node_modules/chevrotain/src/parse/grammar/first.ts
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
import { flatten, map, uniq } from "lodash-es";
|
||||
import {
|
||||
isBranchingProd,
|
||||
isOptionalProd,
|
||||
isSequenceProd,
|
||||
NonTerminal,
|
||||
Terminal,
|
||||
} from "@chevrotain/gast";
|
||||
import { IProduction, TokenType } from "@chevrotain/types";
|
||||
|
||||
export function first(prod: IProduction): TokenType[] {
|
||||
/* istanbul ignore else */
|
||||
if (prod instanceof NonTerminal) {
|
||||
// this could in theory cause infinite loops if
|
||||
// (1) prod A refs prod B.
|
||||
// (2) prod B refs prod A
|
||||
// (3) AB can match the empty set
|
||||
// in other words a cycle where everything is optional so the first will keep
|
||||
// looking ahead for the next optional part and will never exit
|
||||
// currently there is no safeguard for this unique edge case because
|
||||
// (1) not sure a grammar in which this can happen is useful for anything (productive)
|
||||
return first((<NonTerminal>prod).referencedRule);
|
||||
} else if (prod instanceof Terminal) {
|
||||
return firstForTerminal(<Terminal>prod);
|
||||
} else if (isSequenceProd(prod)) {
|
||||
return firstForSequence(prod);
|
||||
} else if (isBranchingProd(prod)) {
|
||||
return firstForBranching(prod);
|
||||
} else {
|
||||
throw Error("non exhaustive match");
|
||||
}
|
||||
}
|
||||
|
||||
export function firstForSequence(prod: {
|
||||
definition: IProduction[];
|
||||
}): TokenType[] {
|
||||
let firstSet: TokenType[] = [];
|
||||
const seq = prod.definition;
|
||||
let nextSubProdIdx = 0;
|
||||
let hasInnerProdsRemaining = seq.length > nextSubProdIdx;
|
||||
let currSubProd;
|
||||
// so we enter the loop at least once (if the definition is not empty
|
||||
let isLastInnerProdOptional = true;
|
||||
// scan a sequence until it's end or until we have found a NONE optional production in it
|
||||
while (hasInnerProdsRemaining && isLastInnerProdOptional) {
|
||||
currSubProd = seq[nextSubProdIdx];
|
||||
isLastInnerProdOptional = isOptionalProd(currSubProd);
|
||||
firstSet = firstSet.concat(first(currSubProd));
|
||||
nextSubProdIdx = nextSubProdIdx + 1;
|
||||
hasInnerProdsRemaining = seq.length > nextSubProdIdx;
|
||||
}
|
||||
|
||||
return uniq(firstSet);
|
||||
}
|
||||
|
||||
export function firstForBranching(prod: {
|
||||
definition: IProduction[];
|
||||
}): TokenType[] {
|
||||
const allAlternativesFirsts: TokenType[][] = map(
|
||||
prod.definition,
|
||||
(innerProd) => {
|
||||
return first(innerProd);
|
||||
},
|
||||
);
|
||||
return uniq(flatten<TokenType>(allAlternativesFirsts));
|
||||
}
|
||||
|
||||
export function firstForTerminal(terminal: Terminal): TokenType[] {
|
||||
return [terminal.terminalType];
|
||||
}
|
||||
50
frontend/node_modules/chevrotain/src/parse/grammar/gast/gast_resolver_public.ts
generated
vendored
Normal file
50
frontend/node_modules/chevrotain/src/parse/grammar/gast/gast_resolver_public.ts
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
import { Rule } from "@chevrotain/gast";
|
||||
import { defaults, forEach } from "lodash-es";
|
||||
import { resolveGrammar as orgResolveGrammar } from "../resolver.js";
|
||||
import { validateGrammar as orgValidateGrammar } from "../checks.js";
|
||||
import {
|
||||
defaultGrammarResolverErrorProvider,
|
||||
defaultGrammarValidatorErrorProvider,
|
||||
} from "../../errors_public.js";
|
||||
import { TokenType } from "@chevrotain/types";
|
||||
import {
|
||||
IGrammarResolverErrorMessageProvider,
|
||||
IGrammarValidatorErrorMessageProvider,
|
||||
IParserDefinitionError,
|
||||
} from "../types.js";
|
||||
|
||||
type ResolveGrammarOpts = {
|
||||
rules: Rule[];
|
||||
errMsgProvider?: IGrammarResolverErrorMessageProvider;
|
||||
};
|
||||
export function resolveGrammar(
|
||||
options: ResolveGrammarOpts,
|
||||
): IParserDefinitionError[] {
|
||||
const actualOptions: Required<ResolveGrammarOpts> = defaults(options, {
|
||||
errMsgProvider: defaultGrammarResolverErrorProvider,
|
||||
});
|
||||
|
||||
const topRulesTable: { [ruleName: string]: Rule } = {};
|
||||
forEach(options.rules, (rule) => {
|
||||
topRulesTable[rule.name] = rule;
|
||||
});
|
||||
return orgResolveGrammar(topRulesTable, actualOptions.errMsgProvider);
|
||||
}
|
||||
|
||||
export function validateGrammar(options: {
|
||||
rules: Rule[];
|
||||
tokenTypes: TokenType[];
|
||||
grammarName: string;
|
||||
errMsgProvider: IGrammarValidatorErrorMessageProvider;
|
||||
}): IParserDefinitionError[] {
|
||||
options = defaults(options, {
|
||||
errMsgProvider: defaultGrammarValidatorErrorProvider,
|
||||
});
|
||||
|
||||
return orgValidateGrammar(
|
||||
options.rules,
|
||||
options.tokenTypes,
|
||||
options.errMsgProvider,
|
||||
options.grammarName,
|
||||
);
|
||||
}
|
||||
623
frontend/node_modules/chevrotain/src/parse/grammar/interpreter.ts
generated
vendored
Normal file
623
frontend/node_modules/chevrotain/src/parse/grammar/interpreter.ts
generated
vendored
Normal file
@@ -0,0 +1,623 @@
|
||||
import {
|
||||
clone,
|
||||
drop,
|
||||
dropRight,
|
||||
first as _first,
|
||||
forEach,
|
||||
isEmpty,
|
||||
last,
|
||||
} from "lodash-es";
|
||||
import { first } from "./first.js";
|
||||
import { RestWalker } from "./rest.js";
|
||||
import { TokenMatcher } from "../parser/parser.js";
|
||||
import {
|
||||
Alternation,
|
||||
Alternative,
|
||||
NonTerminal,
|
||||
Option,
|
||||
Repetition,
|
||||
RepetitionMandatory,
|
||||
RepetitionMandatoryWithSeparator,
|
||||
RepetitionWithSeparator,
|
||||
Rule,
|
||||
Terminal,
|
||||
} from "@chevrotain/gast";
|
||||
import {
|
||||
IGrammarPath,
|
||||
IProduction,
|
||||
ISyntacticContentAssistPath,
|
||||
IToken,
|
||||
ITokenGrammarPath,
|
||||
TokenType,
|
||||
} from "@chevrotain/types";
|
||||
|
||||
export abstract class AbstractNextPossibleTokensWalker extends RestWalker {
|
||||
protected possibleTokTypes: TokenType[] = [];
|
||||
protected ruleStack: string[];
|
||||
protected occurrenceStack: number[];
|
||||
|
||||
protected nextProductionName = "";
|
||||
protected nextProductionOccurrence = 0;
|
||||
protected found = false;
|
||||
protected isAtEndOfPath = false;
|
||||
|
||||
constructor(
|
||||
protected topProd: Rule,
|
||||
protected path: IGrammarPath,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
startWalking(): TokenType[] {
|
||||
this.found = false;
|
||||
|
||||
if (this.path.ruleStack[0] !== this.topProd.name) {
|
||||
throw Error("The path does not start with the walker's top Rule!");
|
||||
}
|
||||
|
||||
// immutable for the win
|
||||
this.ruleStack = clone(this.path.ruleStack).reverse(); // intelij bug requires assertion
|
||||
this.occurrenceStack = clone(this.path.occurrenceStack).reverse(); // intelij bug requires assertion
|
||||
|
||||
// already verified that the first production is valid, we now seek the 2nd production
|
||||
this.ruleStack.pop();
|
||||
this.occurrenceStack.pop();
|
||||
|
||||
this.updateExpectedNext();
|
||||
this.walk(this.topProd);
|
||||
|
||||
return this.possibleTokTypes;
|
||||
}
|
||||
|
||||
walk(
|
||||
prod: { definition: IProduction[] },
|
||||
prevRest: IProduction[] = [],
|
||||
): void {
|
||||
// stop scanning once we found the path
|
||||
if (!this.found) {
|
||||
super.walk(prod, prevRest);
|
||||
}
|
||||
}
|
||||
|
||||
walkProdRef(
|
||||
refProd: NonTerminal,
|
||||
currRest: IProduction[],
|
||||
prevRest: IProduction[],
|
||||
): void {
|
||||
// found the next production, need to keep walking in it
|
||||
if (
|
||||
refProd.referencedRule.name === this.nextProductionName &&
|
||||
refProd.idx === this.nextProductionOccurrence
|
||||
) {
|
||||
const fullRest = currRest.concat(prevRest);
|
||||
this.updateExpectedNext();
|
||||
this.walk(refProd.referencedRule, <any>fullRest);
|
||||
}
|
||||
}
|
||||
|
||||
updateExpectedNext(): void {
|
||||
// need to consume the Terminal
|
||||
if (isEmpty(this.ruleStack)) {
|
||||
// must reset nextProductionXXX to avoid walking down another Top Level production while what we are
|
||||
// really seeking is the last Terminal...
|
||||
this.nextProductionName = "";
|
||||
this.nextProductionOccurrence = 0;
|
||||
this.isAtEndOfPath = true;
|
||||
} else {
|
||||
this.nextProductionName = this.ruleStack.pop()!;
|
||||
this.nextProductionOccurrence = this.occurrenceStack.pop()!;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class NextAfterTokenWalker extends AbstractNextPossibleTokensWalker {
|
||||
private nextTerminalName = "";
|
||||
private nextTerminalOccurrence = 0;
|
||||
|
||||
constructor(
|
||||
topProd: Rule,
|
||||
protected path: ITokenGrammarPath,
|
||||
) {
|
||||
super(topProd, path);
|
||||
this.nextTerminalName = this.path.lastTok.name;
|
||||
this.nextTerminalOccurrence = this.path.lastTokOccurrence;
|
||||
}
|
||||
|
||||
walkTerminal(
|
||||
terminal: Terminal,
|
||||
currRest: IProduction[],
|
||||
prevRest: IProduction[],
|
||||
): void {
|
||||
if (
|
||||
this.isAtEndOfPath &&
|
||||
terminal.terminalType.name === this.nextTerminalName &&
|
||||
terminal.idx === this.nextTerminalOccurrence &&
|
||||
!this.found
|
||||
) {
|
||||
const fullRest = currRest.concat(prevRest);
|
||||
const restProd = new Alternative({ definition: fullRest });
|
||||
this.possibleTokTypes = first(restProd);
|
||||
this.found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type AlternativesFirstTokens = TokenType[][];
|
||||
|
||||
export interface IFirstAfterRepetition {
|
||||
token: TokenType | undefined;
|
||||
occurrence: number | undefined;
|
||||
isEndOfRule: boolean | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* This walker only "walks" a single "TOP" level in the Grammar Ast, this means
|
||||
* it never "follows" production refs
|
||||
*/
|
||||
export class AbstractNextTerminalAfterProductionWalker extends RestWalker {
|
||||
protected result: IFirstAfterRepetition = {
|
||||
token: undefined,
|
||||
occurrence: undefined,
|
||||
isEndOfRule: undefined,
|
||||
};
|
||||
|
||||
constructor(
|
||||
protected topRule: Rule,
|
||||
protected occurrence: number,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
startWalking(): IFirstAfterRepetition {
|
||||
this.walk(this.topRule);
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
|
||||
export class NextTerminalAfterManyWalker extends AbstractNextTerminalAfterProductionWalker {
|
||||
walkMany(
|
||||
manyProd: Repetition,
|
||||
currRest: IProduction[],
|
||||
prevRest: IProduction[],
|
||||
): void {
|
||||
if (manyProd.idx === this.occurrence) {
|
||||
const firstAfterMany = _first(currRest.concat(prevRest));
|
||||
this.result.isEndOfRule = firstAfterMany === undefined;
|
||||
if (firstAfterMany instanceof Terminal) {
|
||||
this.result.token = firstAfterMany.terminalType;
|
||||
this.result.occurrence = firstAfterMany.idx;
|
||||
}
|
||||
} else {
|
||||
super.walkMany(manyProd, currRest, prevRest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class NextTerminalAfterManySepWalker extends AbstractNextTerminalAfterProductionWalker {
|
||||
walkManySep(
|
||||
manySepProd: RepetitionWithSeparator,
|
||||
currRest: IProduction[],
|
||||
prevRest: IProduction[],
|
||||
): void {
|
||||
if (manySepProd.idx === this.occurrence) {
|
||||
const firstAfterManySep = _first(currRest.concat(prevRest));
|
||||
this.result.isEndOfRule = firstAfterManySep === undefined;
|
||||
if (firstAfterManySep instanceof Terminal) {
|
||||
this.result.token = firstAfterManySep.terminalType;
|
||||
this.result.occurrence = firstAfterManySep.idx;
|
||||
}
|
||||
} else {
|
||||
super.walkManySep(manySepProd, currRest, prevRest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class NextTerminalAfterAtLeastOneWalker extends AbstractNextTerminalAfterProductionWalker {
|
||||
walkAtLeastOne(
|
||||
atLeastOneProd: RepetitionMandatory,
|
||||
currRest: IProduction[],
|
||||
prevRest: IProduction[],
|
||||
): void {
|
||||
if (atLeastOneProd.idx === this.occurrence) {
|
||||
const firstAfterAtLeastOne = _first(currRest.concat(prevRest));
|
||||
this.result.isEndOfRule = firstAfterAtLeastOne === undefined;
|
||||
if (firstAfterAtLeastOne instanceof Terminal) {
|
||||
this.result.token = firstAfterAtLeastOne.terminalType;
|
||||
this.result.occurrence = firstAfterAtLeastOne.idx;
|
||||
}
|
||||
} else {
|
||||
super.walkAtLeastOne(atLeastOneProd, currRest, prevRest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: reduce code duplication in the AfterWalkers
|
||||
export class NextTerminalAfterAtLeastOneSepWalker extends AbstractNextTerminalAfterProductionWalker {
|
||||
walkAtLeastOneSep(
|
||||
atleastOneSepProd: RepetitionMandatoryWithSeparator,
|
||||
currRest: IProduction[],
|
||||
prevRest: IProduction[],
|
||||
): void {
|
||||
if (atleastOneSepProd.idx === this.occurrence) {
|
||||
const firstAfterfirstAfterAtLeastOneSep = _first(
|
||||
currRest.concat(prevRest),
|
||||
);
|
||||
this.result.isEndOfRule = firstAfterfirstAfterAtLeastOneSep === undefined;
|
||||
if (firstAfterfirstAfterAtLeastOneSep instanceof Terminal) {
|
||||
this.result.token = firstAfterfirstAfterAtLeastOneSep.terminalType;
|
||||
this.result.occurrence = firstAfterfirstAfterAtLeastOneSep.idx;
|
||||
}
|
||||
} else {
|
||||
super.walkAtLeastOneSep(atleastOneSepProd, currRest, prevRest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface PartialPathAndSuffixes {
|
||||
partialPath: TokenType[];
|
||||
suffixDef: IProduction[];
|
||||
}
|
||||
|
||||
export function possiblePathsFrom(
|
||||
targetDef: IProduction[],
|
||||
maxLength: number,
|
||||
currPath: TokenType[] = [],
|
||||
): PartialPathAndSuffixes[] {
|
||||
// avoid side effects
|
||||
currPath = clone(currPath);
|
||||
let result: PartialPathAndSuffixes[] = [];
|
||||
let i = 0;
|
||||
|
||||
// TODO: avoid inner funcs
|
||||
function remainingPathWith(nextDef: IProduction[]) {
|
||||
return nextDef.concat(drop(targetDef, i + 1));
|
||||
}
|
||||
|
||||
// TODO: avoid inner funcs
|
||||
function getAlternativesForProd(definition: IProduction[]) {
|
||||
const alternatives = possiblePathsFrom(
|
||||
remainingPathWith(definition),
|
||||
maxLength,
|
||||
currPath,
|
||||
);
|
||||
return result.concat(alternatives);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mandatory productions will halt the loop as the paths computed from their recursive calls will already contain the
|
||||
* following (rest) of the targetDef.
|
||||
*
|
||||
* For optional productions (Option/Repetition/...) the loop will continue to represent the paths that do not include the
|
||||
* the optional production.
|
||||
*/
|
||||
while (currPath.length < maxLength && i < targetDef.length) {
|
||||
const prod = targetDef[i];
|
||||
|
||||
/* istanbul ignore else */
|
||||
if (prod instanceof Alternative) {
|
||||
return getAlternativesForProd(prod.definition);
|
||||
} else if (prod instanceof NonTerminal) {
|
||||
return getAlternativesForProd(prod.definition);
|
||||
} else if (prod instanceof Option) {
|
||||
result = getAlternativesForProd(prod.definition);
|
||||
} else if (prod instanceof RepetitionMandatory) {
|
||||
const newDef = prod.definition.concat([
|
||||
new Repetition({
|
||||
definition: prod.definition,
|
||||
}),
|
||||
]);
|
||||
return getAlternativesForProd(newDef);
|
||||
} else if (prod instanceof RepetitionMandatoryWithSeparator) {
|
||||
const newDef = [
|
||||
new Alternative({ definition: prod.definition }),
|
||||
new Repetition({
|
||||
definition: [new Terminal({ terminalType: prod.separator })].concat(
|
||||
<any>prod.definition,
|
||||
),
|
||||
}),
|
||||
];
|
||||
return getAlternativesForProd(newDef);
|
||||
} else if (prod instanceof RepetitionWithSeparator) {
|
||||
const newDef = prod.definition.concat([
|
||||
new Repetition({
|
||||
definition: [new Terminal({ terminalType: prod.separator })].concat(
|
||||
<any>prod.definition,
|
||||
),
|
||||
}),
|
||||
]);
|
||||
result = getAlternativesForProd(newDef);
|
||||
} else if (prod instanceof Repetition) {
|
||||
const newDef = prod.definition.concat([
|
||||
new Repetition({
|
||||
definition: prod.definition,
|
||||
}),
|
||||
]);
|
||||
result = getAlternativesForProd(newDef);
|
||||
} else if (prod instanceof Alternation) {
|
||||
forEach(prod.definition, (currAlt) => {
|
||||
// TODO: this is a limited check for empty alternatives
|
||||
// It would prevent a common case of infinite loops during parser initialization.
|
||||
// However **in-directly** empty alternatives may still cause issues.
|
||||
if (isEmpty(currAlt.definition) === false) {
|
||||
result = getAlternativesForProd(currAlt.definition);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
} else if (prod instanceof Terminal) {
|
||||
currPath.push(prod.terminalType);
|
||||
} else {
|
||||
throw Error("non exhaustive match");
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
result.push({
|
||||
partialPath: currPath,
|
||||
suffixDef: drop(targetDef, i),
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
interface IPathToExamine {
|
||||
idx: number;
|
||||
def: IProduction[];
|
||||
ruleStack: string[];
|
||||
occurrenceStack: number[];
|
||||
}
|
||||
|
||||
export function nextPossibleTokensAfter(
|
||||
initialDef: IProduction[],
|
||||
tokenVector: IToken[],
|
||||
tokMatcher: TokenMatcher,
|
||||
maxLookAhead: number,
|
||||
): ISyntacticContentAssistPath[] {
|
||||
const EXIT_NON_TERMINAL: any = "EXIT_NONE_TERMINAL";
|
||||
// to avoid creating a new Array each time.
|
||||
const EXIT_NON_TERMINAL_ARR = [EXIT_NON_TERMINAL];
|
||||
const EXIT_ALTERNATIVE: any = "EXIT_ALTERNATIVE";
|
||||
let foundCompletePath = false;
|
||||
|
||||
const tokenVectorLength = tokenVector.length;
|
||||
const minimalAlternativesIndex = tokenVectorLength - maxLookAhead - 1;
|
||||
|
||||
const result: ISyntacticContentAssistPath[] = [];
|
||||
|
||||
const possiblePaths: IPathToExamine[] = [];
|
||||
possiblePaths.push({
|
||||
idx: -1,
|
||||
def: initialDef,
|
||||
ruleStack: [],
|
||||
occurrenceStack: [],
|
||||
});
|
||||
|
||||
while (!isEmpty(possiblePaths)) {
|
||||
const currPath = possiblePaths.pop()!;
|
||||
|
||||
// skip alternatives if no more results can be found (assuming deterministic grammar with fixed lookahead)
|
||||
if (currPath === EXIT_ALTERNATIVE) {
|
||||
if (
|
||||
foundCompletePath &&
|
||||
last(possiblePaths)!.idx <= minimalAlternativesIndex
|
||||
) {
|
||||
// remove irrelevant alternative
|
||||
possiblePaths.pop();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const currDef = currPath.def;
|
||||
const currIdx = currPath.idx;
|
||||
const currRuleStack = currPath.ruleStack;
|
||||
const currOccurrenceStack = currPath.occurrenceStack;
|
||||
|
||||
// For Example: an empty path could exist in a valid grammar in the case of an EMPTY_ALT
|
||||
if (isEmpty(currDef)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const prod = currDef[0];
|
||||
/* istanbul ignore else */
|
||||
if (prod === EXIT_NON_TERMINAL) {
|
||||
const nextPath = {
|
||||
idx: currIdx,
|
||||
def: drop(currDef),
|
||||
ruleStack: dropRight(currRuleStack),
|
||||
occurrenceStack: dropRight(currOccurrenceStack),
|
||||
};
|
||||
possiblePaths.push(nextPath);
|
||||
} else if (prod instanceof Terminal) {
|
||||
/* istanbul ignore else */
|
||||
if (currIdx < tokenVectorLength - 1) {
|
||||
const nextIdx = currIdx + 1;
|
||||
const actualToken = tokenVector[nextIdx];
|
||||
if (tokMatcher!(actualToken, prod.terminalType)) {
|
||||
const nextPath = {
|
||||
idx: nextIdx,
|
||||
def: drop(currDef),
|
||||
ruleStack: currRuleStack,
|
||||
occurrenceStack: currOccurrenceStack,
|
||||
};
|
||||
possiblePaths.push(nextPath);
|
||||
}
|
||||
// end of the line
|
||||
} else if (currIdx === tokenVectorLength - 1) {
|
||||
// IGNORE ABOVE ELSE
|
||||
result.push({
|
||||
nextTokenType: prod.terminalType,
|
||||
nextTokenOccurrence: prod.idx,
|
||||
ruleStack: currRuleStack,
|
||||
occurrenceStack: currOccurrenceStack,
|
||||
});
|
||||
foundCompletePath = true;
|
||||
} else {
|
||||
throw Error("non exhaustive match");
|
||||
}
|
||||
} else if (prod instanceof NonTerminal) {
|
||||
const newRuleStack = clone(currRuleStack);
|
||||
newRuleStack.push(prod.nonTerminalName);
|
||||
|
||||
const newOccurrenceStack = clone(currOccurrenceStack);
|
||||
newOccurrenceStack.push(prod.idx);
|
||||
|
||||
const nextPath = {
|
||||
idx: currIdx,
|
||||
def: prod.definition.concat(EXIT_NON_TERMINAL_ARR, drop(currDef)),
|
||||
ruleStack: newRuleStack,
|
||||
occurrenceStack: newOccurrenceStack,
|
||||
};
|
||||
possiblePaths.push(nextPath);
|
||||
} else if (prod instanceof Option) {
|
||||
// the order of alternatives is meaningful, FILO (Last path will be traversed first).
|
||||
const nextPathWithout = {
|
||||
idx: currIdx,
|
||||
def: drop(currDef),
|
||||
ruleStack: currRuleStack,
|
||||
occurrenceStack: currOccurrenceStack,
|
||||
};
|
||||
possiblePaths.push(nextPathWithout);
|
||||
// required marker to avoid backtracking paths whose higher priority alternatives already matched
|
||||
possiblePaths.push(EXIT_ALTERNATIVE);
|
||||
|
||||
const nextPathWith = {
|
||||
idx: currIdx,
|
||||
def: prod.definition.concat(drop(currDef)),
|
||||
ruleStack: currRuleStack,
|
||||
occurrenceStack: currOccurrenceStack,
|
||||
};
|
||||
possiblePaths.push(nextPathWith);
|
||||
} else if (prod instanceof RepetitionMandatory) {
|
||||
// TODO:(THE NEW operators here take a while...) (convert once?)
|
||||
const secondIteration = new Repetition({
|
||||
definition: prod.definition,
|
||||
idx: prod.idx,
|
||||
});
|
||||
const nextDef = prod.definition.concat([secondIteration], drop(currDef));
|
||||
const nextPath = {
|
||||
idx: currIdx,
|
||||
def: nextDef,
|
||||
ruleStack: currRuleStack,
|
||||
occurrenceStack: currOccurrenceStack,
|
||||
};
|
||||
possiblePaths.push(nextPath);
|
||||
} else if (prod instanceof RepetitionMandatoryWithSeparator) {
|
||||
// TODO:(THE NEW operators here take a while...) (convert once?)
|
||||
const separatorGast = new Terminal({
|
||||
terminalType: prod.separator,
|
||||
});
|
||||
const secondIteration = new Repetition({
|
||||
definition: [<any>separatorGast].concat(prod.definition),
|
||||
idx: prod.idx,
|
||||
});
|
||||
const nextDef = prod.definition.concat([secondIteration], drop(currDef));
|
||||
const nextPath = {
|
||||
idx: currIdx,
|
||||
def: nextDef,
|
||||
ruleStack: currRuleStack,
|
||||
occurrenceStack: currOccurrenceStack,
|
||||
};
|
||||
possiblePaths.push(nextPath);
|
||||
} else if (prod instanceof RepetitionWithSeparator) {
|
||||
// the order of alternatives is meaningful, FILO (Last path will be traversed first).
|
||||
const nextPathWithout = {
|
||||
idx: currIdx,
|
||||
def: drop(currDef),
|
||||
ruleStack: currRuleStack,
|
||||
occurrenceStack: currOccurrenceStack,
|
||||
};
|
||||
possiblePaths.push(nextPathWithout);
|
||||
// required marker to avoid backtracking paths whose higher priority alternatives already matched
|
||||
possiblePaths.push(EXIT_ALTERNATIVE);
|
||||
|
||||
const separatorGast = new Terminal({
|
||||
terminalType: prod.separator,
|
||||
});
|
||||
const nthRepetition = new Repetition({
|
||||
definition: [<any>separatorGast].concat(prod.definition),
|
||||
idx: prod.idx,
|
||||
});
|
||||
const nextDef = prod.definition.concat([nthRepetition], drop(currDef));
|
||||
const nextPathWith = {
|
||||
idx: currIdx,
|
||||
def: nextDef,
|
||||
ruleStack: currRuleStack,
|
||||
occurrenceStack: currOccurrenceStack,
|
||||
};
|
||||
possiblePaths.push(nextPathWith);
|
||||
} else if (prod instanceof Repetition) {
|
||||
// the order of alternatives is meaningful, FILO (Last path will be traversed first).
|
||||
const nextPathWithout = {
|
||||
idx: currIdx,
|
||||
def: drop(currDef),
|
||||
ruleStack: currRuleStack,
|
||||
occurrenceStack: currOccurrenceStack,
|
||||
};
|
||||
possiblePaths.push(nextPathWithout);
|
||||
// required marker to avoid backtracking paths whose higher priority alternatives already matched
|
||||
possiblePaths.push(EXIT_ALTERNATIVE);
|
||||
|
||||
// TODO: an empty repetition will cause infinite loops here, will the parser detect this in selfAnalysis?
|
||||
const nthRepetition = new Repetition({
|
||||
definition: prod.definition,
|
||||
idx: prod.idx,
|
||||
});
|
||||
const nextDef = prod.definition.concat([nthRepetition], drop(currDef));
|
||||
const nextPathWith = {
|
||||
idx: currIdx,
|
||||
def: nextDef,
|
||||
ruleStack: currRuleStack,
|
||||
occurrenceStack: currOccurrenceStack,
|
||||
};
|
||||
possiblePaths.push(nextPathWith);
|
||||
} else if (prod instanceof Alternation) {
|
||||
// the order of alternatives is meaningful, FILO (Last path will be traversed first).
|
||||
for (let i = prod.definition.length - 1; i >= 0; i--) {
|
||||
const currAlt: any = prod.definition[i];
|
||||
const currAltPath = {
|
||||
idx: currIdx,
|
||||
def: currAlt.definition.concat(drop(currDef)),
|
||||
ruleStack: currRuleStack,
|
||||
occurrenceStack: currOccurrenceStack,
|
||||
};
|
||||
possiblePaths.push(currAltPath);
|
||||
possiblePaths.push(EXIT_ALTERNATIVE);
|
||||
}
|
||||
} else if (prod instanceof Alternative) {
|
||||
possiblePaths.push({
|
||||
idx: currIdx,
|
||||
def: prod.definition.concat(drop(currDef)),
|
||||
ruleStack: currRuleStack,
|
||||
occurrenceStack: currOccurrenceStack,
|
||||
});
|
||||
} else if (prod instanceof Rule) {
|
||||
// last because we should only encounter at most a single one of these per invocation.
|
||||
possiblePaths.push(
|
||||
expandTopLevelRule(prod, currIdx, currRuleStack, currOccurrenceStack),
|
||||
);
|
||||
} else {
|
||||
throw Error("non exhaustive match");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function expandTopLevelRule(
|
||||
topRule: Rule,
|
||||
currIdx: number,
|
||||
currRuleStack: string[],
|
||||
currOccurrenceStack: number[],
|
||||
): IPathToExamine {
|
||||
const newRuleStack = clone(currRuleStack);
|
||||
newRuleStack.push(topRule.name);
|
||||
|
||||
const newCurrOccurrenceStack = clone(currOccurrenceStack);
|
||||
// top rule is always assumed to have been called with occurrence index 1
|
||||
newCurrOccurrenceStack.push(1);
|
||||
|
||||
return {
|
||||
idx: currIdx,
|
||||
def: topRule.definition,
|
||||
ruleStack: newRuleStack,
|
||||
occurrenceStack: newCurrOccurrenceStack,
|
||||
};
|
||||
}
|
||||
33
frontend/node_modules/chevrotain/src/parse/grammar/keys.ts
generated
vendored
Normal file
33
frontend/node_modules/chevrotain/src/parse/grammar/keys.ts
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
// Lookahead keys are 32Bit integers in the form
|
||||
// TTTTTTTT-ZZZZZZZZZZZZ-YYYY-XXXXXXXX
|
||||
// XXXX -> Occurrence Index bitmap.
|
||||
// YYYY -> DSL Method Type bitmap.
|
||||
// ZZZZZZZZZZZZZZZ -> Rule short Index bitmap.
|
||||
// TTTTTTTTT -> alternation alternative index bitmap
|
||||
|
||||
export const BITS_FOR_METHOD_TYPE = 4;
|
||||
export const BITS_FOR_OCCURRENCE_IDX = 8;
|
||||
export const BITS_FOR_RULE_IDX = 12;
|
||||
// TODO: validation, this means that there may at most 2^8 --> 256 alternatives for an alternation.
|
||||
export const BITS_FOR_ALT_IDX = 8;
|
||||
|
||||
// short string used as part of mapping keys.
|
||||
// being short improves the performance when composing KEYS for maps out of these
|
||||
// The 5 - 8 bits (16 possible values, are reserved for the DSL method indices)
|
||||
export const OR_IDX = 1 << BITS_FOR_OCCURRENCE_IDX;
|
||||
export const OPTION_IDX = 2 << BITS_FOR_OCCURRENCE_IDX;
|
||||
export const MANY_IDX = 3 << BITS_FOR_OCCURRENCE_IDX;
|
||||
export const AT_LEAST_ONE_IDX = 4 << BITS_FOR_OCCURRENCE_IDX;
|
||||
export const MANY_SEP_IDX = 5 << BITS_FOR_OCCURRENCE_IDX;
|
||||
export const AT_LEAST_ONE_SEP_IDX = 6 << BITS_FOR_OCCURRENCE_IDX;
|
||||
|
||||
// this actually returns a number, but it is always used as a string (object prop key)
|
||||
export function getKeyForAutomaticLookahead(
|
||||
ruleIdx: number,
|
||||
dslMethodIdx: number,
|
||||
occurrence: number,
|
||||
): number {
|
||||
return occurrence | dslMethodIdx | ruleIdx;
|
||||
}
|
||||
|
||||
const BITS_START_FOR_ALT_IDX = 32 - BITS_FOR_ALT_IDX;
|
||||
739
frontend/node_modules/chevrotain/src/parse/grammar/lookahead.ts
generated
vendored
Normal file
739
frontend/node_modules/chevrotain/src/parse/grammar/lookahead.ts
generated
vendored
Normal file
@@ -0,0 +1,739 @@
|
||||
import { every, flatten, forEach, has, isEmpty, map, reduce } from "lodash-es";
|
||||
import { possiblePathsFrom } from "./interpreter.js";
|
||||
import { RestWalker } from "./rest.js";
|
||||
import { Predicate, TokenMatcher } from "../parser/parser.js";
|
||||
import {
|
||||
tokenStructuredMatcher,
|
||||
tokenStructuredMatcherNoCategories,
|
||||
} from "../../scan/tokens.js";
|
||||
import {
|
||||
Alternation,
|
||||
Alternative as AlternativeGAST,
|
||||
GAstVisitor,
|
||||
Option,
|
||||
Repetition,
|
||||
RepetitionMandatory,
|
||||
RepetitionMandatoryWithSeparator,
|
||||
RepetitionWithSeparator,
|
||||
} from "@chevrotain/gast";
|
||||
import {
|
||||
BaseParser,
|
||||
IOrAlt,
|
||||
IProduction,
|
||||
IProductionWithOccurrence,
|
||||
LookaheadProductionType,
|
||||
LookaheadSequence,
|
||||
Rule,
|
||||
TokenType,
|
||||
} from "@chevrotain/types";
|
||||
|
||||
export enum PROD_TYPE {
|
||||
OPTION,
|
||||
REPETITION,
|
||||
REPETITION_MANDATORY,
|
||||
REPETITION_MANDATORY_WITH_SEPARATOR,
|
||||
REPETITION_WITH_SEPARATOR,
|
||||
ALTERNATION,
|
||||
}
|
||||
|
||||
export function getProdType(
|
||||
prod: IProduction | LookaheadProductionType,
|
||||
): PROD_TYPE {
|
||||
/* istanbul ignore else */
|
||||
if (prod instanceof Option || prod === "Option") {
|
||||
return PROD_TYPE.OPTION;
|
||||
} else if (prod instanceof Repetition || prod === "Repetition") {
|
||||
return PROD_TYPE.REPETITION;
|
||||
} else if (
|
||||
prod instanceof RepetitionMandatory ||
|
||||
prod === "RepetitionMandatory"
|
||||
) {
|
||||
return PROD_TYPE.REPETITION_MANDATORY;
|
||||
} else if (
|
||||
prod instanceof RepetitionMandatoryWithSeparator ||
|
||||
prod === "RepetitionMandatoryWithSeparator"
|
||||
) {
|
||||
return PROD_TYPE.REPETITION_MANDATORY_WITH_SEPARATOR;
|
||||
} else if (
|
||||
prod instanceof RepetitionWithSeparator ||
|
||||
prod === "RepetitionWithSeparator"
|
||||
) {
|
||||
return PROD_TYPE.REPETITION_WITH_SEPARATOR;
|
||||
} else if (prod instanceof Alternation || prod === "Alternation") {
|
||||
return PROD_TYPE.ALTERNATION;
|
||||
} else {
|
||||
throw Error("non exhaustive match");
|
||||
}
|
||||
}
|
||||
|
||||
export function getLookaheadPaths(options: {
|
||||
occurrence: number;
|
||||
rule: Rule;
|
||||
prodType: LookaheadProductionType;
|
||||
maxLookahead: number;
|
||||
}): LookaheadSequence[] {
|
||||
const { occurrence, rule, prodType, maxLookahead } = options;
|
||||
const type = getProdType(prodType);
|
||||
if (type === PROD_TYPE.ALTERNATION) {
|
||||
return getLookaheadPathsForOr(occurrence, rule, maxLookahead);
|
||||
} else {
|
||||
return getLookaheadPathsForOptionalProd(
|
||||
occurrence,
|
||||
rule,
|
||||
type,
|
||||
maxLookahead,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function buildLookaheadFuncForOr(
|
||||
occurrence: number,
|
||||
ruleGrammar: Rule,
|
||||
maxLookahead: number,
|
||||
hasPredicates: boolean,
|
||||
dynamicTokensEnabled: boolean,
|
||||
laFuncBuilder: Function,
|
||||
): (orAlts?: IOrAlt<any>[]) => number | undefined {
|
||||
const lookAheadPaths = getLookaheadPathsForOr(
|
||||
occurrence,
|
||||
ruleGrammar,
|
||||
maxLookahead,
|
||||
);
|
||||
|
||||
const tokenMatcher = areTokenCategoriesNotUsed(lookAheadPaths)
|
||||
? tokenStructuredMatcherNoCategories
|
||||
: tokenStructuredMatcher;
|
||||
|
||||
return laFuncBuilder(
|
||||
lookAheadPaths,
|
||||
hasPredicates,
|
||||
tokenMatcher,
|
||||
dynamicTokensEnabled,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* When dealing with an Optional production (OPTION/MANY/2nd iteration of AT_LEAST_ONE/...) we need to compare
|
||||
* the lookahead "inside" the production and the lookahead immediately "after" it in the same top level rule (context free).
|
||||
*
|
||||
* Example: given a production:
|
||||
* ABC(DE)?DF
|
||||
*
|
||||
* The optional '(DE)?' should only be entered if we see 'DE'. a single Token 'D' is not sufficient to distinguish between the two
|
||||
* alternatives.
|
||||
*
|
||||
* @returns A Lookahead function which will return true IFF the parser should parse the Optional production.
|
||||
*/
|
||||
export function buildLookaheadFuncForOptionalProd(
|
||||
occurrence: number,
|
||||
ruleGrammar: Rule,
|
||||
k: number,
|
||||
dynamicTokensEnabled: boolean,
|
||||
prodType: PROD_TYPE,
|
||||
lookaheadBuilder: (
|
||||
lookAheadSequence: LookaheadSequence,
|
||||
tokenMatcher: TokenMatcher,
|
||||
dynamicTokensEnabled: boolean,
|
||||
) => () => boolean,
|
||||
): () => boolean {
|
||||
const lookAheadPaths = getLookaheadPathsForOptionalProd(
|
||||
occurrence,
|
||||
ruleGrammar,
|
||||
prodType,
|
||||
k,
|
||||
);
|
||||
|
||||
const tokenMatcher = areTokenCategoriesNotUsed(lookAheadPaths)
|
||||
? tokenStructuredMatcherNoCategories
|
||||
: tokenStructuredMatcher;
|
||||
|
||||
return lookaheadBuilder(
|
||||
lookAheadPaths[0],
|
||||
tokenMatcher,
|
||||
dynamicTokensEnabled,
|
||||
);
|
||||
}
|
||||
|
||||
export type Alternative = TokenType[][];
|
||||
|
||||
export function buildAlternativesLookAheadFunc(
|
||||
alts: LookaheadSequence[],
|
||||
hasPredicates: boolean,
|
||||
tokenMatcher: TokenMatcher,
|
||||
dynamicTokensEnabled: boolean,
|
||||
): (orAlts: IOrAlt<any>[]) => number | undefined {
|
||||
const numOfAlts = alts.length;
|
||||
const areAllOneTokenLookahead = every(alts, (currAlt) => {
|
||||
return every(currAlt, (currPath) => {
|
||||
return currPath.length === 1;
|
||||
});
|
||||
});
|
||||
|
||||
// This version takes into account the predicates as well.
|
||||
if (hasPredicates) {
|
||||
/**
|
||||
* @returns {number} - The chosen alternative index
|
||||
*/
|
||||
return function (
|
||||
this: BaseParser,
|
||||
orAlts: IOrAlt<any>[],
|
||||
): number | undefined {
|
||||
// unfortunately the predicates must be extracted every single time
|
||||
// as they cannot be cached due to references to parameters(vars) which are no longer valid.
|
||||
// note that in the common case of no predicates, no cpu time will be wasted on this (see else block)
|
||||
const predicates: (Predicate | undefined)[] = map(
|
||||
orAlts,
|
||||
(currAlt) => currAlt.GATE,
|
||||
);
|
||||
|
||||
for (let t = 0; t < numOfAlts; t++) {
|
||||
const currAlt = alts[t];
|
||||
const currNumOfPaths = currAlt.length;
|
||||
|
||||
const currPredicate = predicates[t];
|
||||
if (currPredicate !== undefined && currPredicate.call(this) === false) {
|
||||
// if the predicate does not match there is no point in checking the paths
|
||||
continue;
|
||||
}
|
||||
nextPath: for (let j = 0; j < currNumOfPaths; j++) {
|
||||
const currPath = currAlt[j];
|
||||
const currPathLength = currPath.length;
|
||||
for (let i = 0; i < currPathLength; i++) {
|
||||
const nextToken = this.LA(i + 1);
|
||||
if (tokenMatcher(nextToken, currPath[i]) === false) {
|
||||
// mismatch in current path
|
||||
// try the next pth
|
||||
continue nextPath;
|
||||
}
|
||||
}
|
||||
// found a full path that matches.
|
||||
// this will also work for an empty ALT as the loop will be skipped
|
||||
return t;
|
||||
}
|
||||
// none of the paths for the current alternative matched
|
||||
// try the next alternative
|
||||
}
|
||||
// none of the alternatives could be matched
|
||||
return undefined;
|
||||
};
|
||||
} else if (areAllOneTokenLookahead && !dynamicTokensEnabled) {
|
||||
// optimized (common) case of all the lookaheads paths requiring only
|
||||
// a single token lookahead. These Optimizations cannot work if dynamically defined Tokens are used.
|
||||
const singleTokenAlts = map(alts, (currAlt) => {
|
||||
return flatten(currAlt);
|
||||
});
|
||||
|
||||
const choiceToAlt = reduce(
|
||||
singleTokenAlts,
|
||||
(result, currAlt, idx) => {
|
||||
forEach(currAlt, (currTokType) => {
|
||||
if (!has(result, currTokType.tokenTypeIdx!)) {
|
||||
result[currTokType.tokenTypeIdx!] = idx;
|
||||
}
|
||||
forEach(currTokType.categoryMatches!, (currExtendingType) => {
|
||||
if (!has(result, currExtendingType)) {
|
||||
result[currExtendingType] = idx;
|
||||
}
|
||||
});
|
||||
});
|
||||
return result;
|
||||
},
|
||||
{} as Record<number, number>,
|
||||
);
|
||||
|
||||
/**
|
||||
* @returns {number} - The chosen alternative index
|
||||
*/
|
||||
return function (this: BaseParser): number {
|
||||
const nextToken = this.LA(1);
|
||||
return choiceToAlt[nextToken.tokenTypeIdx];
|
||||
};
|
||||
} else {
|
||||
// optimized lookahead without needing to check the predicates at all.
|
||||
// this causes code duplication which is intentional to improve performance.
|
||||
/**
|
||||
* @returns {number} - The chosen alternative index
|
||||
*/
|
||||
return function (this: BaseParser): number | undefined {
|
||||
for (let t = 0; t < numOfAlts; t++) {
|
||||
const currAlt = alts[t];
|
||||
const currNumOfPaths = currAlt.length;
|
||||
nextPath: for (let j = 0; j < currNumOfPaths; j++) {
|
||||
const currPath = currAlt[j];
|
||||
const currPathLength = currPath.length;
|
||||
for (let i = 0; i < currPathLength; i++) {
|
||||
const nextToken = this.LA(i + 1);
|
||||
if (tokenMatcher(nextToken, currPath[i]) === false) {
|
||||
// mismatch in current path
|
||||
// try the next pth
|
||||
continue nextPath;
|
||||
}
|
||||
}
|
||||
// found a full path that matches.
|
||||
// this will also work for an empty ALT as the loop will be skipped
|
||||
return t;
|
||||
}
|
||||
// none of the paths for the current alternative matched
|
||||
// try the next alternative
|
||||
}
|
||||
// none of the alternatives could be matched
|
||||
return undefined;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function buildSingleAlternativeLookaheadFunction(
|
||||
alt: LookaheadSequence,
|
||||
tokenMatcher: TokenMatcher,
|
||||
dynamicTokensEnabled: boolean,
|
||||
): () => boolean {
|
||||
const areAllOneTokenLookahead = every(alt, (currPath) => {
|
||||
return currPath.length === 1;
|
||||
});
|
||||
|
||||
const numOfPaths = alt.length;
|
||||
|
||||
// optimized (common) case of all the lookaheads paths requiring only
|
||||
// a single token lookahead.
|
||||
if (areAllOneTokenLookahead && !dynamicTokensEnabled) {
|
||||
const singleTokensTypes = flatten(alt);
|
||||
|
||||
if (
|
||||
singleTokensTypes.length === 1 &&
|
||||
isEmpty((<any>singleTokensTypes[0]).categoryMatches)
|
||||
) {
|
||||
const expectedTokenType = singleTokensTypes[0];
|
||||
const expectedTokenUniqueKey = (<any>expectedTokenType).tokenTypeIdx;
|
||||
|
||||
return function (this: BaseParser): boolean {
|
||||
return this.LA(1).tokenTypeIdx === expectedTokenUniqueKey;
|
||||
};
|
||||
} else {
|
||||
const choiceToAlt = reduce(
|
||||
singleTokensTypes,
|
||||
(result, currTokType, idx) => {
|
||||
result[currTokType.tokenTypeIdx!] = true;
|
||||
forEach(currTokType.categoryMatches!, (currExtendingType) => {
|
||||
result[currExtendingType] = true;
|
||||
});
|
||||
return result;
|
||||
},
|
||||
[] as boolean[],
|
||||
);
|
||||
|
||||
return function (this: BaseParser): boolean {
|
||||
const nextToken = this.LA(1);
|
||||
return choiceToAlt[nextToken.tokenTypeIdx] === true;
|
||||
};
|
||||
}
|
||||
} else {
|
||||
return function (this: BaseParser): boolean {
|
||||
nextPath: for (let j = 0; j < numOfPaths; j++) {
|
||||
const currPath = alt[j];
|
||||
const currPathLength = currPath.length;
|
||||
for (let i = 0; i < currPathLength; i++) {
|
||||
const nextToken = this.LA(i + 1);
|
||||
if (tokenMatcher(nextToken, currPath[i]) === false) {
|
||||
// mismatch in current path
|
||||
// try the next pth
|
||||
continue nextPath;
|
||||
}
|
||||
}
|
||||
// found a full path that matches.
|
||||
return true;
|
||||
}
|
||||
|
||||
// none of the paths matched
|
||||
return false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class RestDefinitionFinderWalker extends RestWalker {
|
||||
private restDef: IProduction[];
|
||||
|
||||
constructor(
|
||||
private topProd: Rule,
|
||||
private targetOccurrence: number,
|
||||
private targetProdType: PROD_TYPE,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
startWalking(): IProduction[] {
|
||||
this.walk(this.topProd);
|
||||
return this.restDef;
|
||||
}
|
||||
|
||||
private checkIsTarget(
|
||||
node: IProductionWithOccurrence,
|
||||
expectedProdType: PROD_TYPE,
|
||||
currRest: IProduction[],
|
||||
prevRest: IProduction[],
|
||||
): boolean {
|
||||
if (
|
||||
node.idx === this.targetOccurrence &&
|
||||
this.targetProdType === expectedProdType
|
||||
) {
|
||||
this.restDef = currRest.concat(prevRest);
|
||||
return true;
|
||||
}
|
||||
// performance optimization, do not iterate over the entire Grammar ast after we have found the target
|
||||
return false;
|
||||
}
|
||||
|
||||
walkOption(
|
||||
optionProd: Option,
|
||||
currRest: IProduction[],
|
||||
prevRest: IProduction[],
|
||||
): void {
|
||||
if (!this.checkIsTarget(optionProd, PROD_TYPE.OPTION, currRest, prevRest)) {
|
||||
super.walkOption(optionProd, currRest, prevRest);
|
||||
}
|
||||
}
|
||||
|
||||
walkAtLeastOne(
|
||||
atLeastOneProd: RepetitionMandatory,
|
||||
currRest: IProduction[],
|
||||
prevRest: IProduction[],
|
||||
): void {
|
||||
if (
|
||||
!this.checkIsTarget(
|
||||
atLeastOneProd,
|
||||
PROD_TYPE.REPETITION_MANDATORY,
|
||||
currRest,
|
||||
prevRest,
|
||||
)
|
||||
) {
|
||||
super.walkOption(atLeastOneProd, currRest, prevRest);
|
||||
}
|
||||
}
|
||||
|
||||
walkAtLeastOneSep(
|
||||
atLeastOneSepProd: RepetitionMandatoryWithSeparator,
|
||||
currRest: IProduction[],
|
||||
prevRest: IProduction[],
|
||||
): void {
|
||||
if (
|
||||
!this.checkIsTarget(
|
||||
atLeastOneSepProd,
|
||||
PROD_TYPE.REPETITION_MANDATORY_WITH_SEPARATOR,
|
||||
currRest,
|
||||
prevRest,
|
||||
)
|
||||
) {
|
||||
super.walkOption(atLeastOneSepProd, currRest, prevRest);
|
||||
}
|
||||
}
|
||||
|
||||
walkMany(
|
||||
manyProd: Repetition,
|
||||
currRest: IProduction[],
|
||||
prevRest: IProduction[],
|
||||
): void {
|
||||
if (
|
||||
!this.checkIsTarget(manyProd, PROD_TYPE.REPETITION, currRest, prevRest)
|
||||
) {
|
||||
super.walkOption(manyProd, currRest, prevRest);
|
||||
}
|
||||
}
|
||||
|
||||
walkManySep(
|
||||
manySepProd: RepetitionWithSeparator,
|
||||
currRest: IProduction[],
|
||||
prevRest: IProduction[],
|
||||
): void {
|
||||
if (
|
||||
!this.checkIsTarget(
|
||||
manySepProd,
|
||||
PROD_TYPE.REPETITION_WITH_SEPARATOR,
|
||||
currRest,
|
||||
prevRest,
|
||||
)
|
||||
) {
|
||||
super.walkOption(manySepProd, currRest, prevRest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the definition of a target production in a top level level rule.
|
||||
*/
|
||||
class InsideDefinitionFinderVisitor extends GAstVisitor {
|
||||
public result: IProduction[] = [];
|
||||
|
||||
constructor(
|
||||
private targetOccurrence: number,
|
||||
private targetProdType: PROD_TYPE,
|
||||
private targetRef?: any,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
private checkIsTarget(
|
||||
node: { definition: IProduction[] } & IProductionWithOccurrence,
|
||||
expectedProdName: PROD_TYPE,
|
||||
): void {
|
||||
if (
|
||||
node.idx === this.targetOccurrence &&
|
||||
this.targetProdType === expectedProdName &&
|
||||
(this.targetRef === undefined || node === this.targetRef)
|
||||
) {
|
||||
this.result = node.definition;
|
||||
}
|
||||
}
|
||||
|
||||
public visitOption(node: Option): void {
|
||||
this.checkIsTarget(node, PROD_TYPE.OPTION);
|
||||
}
|
||||
|
||||
public visitRepetition(node: Repetition): void {
|
||||
this.checkIsTarget(node, PROD_TYPE.REPETITION);
|
||||
}
|
||||
|
||||
public visitRepetitionMandatory(node: RepetitionMandatory): void {
|
||||
this.checkIsTarget(node, PROD_TYPE.REPETITION_MANDATORY);
|
||||
}
|
||||
|
||||
public visitRepetitionMandatoryWithSeparator(
|
||||
node: RepetitionMandatoryWithSeparator,
|
||||
): void {
|
||||
this.checkIsTarget(node, PROD_TYPE.REPETITION_MANDATORY_WITH_SEPARATOR);
|
||||
}
|
||||
|
||||
public visitRepetitionWithSeparator(node: RepetitionWithSeparator): void {
|
||||
this.checkIsTarget(node, PROD_TYPE.REPETITION_WITH_SEPARATOR);
|
||||
}
|
||||
|
||||
public visitAlternation(node: Alternation): void {
|
||||
this.checkIsTarget(node, PROD_TYPE.ALTERNATION);
|
||||
}
|
||||
}
|
||||
|
||||
function initializeArrayOfArrays(size: number): any[][] {
|
||||
const result = new Array(size);
|
||||
for (let i = 0; i < size; i++) {
|
||||
result[i] = [];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* A sort of hash function between a Path in the grammar and a string.
|
||||
* Note that this returns multiple "hashes" to support the scenario of token categories.
|
||||
* - A single path with categories may match multiple **actual** paths.
|
||||
*/
|
||||
function pathToHashKeys(path: TokenType[]): string[] {
|
||||
let keys = [""];
|
||||
for (let i = 0; i < path.length; i++) {
|
||||
const tokType = path[i];
|
||||
const longerKeys = [];
|
||||
for (let j = 0; j < keys.length; j++) {
|
||||
const currShorterKey = keys[j];
|
||||
longerKeys.push(currShorterKey + "_" + tokType.tokenTypeIdx);
|
||||
for (let t = 0; t < tokType.categoryMatches!.length; t++) {
|
||||
const categoriesKeySuffix = "_" + tokType.categoryMatches![t];
|
||||
longerKeys.push(currShorterKey + categoriesKeySuffix);
|
||||
}
|
||||
}
|
||||
keys = longerKeys;
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imperative style due to being called from a hot spot
|
||||
*/
|
||||
function isUniquePrefixHash(
|
||||
altKnownPathsKeys: Record<string, boolean>[],
|
||||
searchPathKeys: string[],
|
||||
idx: number,
|
||||
): boolean {
|
||||
for (
|
||||
let currAltIdx = 0;
|
||||
currAltIdx < altKnownPathsKeys.length;
|
||||
currAltIdx++
|
||||
) {
|
||||
// We only want to test vs the other alternatives
|
||||
if (currAltIdx === idx) {
|
||||
continue;
|
||||
}
|
||||
const otherAltKnownPathsKeys = altKnownPathsKeys[currAltIdx];
|
||||
for (let searchIdx = 0; searchIdx < searchPathKeys.length; searchIdx++) {
|
||||
const searchKey = searchPathKeys[searchIdx];
|
||||
if (otherAltKnownPathsKeys[searchKey] === true) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// None of the SearchPathKeys were found in any of the other alternatives
|
||||
return true;
|
||||
}
|
||||
|
||||
export function lookAheadSequenceFromAlternatives(
|
||||
altsDefs: IProduction[],
|
||||
k: number,
|
||||
): LookaheadSequence[] {
|
||||
const partialAlts = map(altsDefs, (currAlt) =>
|
||||
possiblePathsFrom([currAlt], 1),
|
||||
);
|
||||
const finalResult = initializeArrayOfArrays(partialAlts.length);
|
||||
const altsHashes = map(partialAlts, (currAltPaths) => {
|
||||
const dict: { [key: string]: boolean } = {};
|
||||
forEach(currAltPaths, (item) => {
|
||||
const keys = pathToHashKeys(item.partialPath);
|
||||
forEach(keys, (currKey) => {
|
||||
dict[currKey] = true;
|
||||
});
|
||||
});
|
||||
return dict;
|
||||
});
|
||||
let newData = partialAlts;
|
||||
|
||||
// maxLookahead loop
|
||||
for (let pathLength = 1; pathLength <= k; pathLength++) {
|
||||
const currDataset = newData;
|
||||
newData = initializeArrayOfArrays(currDataset.length);
|
||||
|
||||
// alternatives loop
|
||||
for (let altIdx = 0; altIdx < currDataset.length; altIdx++) {
|
||||
const currAltPathsAndSuffixes = currDataset[altIdx];
|
||||
// paths in current alternative loop
|
||||
for (
|
||||
let currPathIdx = 0;
|
||||
currPathIdx < currAltPathsAndSuffixes.length;
|
||||
currPathIdx++
|
||||
) {
|
||||
const currPathPrefix = currAltPathsAndSuffixes[currPathIdx].partialPath;
|
||||
const suffixDef = currAltPathsAndSuffixes[currPathIdx].suffixDef;
|
||||
const prefixKeys = pathToHashKeys(currPathPrefix);
|
||||
const isUnique = isUniquePrefixHash(altsHashes, prefixKeys, altIdx);
|
||||
// End of the line for this path.
|
||||
if (isUnique || isEmpty(suffixDef) || currPathPrefix.length === k) {
|
||||
const currAltResult = finalResult[altIdx];
|
||||
// TODO: Can we implement a containsPath using Maps/Dictionaries?
|
||||
if (containsPath(currAltResult, currPathPrefix) === false) {
|
||||
currAltResult.push(currPathPrefix);
|
||||
// Update all new keys for the current path.
|
||||
for (let j = 0; j < prefixKeys.length; j++) {
|
||||
const currKey = prefixKeys[j];
|
||||
altsHashes[altIdx][currKey] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Expand longer paths
|
||||
else {
|
||||
const newPartialPathsAndSuffixes = possiblePathsFrom(
|
||||
suffixDef,
|
||||
pathLength + 1,
|
||||
currPathPrefix,
|
||||
);
|
||||
newData[altIdx] = newData[altIdx].concat(newPartialPathsAndSuffixes);
|
||||
|
||||
// Update keys for new known paths
|
||||
forEach(newPartialPathsAndSuffixes, (item) => {
|
||||
const prefixKeys = pathToHashKeys(item.partialPath);
|
||||
forEach(prefixKeys, (key) => {
|
||||
altsHashes[altIdx][key] = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return finalResult;
|
||||
}
|
||||
|
||||
export function getLookaheadPathsForOr(
|
||||
occurrence: number,
|
||||
ruleGrammar: Rule,
|
||||
k: number,
|
||||
orProd?: Alternation,
|
||||
): LookaheadSequence[] {
|
||||
const visitor = new InsideDefinitionFinderVisitor(
|
||||
occurrence,
|
||||
PROD_TYPE.ALTERNATION,
|
||||
orProd,
|
||||
);
|
||||
ruleGrammar.accept(visitor);
|
||||
return lookAheadSequenceFromAlternatives(visitor.result, k);
|
||||
}
|
||||
|
||||
export function getLookaheadPathsForOptionalProd(
|
||||
occurrence: number,
|
||||
ruleGrammar: Rule,
|
||||
prodType: PROD_TYPE,
|
||||
k: number,
|
||||
): LookaheadSequence[] {
|
||||
const insideDefVisitor = new InsideDefinitionFinderVisitor(
|
||||
occurrence,
|
||||
prodType,
|
||||
);
|
||||
ruleGrammar.accept(insideDefVisitor);
|
||||
const insideDef = insideDefVisitor.result;
|
||||
|
||||
const afterDefWalker = new RestDefinitionFinderWalker(
|
||||
ruleGrammar,
|
||||
occurrence,
|
||||
prodType,
|
||||
);
|
||||
const afterDef = afterDefWalker.startWalking();
|
||||
|
||||
const insideFlat = new AlternativeGAST({ definition: insideDef });
|
||||
const afterFlat = new AlternativeGAST({ definition: afterDef });
|
||||
|
||||
return lookAheadSequenceFromAlternatives([insideFlat, afterFlat], k);
|
||||
}
|
||||
|
||||
export function containsPath(
|
||||
alternative: Alternative,
|
||||
searchPath: TokenType[],
|
||||
): boolean {
|
||||
compareOtherPath: for (let i = 0; i < alternative.length; i++) {
|
||||
const otherPath = alternative[i];
|
||||
if (otherPath.length !== searchPath.length) {
|
||||
continue;
|
||||
}
|
||||
for (let j = 0; j < otherPath.length; j++) {
|
||||
const searchTok = searchPath[j];
|
||||
const otherTok = otherPath[j];
|
||||
|
||||
const matchingTokens =
|
||||
searchTok === otherTok ||
|
||||
otherTok.categoryMatchesMap![searchTok.tokenTypeIdx!] !== undefined;
|
||||
if (matchingTokens === false) {
|
||||
continue compareOtherPath;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isStrictPrefixOfPath(
|
||||
prefix: TokenType[],
|
||||
other: TokenType[],
|
||||
): boolean {
|
||||
return (
|
||||
prefix.length < other.length &&
|
||||
every(prefix, (tokType, idx) => {
|
||||
const otherTokType = other[idx];
|
||||
return (
|
||||
tokType === otherTokType ||
|
||||
otherTokType.categoryMatchesMap![tokType.tokenTypeIdx!]
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export function areTokenCategoriesNotUsed(
|
||||
lookAheadPaths: LookaheadSequence[],
|
||||
): boolean {
|
||||
return every(lookAheadPaths, (singleAltPaths) =>
|
||||
every(singleAltPaths, (singlePath) =>
|
||||
every(singlePath, (token) => isEmpty(token.categoryMatches!)),
|
||||
),
|
||||
);
|
||||
}
|
||||
57
frontend/node_modules/chevrotain/src/parse/grammar/resolver.ts
generated
vendored
Normal file
57
frontend/node_modules/chevrotain/src/parse/grammar/resolver.ts
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
import {
|
||||
IParserUnresolvedRefDefinitionError,
|
||||
ParserDefinitionErrorType,
|
||||
} from "../parser/parser.js";
|
||||
import { forEach, values } from "lodash-es";
|
||||
import { GAstVisitor, NonTerminal, Rule } from "@chevrotain/gast";
|
||||
import {
|
||||
IGrammarResolverErrorMessageProvider,
|
||||
IParserDefinitionError,
|
||||
} from "./types.js";
|
||||
|
||||
export function resolveGrammar(
|
||||
topLevels: Record<string, Rule>,
|
||||
errMsgProvider: IGrammarResolverErrorMessageProvider,
|
||||
): IParserDefinitionError[] {
|
||||
const refResolver = new GastRefResolverVisitor(topLevels, errMsgProvider);
|
||||
refResolver.resolveRefs();
|
||||
return refResolver.errors;
|
||||
}
|
||||
|
||||
export class GastRefResolverVisitor extends GAstVisitor {
|
||||
public errors: IParserUnresolvedRefDefinitionError[] = [];
|
||||
private currTopLevel: Rule;
|
||||
|
||||
constructor(
|
||||
private nameToTopRule: Record<string, Rule>,
|
||||
private errMsgProvider: IGrammarResolverErrorMessageProvider,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
public resolveRefs(): void {
|
||||
forEach(values(this.nameToTopRule), (prod) => {
|
||||
this.currTopLevel = prod;
|
||||
prod.accept(this);
|
||||
});
|
||||
}
|
||||
|
||||
public visitNonTerminal(node: NonTerminal): void {
|
||||
const ref = this.nameToTopRule[node.nonTerminalName];
|
||||
|
||||
if (!ref) {
|
||||
const msg = this.errMsgProvider.buildRuleNotFoundError(
|
||||
this.currTopLevel,
|
||||
node,
|
||||
);
|
||||
this.errors.push({
|
||||
message: msg,
|
||||
type: ParserDefinitionErrorType.UNRESOLVED_SUBRULE_REF,
|
||||
ruleName: this.currTopLevel.name,
|
||||
unresolvedRefName: node.nonTerminalName,
|
||||
});
|
||||
} else {
|
||||
node.referencedRule = ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
314
frontend/node_modules/chevrotain/src/parse/parser/parser.ts
generated
vendored
Normal file
314
frontend/node_modules/chevrotain/src/parse/parser/parser.ts
generated
vendored
Normal file
@@ -0,0 +1,314 @@
|
||||
import { clone, forEach, has, isEmpty, map, values } from "lodash-es";
|
||||
import { toFastProperties } from "@chevrotain/utils";
|
||||
import { computeAllProdsFollows } from "../grammar/follow.js";
|
||||
import { createTokenInstance, EOF } from "../../scan/tokens_public.js";
|
||||
import {
|
||||
defaultGrammarValidatorErrorProvider,
|
||||
defaultParserErrorProvider,
|
||||
} from "../errors_public.js";
|
||||
import {
|
||||
resolveGrammar,
|
||||
validateGrammar,
|
||||
} from "../grammar/gast/gast_resolver_public.js";
|
||||
import {
|
||||
CstNode,
|
||||
IParserConfig,
|
||||
IRecognitionException,
|
||||
IRuleConfig,
|
||||
IToken,
|
||||
TokenType,
|
||||
TokenVocabulary,
|
||||
} from "@chevrotain/types";
|
||||
import { Recoverable } from "./traits/recoverable.js";
|
||||
import { LooksAhead } from "./traits/looksahead.js";
|
||||
import { TreeBuilder } from "./traits/tree_builder.js";
|
||||
import { LexerAdapter } from "./traits/lexer_adapter.js";
|
||||
import { RecognizerApi } from "./traits/recognizer_api.js";
|
||||
import { RecognizerEngine } from "./traits/recognizer_engine.js";
|
||||
|
||||
import { ErrorHandler } from "./traits/error_handler.js";
|
||||
import { MixedInParser } from "./traits/parser_traits.js";
|
||||
import { ContentAssist } from "./traits/context_assist.js";
|
||||
import { GastRecorder } from "./traits/gast_recorder.js";
|
||||
import { PerformanceTracer } from "./traits/perf_tracer.js";
|
||||
import { applyMixins } from "./utils/apply_mixins.js";
|
||||
import { IParserDefinitionError } from "../grammar/types.js";
|
||||
import { Rule } from "@chevrotain/gast";
|
||||
import { IParserConfigInternal, ParserMethodInternal } from "./types.js";
|
||||
import { validateLookahead } from "../grammar/checks.js";
|
||||
|
||||
export const END_OF_FILE = createTokenInstance(
|
||||
EOF,
|
||||
"",
|
||||
NaN,
|
||||
NaN,
|
||||
NaN,
|
||||
NaN,
|
||||
NaN,
|
||||
NaN,
|
||||
);
|
||||
Object.freeze(END_OF_FILE);
|
||||
|
||||
export type TokenMatcher = (token: IToken, tokType: TokenType) => boolean;
|
||||
|
||||
export const DEFAULT_PARSER_CONFIG: Required<
|
||||
Omit<IParserConfigInternal, "lookaheadStrategy">
|
||||
> = Object.freeze({
|
||||
recoveryEnabled: false,
|
||||
maxLookahead: 3,
|
||||
dynamicTokensEnabled: false,
|
||||
outputCst: true,
|
||||
errorMessageProvider: defaultParserErrorProvider,
|
||||
nodeLocationTracking: "none",
|
||||
traceInitPerf: false,
|
||||
skipValidations: false,
|
||||
});
|
||||
|
||||
export const DEFAULT_RULE_CONFIG: Required<IRuleConfig<any>> = Object.freeze({
|
||||
recoveryValueFunc: () => undefined,
|
||||
resyncEnabled: true,
|
||||
});
|
||||
|
||||
export enum ParserDefinitionErrorType {
|
||||
INVALID_RULE_NAME = 0,
|
||||
DUPLICATE_RULE_NAME = 1,
|
||||
INVALID_RULE_OVERRIDE = 2,
|
||||
DUPLICATE_PRODUCTIONS = 3,
|
||||
UNRESOLVED_SUBRULE_REF = 4,
|
||||
LEFT_RECURSION = 5,
|
||||
NONE_LAST_EMPTY_ALT = 6,
|
||||
AMBIGUOUS_ALTS = 7,
|
||||
CONFLICT_TOKENS_RULES_NAMESPACE = 8,
|
||||
INVALID_TOKEN_NAME = 9,
|
||||
NO_NON_EMPTY_LOOKAHEAD = 10,
|
||||
AMBIGUOUS_PREFIX_ALTS = 11,
|
||||
TOO_MANY_ALTS = 12,
|
||||
CUSTOM_LOOKAHEAD_VALIDATION = 13,
|
||||
}
|
||||
|
||||
export interface IParserDuplicatesDefinitionError extends IParserDefinitionError {
|
||||
dslName: string;
|
||||
occurrence: number;
|
||||
parameter?: string;
|
||||
}
|
||||
|
||||
export interface IParserEmptyAlternativeDefinitionError extends IParserDefinitionError {
|
||||
occurrence: number;
|
||||
alternative: number;
|
||||
}
|
||||
|
||||
export interface IParserAmbiguousAlternativesDefinitionError extends IParserDefinitionError {
|
||||
occurrence: number | string;
|
||||
alternatives: number[];
|
||||
}
|
||||
|
||||
export interface IParserUnresolvedRefDefinitionError extends IParserDefinitionError {
|
||||
unresolvedRefName: string;
|
||||
}
|
||||
|
||||
export interface IParserState {
|
||||
errors: IRecognitionException[];
|
||||
lexerState: any;
|
||||
RULE_STACK: number[];
|
||||
CST_STACK: CstNode[];
|
||||
}
|
||||
|
||||
export type Predicate = () => boolean;
|
||||
|
||||
export function EMPTY_ALT(): () => undefined;
|
||||
export function EMPTY_ALT<T>(value: T): () => T;
|
||||
export function EMPTY_ALT(value: any = undefined) {
|
||||
return function () {
|
||||
return value;
|
||||
};
|
||||
}
|
||||
|
||||
export class Parser {
|
||||
// Set this flag to true if you don't want the Parser to throw error when problems in it's definition are detected.
|
||||
// (normally during the parser's constructor).
|
||||
// This is a design time flag, it will not affect the runtime error handling of the parser, just design time errors,
|
||||
// for example: duplicate rule names, referencing an unresolved subrule, etc...
|
||||
// This flag should not be enabled during normal usage, it is used in special situations, for example when
|
||||
// needing to display the parser definition errors in some GUI(online playground).
|
||||
static DEFER_DEFINITION_ERRORS_HANDLING: boolean = false;
|
||||
|
||||
/**
|
||||
* @deprecated use the **instance** method with the same name instead
|
||||
*/
|
||||
static performSelfAnalysis(parserInstance: Parser): void {
|
||||
throw Error(
|
||||
"The **static** `performSelfAnalysis` method has been deprecated." +
|
||||
"\t\nUse the **instance** method with the same name instead.",
|
||||
);
|
||||
}
|
||||
|
||||
public performSelfAnalysis(this: MixedInParser): void {
|
||||
this.TRACE_INIT("performSelfAnalysis", () => {
|
||||
let defErrorsMsgs;
|
||||
|
||||
this.selfAnalysisDone = true;
|
||||
const className = this.className;
|
||||
|
||||
this.TRACE_INIT("toFastProps", () => {
|
||||
// Without this voodoo magic the parser would be x3-x4 slower
|
||||
// It seems it is better to invoke `toFastProperties` **before**
|
||||
// Any manipulations of the `this` object done during the recording phase.
|
||||
toFastProperties(this);
|
||||
});
|
||||
|
||||
this.TRACE_INIT("Grammar Recording", () => {
|
||||
try {
|
||||
this.enableRecording();
|
||||
// Building the GAST
|
||||
forEach(this.definedRulesNames, (currRuleName) => {
|
||||
const wrappedRule = (this as any)[
|
||||
currRuleName
|
||||
] as ParserMethodInternal<unknown[], unknown>;
|
||||
const originalGrammarAction = wrappedRule["originalGrammarAction"];
|
||||
let recordedRuleGast!: Rule;
|
||||
this.TRACE_INIT(`${currRuleName} Rule`, () => {
|
||||
recordedRuleGast = this.topLevelRuleRecord(
|
||||
currRuleName,
|
||||
originalGrammarAction,
|
||||
);
|
||||
});
|
||||
this.gastProductionsCache[currRuleName] = recordedRuleGast;
|
||||
});
|
||||
} finally {
|
||||
this.disableRecording();
|
||||
}
|
||||
});
|
||||
|
||||
let resolverErrors: IParserDefinitionError[] = [];
|
||||
this.TRACE_INIT("Grammar Resolving", () => {
|
||||
resolverErrors = resolveGrammar({
|
||||
rules: values(this.gastProductionsCache),
|
||||
});
|
||||
this.definitionErrors = this.definitionErrors.concat(resolverErrors);
|
||||
});
|
||||
|
||||
this.TRACE_INIT("Grammar Validations", () => {
|
||||
// only perform additional grammar validations IFF no resolving errors have occurred.
|
||||
// as unresolved grammar may lead to unhandled runtime exceptions in the follow up validations.
|
||||
if (isEmpty(resolverErrors) && this.skipValidations === false) {
|
||||
const validationErrors = validateGrammar({
|
||||
rules: values(this.gastProductionsCache),
|
||||
tokenTypes: values(this.tokensMap),
|
||||
errMsgProvider: defaultGrammarValidatorErrorProvider,
|
||||
grammarName: className,
|
||||
});
|
||||
const lookaheadValidationErrors = validateLookahead({
|
||||
lookaheadStrategy: this.lookaheadStrategy,
|
||||
rules: values(this.gastProductionsCache),
|
||||
tokenTypes: values(this.tokensMap),
|
||||
grammarName: className,
|
||||
});
|
||||
this.definitionErrors = this.definitionErrors.concat(
|
||||
validationErrors,
|
||||
lookaheadValidationErrors,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// this analysis may fail if the grammar is not perfectly valid
|
||||
if (isEmpty(this.definitionErrors)) {
|
||||
// The results of these computations are not needed unless error recovery is enabled.
|
||||
if (this.recoveryEnabled) {
|
||||
this.TRACE_INIT("computeAllProdsFollows", () => {
|
||||
const allFollows = computeAllProdsFollows(
|
||||
values(this.gastProductionsCache),
|
||||
);
|
||||
this.resyncFollows = allFollows;
|
||||
});
|
||||
}
|
||||
|
||||
this.TRACE_INIT("ComputeLookaheadFunctions", () => {
|
||||
this.lookaheadStrategy.initialize?.({
|
||||
rules: values(this.gastProductionsCache),
|
||||
});
|
||||
this.preComputeLookaheadFunctions(values(this.gastProductionsCache));
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
!Parser.DEFER_DEFINITION_ERRORS_HANDLING &&
|
||||
!isEmpty(this.definitionErrors)
|
||||
) {
|
||||
defErrorsMsgs = map(
|
||||
this.definitionErrors,
|
||||
(defError) => defError.message,
|
||||
);
|
||||
throw new Error(
|
||||
`Parser Definition Errors detected:\n ${defErrorsMsgs.join(
|
||||
"\n-------------------------------\n",
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
definitionErrors: IParserDefinitionError[] = [];
|
||||
selfAnalysisDone = false;
|
||||
protected skipValidations: boolean;
|
||||
|
||||
constructor(tokenVocabulary: TokenVocabulary, config: IParserConfig) {
|
||||
const that: MixedInParser = this as any;
|
||||
that.initErrorHandler(config);
|
||||
that.initLexerAdapter();
|
||||
that.initLooksAhead(config);
|
||||
that.initRecognizerEngine(tokenVocabulary, config);
|
||||
that.initRecoverable(config);
|
||||
that.initTreeBuilder(config);
|
||||
that.initContentAssist();
|
||||
that.initGastRecorder(config);
|
||||
that.initPerformanceTracer(config);
|
||||
|
||||
if (has(config, "ignoredIssues")) {
|
||||
throw new Error(
|
||||
"The <ignoredIssues> IParserConfig property has been deprecated.\n\t" +
|
||||
"Please use the <IGNORE_AMBIGUITIES> flag on the relevant DSL method instead.\n\t" +
|
||||
"See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#IGNORING_AMBIGUITIES\n\t" +
|
||||
"For further details.",
|
||||
);
|
||||
}
|
||||
|
||||
this.skipValidations = has(config, "skipValidations")
|
||||
? (config.skipValidations as boolean) // casting assumes the end user passing the correct type
|
||||
: DEFAULT_PARSER_CONFIG.skipValidations;
|
||||
}
|
||||
}
|
||||
|
||||
applyMixins(Parser, [
|
||||
Recoverable,
|
||||
LooksAhead,
|
||||
TreeBuilder,
|
||||
LexerAdapter,
|
||||
RecognizerEngine,
|
||||
RecognizerApi,
|
||||
ErrorHandler,
|
||||
ContentAssist,
|
||||
GastRecorder,
|
||||
PerformanceTracer,
|
||||
]);
|
||||
|
||||
export class CstParser extends Parser {
|
||||
constructor(
|
||||
tokenVocabulary: TokenVocabulary,
|
||||
config: IParserConfigInternal = DEFAULT_PARSER_CONFIG,
|
||||
) {
|
||||
const configClone = clone(config);
|
||||
configClone.outputCst = true;
|
||||
super(tokenVocabulary, configClone);
|
||||
}
|
||||
}
|
||||
|
||||
export class EmbeddedActionsParser extends Parser {
|
||||
constructor(
|
||||
tokenVocabulary: TokenVocabulary,
|
||||
config: IParserConfigInternal = DEFAULT_PARSER_CONFIG,
|
||||
) {
|
||||
const configClone = clone(config);
|
||||
configClone.outputCst = false;
|
||||
super(tokenVocabulary, configClone);
|
||||
}
|
||||
}
|
||||
269
frontend/node_modules/chevrotain/src/parse/parser/traits/looksahead.ts
generated
vendored
Normal file
269
frontend/node_modules/chevrotain/src/parse/parser/traits/looksahead.ts
generated
vendored
Normal file
@@ -0,0 +1,269 @@
|
||||
import { forEach, has } from "lodash-es";
|
||||
import { DEFAULT_PARSER_CONFIG } from "../parser.js";
|
||||
import {
|
||||
ILookaheadStrategy,
|
||||
IParserConfig,
|
||||
OptionalProductionType,
|
||||
} from "@chevrotain/types";
|
||||
import {
|
||||
AT_LEAST_ONE_IDX,
|
||||
AT_LEAST_ONE_SEP_IDX,
|
||||
getKeyForAutomaticLookahead,
|
||||
MANY_IDX,
|
||||
MANY_SEP_IDX,
|
||||
OPTION_IDX,
|
||||
OR_IDX,
|
||||
} from "../../grammar/keys.js";
|
||||
import { MixedInParser } from "./parser_traits.js";
|
||||
import {
|
||||
Alternation,
|
||||
GAstVisitor,
|
||||
getProductionDslName,
|
||||
Option,
|
||||
Repetition,
|
||||
RepetitionMandatory,
|
||||
RepetitionMandatoryWithSeparator,
|
||||
RepetitionWithSeparator,
|
||||
Rule,
|
||||
} from "@chevrotain/gast";
|
||||
import { LLkLookaheadStrategy } from "../../grammar/llk_lookahead.js";
|
||||
|
||||
/**
|
||||
* Trait responsible for the lookahead related utilities and optimizations.
|
||||
*/
|
||||
export class LooksAhead {
|
||||
maxLookahead: number;
|
||||
lookAheadFuncsCache: any;
|
||||
dynamicTokensEnabled: boolean;
|
||||
lookaheadStrategy: ILookaheadStrategy;
|
||||
|
||||
initLooksAhead(config: IParserConfig) {
|
||||
this.dynamicTokensEnabled = has(config, "dynamicTokensEnabled")
|
||||
? (config.dynamicTokensEnabled as boolean) // assumes end user provides the correct config value/type
|
||||
: DEFAULT_PARSER_CONFIG.dynamicTokensEnabled;
|
||||
|
||||
this.maxLookahead = has(config, "maxLookahead")
|
||||
? (config.maxLookahead as number) // assumes end user provides the correct config value/type
|
||||
: DEFAULT_PARSER_CONFIG.maxLookahead;
|
||||
|
||||
this.lookaheadStrategy = has(config, "lookaheadStrategy")
|
||||
? (config.lookaheadStrategy as ILookaheadStrategy) // assumes end user provides the correct config value/type
|
||||
: new LLkLookaheadStrategy({ maxLookahead: this.maxLookahead });
|
||||
|
||||
this.lookAheadFuncsCache = new Map();
|
||||
}
|
||||
|
||||
preComputeLookaheadFunctions(this: MixedInParser, rules: Rule[]): void {
|
||||
forEach(rules, (currRule) => {
|
||||
this.TRACE_INIT(`${currRule.name} Rule Lookahead`, () => {
|
||||
const {
|
||||
alternation,
|
||||
repetition,
|
||||
option,
|
||||
repetitionMandatory,
|
||||
repetitionMandatoryWithSeparator,
|
||||
repetitionWithSeparator,
|
||||
} = collectMethods(currRule);
|
||||
|
||||
forEach(alternation, (currProd) => {
|
||||
const prodIdx = currProd.idx === 0 ? "" : currProd.idx;
|
||||
this.TRACE_INIT(`${getProductionDslName(currProd)}${prodIdx}`, () => {
|
||||
const laFunc = this.lookaheadStrategy.buildLookaheadForAlternation({
|
||||
prodOccurrence: currProd.idx,
|
||||
rule: currRule,
|
||||
maxLookahead: currProd.maxLookahead || this.maxLookahead,
|
||||
hasPredicates: currProd.hasPredicates,
|
||||
dynamicTokensEnabled: this.dynamicTokensEnabled,
|
||||
});
|
||||
|
||||
const key = getKeyForAutomaticLookahead(
|
||||
this.fullRuleNameToShort[currRule.name],
|
||||
OR_IDX,
|
||||
currProd.idx,
|
||||
);
|
||||
this.setLaFuncCache(key, laFunc);
|
||||
});
|
||||
});
|
||||
|
||||
forEach(repetition, (currProd) => {
|
||||
this.computeLookaheadFunc(
|
||||
currRule,
|
||||
currProd.idx,
|
||||
MANY_IDX,
|
||||
"Repetition",
|
||||
currProd.maxLookahead,
|
||||
getProductionDslName(currProd),
|
||||
);
|
||||
});
|
||||
|
||||
forEach(option, (currProd) => {
|
||||
this.computeLookaheadFunc(
|
||||
currRule,
|
||||
currProd.idx,
|
||||
OPTION_IDX,
|
||||
"Option",
|
||||
currProd.maxLookahead,
|
||||
getProductionDslName(currProd),
|
||||
);
|
||||
});
|
||||
|
||||
forEach(repetitionMandatory, (currProd) => {
|
||||
this.computeLookaheadFunc(
|
||||
currRule,
|
||||
currProd.idx,
|
||||
AT_LEAST_ONE_IDX,
|
||||
"RepetitionMandatory",
|
||||
currProd.maxLookahead,
|
||||
getProductionDslName(currProd),
|
||||
);
|
||||
});
|
||||
|
||||
forEach(repetitionMandatoryWithSeparator, (currProd) => {
|
||||
this.computeLookaheadFunc(
|
||||
currRule,
|
||||
currProd.idx,
|
||||
AT_LEAST_ONE_SEP_IDX,
|
||||
"RepetitionMandatoryWithSeparator",
|
||||
currProd.maxLookahead,
|
||||
getProductionDslName(currProd),
|
||||
);
|
||||
});
|
||||
|
||||
forEach(repetitionWithSeparator, (currProd) => {
|
||||
this.computeLookaheadFunc(
|
||||
currRule,
|
||||
currProd.idx,
|
||||
MANY_SEP_IDX,
|
||||
"RepetitionWithSeparator",
|
||||
currProd.maxLookahead,
|
||||
getProductionDslName(currProd),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
computeLookaheadFunc(
|
||||
this: MixedInParser,
|
||||
rule: Rule,
|
||||
prodOccurrence: number,
|
||||
prodKey: number,
|
||||
prodType: OptionalProductionType,
|
||||
prodMaxLookahead: number | undefined,
|
||||
dslMethodName: string,
|
||||
): void {
|
||||
this.TRACE_INIT(
|
||||
`${dslMethodName}${prodOccurrence === 0 ? "" : prodOccurrence}`,
|
||||
() => {
|
||||
const laFunc = this.lookaheadStrategy.buildLookaheadForOptional({
|
||||
prodOccurrence,
|
||||
rule,
|
||||
maxLookahead: prodMaxLookahead || this.maxLookahead,
|
||||
dynamicTokensEnabled: this.dynamicTokensEnabled,
|
||||
prodType,
|
||||
});
|
||||
const key = getKeyForAutomaticLookahead(
|
||||
this.fullRuleNameToShort[rule.name],
|
||||
prodKey,
|
||||
prodOccurrence,
|
||||
);
|
||||
this.setLaFuncCache(key, laFunc);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// this actually returns a number, but it is always used as a string (object prop key)
|
||||
getKeyForAutomaticLookahead(
|
||||
this: MixedInParser,
|
||||
dslMethodIdx: number,
|
||||
occurrence: number,
|
||||
): number {
|
||||
const currRuleShortName: any = this.getLastExplicitRuleShortName();
|
||||
return getKeyForAutomaticLookahead(
|
||||
currRuleShortName,
|
||||
dslMethodIdx,
|
||||
occurrence,
|
||||
);
|
||||
}
|
||||
|
||||
getLaFuncFromCache(this: MixedInParser, key: number): Function {
|
||||
return this.lookAheadFuncsCache.get(key);
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
setLaFuncCache(this: MixedInParser, key: number, value: Function): void {
|
||||
this.lookAheadFuncsCache.set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
class DslMethodsCollectorVisitor extends GAstVisitor {
|
||||
public dslMethods: {
|
||||
option: Option[];
|
||||
alternation: Alternation[];
|
||||
repetition: Repetition[];
|
||||
repetitionWithSeparator: RepetitionWithSeparator[];
|
||||
repetitionMandatory: RepetitionMandatory[];
|
||||
repetitionMandatoryWithSeparator: RepetitionMandatoryWithSeparator[];
|
||||
} = {
|
||||
option: [],
|
||||
alternation: [],
|
||||
repetition: [],
|
||||
repetitionWithSeparator: [],
|
||||
repetitionMandatory: [],
|
||||
repetitionMandatoryWithSeparator: [],
|
||||
};
|
||||
|
||||
reset() {
|
||||
this.dslMethods = {
|
||||
option: [],
|
||||
alternation: [],
|
||||
repetition: [],
|
||||
repetitionWithSeparator: [],
|
||||
repetitionMandatory: [],
|
||||
repetitionMandatoryWithSeparator: [],
|
||||
};
|
||||
}
|
||||
|
||||
public visitOption(option: Option): void {
|
||||
this.dslMethods.option.push(option);
|
||||
}
|
||||
|
||||
public visitRepetitionWithSeparator(manySep: RepetitionWithSeparator): void {
|
||||
this.dslMethods.repetitionWithSeparator.push(manySep);
|
||||
}
|
||||
|
||||
public visitRepetitionMandatory(atLeastOne: RepetitionMandatory): void {
|
||||
this.dslMethods.repetitionMandatory.push(atLeastOne);
|
||||
}
|
||||
|
||||
public visitRepetitionMandatoryWithSeparator(
|
||||
atLeastOneSep: RepetitionMandatoryWithSeparator,
|
||||
): void {
|
||||
this.dslMethods.repetitionMandatoryWithSeparator.push(atLeastOneSep);
|
||||
}
|
||||
|
||||
public visitRepetition(many: Repetition): void {
|
||||
this.dslMethods.repetition.push(many);
|
||||
}
|
||||
|
||||
public visitAlternation(or: Alternation): void {
|
||||
this.dslMethods.alternation.push(or);
|
||||
}
|
||||
}
|
||||
|
||||
const collectorVisitor = new DslMethodsCollectorVisitor();
|
||||
export function collectMethods(rule: Rule): {
|
||||
option: Option[];
|
||||
alternation: Alternation[];
|
||||
repetition: Repetition[];
|
||||
repetitionWithSeparator: RepetitionWithSeparator[];
|
||||
repetitionMandatory: RepetitionMandatory[];
|
||||
repetitionMandatoryWithSeparator: RepetitionMandatoryWithSeparator[];
|
||||
} {
|
||||
collectorVisitor.reset();
|
||||
rule.accept(collectorVisitor);
|
||||
const dslMethods = collectorVisitor.dslMethods;
|
||||
// avoid uncleaned references
|
||||
collectorVisitor.reset();
|
||||
return <any>dslMethods;
|
||||
}
|
||||
54
frontend/node_modules/chevrotain/src/parse/parser/traits/perf_tracer.ts
generated
vendored
Normal file
54
frontend/node_modules/chevrotain/src/parse/parser/traits/perf_tracer.ts
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
import { IParserConfig } from "@chevrotain/types";
|
||||
import { has } from "lodash-es";
|
||||
import { timer } from "@chevrotain/utils";
|
||||
import { MixedInParser } from "./parser_traits.js";
|
||||
import { DEFAULT_PARSER_CONFIG } from "../parser.js";
|
||||
|
||||
/**
|
||||
* Trait responsible for runtime parsing errors.
|
||||
*/
|
||||
export class PerformanceTracer {
|
||||
traceInitPerf: boolean | number;
|
||||
traceInitMaxIdent: number;
|
||||
traceInitIndent: number;
|
||||
|
||||
initPerformanceTracer(config: IParserConfig) {
|
||||
if (has(config, "traceInitPerf")) {
|
||||
const userTraceInitPerf = config.traceInitPerf;
|
||||
const traceIsNumber = typeof userTraceInitPerf === "number";
|
||||
this.traceInitMaxIdent = traceIsNumber
|
||||
? <number>userTraceInitPerf
|
||||
: Infinity;
|
||||
this.traceInitPerf = traceIsNumber
|
||||
? userTraceInitPerf > 0
|
||||
: (userTraceInitPerf as boolean); // assumes end user provides the correct config value/type
|
||||
} else {
|
||||
this.traceInitMaxIdent = 0;
|
||||
this.traceInitPerf = DEFAULT_PARSER_CONFIG.traceInitPerf;
|
||||
}
|
||||
|
||||
this.traceInitIndent = -1;
|
||||
}
|
||||
|
||||
TRACE_INIT<T>(this: MixedInParser, phaseDesc: string, phaseImpl: () => T): T {
|
||||
// No need to optimize this using NOOP pattern because
|
||||
// It is not called in a hot spot...
|
||||
if (this.traceInitPerf === true) {
|
||||
this.traceInitIndent++;
|
||||
const indent = new Array(this.traceInitIndent + 1).join("\t");
|
||||
if (this.traceInitIndent < this.traceInitMaxIdent) {
|
||||
console.log(`${indent}--> <${phaseDesc}>`);
|
||||
}
|
||||
const { time, value } = timer(phaseImpl);
|
||||
/* istanbul ignore next - Difficult to reproduce specific performance behavior (>10ms) in tests */
|
||||
const traceMethod = time > 10 ? console.warn : console.log;
|
||||
if (this.traceInitIndent < this.traceInitMaxIdent) {
|
||||
traceMethod(`${indent}<-- <${phaseDesc}> time: ${time}ms`);
|
||||
}
|
||||
this.traceInitIndent--;
|
||||
return value;
|
||||
} else {
|
||||
return phaseImpl();
|
||||
}
|
||||
}
|
||||
}
|
||||
719
frontend/node_modules/chevrotain/src/parse/parser/traits/recognizer_api.ts
generated
vendored
Normal file
719
frontend/node_modules/chevrotain/src/parse/parser/traits/recognizer_api.ts
generated
vendored
Normal file
@@ -0,0 +1,719 @@
|
||||
import {
|
||||
AtLeastOneSepMethodOpts,
|
||||
ConsumeMethodOpts,
|
||||
DSLMethodOpts,
|
||||
DSLMethodOptsWithErr,
|
||||
GrammarAction,
|
||||
IOrAlt,
|
||||
IRuleConfig,
|
||||
ISerializedGast,
|
||||
IToken,
|
||||
ManySepMethodOpts,
|
||||
OrMethodOpts,
|
||||
SubruleMethodOpts,
|
||||
TokenType,
|
||||
} from "@chevrotain/types";
|
||||
import { includes, values } from "lodash-es";
|
||||
import { isRecognitionException } from "../../exceptions_public.js";
|
||||
import { DEFAULT_RULE_CONFIG, ParserDefinitionErrorType } from "../parser.js";
|
||||
import { defaultGrammarValidatorErrorProvider } from "../../errors_public.js";
|
||||
import { validateRuleIsOverridden } from "../../grammar/checks.js";
|
||||
import { MixedInParser } from "./parser_traits.js";
|
||||
import { Rule, serializeGrammar } from "@chevrotain/gast";
|
||||
import { IParserDefinitionError } from "../../grammar/types.js";
|
||||
import { ParserMethodInternal } from "../types.js";
|
||||
|
||||
/**
|
||||
* This trait is responsible for implementing the public API
|
||||
* for defining Chevrotain parsers, i.e:
|
||||
* - CONSUME
|
||||
* - RULE
|
||||
* - OPTION
|
||||
* - ...
|
||||
*/
|
||||
export class RecognizerApi {
|
||||
ACTION<T>(this: MixedInParser, impl: () => T): T {
|
||||
return impl.call(this);
|
||||
}
|
||||
|
||||
consume(
|
||||
this: MixedInParser,
|
||||
idx: number,
|
||||
tokType: TokenType,
|
||||
options?: ConsumeMethodOpts,
|
||||
): IToken {
|
||||
return this.consumeInternal(tokType, idx, options);
|
||||
}
|
||||
|
||||
subrule<ARGS extends unknown[], R>(
|
||||
this: MixedInParser,
|
||||
idx: number,
|
||||
ruleToCall: ParserMethodInternal<ARGS, R>,
|
||||
options?: SubruleMethodOpts<ARGS>,
|
||||
): R {
|
||||
return this.subruleInternal(ruleToCall, idx, options);
|
||||
}
|
||||
|
||||
option<OUT>(
|
||||
this: MixedInParser,
|
||||
idx: number,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOpts<OUT>,
|
||||
): OUT | undefined {
|
||||
return this.optionInternal(actionORMethodDef, idx);
|
||||
}
|
||||
|
||||
or(
|
||||
this: MixedInParser,
|
||||
idx: number,
|
||||
altsOrOpts: IOrAlt<any>[] | OrMethodOpts<any>,
|
||||
): any {
|
||||
return this.orInternal(altsOrOpts, idx);
|
||||
}
|
||||
|
||||
many(
|
||||
this: MixedInParser,
|
||||
idx: number,
|
||||
actionORMethodDef: GrammarAction<any> | DSLMethodOpts<any>,
|
||||
): void {
|
||||
return this.manyInternal(idx, actionORMethodDef);
|
||||
}
|
||||
|
||||
atLeastOne(
|
||||
this: MixedInParser,
|
||||
idx: number,
|
||||
actionORMethodDef: GrammarAction<any> | DSLMethodOptsWithErr<any>,
|
||||
): void {
|
||||
return this.atLeastOneInternal(idx, actionORMethodDef);
|
||||
}
|
||||
|
||||
CONSUME(
|
||||
this: MixedInParser,
|
||||
tokType: TokenType,
|
||||
options?: ConsumeMethodOpts,
|
||||
): IToken {
|
||||
return this.consumeInternal(tokType, 0, options);
|
||||
}
|
||||
|
||||
CONSUME1(
|
||||
this: MixedInParser,
|
||||
tokType: TokenType,
|
||||
options?: ConsumeMethodOpts,
|
||||
): IToken {
|
||||
return this.consumeInternal(tokType, 1, options);
|
||||
}
|
||||
|
||||
CONSUME2(
|
||||
this: MixedInParser,
|
||||
tokType: TokenType,
|
||||
options?: ConsumeMethodOpts,
|
||||
): IToken {
|
||||
return this.consumeInternal(tokType, 2, options);
|
||||
}
|
||||
|
||||
CONSUME3(
|
||||
this: MixedInParser,
|
||||
tokType: TokenType,
|
||||
options?: ConsumeMethodOpts,
|
||||
): IToken {
|
||||
return this.consumeInternal(tokType, 3, options);
|
||||
}
|
||||
|
||||
CONSUME4(
|
||||
this: MixedInParser,
|
||||
tokType: TokenType,
|
||||
options?: ConsumeMethodOpts,
|
||||
): IToken {
|
||||
return this.consumeInternal(tokType, 4, options);
|
||||
}
|
||||
|
||||
CONSUME5(
|
||||
this: MixedInParser,
|
||||
tokType: TokenType,
|
||||
options?: ConsumeMethodOpts,
|
||||
): IToken {
|
||||
return this.consumeInternal(tokType, 5, options);
|
||||
}
|
||||
|
||||
CONSUME6(
|
||||
this: MixedInParser,
|
||||
tokType: TokenType,
|
||||
options?: ConsumeMethodOpts,
|
||||
): IToken {
|
||||
return this.consumeInternal(tokType, 6, options);
|
||||
}
|
||||
|
||||
CONSUME7(
|
||||
this: MixedInParser,
|
||||
tokType: TokenType,
|
||||
options?: ConsumeMethodOpts,
|
||||
): IToken {
|
||||
return this.consumeInternal(tokType, 7, options);
|
||||
}
|
||||
|
||||
CONSUME8(
|
||||
this: MixedInParser,
|
||||
tokType: TokenType,
|
||||
options?: ConsumeMethodOpts,
|
||||
): IToken {
|
||||
return this.consumeInternal(tokType, 8, options);
|
||||
}
|
||||
|
||||
CONSUME9(
|
||||
this: MixedInParser,
|
||||
tokType: TokenType,
|
||||
options?: ConsumeMethodOpts,
|
||||
): IToken {
|
||||
return this.consumeInternal(tokType, 9, options);
|
||||
}
|
||||
|
||||
SUBRULE<ARGS extends unknown[], R>(
|
||||
this: MixedInParser,
|
||||
ruleToCall: ParserMethodInternal<ARGS, R>,
|
||||
options?: SubruleMethodOpts<ARGS>,
|
||||
): R {
|
||||
return this.subruleInternal(ruleToCall, 0, options);
|
||||
}
|
||||
|
||||
SUBRULE1<ARGS extends unknown[], R>(
|
||||
this: MixedInParser,
|
||||
ruleToCall: ParserMethodInternal<ARGS, R>,
|
||||
options?: SubruleMethodOpts<ARGS>,
|
||||
): R {
|
||||
return this.subruleInternal(ruleToCall, 1, options);
|
||||
}
|
||||
|
||||
SUBRULE2<ARGS extends unknown[], R>(
|
||||
this: MixedInParser,
|
||||
ruleToCall: ParserMethodInternal<ARGS, R>,
|
||||
options?: SubruleMethodOpts<ARGS>,
|
||||
): R {
|
||||
return this.subruleInternal(ruleToCall, 2, options);
|
||||
}
|
||||
|
||||
SUBRULE3<ARGS extends unknown[], R>(
|
||||
this: MixedInParser,
|
||||
ruleToCall: ParserMethodInternal<ARGS, R>,
|
||||
options?: SubruleMethodOpts<ARGS>,
|
||||
): R {
|
||||
return this.subruleInternal(ruleToCall, 3, options);
|
||||
}
|
||||
|
||||
SUBRULE4<ARGS extends unknown[], R>(
|
||||
this: MixedInParser,
|
||||
ruleToCall: ParserMethodInternal<ARGS, R>,
|
||||
options?: SubruleMethodOpts<ARGS>,
|
||||
): R {
|
||||
return this.subruleInternal(ruleToCall, 4, options);
|
||||
}
|
||||
|
||||
SUBRULE5<ARGS extends unknown[], R>(
|
||||
this: MixedInParser,
|
||||
ruleToCall: ParserMethodInternal<ARGS, R>,
|
||||
options?: SubruleMethodOpts<ARGS>,
|
||||
): R {
|
||||
return this.subruleInternal(ruleToCall, 5, options);
|
||||
}
|
||||
|
||||
SUBRULE6<ARGS extends unknown[], R>(
|
||||
this: MixedInParser,
|
||||
ruleToCall: ParserMethodInternal<ARGS, R>,
|
||||
options?: SubruleMethodOpts<ARGS>,
|
||||
): R {
|
||||
return this.subruleInternal(ruleToCall, 6, options);
|
||||
}
|
||||
|
||||
SUBRULE7<ARGS extends unknown[], R>(
|
||||
this: MixedInParser,
|
||||
ruleToCall: ParserMethodInternal<ARGS, R>,
|
||||
options?: SubruleMethodOpts<ARGS>,
|
||||
): R {
|
||||
return this.subruleInternal(ruleToCall, 7, options);
|
||||
}
|
||||
|
||||
SUBRULE8<ARGS extends unknown[], R>(
|
||||
this: MixedInParser,
|
||||
ruleToCall: ParserMethodInternal<ARGS, R>,
|
||||
options?: SubruleMethodOpts<ARGS>,
|
||||
): R {
|
||||
return this.subruleInternal(ruleToCall, 8, options);
|
||||
}
|
||||
|
||||
SUBRULE9<ARGS extends unknown[], R>(
|
||||
this: MixedInParser,
|
||||
ruleToCall: ParserMethodInternal<ARGS, R>,
|
||||
options?: SubruleMethodOpts<ARGS>,
|
||||
): R {
|
||||
return this.subruleInternal(ruleToCall, 9, options);
|
||||
}
|
||||
|
||||
OPTION<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOpts<OUT>,
|
||||
): OUT | undefined {
|
||||
return this.optionInternal(actionORMethodDef, 0);
|
||||
}
|
||||
|
||||
OPTION1<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOpts<OUT>,
|
||||
): OUT | undefined {
|
||||
return this.optionInternal(actionORMethodDef, 1);
|
||||
}
|
||||
|
||||
OPTION2<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOpts<OUT>,
|
||||
): OUT | undefined {
|
||||
return this.optionInternal(actionORMethodDef, 2);
|
||||
}
|
||||
|
||||
OPTION3<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOpts<OUT>,
|
||||
): OUT | undefined {
|
||||
return this.optionInternal(actionORMethodDef, 3);
|
||||
}
|
||||
|
||||
OPTION4<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOpts<OUT>,
|
||||
): OUT | undefined {
|
||||
return this.optionInternal(actionORMethodDef, 4);
|
||||
}
|
||||
|
||||
OPTION5<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOpts<OUT>,
|
||||
): OUT | undefined {
|
||||
return this.optionInternal(actionORMethodDef, 5);
|
||||
}
|
||||
|
||||
OPTION6<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOpts<OUT>,
|
||||
): OUT | undefined {
|
||||
return this.optionInternal(actionORMethodDef, 6);
|
||||
}
|
||||
|
||||
OPTION7<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOpts<OUT>,
|
||||
): OUT | undefined {
|
||||
return this.optionInternal(actionORMethodDef, 7);
|
||||
}
|
||||
|
||||
OPTION8<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOpts<OUT>,
|
||||
): OUT | undefined {
|
||||
return this.optionInternal(actionORMethodDef, 8);
|
||||
}
|
||||
|
||||
OPTION9<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOpts<OUT>,
|
||||
): OUT | undefined {
|
||||
return this.optionInternal(actionORMethodDef, 9);
|
||||
}
|
||||
|
||||
OR<T>(
|
||||
this: MixedInParser,
|
||||
altsOrOpts: IOrAlt<any>[] | OrMethodOpts<unknown>,
|
||||
): T {
|
||||
return this.orInternal(altsOrOpts, 0);
|
||||
}
|
||||
|
||||
OR1<T>(
|
||||
this: MixedInParser,
|
||||
altsOrOpts: IOrAlt<any>[] | OrMethodOpts<unknown>,
|
||||
): T {
|
||||
return this.orInternal(altsOrOpts, 1);
|
||||
}
|
||||
|
||||
OR2<T>(
|
||||
this: MixedInParser,
|
||||
altsOrOpts: IOrAlt<any>[] | OrMethodOpts<unknown>,
|
||||
): T {
|
||||
return this.orInternal(altsOrOpts, 2);
|
||||
}
|
||||
|
||||
OR3<T>(
|
||||
this: MixedInParser,
|
||||
altsOrOpts: IOrAlt<any>[] | OrMethodOpts<unknown>,
|
||||
): T {
|
||||
return this.orInternal(altsOrOpts, 3);
|
||||
}
|
||||
|
||||
OR4<T>(
|
||||
this: MixedInParser,
|
||||
altsOrOpts: IOrAlt<any>[] | OrMethodOpts<unknown>,
|
||||
): T {
|
||||
return this.orInternal(altsOrOpts, 4);
|
||||
}
|
||||
|
||||
OR5<T>(
|
||||
this: MixedInParser,
|
||||
altsOrOpts: IOrAlt<any>[] | OrMethodOpts<unknown>,
|
||||
): T {
|
||||
return this.orInternal(altsOrOpts, 5);
|
||||
}
|
||||
|
||||
OR6<T>(
|
||||
this: MixedInParser,
|
||||
altsOrOpts: IOrAlt<any>[] | OrMethodOpts<unknown>,
|
||||
): T {
|
||||
return this.orInternal(altsOrOpts, 6);
|
||||
}
|
||||
|
||||
OR7<T>(
|
||||
this: MixedInParser,
|
||||
altsOrOpts: IOrAlt<any>[] | OrMethodOpts<unknown>,
|
||||
): T {
|
||||
return this.orInternal(altsOrOpts, 7);
|
||||
}
|
||||
|
||||
OR8<T>(
|
||||
this: MixedInParser,
|
||||
altsOrOpts: IOrAlt<any>[] | OrMethodOpts<unknown>,
|
||||
): T {
|
||||
return this.orInternal(altsOrOpts, 8);
|
||||
}
|
||||
|
||||
OR9<T>(
|
||||
this: MixedInParser,
|
||||
altsOrOpts: IOrAlt<any>[] | OrMethodOpts<unknown>,
|
||||
): T {
|
||||
return this.orInternal(altsOrOpts, 9);
|
||||
}
|
||||
|
||||
MANY<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOpts<OUT>,
|
||||
): void {
|
||||
this.manyInternal(0, actionORMethodDef);
|
||||
}
|
||||
|
||||
MANY1<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOpts<OUT>,
|
||||
): void {
|
||||
this.manyInternal(1, actionORMethodDef);
|
||||
}
|
||||
|
||||
MANY2<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOpts<OUT>,
|
||||
): void {
|
||||
this.manyInternal(2, actionORMethodDef);
|
||||
}
|
||||
|
||||
MANY3<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOpts<OUT>,
|
||||
): void {
|
||||
this.manyInternal(3, actionORMethodDef);
|
||||
}
|
||||
|
||||
MANY4<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOpts<OUT>,
|
||||
): void {
|
||||
this.manyInternal(4, actionORMethodDef);
|
||||
}
|
||||
|
||||
MANY5<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOpts<OUT>,
|
||||
): void {
|
||||
this.manyInternal(5, actionORMethodDef);
|
||||
}
|
||||
|
||||
MANY6<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOpts<OUT>,
|
||||
): void {
|
||||
this.manyInternal(6, actionORMethodDef);
|
||||
}
|
||||
|
||||
MANY7<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOpts<OUT>,
|
||||
): void {
|
||||
this.manyInternal(7, actionORMethodDef);
|
||||
}
|
||||
|
||||
MANY8<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOpts<OUT>,
|
||||
): void {
|
||||
this.manyInternal(8, actionORMethodDef);
|
||||
}
|
||||
|
||||
MANY9<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOpts<OUT>,
|
||||
): void {
|
||||
this.manyInternal(9, actionORMethodDef);
|
||||
}
|
||||
|
||||
MANY_SEP<OUT>(this: MixedInParser, options: ManySepMethodOpts<OUT>): void {
|
||||
this.manySepFirstInternal(0, options);
|
||||
}
|
||||
|
||||
MANY_SEP1<OUT>(this: MixedInParser, options: ManySepMethodOpts<OUT>): void {
|
||||
this.manySepFirstInternal(1, options);
|
||||
}
|
||||
|
||||
MANY_SEP2<OUT>(this: MixedInParser, options: ManySepMethodOpts<OUT>): void {
|
||||
this.manySepFirstInternal(2, options);
|
||||
}
|
||||
|
||||
MANY_SEP3<OUT>(this: MixedInParser, options: ManySepMethodOpts<OUT>): void {
|
||||
this.manySepFirstInternal(3, options);
|
||||
}
|
||||
|
||||
MANY_SEP4<OUT>(this: MixedInParser, options: ManySepMethodOpts<OUT>): void {
|
||||
this.manySepFirstInternal(4, options);
|
||||
}
|
||||
|
||||
MANY_SEP5<OUT>(this: MixedInParser, options: ManySepMethodOpts<OUT>): void {
|
||||
this.manySepFirstInternal(5, options);
|
||||
}
|
||||
|
||||
MANY_SEP6<OUT>(this: MixedInParser, options: ManySepMethodOpts<OUT>): void {
|
||||
this.manySepFirstInternal(6, options);
|
||||
}
|
||||
|
||||
MANY_SEP7<OUT>(this: MixedInParser, options: ManySepMethodOpts<OUT>): void {
|
||||
this.manySepFirstInternal(7, options);
|
||||
}
|
||||
|
||||
MANY_SEP8<OUT>(this: MixedInParser, options: ManySepMethodOpts<OUT>): void {
|
||||
this.manySepFirstInternal(8, options);
|
||||
}
|
||||
|
||||
MANY_SEP9<OUT>(this: MixedInParser, options: ManySepMethodOpts<OUT>): void {
|
||||
this.manySepFirstInternal(9, options);
|
||||
}
|
||||
|
||||
AT_LEAST_ONE<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOptsWithErr<OUT>,
|
||||
): void {
|
||||
this.atLeastOneInternal(0, actionORMethodDef);
|
||||
}
|
||||
|
||||
AT_LEAST_ONE1<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOptsWithErr<OUT>,
|
||||
): void {
|
||||
return this.atLeastOneInternal(1, actionORMethodDef);
|
||||
}
|
||||
|
||||
AT_LEAST_ONE2<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOptsWithErr<OUT>,
|
||||
): void {
|
||||
this.atLeastOneInternal(2, actionORMethodDef);
|
||||
}
|
||||
|
||||
AT_LEAST_ONE3<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOptsWithErr<OUT>,
|
||||
): void {
|
||||
this.atLeastOneInternal(3, actionORMethodDef);
|
||||
}
|
||||
|
||||
AT_LEAST_ONE4<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOptsWithErr<OUT>,
|
||||
): void {
|
||||
this.atLeastOneInternal(4, actionORMethodDef);
|
||||
}
|
||||
|
||||
AT_LEAST_ONE5<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOptsWithErr<OUT>,
|
||||
): void {
|
||||
this.atLeastOneInternal(5, actionORMethodDef);
|
||||
}
|
||||
|
||||
AT_LEAST_ONE6<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOptsWithErr<OUT>,
|
||||
): void {
|
||||
this.atLeastOneInternal(6, actionORMethodDef);
|
||||
}
|
||||
|
||||
AT_LEAST_ONE7<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOptsWithErr<OUT>,
|
||||
): void {
|
||||
this.atLeastOneInternal(7, actionORMethodDef);
|
||||
}
|
||||
|
||||
AT_LEAST_ONE8<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOptsWithErr<OUT>,
|
||||
): void {
|
||||
this.atLeastOneInternal(8, actionORMethodDef);
|
||||
}
|
||||
|
||||
AT_LEAST_ONE9<OUT>(
|
||||
this: MixedInParser,
|
||||
actionORMethodDef: GrammarAction<OUT> | DSLMethodOptsWithErr<OUT>,
|
||||
): void {
|
||||
this.atLeastOneInternal(9, actionORMethodDef);
|
||||
}
|
||||
|
||||
AT_LEAST_ONE_SEP<OUT>(
|
||||
this: MixedInParser,
|
||||
options: AtLeastOneSepMethodOpts<OUT>,
|
||||
): void {
|
||||
this.atLeastOneSepFirstInternal(0, options);
|
||||
}
|
||||
|
||||
AT_LEAST_ONE_SEP1<OUT>(
|
||||
this: MixedInParser,
|
||||
options: AtLeastOneSepMethodOpts<OUT>,
|
||||
): void {
|
||||
this.atLeastOneSepFirstInternal(1, options);
|
||||
}
|
||||
|
||||
AT_LEAST_ONE_SEP2<OUT>(
|
||||
this: MixedInParser,
|
||||
options: AtLeastOneSepMethodOpts<OUT>,
|
||||
): void {
|
||||
this.atLeastOneSepFirstInternal(2, options);
|
||||
}
|
||||
|
||||
AT_LEAST_ONE_SEP3<OUT>(
|
||||
this: MixedInParser,
|
||||
options: AtLeastOneSepMethodOpts<OUT>,
|
||||
): void {
|
||||
this.atLeastOneSepFirstInternal(3, options);
|
||||
}
|
||||
|
||||
AT_LEAST_ONE_SEP4<OUT>(
|
||||
this: MixedInParser,
|
||||
options: AtLeastOneSepMethodOpts<OUT>,
|
||||
): void {
|
||||
this.atLeastOneSepFirstInternal(4, options);
|
||||
}
|
||||
|
||||
AT_LEAST_ONE_SEP5<OUT>(
|
||||
this: MixedInParser,
|
||||
options: AtLeastOneSepMethodOpts<OUT>,
|
||||
): void {
|
||||
this.atLeastOneSepFirstInternal(5, options);
|
||||
}
|
||||
|
||||
AT_LEAST_ONE_SEP6<OUT>(
|
||||
this: MixedInParser,
|
||||
options: AtLeastOneSepMethodOpts<OUT>,
|
||||
): void {
|
||||
this.atLeastOneSepFirstInternal(6, options);
|
||||
}
|
||||
|
||||
AT_LEAST_ONE_SEP7<OUT>(
|
||||
this: MixedInParser,
|
||||
options: AtLeastOneSepMethodOpts<OUT>,
|
||||
): void {
|
||||
this.atLeastOneSepFirstInternal(7, options);
|
||||
}
|
||||
|
||||
AT_LEAST_ONE_SEP8<OUT>(
|
||||
this: MixedInParser,
|
||||
options: AtLeastOneSepMethodOpts<OUT>,
|
||||
): void {
|
||||
this.atLeastOneSepFirstInternal(8, options);
|
||||
}
|
||||
|
||||
AT_LEAST_ONE_SEP9<OUT>(
|
||||
this: MixedInParser,
|
||||
options: AtLeastOneSepMethodOpts<OUT>,
|
||||
): void {
|
||||
this.atLeastOneSepFirstInternal(9, options);
|
||||
}
|
||||
|
||||
RULE<T>(
|
||||
this: MixedInParser,
|
||||
name: string,
|
||||
implementation: (...implArgs: any[]) => T,
|
||||
config: IRuleConfig<T> = DEFAULT_RULE_CONFIG,
|
||||
): (idxInCallingRule?: number, ...args: any[]) => T | any {
|
||||
if (includes(this.definedRulesNames, name)) {
|
||||
const errMsg =
|
||||
defaultGrammarValidatorErrorProvider.buildDuplicateRuleNameError({
|
||||
topLevelRule: name,
|
||||
grammarName: this.className,
|
||||
});
|
||||
|
||||
const error = {
|
||||
message: errMsg,
|
||||
type: ParserDefinitionErrorType.DUPLICATE_RULE_NAME,
|
||||
ruleName: name,
|
||||
};
|
||||
this.definitionErrors.push(error);
|
||||
}
|
||||
|
||||
this.definedRulesNames.push(name);
|
||||
|
||||
const ruleImplementation = this.defineRule(name, implementation, config);
|
||||
(this as any)[name] = ruleImplementation;
|
||||
return ruleImplementation;
|
||||
}
|
||||
|
||||
OVERRIDE_RULE<T>(
|
||||
this: MixedInParser,
|
||||
name: string,
|
||||
impl: (...implArgs: any[]) => T,
|
||||
config: IRuleConfig<T> = DEFAULT_RULE_CONFIG,
|
||||
): (idxInCallingRule?: number, ...args: any[]) => T {
|
||||
const ruleErrors: IParserDefinitionError[] = validateRuleIsOverridden(
|
||||
name,
|
||||
this.definedRulesNames,
|
||||
this.className,
|
||||
);
|
||||
this.definitionErrors = this.definitionErrors.concat(ruleErrors);
|
||||
|
||||
const ruleImplementation = this.defineRule(name, impl, config);
|
||||
(this as any)[name] = ruleImplementation;
|
||||
return ruleImplementation;
|
||||
}
|
||||
|
||||
BACKTRACK<T>(
|
||||
this: MixedInParser,
|
||||
grammarRule: (...args: any[]) => T,
|
||||
args?: any[],
|
||||
): () => boolean {
|
||||
return function () {
|
||||
// save org state
|
||||
this.isBackTrackingStack.push(1);
|
||||
const orgState = this.saveRecogState();
|
||||
try {
|
||||
grammarRule.apply(this, args);
|
||||
// if no exception was thrown we have succeed parsing the rule.
|
||||
return true;
|
||||
} catch (e) {
|
||||
if (isRecognitionException(e)) {
|
||||
return false;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
this.reloadRecogState(orgState);
|
||||
this.isBackTrackingStack.pop();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// GAST export APIs
|
||||
public getGAstProductions(this: MixedInParser): Record<string, Rule> {
|
||||
return this.gastProductionsCache;
|
||||
}
|
||||
|
||||
public getSerializedGastProductions(this: MixedInParser): ISerializedGast[] {
|
||||
return serializeGrammar(values(this.gastProductionsCache));
|
||||
}
|
||||
}
|
||||
1165
frontend/node_modules/chevrotain/src/scan/lexer.ts
generated
vendored
Normal file
1165
frontend/node_modules/chevrotain/src/scan/lexer.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
323
frontend/node_modules/chevrotain/src/scan/reg_exp.ts
generated
vendored
Normal file
323
frontend/node_modules/chevrotain/src/scan/reg_exp.ts
generated
vendored
Normal file
@@ -0,0 +1,323 @@
|
||||
import {
|
||||
Alternative,
|
||||
Atom,
|
||||
BaseRegExpVisitor,
|
||||
Character,
|
||||
Disjunction,
|
||||
Group,
|
||||
Set,
|
||||
} from "@chevrotain/regexp-to-ast";
|
||||
import { every, find, forEach, includes, isArray, values } from "lodash-es";
|
||||
import { PRINT_ERROR, PRINT_WARNING } from "@chevrotain/utils";
|
||||
import { ASTNode, getRegExpAst } from "./reg_exp_parser.js";
|
||||
import { charCodeToOptimizedIndex, minOptimizationVal } from "./lexer.js";
|
||||
|
||||
const complementErrorMessage =
|
||||
"Complement Sets are not supported for first char optimization";
|
||||
export const failedOptimizationPrefixMsg =
|
||||
'Unable to use "first char" lexer optimizations:\n';
|
||||
|
||||
export function getOptimizedStartCodesIndices(
|
||||
regExp: RegExp,
|
||||
ensureOptimizations = false,
|
||||
): number[] {
|
||||
try {
|
||||
const ast = getRegExpAst(regExp);
|
||||
const firstChars = firstCharOptimizedIndices(
|
||||
ast.value,
|
||||
{},
|
||||
ast.flags.ignoreCase,
|
||||
);
|
||||
return firstChars;
|
||||
} catch (e) {
|
||||
/* istanbul ignore next */
|
||||
// Testing this relies on the regexp-to-ast library having a bug... */
|
||||
// TODO: only the else branch needs to be ignored, try to fix with newer prettier / tsc
|
||||
if (e.message === complementErrorMessage) {
|
||||
if (ensureOptimizations) {
|
||||
PRINT_WARNING(
|
||||
`${failedOptimizationPrefixMsg}` +
|
||||
`\tUnable to optimize: < ${regExp.toString()} >\n` +
|
||||
"\tComplement Sets cannot be automatically optimized.\n" +
|
||||
"\tThis will disable the lexer's first char optimizations.\n" +
|
||||
"\tSee: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#COMPLEMENT for details.",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
let msgSuffix = "";
|
||||
if (ensureOptimizations) {
|
||||
msgSuffix =
|
||||
"\n\tThis will disable the lexer's first char optimizations.\n" +
|
||||
"\tSee: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#REGEXP_PARSING for details.";
|
||||
}
|
||||
PRINT_ERROR(
|
||||
`${failedOptimizationPrefixMsg}\n` +
|
||||
`\tFailed parsing: < ${regExp.toString()} >\n` +
|
||||
`\tUsing the @chevrotain/regexp-to-ast library\n` +
|
||||
"\tPlease open an issue at: https://github.com/chevrotain/chevrotain/issues" +
|
||||
msgSuffix,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
export function firstCharOptimizedIndices(
|
||||
ast: ASTNode,
|
||||
result: { [charCode: number]: number },
|
||||
ignoreCase: boolean,
|
||||
): number[] {
|
||||
switch (ast.type) {
|
||||
case "Disjunction":
|
||||
for (let i = 0; i < ast.value.length; i++) {
|
||||
firstCharOptimizedIndices(ast.value[i], result, ignoreCase);
|
||||
}
|
||||
break;
|
||||
case "Alternative":
|
||||
const terms = ast.value;
|
||||
for (let i = 0; i < terms.length; i++) {
|
||||
const term = terms[i];
|
||||
|
||||
// skip terms that cannot effect the first char results
|
||||
switch (term.type) {
|
||||
case "EndAnchor":
|
||||
// A group back reference cannot affect potential starting char.
|
||||
// because if a back reference is the first production than automatically
|
||||
// the group being referenced has had to come BEFORE so its codes have already been added
|
||||
case "GroupBackReference":
|
||||
// assertions do not affect potential starting codes
|
||||
case "Lookahead":
|
||||
case "NegativeLookahead":
|
||||
case "Lookbehind":
|
||||
case "NegativeLookbehind":
|
||||
case "StartAnchor":
|
||||
case "WordBoundary":
|
||||
case "NonWordBoundary":
|
||||
continue;
|
||||
}
|
||||
|
||||
const atom = term;
|
||||
switch (atom.type) {
|
||||
case "Character":
|
||||
addOptimizedIdxToResult(atom.value, result, ignoreCase);
|
||||
break;
|
||||
case "Set":
|
||||
if (atom.complement === true) {
|
||||
throw Error(complementErrorMessage);
|
||||
}
|
||||
forEach(atom.value, (code) => {
|
||||
if (typeof code === "number") {
|
||||
addOptimizedIdxToResult(code, result, ignoreCase);
|
||||
} else {
|
||||
// range
|
||||
const range = code as any;
|
||||
// cannot optimize when ignoreCase is
|
||||
if (ignoreCase === true) {
|
||||
for (
|
||||
let rangeCode = range.from;
|
||||
rangeCode <= range.to;
|
||||
rangeCode++
|
||||
) {
|
||||
addOptimizedIdxToResult(rangeCode, result, ignoreCase);
|
||||
}
|
||||
}
|
||||
// Optimization (2 orders of magnitude less work for very large ranges)
|
||||
else {
|
||||
// handle unoptimized values
|
||||
for (
|
||||
let rangeCode = range.from;
|
||||
rangeCode <= range.to && rangeCode < minOptimizationVal;
|
||||
rangeCode++
|
||||
) {
|
||||
addOptimizedIdxToResult(rangeCode, result, ignoreCase);
|
||||
}
|
||||
|
||||
// Less common charCode where we optimize for faster init time, by using larger "buckets"
|
||||
if (range.to >= minOptimizationVal) {
|
||||
const minUnOptVal =
|
||||
range.from >= minOptimizationVal
|
||||
? range.from
|
||||
: minOptimizationVal;
|
||||
const maxUnOptVal = range.to;
|
||||
const minOptIdx = charCodeToOptimizedIndex(minUnOptVal);
|
||||
const maxOptIdx = charCodeToOptimizedIndex(maxUnOptVal);
|
||||
|
||||
for (
|
||||
let currOptIdx = minOptIdx;
|
||||
currOptIdx <= maxOptIdx;
|
||||
currOptIdx++
|
||||
) {
|
||||
result[currOptIdx] = currOptIdx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "Group":
|
||||
firstCharOptimizedIndices(atom.value, result, ignoreCase);
|
||||
break;
|
||||
/* istanbul ignore next */
|
||||
default:
|
||||
throw Error("Non Exhaustive Match");
|
||||
}
|
||||
|
||||
// reached a mandatory production, no more **start** codes can be found on this alternative
|
||||
const isOptionalQuantifier =
|
||||
atom.quantifier !== undefined && atom.quantifier.atLeast === 0;
|
||||
if (
|
||||
// A group may be optional due to empty contents /(?:)/
|
||||
// or if everything inside it is optional /((a)?)/
|
||||
(atom.type === "Group" && isWholeOptional(atom) === false) ||
|
||||
// If this term is not a group it may only be optional if it has an optional quantifier
|
||||
(atom.type !== "Group" && isOptionalQuantifier === false)
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
/* istanbul ignore next */
|
||||
default:
|
||||
throw Error("non exhaustive match!");
|
||||
}
|
||||
|
||||
// console.log(Object.keys(result).length)
|
||||
return values(result);
|
||||
}
|
||||
|
||||
function addOptimizedIdxToResult(
|
||||
code: number,
|
||||
result: { [charCode: number]: number },
|
||||
ignoreCase: boolean,
|
||||
) {
|
||||
const optimizedCharIdx = charCodeToOptimizedIndex(code);
|
||||
result[optimizedCharIdx] = optimizedCharIdx;
|
||||
|
||||
if (ignoreCase === true) {
|
||||
handleIgnoreCase(code, result);
|
||||
}
|
||||
}
|
||||
|
||||
function handleIgnoreCase(
|
||||
code: number,
|
||||
result: { [charCode: number]: number },
|
||||
) {
|
||||
const char = String.fromCharCode(code);
|
||||
const upperChar = char.toUpperCase();
|
||||
/* istanbul ignore else */
|
||||
if (upperChar !== char) {
|
||||
const optimizedCharIdx = charCodeToOptimizedIndex(upperChar.charCodeAt(0));
|
||||
result[optimizedCharIdx] = optimizedCharIdx;
|
||||
} else {
|
||||
const lowerChar = char.toLowerCase();
|
||||
if (lowerChar !== char) {
|
||||
const optimizedCharIdx = charCodeToOptimizedIndex(
|
||||
lowerChar.charCodeAt(0),
|
||||
);
|
||||
result[optimizedCharIdx] = optimizedCharIdx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function findCode(setNode: Set, targetCharCodes: number[]) {
|
||||
return find(setNode.value, (codeOrRange) => {
|
||||
if (typeof codeOrRange === "number") {
|
||||
return includes(targetCharCodes, codeOrRange);
|
||||
} else {
|
||||
// range
|
||||
const range = <any>codeOrRange;
|
||||
return (
|
||||
find(
|
||||
targetCharCodes,
|
||||
(targetCode) => range.from <= targetCode && targetCode <= range.to,
|
||||
) !== undefined
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function isWholeOptional(ast: any): boolean {
|
||||
const quantifier = (ast as Atom).quantifier;
|
||||
if (quantifier && quantifier.atLeast === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!ast.value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isArray(ast.value)
|
||||
? every(ast.value, isWholeOptional)
|
||||
: isWholeOptional(ast.value);
|
||||
}
|
||||
|
||||
class CharCodeFinder extends BaseRegExpVisitor {
|
||||
found: boolean = false;
|
||||
|
||||
constructor(private targetCharCodes: number[]) {
|
||||
super();
|
||||
}
|
||||
|
||||
visitChildren(node: ASTNode) {
|
||||
// No need to keep looking...
|
||||
if (this.found === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
// switch lookaheads / lookbehinds as they do not actually consume any characters thus
|
||||
// finding a charCode at lookahead context does not mean that regexp can actually contain it in a match.
|
||||
switch (node.type) {
|
||||
case "Lookahead":
|
||||
this.visitLookahead(node);
|
||||
return;
|
||||
case "NegativeLookahead":
|
||||
this.visitNegativeLookahead(node);
|
||||
return;
|
||||
case "Lookbehind":
|
||||
this.visitLookbehind(node);
|
||||
return;
|
||||
case "NegativeLookbehind":
|
||||
this.visitNegativeLookbehind(node);
|
||||
return;
|
||||
}
|
||||
|
||||
super.visitChildren(node);
|
||||
}
|
||||
|
||||
visitCharacter(node: Character) {
|
||||
if (includes(this.targetCharCodes, node.value)) {
|
||||
this.found = true;
|
||||
}
|
||||
}
|
||||
|
||||
visitSet(node: Set) {
|
||||
if (node.complement) {
|
||||
if (findCode(node, this.targetCharCodes) === undefined) {
|
||||
this.found = true;
|
||||
}
|
||||
} else {
|
||||
if (findCode(node, this.targetCharCodes) !== undefined) {
|
||||
this.found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function canMatchCharCode(
|
||||
charCodes: number[],
|
||||
pattern: RegExp | string,
|
||||
) {
|
||||
if (pattern instanceof RegExp) {
|
||||
const ast = getRegExpAst(pattern);
|
||||
const charCodeFinder = new CharCodeFinder(charCodes);
|
||||
charCodeFinder.visit(ast);
|
||||
return charCodeFinder.found;
|
||||
} else {
|
||||
return (
|
||||
find(<any>pattern, (char) => {
|
||||
return includes(charCodes, (<string>char).charCodeAt(0));
|
||||
}) !== undefined
|
||||
);
|
||||
}
|
||||
}
|
||||
1
frontend/node_modules/chevrotain/src/scan/tokens_constants.ts
generated
vendored
Normal file
1
frontend/node_modules/chevrotain/src/scan/tokens_constants.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export const EOF_TOKEN_TYPE = 1;
|
||||
Reference in New Issue
Block a user