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.

75 lines
1.9 KiB
JavaScript

"use strict";
const Promise = require("bluebird");
const pegRedux = require("peg-redux");
const moduleEval = require("eval");
const vm = require("vm");
const asExpression = require("as-expression");
const { chain } = require("error-chain");
const textParser = require("../text-parser");
const { validateOptions } = require("@validatem/core");
const isString = require("@validatem/is-string");
const isPlainObject = require("@validatem/is-plain-object");
const requireEither = require("@validatem/require-either");
module.exports = function createPegParser(_options) {
let { grammar, grammarFile, options } = validateOptions(arguments, [
{
grammar: [ isString ],
grammarFile: [ isString ],
options: [ isPlainObject ]
}, requireEither([ "grammar", "grammarFile" ])
]);
let parserOptions = {
... options,
output: "source",
format: "commonjs"
};
return Promise.try(() => {
return (grammarFile != null)
? pegRedux.generateFromFile(grammarFile, parserOptions)
: pegRedux.generate(grammar, parserOptions);
}).then((parserCode) => {
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 chain(error, textParser.NoResult, "Parsing output failed");
} else {
throw error;
}
}
}
};
});
};