122 lines
3.9 KiB
JavaScript
Executable File
122 lines
3.9 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
try {
|
|
var rr = require('railroad-diagrams');
|
|
} catch(e) {
|
|
// optional dependency not fullfilled
|
|
console.log('Error: When you installed nearley, the dependency "railroad-diagrams" failed to install. Try running "npm install -g nearley" to re-install nearley. If that doesn\'t fix the problem, please file an issue on the nearley GitHub repository.')
|
|
process.exit(1)
|
|
}
|
|
|
|
var fs = require('fs');
|
|
var path = require('path');
|
|
var opts = require('commander');
|
|
|
|
var version = require('../package.json').version;
|
|
opts.version(version, '-v, --version')
|
|
.arguments('<file.ne>')
|
|
.option('-o, --out [filename.svg]', 'File to output to (default stdout).', false)
|
|
.parse(process.argv);
|
|
|
|
var input = opts.args[0] ? fs.createReadStream(opts.args[0]) : process.stdin;
|
|
var output = opts.out ? fs.createWriteStream(opts.out) : process.stdout;
|
|
|
|
function railroad(grm) {
|
|
var rules = {};
|
|
grm.forEach(function(instr) {
|
|
if (instr.rules) {
|
|
if (!rules[instr.name]) {
|
|
rules[instr.name] = [];
|
|
}
|
|
rules[instr.name] = rules[instr.name].concat(instr.rules);
|
|
}
|
|
});
|
|
|
|
var style = fs.readFileSync(
|
|
path.join(
|
|
path.dirname(require.resolve('railroad-diagrams')),
|
|
'railroad-diagrams.css'
|
|
)
|
|
);
|
|
|
|
var diagrams = Object.keys(rules).map(function(r) {
|
|
return [
|
|
'<h1><code>' + r + '</code></h1>',
|
|
'<div>',
|
|
diagram(r).toString(),
|
|
'</div>'
|
|
].join('\n');
|
|
});
|
|
|
|
function diagram(name) {
|
|
var selectedrules = rules[name];
|
|
var outer = {subexpression: selectedrules};
|
|
|
|
function renderTok(tok) {
|
|
// ctx translated to correct position already
|
|
if (tok.subexpression) {
|
|
return new rr.Choice(0, tok.subexpression.map(renderTok));
|
|
} else if (tok.ebnf) {
|
|
switch (tok.modifier) {
|
|
case ":+":
|
|
return new rr.OneOrMore(renderTok(tok.ebnf));
|
|
break;
|
|
case ":*":
|
|
return new rr.ZeroOrMore(renderTok(tok.ebnf));
|
|
break;
|
|
case ":?":
|
|
return new rr.Optional(renderTok(tok.ebnf));
|
|
break;
|
|
}
|
|
} else if (tok.literal) {
|
|
return new rr.Terminal(JSON.stringify(tok.literal));
|
|
} else if (tok.mixin) {
|
|
return new rr.Comment("Pas implementé.");
|
|
} else if (tok.macrocall) {
|
|
return new rr.Comment("Pas implementé.");
|
|
} else if (tok.tokens) {
|
|
return new rr.Sequence(tok.tokens.map(renderTok));
|
|
} else if (typeof(tok) === 'string') {
|
|
return new rr.NonTerminal(tok);
|
|
} else if (tok.constructor === RegExp) {
|
|
return new rr.Terminal(tok.toString());
|
|
} else if (tok.token) {
|
|
return new rr.Terminal(tok.token);
|
|
} else {
|
|
return new rr.Comment("[Unimplemented]");
|
|
}
|
|
}
|
|
|
|
return new rr.Diagram([renderTok(outer)]);
|
|
}
|
|
|
|
return [
|
|
'<!DOCTYPE html>',
|
|
'<html>',
|
|
'<head>',
|
|
'<meta charset="UTF-8">',
|
|
'<style type="text/css">',
|
|
style.toString(),
|
|
'</style>',
|
|
'</head>',
|
|
'<body>',
|
|
diagrams.join('\n'),
|
|
'</body>',
|
|
'</html>'
|
|
].join('\n');
|
|
}
|
|
|
|
var nearley = require('../lib/nearley.js');
|
|
var StreamWrapper = require('../lib/stream.js');
|
|
var parserGrammar = nearley.Grammar.fromCompiled(require('../lib/nearley-language-bootstrapped.js'));
|
|
var parser = new nearley.Parser(parserGrammar);
|
|
input
|
|
.pipe(new StreamWrapper(parser))
|
|
.on('finish', function() {
|
|
if (parser.results[0]) {
|
|
output.write(railroad(parser.results[0]));
|
|
} else {
|
|
process.stderr.write('SyntaxError: unexpected EOF\n');
|
|
}
|
|
});
|