Show More
Commit Description:
fix wrong merge
Commit Description:
fix wrong merge
References:
File last commit:
Show/Diff file:
Action:
node_modules/dfa/compile.js
| 1834 lines
| 40.4 KiB
| application/javascript
| JavascriptLexer
|
r789 | 'use strict'; | |||
Object.defineProperty(exports, '__esModule', { value: true }); | ||||
/** | ||||
* Returns a new set representing the union of a and b. | ||||
*/ | ||||
function union(a, b) { | ||||
var s = new Set(a); | ||||
addAll(s, b); | ||||
return s; | ||||
} | ||||
/** | ||||
* Adds all items from the set b to a. | ||||
*/ | ||||
function addAll(a, b) { | ||||
for (var x of b) { | ||||
a.add(x); | ||||
} | ||||
} | ||||
/** | ||||
* Returns whether two sets are equal | ||||
*/ | ||||
function equal(a, b) { | ||||
if (a === b) return true; | ||||
if (a.size !== b.size) return false; | ||||
for (var x of a) { | ||||
if (!b.has(x)) { | ||||
return false; | ||||
} | ||||
} | ||||
return true; | ||||
} | ||||
/** | ||||
* Base AST node | ||||
*/ | ||||
class Node { | ||||
constructor() { | ||||
Object.defineProperty(this, 'followpos', { | ||||
value: new Set() | ||||
}); | ||||
} | ||||
calcFollowpos() { | ||||
for (var key in this) { | ||||
if (this[key] instanceof Node) { | ||||
this[key].calcFollowpos(); | ||||
} | ||||
} | ||||
} | ||||
} | ||||
/** | ||||
* Represents a variable reference | ||||
*/ | ||||
class Variable extends Node { | ||||
constructor(name) { | ||||
super(); | ||||
this.name = name; | ||||
} | ||||
copy() { | ||||
return new Variable(this.name); | ||||
} | ||||
} | ||||
/** | ||||
* Represents a comment | ||||
*/ | ||||
class Comment extends Node { | ||||
constructor(value) { | ||||
super(); | ||||
this.value = value; | ||||
} | ||||
} | ||||
/** | ||||
* Represents an assignment statement. | ||||
* e.g. `variable = expression;` | ||||
*/ | ||||
class Assignment extends Node { | ||||
constructor(variable, expression) { | ||||
super(); | ||||
this.variable = variable; | ||||
this.expression = expression; | ||||
} | ||||
} | ||||
/** | ||||
* Represents an alternation. | ||||
* e.g. `a | b` | ||||
*/ | ||||
class Alternation extends Node { | ||||
constructor(a, b) { | ||||
super(); | ||||
this.a = a; | ||||
this.b = b; | ||||
} | ||||
get nullable() { | ||||
return this.a.nullable || this.b.nullable; | ||||
} | ||||
get firstpos() { | ||||
return union(this.a.firstpos, this.b.firstpos); | ||||
} | ||||
get lastpos() { | ||||
return union(this.a.lastpos, this.b.lastpos); | ||||
} | ||||
copy() { | ||||
return new Alternation(this.a.copy(), this.b.copy()); | ||||
} | ||||
} | ||||
/** | ||||
* Represents a concatenation, or chain. | ||||
* e.g. `a b c` | ||||
*/ | ||||
class Concatenation extends Node { | ||||
constructor(a, b) { | ||||
super(); | ||||
this.a = a; | ||||
this.b = b; | ||||
} | ||||
get nullable() { | ||||
return this.a.nullable && this.b.nullable; | ||||
} | ||||
get firstpos() { | ||||
var s = this.a.firstpos; | ||||
if (this.a.nullable) { | ||||
s = union(s, this.b.firstpos); | ||||
} | ||||
return s; | ||||
} | ||||
get lastpos() { | ||||
var s = this.b.lastpos; | ||||
if (this.b.nullable) { | ||||
s = union(s, this.a.lastpos); | ||||
} | ||||
return s; | ||||
} | ||||
calcFollowpos() { | ||||
super.calcFollowpos(); | ||||
for (var n of this.a.lastpos) { | ||||
addAll(n.followpos, this.b.firstpos); | ||||
} | ||||
} | ||||
copy() { | ||||
return new Concatenation(this.a.copy(), this.b.copy()); | ||||
} | ||||
} | ||||
/** | ||||
* Represents a repetition. | ||||
* e.g. `a+`, `b*`, or `c?` | ||||
*/ | ||||
class Repeat extends Node { | ||||
constructor(expression, op) { | ||||
super(); | ||||
this.expression = expression; | ||||
this.op = op; | ||||
} | ||||
get nullable() { | ||||
return this.op === '*' || this.op === '?'; | ||||
} | ||||
get firstpos() { | ||||
return this.expression.firstpos; | ||||
} | ||||
get lastpos() { | ||||
return this.expression.lastpos; | ||||
} | ||||
calcFollowpos() { | ||||
super.calcFollowpos(); | ||||
if (this.op === '*' || this.op === '+') { | ||||
for (var n of this.lastpos) { | ||||
addAll(n.followpos, this.firstpos); | ||||
} | ||||
} | ||||
} | ||||
copy() { | ||||
return new Repeat(this.expression.copy(), this.op); | ||||
} | ||||
} | ||||
function buildRepetition(expression, min = 0, max = Infinity) { | ||||
if (min < 0 || min > max) { | ||||
throw new Error("Invalid repetition range: ".concat(min, " ").concat(max)); | ||||
} | ||||
var res = null; | ||||
for (var i = 0; i < min; i++) { | ||||
res = concat(res, expression.copy()); | ||||
} | ||||
if (max === Infinity) { | ||||
res = concat(res, new Repeat(expression.copy(), '*')); | ||||
} else { | ||||
for (var _i = min; _i < max; _i++) { | ||||
res = concat(res, new Repeat(expression.copy(), '?')); | ||||
} | ||||
} | ||||
return res; | ||||
} | ||||
function concat(a, b) { | ||||
if (!a) { | ||||
return b; | ||||
} | ||||
return new Concatenation(a, b); | ||||
} | ||||
/** | ||||
* Base class for leaf nodes | ||||
*/ | ||||
class Leaf extends Node { | ||||
get nullable() { | ||||
return false; | ||||
} | ||||
get firstpos() { | ||||
return new Set([this]); | ||||
} | ||||
get lastpos() { | ||||
return new Set([this]); | ||||
} | ||||
} | ||||
/** | ||||
* Represents a literal value, e.g. a number | ||||
*/ | ||||
class Literal extends Leaf { | ||||
constructor(value) { | ||||
super(); | ||||
this.value = value; | ||||
} | ||||
copy() { | ||||
return new Literal(this.value); | ||||
} | ||||
} | ||||
/** | ||||
* Marks the end of an expression | ||||
*/ | ||||
class EndMarker extends Leaf {} | ||||
/** | ||||
* Represents a tag | ||||
* e.g. `a:(a b)` | ||||
*/ | ||||
class Tag extends Leaf { | ||||
constructor(name) { | ||||
super(); | ||||
this.name = name; | ||||
} | ||||
get nullable() { | ||||
return true; | ||||
} | ||||
copy() { | ||||
return new Tag(this.name); | ||||
} | ||||
} | ||||
var nodes = /*#__PURE__*/Object.freeze({ | ||||
Node: Node, | ||||
Variable: Variable, | ||||
Comment: Comment, | ||||
Assignment: Assignment, | ||||
Alternation: Alternation, | ||||
Concatenation: Concatenation, | ||||
Repeat: Repeat, | ||||
buildRepetition: buildRepetition, | ||||
Literal: Literal, | ||||
EndMarker: EndMarker, | ||||
Tag: Tag | ||||
}); | ||||
function peg$subclass(child, parent) { | ||||
function ctor() { | ||||
this.constructor = child; | ||||
} | ||||
ctor.prototype = parent.prototype; | ||||
child.prototype = new ctor(); | ||||
} | ||||
function peg$SyntaxError(message, expected, found, location) { | ||||
this.message = message; | ||||
this.expected = expected; | ||||
this.found = found; | ||||
this.location = location; | ||||
this.name = "SyntaxError"; | ||||
if (typeof Error.captureStackTrace === "function") { | ||||
Error.captureStackTrace(this, peg$SyntaxError); | ||||
} | ||||
} | ||||
peg$subclass(peg$SyntaxError, Error); | ||||
peg$SyntaxError.buildMessage = function (expected, found) { | ||||
var DESCRIBE_EXPECTATION_FNS = { | ||||
literal: function (expectation) { | ||||
return "\"" + literalEscape(expectation.text) + "\""; | ||||
}, | ||||
"class": function (expectation) { | ||||
var escapedParts = "", | ||||
i; | ||||
for (i = 0; i < expectation.parts.length; i++) { | ||||
escapedParts += expectation.parts[i] instanceof Array ? classEscape(expectation.parts[i][0]) + "-" + classEscape(expectation.parts[i][1]) : classEscape(expectation.parts[i]); | ||||
} | ||||
return "[" + (expectation.inverted ? "^" : "") + escapedParts + "]"; | ||||
}, | ||||
any: function (expectation) { | ||||
return "any character"; | ||||
}, | ||||
end: function (expectation) { | ||||
return "end of input"; | ||||
}, | ||||
other: function (expectation) { | ||||
return expectation.description; | ||||
} | ||||
}; | ||||
function hex(ch) { | ||||
return ch.charCodeAt(0).toString(16).toUpperCase(); | ||||
} | ||||
function literalEscape(s) { | ||||
return s.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\0/g, '\\0').replace(/\t/g, '\\t').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/[\x00-\x0F]/g, function (ch) { | ||||
return '\\x0' + hex(ch); | ||||
}).replace(/[\x10-\x1F\x7F-\x9F]/g, function (ch) { | ||||
return '\\x' + hex(ch); | ||||
}); | ||||
} | ||||
function classEscape(s) { | ||||
return s.replace(/\\/g, '\\\\').replace(/\]/g, '\\]').replace(/\^/g, '\\^').replace(/-/g, '\\-').replace(/\0/g, '\\0').replace(/\t/g, '\\t').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/[\x00-\x0F]/g, function (ch) { | ||||
return '\\x0' + hex(ch); | ||||
}).replace(/[\x10-\x1F\x7F-\x9F]/g, function (ch) { | ||||
return '\\x' + hex(ch); | ||||
}); | ||||
} | ||||
function describeExpectation(expectation) { | ||||
return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation); | ||||
} | ||||
function describeExpected(expected) { | ||||
var descriptions = new Array(expected.length), | ||||
i, | ||||
j; | ||||
for (i = 0; i < expected.length; i++) { | ||||
descriptions[i] = describeExpectation(expected[i]); | ||||
} | ||||
descriptions.sort(); | ||||
if (descriptions.length > 0) { | ||||
for (i = 1, j = 1; i < descriptions.length; i++) { | ||||
if (descriptions[i - 1] !== descriptions[i]) { | ||||
descriptions[j] = descriptions[i]; | ||||
j++; | ||||
} | ||||
} | ||||
descriptions.length = j; | ||||
} | ||||
switch (descriptions.length) { | ||||
case 1: | ||||
return descriptions[0]; | ||||
case 2: | ||||
return descriptions[0] + " or " + descriptions[1]; | ||||
default: | ||||
return descriptions.slice(0, -1).join(", ") + ", or " + descriptions[descriptions.length - 1]; | ||||
} | ||||
} | ||||
function describeFound(found) { | ||||
return found ? "\"" + literalEscape(found) + "\"" : "end of input"; | ||||
} | ||||
return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found."; | ||||
}; | ||||
function peg$parse(input, options) { | ||||
options = options !== void 0 ? options : {}; | ||||
var peg$FAILED = {}, | ||||
peg$startRuleFunctions = { | ||||
rules: peg$parserules | ||||
}, | ||||
peg$startRuleFunction = peg$parserules, | ||||
peg$c0 = function (s) { | ||||
return s; | ||||
}, | ||||
peg$c1 = "#", | ||||
peg$c2 = peg$literalExpectation("#", false), | ||||
peg$c3 = /^[^\r\n]/, | ||||
peg$c4 = peg$classExpectation(["\r", "\n"], true, false), | ||||
peg$c5 = /^[\r\n]/, | ||||
peg$c6 = peg$classExpectation(["\r", "\n"], false, false), | ||||
peg$c7 = function (v) { | ||||
return new n.Comment(v.join('')); | ||||
}, | ||||
peg$c8 = "=", | ||||
peg$c9 = peg$literalExpectation("=", false), | ||||
peg$c10 = ";", | ||||
peg$c11 = peg$literalExpectation(";", false), | ||||
peg$c12 = function (v, e) { | ||||
return new n.Assignment(v, e); | ||||
}, | ||||
peg$c13 = function (v) { | ||||
return new n.Variable(v); | ||||
}, | ||||
peg$c14 = "|", | ||||
peg$c15 = peg$literalExpectation("|", false), | ||||
peg$c16 = function (a, b) { | ||||
return new n.Alternation(a, b); | ||||
}, | ||||
peg$c17 = function (a, b) { | ||||
return new n.Concatenation(a, b); | ||||
}, | ||||
peg$c18 = ":", | ||||
peg$c19 = peg$literalExpectation(":", false), | ||||
peg$c20 = function (t, e) { | ||||
return new n.Concatenation(e, new n.Tag(t)); | ||||
}, | ||||
peg$c21 = "*", | ||||
peg$c22 = peg$literalExpectation("*", false), | ||||
peg$c23 = function (t) { | ||||
return new n.Repeat(t, '*'); | ||||
}, | ||||
peg$c24 = "?", | ||||
peg$c25 = peg$literalExpectation("?", false), | ||||
peg$c26 = function (t) { | ||||
return new n.Repeat(t, '?'); | ||||
}, | ||||
peg$c27 = "+", | ||||
peg$c28 = peg$literalExpectation("+", false), | ||||
peg$c29 = function (t) { | ||||
return new n.Repeat(t, '+'); | ||||
}, | ||||
peg$c30 = "{", | ||||
peg$c31 = peg$literalExpectation("{", false), | ||||
peg$c32 = "}", | ||||
peg$c33 = peg$literalExpectation("}", false), | ||||
peg$c34 = function (t, m) { | ||||
return n.buildRepetition(t, m, m); | ||||
}, | ||||
peg$c35 = ",", | ||||
peg$c36 = peg$literalExpectation(",", false), | ||||
peg$c37 = function (t, min) { | ||||
return n.buildRepetition(t, min, Infinity); | ||||
}, | ||||
peg$c38 = function (t, max) { | ||||
return n.buildRepetition(t, 0, max); | ||||
}, | ||||
peg$c39 = function (t, min, max) { | ||||
return n.buildRepetition(t, min, max); | ||||
}, | ||||
peg$c40 = function (x) { | ||||
return new n.Literal(x); | ||||
}, | ||||
peg$c41 = "(", | ||||
peg$c42 = peg$literalExpectation("(", false), | ||||
peg$c43 = ")", | ||||
peg$c44 = peg$literalExpectation(")", false), | ||||
peg$c45 = function (e) { | ||||
return e; | ||||
}, | ||||
peg$c47 = function (a, b) { | ||||
return a + b.join(''); | ||||
}, | ||||
peg$c48 = "_", | ||||
peg$c49 = peg$literalExpectation("_", false), | ||||
peg$c50 = /^[a-zA-Z]/, | ||||
peg$c51 = peg$classExpectation([["a", "z"], ["A", "Z"]], false, false), | ||||
peg$c52 = /^[0-9]/, | ||||
peg$c53 = peg$classExpectation([["0", "9"]], false, false), | ||||
peg$c54 = function (num) { | ||||
return parseInt(num.join('')); | ||||
}, | ||||
peg$c55 = /^[ \t\r\n]/, | ||||
peg$c56 = peg$classExpectation([" ", "\t", "\r", "\n"], false, false), | ||||
peg$currPos = 0, | ||||
peg$posDetailsCache = [{ | ||||
line: 1, | ||||
column: 1 | ||||
}], | ||||
peg$maxFailPos = 0, | ||||
peg$maxFailExpected = [], | ||||
peg$result; | ||||
if ("startRule" in options) { | ||||
if (!(options.startRule in peg$startRuleFunctions)) { | ||||
throw new Error("Can't start parsing from rule \"" + options.startRule + "\"."); | ||||
} | ||||
peg$startRuleFunction = peg$startRuleFunctions[options.startRule]; | ||||
} | ||||
function peg$literalExpectation(text, ignoreCase) { | ||||
return { | ||||
type: "literal", | ||||
text: text, | ||||
ignoreCase: ignoreCase | ||||
}; | ||||
} | ||||
function peg$classExpectation(parts, inverted, ignoreCase) { | ||||
return { | ||||
type: "class", | ||||
parts: parts, | ||||
inverted: inverted, | ||||
ignoreCase: ignoreCase | ||||
}; | ||||
} | ||||
function peg$endExpectation() { | ||||
return { | ||||
type: "end" | ||||
}; | ||||
} | ||||
function peg$computePosDetails(pos) { | ||||
var details = peg$posDetailsCache[pos], | ||||
p; | ||||
if (details) { | ||||
return details; | ||||
} else { | ||||
p = pos - 1; | ||||
while (!peg$posDetailsCache[p]) { | ||||
p--; | ||||
} | ||||
details = peg$posDetailsCache[p]; | ||||
details = { | ||||
line: details.line, | ||||
column: details.column | ||||
}; | ||||
while (p < pos) { | ||||
if (input.charCodeAt(p) === 10) { | ||||
details.line++; | ||||
details.column = 1; | ||||
} else { | ||||
details.column++; | ||||
} | ||||
p++; | ||||
} | ||||
peg$posDetailsCache[pos] = details; | ||||
return details; | ||||
} | ||||
} | ||||
function peg$computeLocation(startPos, endPos) { | ||||
var startPosDetails = peg$computePosDetails(startPos), | ||||
endPosDetails = peg$computePosDetails(endPos); | ||||
return { | ||||
start: { | ||||
offset: startPos, | ||||
line: startPosDetails.line, | ||||
column: startPosDetails.column | ||||
}, | ||||
end: { | ||||
offset: endPos, | ||||
line: endPosDetails.line, | ||||
column: endPosDetails.column | ||||
} | ||||
}; | ||||
} | ||||
function peg$fail(expected) { | ||||
if (peg$currPos < peg$maxFailPos) { | ||||
return; | ||||
} | ||||
if (peg$currPos > peg$maxFailPos) { | ||||
peg$maxFailPos = peg$currPos; | ||||
peg$maxFailExpected = []; | ||||
} | ||||
peg$maxFailExpected.push(expected); | ||||
} | ||||
function peg$buildStructuredError(expected, found, location) { | ||||
return new peg$SyntaxError(peg$SyntaxError.buildMessage(expected, found), expected, found, location); | ||||
} | ||||
function peg$parserules() { | ||||
var s0, s1; | ||||
s0 = []; | ||||
s1 = peg$parsestatement(); | ||||
if (s1 !== peg$FAILED) { | ||||
while (s1 !== peg$FAILED) { | ||||
s0.push(s1); | ||||
s1 = peg$parsestatement(); | ||||
} | ||||
} else { | ||||
s0 = peg$FAILED; | ||||
} | ||||
return s0; | ||||
} | ||||
function peg$parsestatement() { | ||||
var s0, s1, s2; | ||||
s0 = peg$currPos; | ||||
s1 = peg$parsestatement_type(); | ||||
if (s1 !== peg$FAILED) { | ||||
s2 = peg$parse_(); | ||||
if (s2 !== peg$FAILED) { | ||||
s1 = peg$c0(s1); | ||||
s0 = s1; | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
return s0; | ||||
} | ||||
function peg$parsestatement_type() { | ||||
var s0; | ||||
s0 = peg$parseassignment(); | ||||
if (s0 === peg$FAILED) { | ||||
s0 = peg$parsecomment(); | ||||
} | ||||
return s0; | ||||
} | ||||
function peg$parsecomment() { | ||||
var s0, s1, s2, s3; | ||||
s0 = peg$currPos; | ||||
if (input.charCodeAt(peg$currPos) === 35) { | ||||
s1 = peg$c1; | ||||
peg$currPos++; | ||||
} else { | ||||
s1 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c2); | ||||
} | ||||
} | ||||
if (s1 !== peg$FAILED) { | ||||
s2 = []; | ||||
if (peg$c3.test(input.charAt(peg$currPos))) { | ||||
s3 = input.charAt(peg$currPos); | ||||
peg$currPos++; | ||||
} else { | ||||
s3 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c4); | ||||
} | ||||
} | ||||
while (s3 !== peg$FAILED) { | ||||
s2.push(s3); | ||||
if (peg$c3.test(input.charAt(peg$currPos))) { | ||||
s3 = input.charAt(peg$currPos); | ||||
peg$currPos++; | ||||
} else { | ||||
s3 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c4); | ||||
} | ||||
} | ||||
} | ||||
if (s2 !== peg$FAILED) { | ||||
if (peg$c5.test(input.charAt(peg$currPos))) { | ||||
s3 = input.charAt(peg$currPos); | ||||
peg$currPos++; | ||||
} else { | ||||
s3 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c6); | ||||
} | ||||
} | ||||
if (s3 !== peg$FAILED) { | ||||
s1 = peg$c7(s2); | ||||
s0 = s1; | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
return s0; | ||||
} | ||||
function peg$parseassignment() { | ||||
var s0, s1, s2, s3, s4, s5, s6, s7; | ||||
s0 = peg$currPos; | ||||
s1 = peg$parsevariable(); | ||||
if (s1 !== peg$FAILED) { | ||||
s2 = peg$parse_(); | ||||
if (s2 !== peg$FAILED) { | ||||
if (input.charCodeAt(peg$currPos) === 61) { | ||||
s3 = peg$c8; | ||||
peg$currPos++; | ||||
} else { | ||||
s3 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c9); | ||||
} | ||||
} | ||||
if (s3 !== peg$FAILED) { | ||||
s4 = peg$parse_(); | ||||
if (s4 !== peg$FAILED) { | ||||
s5 = peg$parsealternation(); | ||||
if (s5 !== peg$FAILED) { | ||||
s6 = peg$parse_(); | ||||
if (s6 !== peg$FAILED) { | ||||
if (input.charCodeAt(peg$currPos) === 59) { | ||||
s7 = peg$c10; | ||||
peg$currPos++; | ||||
} else { | ||||
s7 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c11); | ||||
} | ||||
} | ||||
if (s7 !== peg$FAILED) { | ||||
s1 = peg$c12(s1, s5); | ||||
s0 = s1; | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
return s0; | ||||
} | ||||
function peg$parsevariable() { | ||||
var s0, s1; | ||||
s0 = peg$currPos; | ||||
s1 = peg$parsename(); | ||||
if (s1 !== peg$FAILED) { | ||||
s1 = peg$c13(s1); | ||||
} | ||||
s0 = s1; | ||||
return s0; | ||||
} | ||||
function peg$parsealternation() { | ||||
var s0, s1, s2, s3, s4, s5; | ||||
s0 = peg$currPos; | ||||
s1 = peg$parseconcatenation(); | ||||
if (s1 !== peg$FAILED) { | ||||
s2 = peg$parse_(); | ||||
if (s2 !== peg$FAILED) { | ||||
if (input.charCodeAt(peg$currPos) === 124) { | ||||
s3 = peg$c14; | ||||
peg$currPos++; | ||||
} else { | ||||
s3 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c15); | ||||
} | ||||
} | ||||
if (s3 !== peg$FAILED) { | ||||
s4 = peg$parse_(); | ||||
if (s4 !== peg$FAILED) { | ||||
s5 = peg$parsealternation(); | ||||
if (s5 !== peg$FAILED) { | ||||
s1 = peg$c16(s1, s5); | ||||
s0 = s1; | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
if (s0 === peg$FAILED) { | ||||
s0 = peg$parseconcatenation(); | ||||
} | ||||
return s0; | ||||
} | ||||
function peg$parseconcatenation() { | ||||
var s0, s1, s2, s3; | ||||
s0 = peg$currPos; | ||||
s1 = peg$parserepeat(); | ||||
if (s1 !== peg$FAILED) { | ||||
s2 = peg$parse_(); | ||||
if (s2 !== peg$FAILED) { | ||||
s3 = peg$parseconcatenation(); | ||||
if (s3 !== peg$FAILED) { | ||||
s1 = peg$c17(s1, s3); | ||||
s0 = s1; | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
if (s0 === peg$FAILED) { | ||||
s0 = peg$parserepeat(); | ||||
} | ||||
return s0; | ||||
} | ||||
function peg$parserepeat() { | ||||
var s0, s1, s2, s3, s4, s5, s6; | ||||
s0 = peg$currPos; | ||||
s1 = peg$parsename(); | ||||
if (s1 !== peg$FAILED) { | ||||
if (input.charCodeAt(peg$currPos) === 58) { | ||||
s2 = peg$c18; | ||||
peg$currPos++; | ||||
} else { | ||||
s2 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c19); | ||||
} | ||||
} | ||||
if (s2 !== peg$FAILED) { | ||||
s3 = peg$parserepeat(); | ||||
if (s3 !== peg$FAILED) { | ||||
s1 = peg$c20(s1, s3); | ||||
s0 = s1; | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
if (s0 === peg$FAILED) { | ||||
s0 = peg$currPos; | ||||
s1 = peg$parseterm(); | ||||
if (s1 !== peg$FAILED) { | ||||
if (input.charCodeAt(peg$currPos) === 42) { | ||||
s2 = peg$c21; | ||||
peg$currPos++; | ||||
} else { | ||||
s2 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c22); | ||||
} | ||||
} | ||||
if (s2 !== peg$FAILED) { | ||||
s1 = peg$c23(s1); | ||||
s0 = s1; | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
if (s0 === peg$FAILED) { | ||||
s0 = peg$currPos; | ||||
s1 = peg$parseterm(); | ||||
if (s1 !== peg$FAILED) { | ||||
if (input.charCodeAt(peg$currPos) === 63) { | ||||
s2 = peg$c24; | ||||
peg$currPos++; | ||||
} else { | ||||
s2 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c25); | ||||
} | ||||
} | ||||
if (s2 !== peg$FAILED) { | ||||
s1 = peg$c26(s1); | ||||
s0 = s1; | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
if (s0 === peg$FAILED) { | ||||
s0 = peg$currPos; | ||||
s1 = peg$parseterm(); | ||||
if (s1 !== peg$FAILED) { | ||||
if (input.charCodeAt(peg$currPos) === 43) { | ||||
s2 = peg$c27; | ||||
peg$currPos++; | ||||
} else { | ||||
s2 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c28); | ||||
} | ||||
} | ||||
if (s2 !== peg$FAILED) { | ||||
s1 = peg$c29(s1); | ||||
s0 = s1; | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
if (s0 === peg$FAILED) { | ||||
s0 = peg$currPos; | ||||
s1 = peg$parseterm(); | ||||
if (s1 !== peg$FAILED) { | ||||
if (input.charCodeAt(peg$currPos) === 123) { | ||||
s2 = peg$c30; | ||||
peg$currPos++; | ||||
} else { | ||||
s2 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c31); | ||||
} | ||||
} | ||||
if (s2 !== peg$FAILED) { | ||||
s3 = peg$parsenumber(); | ||||
if (s3 !== peg$FAILED) { | ||||
if (input.charCodeAt(peg$currPos) === 125) { | ||||
s4 = peg$c32; | ||||
peg$currPos++; | ||||
} else { | ||||
s4 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c33); | ||||
} | ||||
} | ||||
if (s4 !== peg$FAILED) { | ||||
s1 = peg$c34(s1, s3); | ||||
s0 = s1; | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
if (s0 === peg$FAILED) { | ||||
s0 = peg$currPos; | ||||
s1 = peg$parseterm(); | ||||
if (s1 !== peg$FAILED) { | ||||
if (input.charCodeAt(peg$currPos) === 123) { | ||||
s2 = peg$c30; | ||||
peg$currPos++; | ||||
} else { | ||||
s2 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c31); | ||||
} | ||||
} | ||||
if (s2 !== peg$FAILED) { | ||||
s3 = peg$parsenumber(); | ||||
if (s3 !== peg$FAILED) { | ||||
if (input.charCodeAt(peg$currPos) === 44) { | ||||
s4 = peg$c35; | ||||
peg$currPos++; | ||||
} else { | ||||
s4 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c36); | ||||
} | ||||
} | ||||
if (s4 !== peg$FAILED) { | ||||
if (input.charCodeAt(peg$currPos) === 125) { | ||||
s5 = peg$c32; | ||||
peg$currPos++; | ||||
} else { | ||||
s5 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c33); | ||||
} | ||||
} | ||||
if (s5 !== peg$FAILED) { | ||||
s1 = peg$c37(s1, s3); | ||||
s0 = s1; | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
if (s0 === peg$FAILED) { | ||||
s0 = peg$currPos; | ||||
s1 = peg$parseterm(); | ||||
if (s1 !== peg$FAILED) { | ||||
if (input.charCodeAt(peg$currPos) === 123) { | ||||
s2 = peg$c30; | ||||
peg$currPos++; | ||||
} else { | ||||
s2 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c31); | ||||
} | ||||
} | ||||
if (s2 !== peg$FAILED) { | ||||
if (input.charCodeAt(peg$currPos) === 44) { | ||||
s3 = peg$c35; | ||||
peg$currPos++; | ||||
} else { | ||||
s3 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c36); | ||||
} | ||||
} | ||||
if (s3 !== peg$FAILED) { | ||||
s4 = peg$parsenumber(); | ||||
if (s4 !== peg$FAILED) { | ||||
if (input.charCodeAt(peg$currPos) === 125) { | ||||
s5 = peg$c32; | ||||
peg$currPos++; | ||||
} else { | ||||
s5 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c33); | ||||
} | ||||
} | ||||
if (s5 !== peg$FAILED) { | ||||
s1 = peg$c38(s1, s4); | ||||
s0 = s1; | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
if (s0 === peg$FAILED) { | ||||
s0 = peg$currPos; | ||||
s1 = peg$parseterm(); | ||||
if (s1 !== peg$FAILED) { | ||||
if (input.charCodeAt(peg$currPos) === 123) { | ||||
s2 = peg$c30; | ||||
peg$currPos++; | ||||
} else { | ||||
s2 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c31); | ||||
} | ||||
} | ||||
if (s2 !== peg$FAILED) { | ||||
s3 = peg$parsenumber(); | ||||
if (s3 !== peg$FAILED) { | ||||
if (input.charCodeAt(peg$currPos) === 44) { | ||||
s4 = peg$c35; | ||||
peg$currPos++; | ||||
} else { | ||||
s4 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c36); | ||||
} | ||||
} | ||||
if (s4 !== peg$FAILED) { | ||||
s5 = peg$parsenumber(); | ||||
if (s5 !== peg$FAILED) { | ||||
if (input.charCodeAt(peg$currPos) === 125) { | ||||
s6 = peg$c32; | ||||
peg$currPos++; | ||||
} else { | ||||
s6 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c33); | ||||
} | ||||
} | ||||
if (s6 !== peg$FAILED) { | ||||
s1 = peg$c39(s1, s3, s5); | ||||
s0 = s1; | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
if (s0 === peg$FAILED) { | ||||
s0 = peg$parseterm(); | ||||
} | ||||
} | ||||
} | ||||
} | ||||
} | ||||
} | ||||
} | ||||
} | ||||
return s0; | ||||
} | ||||
function peg$parseterm() { | ||||
var s0, s1, s2, s3; | ||||
s0 = peg$parsevariable(); | ||||
if (s0 === peg$FAILED) { | ||||
s0 = peg$currPos; | ||||
s1 = peg$parsenumber(); | ||||
if (s1 !== peg$FAILED) { | ||||
s1 = peg$c40(s1); | ||||
} | ||||
s0 = s1; | ||||
if (s0 === peg$FAILED) { | ||||
s0 = peg$currPos; | ||||
if (input.charCodeAt(peg$currPos) === 40) { | ||||
s1 = peg$c41; | ||||
peg$currPos++; | ||||
} else { | ||||
s1 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c42); | ||||
} | ||||
} | ||||
if (s1 !== peg$FAILED) { | ||||
s2 = peg$parsealternation(); | ||||
if (s2 !== peg$FAILED) { | ||||
if (input.charCodeAt(peg$currPos) === 41) { | ||||
s3 = peg$c43; | ||||
peg$currPos++; | ||||
} else { | ||||
s3 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c44); | ||||
} | ||||
} | ||||
if (s3 !== peg$FAILED) { | ||||
s1 = peg$c45(s2); | ||||
s0 = s1; | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} | ||||
} | ||||
return s0; | ||||
} | ||||
function peg$parsename() { | ||||
var s0, s1, s2, s3; | ||||
s0 = peg$currPos; | ||||
s1 = peg$parsename_start_char(); | ||||
if (s1 !== peg$FAILED) { | ||||
s2 = []; | ||||
s3 = peg$parsename_char(); | ||||
while (s3 !== peg$FAILED) { | ||||
s2.push(s3); | ||||
s3 = peg$parsename_char(); | ||||
} | ||||
if (s2 !== peg$FAILED) { | ||||
s1 = peg$c47(s1, s2); | ||||
s0 = s1; | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
} else { | ||||
peg$currPos = s0; | ||||
s0 = peg$FAILED; | ||||
} | ||||
return s0; | ||||
} | ||||
function peg$parsename_start_char() { | ||||
var s0; | ||||
if (input.charCodeAt(peg$currPos) === 95) { | ||||
s0 = peg$c48; | ||||
peg$currPos++; | ||||
} else { | ||||
s0 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c49); | ||||
} | ||||
} | ||||
if (s0 === peg$FAILED) { | ||||
if (peg$c50.test(input.charAt(peg$currPos))) { | ||||
s0 = input.charAt(peg$currPos); | ||||
peg$currPos++; | ||||
} else { | ||||
s0 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c51); | ||||
} | ||||
} | ||||
} | ||||
return s0; | ||||
} | ||||
function peg$parsename_char() { | ||||
var s0; | ||||
s0 = peg$parsename_start_char(); | ||||
if (s0 === peg$FAILED) { | ||||
if (peg$c52.test(input.charAt(peg$currPos))) { | ||||
s0 = input.charAt(peg$currPos); | ||||
peg$currPos++; | ||||
} else { | ||||
s0 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c53); | ||||
} | ||||
} | ||||
} | ||||
return s0; | ||||
} | ||||
function peg$parsenumber() { | ||||
var s0, s1, s2; | ||||
s0 = peg$currPos; | ||||
s1 = []; | ||||
if (peg$c52.test(input.charAt(peg$currPos))) { | ||||
s2 = input.charAt(peg$currPos); | ||||
peg$currPos++; | ||||
} else { | ||||
s2 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c53); | ||||
} | ||||
} | ||||
if (s2 !== peg$FAILED) { | ||||
while (s2 !== peg$FAILED) { | ||||
s1.push(s2); | ||||
if (peg$c52.test(input.charAt(peg$currPos))) { | ||||
s2 = input.charAt(peg$currPos); | ||||
peg$currPos++; | ||||
} else { | ||||
s2 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c53); | ||||
} | ||||
} | ||||
} | ||||
} else { | ||||
s1 = peg$FAILED; | ||||
} | ||||
if (s1 !== peg$FAILED) { | ||||
s1 = peg$c54(s1); | ||||
} | ||||
s0 = s1; | ||||
return s0; | ||||
} | ||||
function peg$parse_() { | ||||
var s0, s1; | ||||
s0 = []; | ||||
if (peg$c55.test(input.charAt(peg$currPos))) { | ||||
s1 = input.charAt(peg$currPos); | ||||
peg$currPos++; | ||||
} else { | ||||
s1 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c56); | ||||
} | ||||
} | ||||
while (s1 !== peg$FAILED) { | ||||
s0.push(s1); | ||||
if (peg$c55.test(input.charAt(peg$currPos))) { | ||||
s1 = input.charAt(peg$currPos); | ||||
peg$currPos++; | ||||
} else { | ||||
s1 = peg$FAILED; | ||||
{ | ||||
peg$fail(peg$c56); | ||||
} | ||||
} | ||||
} | ||||
return s0; | ||||
} | ||||
var n = nodes; | ||||
peg$result = peg$startRuleFunction(); | ||||
if (peg$result !== peg$FAILED && peg$currPos === input.length) { | ||||
return peg$result; | ||||
} else { | ||||
if (peg$result !== peg$FAILED && peg$currPos < input.length) { | ||||
peg$fail(peg$endExpectation()); | ||||
} | ||||
throw peg$buildStructuredError(peg$maxFailExpected, peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null, peg$maxFailPos < input.length ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1) : peg$computeLocation(peg$maxFailPos, peg$maxFailPos)); | ||||
} | ||||
} | ||||
var grammar = { | ||||
SyntaxError: peg$SyntaxError, | ||||
parse: peg$parse | ||||
}; | ||||
/** | ||||
* Processes a list of statements into a symbol table | ||||
*/ | ||||
class SymbolTable { | ||||
constructor(statements, externalSymbols = {}) { | ||||
this.variables = {}; | ||||
this.symbols = {}; | ||||
this.main = null; | ||||
this.size = 0; | ||||
this.addExternalSymbols(externalSymbols); | ||||
this.process(statements); | ||||
} | ||||
addExternalSymbols(externalSymbols) { | ||||
for (var key in externalSymbols) { | ||||
this.variables[key] = new Literal(externalSymbols[key]); | ||||
this.symbols[key] = externalSymbols[key]; | ||||
this.size++; | ||||
} | ||||
} | ||||
process(statements) { | ||||
for (var statement of statements) { | ||||
if (statement instanceof Assignment) { | ||||
this.variables[statement.variable.name] = this.processExpression(statement.expression); | ||||
if (statement.expression instanceof Literal) { | ||||
this.symbols[statement.variable.name] = statement.expression.value; | ||||
this.size++; | ||||
} | ||||
} | ||||
} | ||||
this.main = this.variables.main; | ||||
if (!this.main) { | ||||
throw new Error('No main variable declaration found'); | ||||
} | ||||
} | ||||
processExpression(expr) { | ||||
// Process children | ||||
for (var key in expr) { | ||||
if (expr[key] instanceof Node) { | ||||
expr[key] = this.processExpression(expr[key]); | ||||
} | ||||
} // Replace variable references with their values | ||||
if (expr instanceof Variable) { | ||||
var value = this.variables[expr.name]; | ||||
if (value == null) throw new Error("Undeclared indentifier ".concat(expr.name)); | ||||
expr = this.processExpression(value.copy()); | ||||
} | ||||
return expr; | ||||
} | ||||
} | ||||
var END_MARKER = new EndMarker(); | ||||
/** | ||||
* This is an implementation of the direct regular expression to DFA algorithm described | ||||
* in section 3.9.5 of "Compilers: Principles, Techniques, and Tools" by Aho, | ||||
* Lam, Sethi, and Ullman. http://dragonbook.stanford.edu | ||||
* There is a PDF of the book here: | ||||
* http://www.informatik.uni-bremen.de/agbkb/lehre/ccfl/Material/ALSUdragonbook.pdf | ||||
*/ | ||||
function buildDFA(root, numSymbols) { | ||||
root = new Concatenation(root, END_MARKER); | ||||
root.calcFollowpos(); | ||||
var failState = new State(new Set(), numSymbols); | ||||
var initialState = new State(root.firstpos, numSymbols); | ||||
var dstates = [failState, initialState]; // while there is an unmarked state S in dstates | ||||
while (1) { | ||||
var s = null; | ||||
for (var j = 1; j < dstates.length; j++) { | ||||
if (!dstates[j].marked) { | ||||
s = dstates[j]; | ||||
break; | ||||
} | ||||
} | ||||
if (s == null) { | ||||
break; | ||||
} // mark S | ||||
s.marked = true; // for each input symbol a | ||||
for (var a = 0; a < numSymbols; a++) { | ||||
// let U be the union of followpos(p) for all | ||||
// p in S that correspond to a | ||||
var u = new Set(); | ||||
for (var p of s.positions) { | ||||
if (p instanceof Literal && p.value === a) { | ||||
addAll(u, p.followpos); | ||||
} | ||||
} | ||||
if (u.size === 0) { | ||||
continue; | ||||
} // if U is not in dstates | ||||
var ux = -1; | ||||
for (var i = 0; i < dstates.length; i++) { | ||||
if (equal(u, dstates[i].positions)) { | ||||
ux = i; | ||||
break; | ||||
} | ||||
} | ||||
if (ux === -1) { | ||||
// Add U as an unmarked state to dstates | ||||
dstates.push(new State(u, numSymbols)); | ||||
ux = dstates.length - 1; | ||||
} | ||||
s.transitions[a] = ux; | ||||
} | ||||
} | ||||
return dstates; | ||||
} | ||||
class State { | ||||
constructor(positions, len) { | ||||
this.positions = positions; | ||||
this.transitions = new Uint16Array(len); | ||||
this.accepting = positions.has(END_MARKER); | ||||
this.marked = false; | ||||
this.tags = new Set(); | ||||
for (var pos of positions) { | ||||
if (pos instanceof Tag) { | ||||
this.tags.add(pos.name); | ||||
} | ||||
} | ||||
} | ||||
} | ||||
var INITIAL_STATE = 1; | ||||
var FAIL_STATE = 0; | ||||
/** | ||||
* A StateMachine represents a deterministic finite automaton. | ||||
* It can perform matches over a sequence of values, similar to a regular expression. | ||||
*/ | ||||
class StateMachine { | ||||
constructor(dfa) { | ||||
this.stateTable = dfa.stateTable; | ||||
this.accepting = dfa.accepting; | ||||
this.tags = dfa.tags; | ||||
} | ||||
/** | ||||
* Returns an iterable object that yields pattern matches over the input sequence. | ||||
* Matches are of the form [startIndex, endIndex, tags]. | ||||
*/ | ||||
match(str) { | ||||
var self = this; | ||||
return { | ||||
*[Symbol.iterator]() { | ||||
var state = INITIAL_STATE; | ||||
var startRun = null; | ||||
var lastAccepting = null; | ||||
var lastState = null; | ||||
for (var p = 0; p < str.length; p++) { | ||||
var c = str[p]; | ||||
lastState = state; | ||||
state = self.stateTable[state][c]; | ||||
if (state === FAIL_STATE) { | ||||
// yield the last match if any | ||||
if (startRun != null && lastAccepting != null && lastAccepting >= startRun) { | ||||
yield [startRun, lastAccepting, self.tags[lastState]]; | ||||
} // reset the state as if we started over from the initial state | ||||
state = self.stateTable[INITIAL_STATE][c]; | ||||
startRun = null; | ||||
} // start a run if not in the failure state | ||||
if (state !== FAIL_STATE && startRun == null) { | ||||
startRun = p; | ||||
} // if accepting, mark the potential match end | ||||
if (self.accepting[state]) { | ||||
lastAccepting = p; | ||||
} // reset the state to the initial state if we get into the failure state | ||||
if (state === FAIL_STATE) { | ||||
state = INITIAL_STATE; | ||||
} | ||||
} // yield the last match if any | ||||
if (startRun != null && lastAccepting != null && lastAccepting >= startRun) { | ||||
yield [startRun, lastAccepting, self.tags[state]]; | ||||
} | ||||
} | ||||
}; | ||||
} | ||||
/** | ||||
* For each match over the input sequence, action functions matching | ||||
* the tag definitions in the input pattern are called with the startIndex, | ||||
* endIndex, and sub-match sequence. | ||||
*/ | ||||
apply(str, actions) { | ||||
for (var [start, end, tags] of this.match(str)) { | ||||
for (var tag of tags) { | ||||
if (typeof actions[tag] === 'function') { | ||||
actions[tag](start, end, str.slice(start, end + 1)); | ||||
} | ||||
} | ||||
} | ||||
} | ||||
} | ||||
function parse(string, externalSymbols) { | ||||
var ast = grammar.parse(string); | ||||
return new SymbolTable(ast, externalSymbols); | ||||
} | ||||
function build(symbolTable) { | ||||
var states = buildDFA(symbolTable.main, symbolTable.size); | ||||
return new StateMachine({ | ||||
stateTable: states.map(s => Array.from(s.transitions)), | ||||
accepting: states.map(s => s.accepting), | ||||
tags: states.map(s => Array.from(s.tags)) | ||||
}); | ||||
} | ||||
function compile(string, externalSymbols) { | ||||
return build(parse(string, externalSymbols)); | ||||
} | ||||
exports.build = build; | ||||
exports.default = compile; | ||||
exports.parse = parse; | ||||
//# sourceMappingURL=compile.js.map | ||||