From 810567d865930f2ef379aaaffdc6d0e87ca1555c Mon Sep 17 00:00:00 2001 From: David Majda Date: Tue, 3 May 2016 11:16:03 +0200 Subject: [PATCH] UMD parsers: Allow specifying parser dependencies Introduce two ways of specifying parser dependencies: the "dependencies" option of PEG.buildParser and the -d/--dependency CLI option. Specified dependencies are translated into AMD dependencies and Node.js's "require" calls when generating an UMD parser. Part of work on #362. --- README.md | 3 +++ bin/pegjs | 31 +++++++++++++++++++++++------- lib/compiler.js | 1 + lib/compiler/passes/generate-js.js | 30 +++++++++++++++++++++-------- spec/api/pegjs-api.spec.js | 6 +++--- 5 files changed, 53 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index eaf625e..676cac9 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,9 @@ object to `PEG.buildParser`. The following options are supported: `false`) * `allowedStartRules` — rules the parser will be allowed to start parsing from (default: the first rule in the grammar) + * `dependencies` — parser dependencies, the value is an object which maps + variables used to access the dependencies in the parser to module IDs used + to load them; valid only when `format` is set to `"umd"` (default: `{}`) * `exportVar` — name of a global variable into which the parser object is assigned to when no module loader is detected; valid only when `format` is set to `"umd"` (default: `null`) diff --git a/bin/pegjs b/bin/pegjs index 3ecdc74..05a2b46 100755 --- a/bin/pegjs +++ b/bin/pegjs @@ -28,6 +28,8 @@ function printHelp() { console.log(" -e, --export-var name of a global variable into which the"); console.log(" parser object is assigned to when no module"); console.log(" loader is detected (default: \"\")"); + console.log(" -d, --dependency use specified dependency (can be specified"); + console.log(" multiple times)"); console.log(" --cache make generated parser cache results"); console.log(" --allowed-start-rules comma-separated list of rules the generated"); console.log(" parser will be allowed to start parsing"); @@ -111,13 +113,14 @@ function readStream(inputStream, callback) { /* Main */ var options = { - cache: false, - output: "source", - format: "umd", - exportVar: null, - optimize: "speed", - trace: false, - plugins: [] + cache: false, + output: "source", + format: "umd", + exportVar: null, + dependencies: {}, + optimize: "speed", + trace: false, + plugins: [] }; while (args.length > 0 && isOption(args[0])) { @@ -131,6 +134,20 @@ while (args.length > 0 && isOption(args[0])) { options.exportVar = args[0]; break; + case "-d": + case "--dependency": + nextArg(); + if (args.length === 0) { + abort("Missing parameter of the -d/--dependency option."); + } + if (args[0].indexOf(":") !== -1) { + var parts = args[0].split(":"); + options.dependencies[parts[0]] = parts[1]; + } else { + options.dependencies[args[0]] = args[0]; + } + break; + case "--cache": options.cache = true; break; diff --git a/lib/compiler.js b/lib/compiler.js index d5a3225..068fb01 100644 --- a/lib/compiler.js +++ b/lib/compiler.js @@ -51,6 +51,7 @@ var compiler = { optimize: "speed", output: "parser", format: "bare", + dependencies: {}, exportVar: null }); diff --git a/lib/compiler/passes/generate-js.js b/lib/compiler/passes/generate-js.js index 0d97cbe..dc636cc 100644 --- a/lib/compiler/passes/generate-js.js +++ b/lib/compiler/passes/generate-js.js @@ -1,9 +1,10 @@ "use strict"; -var arrays = require("../../utils/arrays"), - asts = require("../asts"), - op = require("../opcodes"), - js = require("../js"); +var arrays = require("../../utils/arrays"), + objects = require("../../utils/objects"), + asts = require("../asts"), + op = require("../opcodes"), + js = require("../js"); /* Generates parser JavaScript code. */ function generateJS(ast, options) { @@ -1184,14 +1185,27 @@ function generateJS(ast, options) { }, umd: function() { - var parts = []; + var parts = [], + dependencyIds = objects.values(options.dependencies), + dependencyVars = objects.keys(options.dependencies), + dependencies = '[' + + arrays.map( + dependencyIds, + function(id) { return '"' + js.stringEscape(id) + '"'; } + ).join(', ') + + ']', + requires = arrays.map( + dependencyIds, + function(id) { return 'require("' + js.stringEscape(id) + '")'; } + ).join(', '), + params = dependencyVars.join(', '); parts.push([ '(function(root, factory) {', ' if (typeof define === "function" && define.amd) {', - ' define([], factory);', + ' define(' + dependencies + ', factory);', ' } else if (typeof module === "object" && module.exports) {', - ' module.exports = factory();' + ' module.exports = factory(' + requires + ');' ].join('\n')); if (options.exportVar !== null) { @@ -1203,7 +1217,7 @@ function generateJS(ast, options) { parts.push([ ' }', - '})(this, function() {' + '})(this, function(' + params + ') {' ].join('\n')); parts.push(indent2(generateIntro())); diff --git a/spec/api/pegjs-api.spec.js b/spec/api/pegjs-api.spec.js index 8a0d11a..07b7b02 100644 --- a/spec/api/pegjs-api.spec.js +++ b/spec/api/pegjs-api.spec.js @@ -200,9 +200,9 @@ describe("PEG.js API", function() { }); /* - * The |format| and |exportVars| options are not tested becasue there is no - * meaningful way to thest their effects without turning this into an - * integration test. + * The |format|, |exportVars|, and |dependencies| options are not tested + * becasue there is no meaningful way to thest their effects without turning + * this into an integration test. */ /* The |plugins| option is tested in plugin API specs. */