Initial
This commit is contained in:
145
resources/app/node_modules/peggy/lib/compiler/asts.js
generated
vendored
Normal file
145
resources/app/node_modules/peggy/lib/compiler/asts.js
generated
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
"use strict";
|
||||
|
||||
const visitor = require("./visitor");
|
||||
|
||||
/**
|
||||
* Combine two things, each of which might be an array, into a single value,
|
||||
* in the order [...a, ...b].
|
||||
*
|
||||
* @template T
|
||||
* @param {T | T[]} a
|
||||
* @param {T | T[]} b
|
||||
* @returns {T | T[]}
|
||||
*/
|
||||
function combinePossibleArrays(a, b) {
|
||||
// First might be an array, second will not. Either might be null.
|
||||
if (!(a && b)) {
|
||||
return a || b;
|
||||
}
|
||||
const aa = Array.isArray(a) ? a : [a];
|
||||
aa.push(b);
|
||||
return aa;
|
||||
}
|
||||
|
||||
// AST utilities.
|
||||
const asts = {
|
||||
/**
|
||||
* Find the rule with the given name, if it exists.
|
||||
*
|
||||
* @param {PEG.ast.Grammar} ast
|
||||
* @param {string} name
|
||||
* @returns {PEG.ast.Rule | undefined}
|
||||
*/
|
||||
findRule(ast, name) {
|
||||
for (let i = 0; i < ast.rules.length; i++) {
|
||||
if (ast.rules[i].name === name) {
|
||||
return ast.rules[i];
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* Find the index of the rule with the given name, if it exists.
|
||||
* Otherwise returns -1.
|
||||
*
|
||||
* @param {PEG.ast.Grammar} ast
|
||||
* @param {string} name
|
||||
* @returns {number}
|
||||
*/
|
||||
indexOfRule(ast, name) {
|
||||
for (let i = 0; i < ast.rules.length; i++) {
|
||||
if (ast.rules[i].name === name) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// istanbul ignore next Presence of rules checked using another approach that not involve this function
|
||||
// Any time when it is called the rules always exist
|
||||
return -1;
|
||||
},
|
||||
|
||||
alwaysConsumesOnSuccess(ast, node) {
|
||||
function consumesTrue() { return true; }
|
||||
function consumesFalse() { return false; }
|
||||
|
||||
const consumes = visitor.build({
|
||||
choice(node) {
|
||||
return node.alternatives.every(consumes);
|
||||
},
|
||||
|
||||
sequence(node) {
|
||||
return node.elements.some(consumes);
|
||||
},
|
||||
|
||||
simple_and: consumesFalse,
|
||||
simple_not: consumesFalse,
|
||||
optional: consumesFalse,
|
||||
zero_or_more: consumesFalse,
|
||||
repeated(node) {
|
||||
// If minimum is `null` it is equals to maximum (parsed from `|exact|` syntax)
|
||||
const min = node.min ? node.min : node.max;
|
||||
|
||||
// If the low boundary is variable then it can be zero.
|
||||
// Expression, repeated zero times, does not consume any input
|
||||
// but always matched - so it does not always consumes on success
|
||||
if (min.type !== "constant" || min.value === 0) {
|
||||
return false;
|
||||
}
|
||||
if (consumes(node.expression)) {
|
||||
return true;
|
||||
}
|
||||
// |node.delimiter| used only when |node.expression| match at least two times
|
||||
// The first `if` filtered out all non-constant minimums, so at this point
|
||||
// |min.value| is always a constant
|
||||
if (min.value > 1 && node.delimiter && consumes(node.delimiter)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
semantic_and: consumesFalse,
|
||||
semantic_not: consumesFalse,
|
||||
|
||||
rule_ref(node) {
|
||||
const rule = asts.findRule(ast, node.name);
|
||||
|
||||
// Because we run all checks in one stage, some rules could be missing.
|
||||
// Checking for missing rules could be executed in parallel to this check
|
||||
return rule ? consumes(rule) : undefined;
|
||||
},
|
||||
|
||||
library_ref() {
|
||||
// No way to know for external rules.
|
||||
return false;
|
||||
},
|
||||
|
||||
literal(node) {
|
||||
return node.value !== "";
|
||||
},
|
||||
|
||||
class: consumesTrue,
|
||||
any: consumesTrue,
|
||||
});
|
||||
|
||||
return consumes(node);
|
||||
},
|
||||
|
||||
combine(asts) {
|
||||
return asts.reduce((combined, ast) => {
|
||||
combined.topLevelInitializer = combinePossibleArrays(
|
||||
combined.topLevelInitializer,
|
||||
ast.topLevelInitializer
|
||||
);
|
||||
combined.initializer = combinePossibleArrays(
|
||||
combined.initializer,
|
||||
ast.initializer
|
||||
);
|
||||
combined.rules = combined.rules.concat(ast.rules);
|
||||
return combined;
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = asts;
|
||||
Reference in New Issue
Block a user