Files
Foundry-VTT-Docker/resources/app/node_modules/peggy/lib/compiler/index.js

171 lines
5.3 KiB
JavaScript
Raw Normal View History

2025-01-04 00:34:03 +01:00
"use strict";
const addImportedRules = require("./passes/add-imported-rules");
const fixLibraryNumbers = require("./passes/fix-library-numbers");
const generateBytecode = require("./passes/generate-bytecode");
const generateJS = require("./passes/generate-js");
const inferenceMatchResult = require("./passes/inference-match-result");
const removeProxyRules = require("./passes/remove-proxy-rules");
const mergeCharacterClasses = require("./passes/merge-character-classes");
const reportDuplicateImports = require("./passes/report-duplicate-imports");
const reportDuplicateLabels = require("./passes/report-duplicate-labels");
const reportDuplicateRules = require("./passes/report-duplicate-rules");
const reportInfiniteRecursion = require("./passes/report-infinite-recursion");
const reportInfiniteRepetition = require("./passes/report-infinite-repetition");
const reportUndefinedRules = require("./passes/report-undefined-rules");
const reportIncorrectPlucking = require("./passes/report-incorrect-plucking");
const Session = require("./session");
const visitor = require("./visitor");
const { base64 } = require("./utils");
function processOptions(options, defaults) {
const processedOptions = {};
Object.keys(options).forEach(name => {
processedOptions[name] = options[name];
});
Object.keys(defaults).forEach(name => {
if (!Object.prototype.hasOwnProperty.call(processedOptions, name)) {
processedOptions[name] = defaults[name];
}
});
return processedOptions;
}
function isSourceMapCapable(target) {
if (typeof target === "string") {
return target.length > 0;
}
return target && (typeof target.offset === "function");
}
const compiler = {
// AST node visitor builder. Useful mainly for plugins which manipulate the
// AST.
visitor,
// Compiler passes.
//
// Each pass is a function that is passed the AST. It can perform checks on it
// or modify it as needed. If the pass encounters a semantic error, it throws
// |peg.GrammarError|.
passes: {
prepare: [
addImportedRules,
reportInfiniteRecursion,
],
check: [
reportUndefinedRules,
reportDuplicateRules,
reportDuplicateLabels,
reportInfiniteRepetition,
reportIncorrectPlucking,
reportDuplicateImports,
],
transform: [
fixLibraryNumbers,
removeProxyRules,
mergeCharacterClasses,
inferenceMatchResult,
],
generate: [
generateBytecode,
generateJS,
],
},
// Generates a parser from a specified grammar AST. Throws |peg.GrammarError|
// if the AST contains a semantic error. Note that not all errors are detected
// during the generation and some may protrude to the generated parser and
// cause its malfunction.
compile(ast, passes, options) {
options = options !== undefined ? options : {};
options = processOptions(options, {
allowedStartRules: [ast.rules[0].name],
cache: false,
dependencies: {},
exportVar: null,
format: "bare",
output: "parser",
trace: false,
});
if (!Array.isArray(options.allowedStartRules)) {
throw new Error("allowedStartRules must be an array");
}
if (options.allowedStartRules.length === 0) {
throw new Error("Must have at least one start rule");
}
const allRules = ast.rules.map(r => r.name);
// "*" means all rules are start rules. "*" is not a valid rule name.
if (options.allowedStartRules.some(r => r === "*")) {
options.allowedStartRules = allRules;
} else {
for (const rule of options.allowedStartRules) {
if (allRules.indexOf(rule) === -1) {
throw new Error(`Unknown start rule "${rule}"`);
}
}
}
// Due to https://github.com/mozilla/source-map/issues/444
// grammarSource is required
if (((options.output === "source-and-map")
|| (options.output === "source-with-inline-map"))
&& !isSourceMapCapable(options.grammarSource)) {
throw new Error("Must provide grammarSource (as a string or GrammarLocation) in order to generate source maps");
}
const session = new Session(options);
Object.keys(passes).forEach(stage => {
session.stage = stage;
session.info(`Process stage ${stage}`);
passes[stage].forEach(pass => {
session.info(`Process pass ${stage}.${pass.name}`);
pass(ast, options, session);
});
// Collect all errors by stage
session.checkErrors();
});
switch (options.output) {
case "parser":
// eslint-disable-next-line no-eval -- Required
return eval(ast.code.toString());
case "source":
return ast.code.toString();
case "source-and-map":
return ast.code;
case "source-with-inline-map": {
if (typeof TextEncoder === "undefined") {
throw new Error("TextEncoder is not supported by this platform");
}
const sourceMap = ast.code.toStringWithSourceMap();
const encoder = new TextEncoder();
const b64 = base64(
encoder.encode(JSON.stringify(sourceMap.map.toJSON()))
);
return sourceMap.code + `\
//\x23 sourceMappingURL=data:application/json;charset=utf-8;base64,${b64}
`;
}
case "ast":
return ast;
default:
throw new Error("Invalid output format: " + options.output + ".");
}
},
};
module.exports = compiler;