Various refactoring

redux
Sven Slootweg 4 years ago
parent 51d6414151
commit f11ef306c8

@ -11,19 +11,7 @@ let reportUndefinedRules = require("./passes/report-undefined-rules");
let visitor = require("./visitor"); let visitor = require("./visitor");
function processOptions(options, defaults) { function processOptions(options, defaults) {
let processedOptions = {}; return Object.assign({}, defaults, options);
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;
} }
let compiler = { let compiler = {
@ -57,10 +45,8 @@ let compiler = {
// if the AST contains a semantic error. Note that not all errors are detected // 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 // during the generation and some may protrude to the generated parser and
// cause its malfunction. // cause its malfunction.
compile(ast, passes, options) { compile(ast, passes, options = {}) {
options = options !== undefined ? options : {}; let processedOptions = processOptions(options, {
options = processOptions(options, {
allowedStartRules: [ast.rules[0].name], allowedStartRules: [ast.rules[0].name],
cache: false, cache: false,
dependencies: {}, dependencies: {},
@ -71,19 +57,20 @@ let compiler = {
trace: false trace: false
}); });
Object.keys(passes).forEach(stage => { Object.values(passes).forEach((stagePasses) => {
passes[stage].forEach(p => { p(ast, options); }); stagePasses.forEach(pass => { pass(ast, processedOptions); });
}); });
switch (options.output) { switch (processedOptions.output) {
case "parser": case "parser":
return eval(ast.code); return eval(ast.code);
case "source": case "source":
return ast.code; return ast.code;
// FIXME: Move to Validatem code at entrypoint
default: default:
throw new Error("Invalid output format: " + options.output + "."); throw new Error("Invalid output format: " + processedOptions.output + ".");
} }
} }
}; };

@ -1,6 +1,11 @@
"use strict"; "use strict";
function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); } function hex(character) {
return character
.charCodeAt(0)
.toString(16)
.toUpperCase();
}
// JavaScript code generation helpers. // JavaScript code generation helpers.
let js = { let js = {

@ -1204,7 +1204,7 @@ function generateJS(ast, options) {
function generateWrapper(toplevelCode) { function generateWrapper(toplevelCode) {
function generateGeneratedByComment() { function generateGeneratedByComment() {
return [ return [
"// Generated by PEG.js 0.10.0.", `// Generated by PEG.js ${require("../../../package.json").version}.`,
"//", "//",
"// https://pegjs.org/" "// https://pegjs.org/"
].join("\n"); ].join("\n");

@ -1,12 +1,14 @@
"use strict"; "use strict";
const mapObj = require("map-obj");
let GrammarError = require("./grammar-error"); let GrammarError = require("./grammar-error");
let compiler = require("./compiler"); let compiler = require("./compiler");
let parser = require("./parser"); let parser = require("./parser");
let peg = { module.exports = {
// PEG.js version (uses semantic versioning). // PEG.js version (uses semantic versioning).
VERSION: "0.10.0", VERSION: require("../package.json").version,
GrammarError: GrammarError, GrammarError: GrammarError,
parser: parser, parser: parser,
@ -21,34 +23,20 @@ let peg = {
// |peg.GrammarError| if it contains a semantic error. Note that not all // |peg.GrammarError| if it contains a semantic error. Note that not all
// errors are detected during the generation and some may protrude to the // errors are detected during the generation and some may protrude to the
// generated parser and cause its malfunction. // generated parser and cause its malfunction.
generate(grammar, options) { generate(grammar, options = {}) {
options = options !== undefined ? options : {}; // FIXME: Validatem
function convertPasses(passes) {
let converted = {};
Object.keys(passes).forEach(stage => {
converted[stage] = Object.keys(passes[stage])
.map(name => passes[stage][name]);
});
return converted;
}
let plugins = "plugins" in options ? options.plugins : [];
let config = { let config = {
parser: peg.parser, parser: parser,
passes: convertPasses(peg.compiler.passes) passes: mapObj(compiler.passes, (stage, passesForStage) => {
return [ stage, Object.values(passesForStage) ];
})
}; };
plugins.forEach(p => { p.use(config, options); }); return compiler.compile(
return peg.compiler.compile(
config.parser.parse(grammar), config.parser.parse(grammar),
config.passes, config.passes,
options options
); );
} }
}; };
module.exports = peg;

@ -67,6 +67,7 @@
}, },
"dependencies": { "dependencies": {
"@babel/preset-env": "^7.12.1", "@babel/preset-env": "^7.12.1",
"eslint": "^7.12.0" "eslint": "^7.12.0",
"map-obj": "^4.1.0"
} }
} }

@ -1,128 +0,0 @@
"use strict";
let chai = require("chai");
let peg = require("../../lib/peg");
let expect = chai.expect;
describe("plugin API", function() {
describe("use", function() {
let grammar = "start = 'a'";
it("is called for each plugin", function() {
let pluginsUsed = [false, false, false];
let plugins = [
{ use() { pluginsUsed[0] = true; } },
{ use() { pluginsUsed[1] = true; } },
{ use() { pluginsUsed[2] = true; } }
];
peg.generate(grammar, { plugins: plugins });
expect(pluginsUsed).to.deep.equal([true, true, true]);
});
it("receives configuration", function() {
let plugin = {
use(config) {
expect(config).to.be.an("object");
expect(config.parser).to.be.an("object");
expect(config.parser.parse("start = 'a'")).to.be.an("object");
expect(config.passes).to.be.an("object");
expect(config.passes.check).to.be.an("array");
config.passes.check.forEach(pass => {
expect(pass).to.be.a("function");
});
expect(config.passes.transform).to.be.an("array");
config.passes.transform.forEach(pass => {
expect(pass).to.be.a("function");
});
expect(config.passes.generate).to.be.an("array");
config.passes.generate.forEach(pass => {
expect(pass).to.be.a("function");
});
}
};
peg.generate(grammar, { plugins: [plugin] });
});
it("receives options", function() {
let plugin = {
use(config, options) {
expect(options).to.equal(generateOptions);
}
};
let generateOptions = { plugins: [plugin], foo: 42 };
peg.generate(grammar, generateOptions);
});
it("can replace parser", function() {
let plugin = {
use(config) {
let parser = peg.generate([
"start = .* {",
" return {",
" type: 'grammar',",
" rules: [",
" {",
" type: 'rule',",
" name: 'start',",
" expression: { type: 'literal', value: text(), ignoreCase: false }",
" }",
" ]",
" };",
"}"
].join("\n"));
config.parser = parser;
}
};
let parser = peg.generate("a", { plugins: [plugin] });
expect(parser.parse("a")).to.equal("a");
});
it("can change compiler passes", function() {
let plugin = {
use(config) {
function pass(ast) {
ast.code = "({ parse: function() { return 42; } })";
}
config.passes.generate = [pass];
}
};
let parser = peg.generate(grammar, { plugins: [plugin] });
expect(parser.parse("a")).to.equal(42);
});
it("can change options", function() {
let grammar = [
"a = 'x'",
"b = 'x'",
"c = 'x'"
].join("\n");
let plugin = {
use(config, options) {
options.allowedStartRules = ["b", "c"];
}
};
let parser = peg.generate(grammar, {
allowedStartRules: ["a"],
plugins: [plugin]
});
expect(() => { parser.parse("x", { startRule: "a" }); }).to.throw();
expect(parser.parse("x", { startRule: "b" })).to.equal("x");
expect(parser.parse("x", { startRule: "c" })).to.equal("x");
});
});
});

@ -3699,6 +3699,11 @@ map-cache@^0.2.0, map-cache@^0.2.2:
resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=
map-obj@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.1.0.tgz#b91221b542734b9f14256c0132c897c5d7256fd5"
integrity sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==
map-visit@^1.0.0: map-visit@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"

Loading…
Cancel
Save