You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

73 lines
1.7 KiB
JavaScript

4 years ago
"use strict";
const pegjs = require("pegjs");
const fs = require("fs");
const moduleEval = require("eval");
const vm = require("vm");
const asExpression = require("as-expression");
const textParser = require("../text-parser");
4 years ago
const { validateOptions } = require("@validatem/core");
const isString = require("@validatem/is-string");
const isPlainObject = require("@validatem/is-plain-object");
const requireEither = require("@validatem/require-either");
4 years ago
module.exports = function createPegParser({ grammar, grammarFile, options }) {
validateOptions(arguments, [
{
grammar: [ isString ],
grammarFile: [ isString ],
options: [ isPlainObject ]
4 years ago
}, requireEither([ "grammar", "grammarFile" ])
4 years ago
]);
if (grammarFile != null) {
// FIXME: cache
grammar = fs.readFileSync(grammarFile, "utf8");
}
let parserCode = pegjs.generate(grammar, {
... options,
output: "source",
format: "commonjs"
});
let parser = asExpression(() => {
if (grammarFile != null) {
return moduleEval(parserCode, grammarFile, {}, true);
} else {
let exports_ = {};
let sandbox = {
exports: exports_,
module: {
exports: exports_,
},
require: function () {
throw new Error("You cannot use require() when loading a grammar as a string; use the `grammarFile` option instead");
}
};
let script = new vm.Script(parserCode.replace(/^\#\!.*/, ''));
script.runInNewContext(sandbox);
return sandbox.module.exports;
}
});
return {
supportsStreams: false,
parse: function (text) {
try {
return parser.parse(text);
} catch (error) {
if (error.name === "SyntaxError") {
throw textParser.NoResult.chain(error, "Parsing output failed");
} else {
throw error;
}
}
}
};
};