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.
306 lines
7.7 KiB
JavaScript
306 lines
7.7 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
"use strict";
|
|
|
|
var fs = require("fs");
|
|
var path = require("path");
|
|
var peg = require("../lib/peg");
|
|
|
|
/* Helpers */
|
|
|
|
function printVersion() {
|
|
console.log("PEG.js " + peg.VERSION);
|
|
}
|
|
|
|
function printHelp() {
|
|
console.log("Usage: pegjs [options] [--] [<input_file>]");
|
|
console.log("");
|
|
console.log("Options:");
|
|
console.log(" --allowed-start-rules <rules> comma-separated list of rules the generated");
|
|
console.log(" parser will be allowed to start parsing");
|
|
console.log(" from (default: the first rule in the");
|
|
console.log(" grammar)");
|
|
console.log(" --cache make generated parser cache results");
|
|
console.log(" -d, --dependency <dependency> use specified dependency (can be specified");
|
|
console.log(" multiple times)");
|
|
console.log(" -e, --export-var <variable> 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(" --extra-options <options> additional options (in JSON format) to pass");
|
|
console.log(" to peg.generate");
|
|
console.log(" --extra-options-file <file> file with additional options (in JSON");
|
|
console.log(" format) to pass to peg.generate");
|
|
console.log(" -h, --help print help and exit");
|
|
console.log(" -O, --optimize <goal> select optimization for speed or size");
|
|
console.log(" (default: speed)");
|
|
console.log(" -o, --output <file> output file");
|
|
console.log(" --plugin <plugin> use a specified plugin (can be specified");
|
|
console.log(" multiple times)");
|
|
console.log(" --trace enable tracing in generated parser");
|
|
console.log(" -v, --version print version information and exit");
|
|
}
|
|
|
|
function exitSuccess() {
|
|
process.exit(0);
|
|
}
|
|
|
|
function exitFailure() {
|
|
process.exit(1);
|
|
}
|
|
|
|
function abort(message) {
|
|
console.error(message);
|
|
exitFailure();
|
|
}
|
|
|
|
function addExtraOptions(options, json) {
|
|
var extraOptions;
|
|
|
|
try {
|
|
extraOptions = JSON.parse(json);
|
|
} catch (e) {
|
|
if (!(e instanceof SyntaxError)) { throw e; }
|
|
|
|
abort("Error parsing JSON: " + e.message);
|
|
}
|
|
if (typeof extraOptions !== "object") {
|
|
abort("The JSON with extra options has to represent an object.");
|
|
}
|
|
|
|
for (var key in extraOptions) {
|
|
if (extraOptions.hasOwnProperty(key)) {
|
|
options[key] = extraOptions[key];
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Extracted into a function just to silence JSHint complaining about creating
|
|
* functions in a loop.
|
|
*/
|
|
function trim(s) {
|
|
return s.trim();
|
|
}
|
|
|
|
/* Arguments */
|
|
|
|
var args = process.argv.slice(2); // Trim "node" and the script path.
|
|
|
|
function isOption(arg) {
|
|
return (/^-.+/).test(arg);
|
|
}
|
|
|
|
function nextArg() {
|
|
args.shift();
|
|
}
|
|
|
|
/* Files */
|
|
|
|
function readStream(inputStream, callback) {
|
|
var input = "";
|
|
inputStream.on("data", function(data) { input += data; });
|
|
inputStream.on("end", function() { callback(input); });
|
|
}
|
|
|
|
/* Main */
|
|
|
|
var inputFile = null;
|
|
var outputFile = null;
|
|
|
|
var options = {
|
|
cache: false,
|
|
dependencies: {},
|
|
exportVar: null,
|
|
format: "umd",
|
|
optimize: "speed",
|
|
output: "source",
|
|
plugins: [],
|
|
trace: false
|
|
};
|
|
|
|
while (args.length > 0 && isOption(args[0])) {
|
|
switch (args[0]) {
|
|
case "--allowed-start-rules":
|
|
nextArg();
|
|
if (args.length === 0) {
|
|
abort("Missing parameter of the -e/--allowed-start-rules option.");
|
|
}
|
|
options.allowedStartRules = args[0]
|
|
.split(",")
|
|
.map(trim);
|
|
break;
|
|
|
|
case "--cache":
|
|
options.cache = true;
|
|
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 "-e":
|
|
case "--export-var":
|
|
nextArg();
|
|
if (args.length === 0) {
|
|
abort("Missing parameter of the -e/--export-var option.");
|
|
}
|
|
options.exportVar = args[0];
|
|
break;
|
|
|
|
case "--extra-options":
|
|
nextArg();
|
|
if (args.length === 0) {
|
|
abort("Missing parameter of the --extra-options option.");
|
|
}
|
|
addExtraOptions(options, args[0]);
|
|
break;
|
|
|
|
case "--extra-options-file":
|
|
nextArg();
|
|
if (args.length === 0) {
|
|
abort("Missing parameter of the --extra-options-file option.");
|
|
}
|
|
try {
|
|
var json = fs.readFileSync(args[0]);
|
|
} catch(e) {
|
|
abort("Can't read from file \"" + args[0] + "\".");
|
|
}
|
|
addExtraOptions(options, json);
|
|
break;
|
|
|
|
case "-h":
|
|
case "--help":
|
|
printHelp();
|
|
exitSuccess();
|
|
break;
|
|
|
|
case "-O":
|
|
case "--optimize":
|
|
nextArg();
|
|
if (args.length === 0) {
|
|
abort("Missing parameter of the -O/--optimize option.");
|
|
}
|
|
if (args[0] !== "speed" && args[0] !== "size") {
|
|
abort("Optimization goal must be either \"speed\" or \"size\".");
|
|
}
|
|
options.optimize = args[0];
|
|
break;
|
|
|
|
case "-o":
|
|
case "--output":
|
|
nextArg();
|
|
if (args.length === 0) {
|
|
abort("Missing parameter of the -o/--output option.");
|
|
}
|
|
outputFile = args[0];
|
|
break;
|
|
|
|
case "--plugin":
|
|
nextArg();
|
|
if (args.length === 0) {
|
|
abort("Missing parameter of the --plugin option.");
|
|
}
|
|
var id = /^(\.\/|\.\.\/)/.test(args[0]) ? path.resolve(args[0]) : args[0];
|
|
var mod;
|
|
try {
|
|
mod = require(id);
|
|
} catch (e) {
|
|
if (e.code !== "MODULE_NOT_FOUND") { throw e; }
|
|
|
|
abort("Can't load module \"" + id + "\".");
|
|
}
|
|
options.plugins.push(mod);
|
|
break;
|
|
|
|
case "--trace":
|
|
options.trace = true;
|
|
break;
|
|
|
|
case "-v":
|
|
case "--version":
|
|
printVersion();
|
|
exitSuccess();
|
|
break;
|
|
|
|
case "--":
|
|
nextArg();
|
|
break;
|
|
|
|
default:
|
|
abort("Unknown option: " + args[0] + ".");
|
|
}
|
|
nextArg();
|
|
}
|
|
|
|
var inputStream;
|
|
var outputStream;
|
|
|
|
switch (args.length) {
|
|
case 0:
|
|
inputFile = "-";
|
|
break;
|
|
|
|
case 1:
|
|
inputFile = args[0];
|
|
break;
|
|
|
|
default:
|
|
abort("Too many arguments.");
|
|
}
|
|
|
|
if (outputFile === null) {
|
|
if (inputFile === "-") {
|
|
outputFile = "-";
|
|
} else {
|
|
outputFile = inputFile.substr(0, inputFile.length - path.extname(inputFile).length) + ".js";
|
|
}
|
|
}
|
|
|
|
if (inputFile === "-") {
|
|
process.stdin.resume();
|
|
inputStream = process.stdin;
|
|
inputStream.on("error", function() {
|
|
abort("Can't read from file \"" + inputFile + "\".");
|
|
});
|
|
} else {
|
|
inputStream = fs.createReadStream(inputFile);
|
|
}
|
|
|
|
if (outputFile === "-") {
|
|
outputStream = process.stdout;
|
|
} else {
|
|
outputStream = fs.createWriteStream(outputFile);
|
|
outputStream.on("error", function() {
|
|
abort("Can't write to file \"" + outputFile + "\".");
|
|
});
|
|
}
|
|
|
|
readStream(inputStream, function(input) {
|
|
var source;
|
|
|
|
try {
|
|
source = peg.generate(input, options);
|
|
} catch (e) {
|
|
if (e.location !== undefined) {
|
|
abort(e.location.start.line + ":" + e.location.start.column + ": " + e.message);
|
|
} else {
|
|
abort(e.message);
|
|
}
|
|
}
|
|
|
|
outputStream.write(source);
|
|
if (outputStream !== process.stdout) {
|
|
outputStream.end();
|
|
}
|
|
});
|