function Grammar(rules, start) {
this.rules = rules;
this.start = start || this.rules[0].name;
var byName = this.byName = {};
this.rules.forEach(function(rule) {
if (!byName.hasOwnProperty(rule.name)) {
byName[rule.name] = [];
}
byName[rule.name].push(rule);
});
}n/a
function Parser(rules, start, options) {
if (rules instanceof Grammar) {
var grammar = rules;
var options = start;
} else {
var grammar = Grammar.fromCompiled(rules, start);
}
this.grammar = grammar;
// Read options
this.options = {
keepHistory: false,
// rewindable: false,
};
for (var key in (options || {})) {
this.options[key] = options[key];
}
// if (this.options.rewindable) { this.options.keepHistory = true; }
// Setup a table
var column = new Column(grammar, 0);
var table = this.table = [column];
// I could be expecting anything.
column.wants[grammar.start] = [];
column.predict(grammar.start);
// TODO what if start rule is nullable?
column.process();
this.current = 0;
}...
nearley exposes the following API:
var grammar = require("generated-code.js");
var nearley = require("nearley");
// Create a Parser object from our grammar.
var p = new nearley.Parser(grammar.ParserRules, grammar.ParserStart);
// Parse something
p.feed("1+1");
// p.results --> [ ["sum", "1", "1"] ]
The `Parser` object can be fed data in parts with `.feed(data)`. You can then
find an array of parsings with the `.results` property. If `results` is empty,
...function Rule(name, symbols, postprocess) {
this.id = ++Rule.highestId;
this.name = name;
this.symbols = symbols; // a list of literal | regex class | nonterminal
this.postprocess = postprocess;
return this;
}...
var tokens = [];
for (var i = 0; i < rule.tokens.length; i++) {
var token = buildToken(ruleName, rule.tokens[i], env);
if (token !== null) {
tokens.push(token);
}
}
return new nearley.Rule(
ruleName,
tokens,
rule.postprocess
);
}
function buildToken(ruleName, token, env) {
...generate = function (parser, exportName) {
if(!parser.config.preprocessor) {
parser.config.preprocessor = "_default";
}
if(!generate[parser.config.preprocessor]) {
throw new Error("No such preprocessor: " + parser.config.preprocessor)
}
return generate[parser.config.preprocessor](parser, exportName);
}n/a
function StreamWrapper(parser) {
Writable.call(this);
this._parser = parser;
}n/a
function Grammar(rules, start) {
this.rules = rules;
this.start = start || this.rules[0].name;
var byName = this.byName = {};
this.rules.forEach(function(rule) {
if (!byName.hasOwnProperty(rule.name)) {
byName[rule.name] = [];
}
byName[rule.name].push(rule);
});
}n/a
fromCompiled = function (rules, start) {
if (rules.ParserStart) {
start = rules.ParserStart;
rules = rules.ParserRules;
}
var rules = rules.map(function (r) { return (new Rule(r.name, r.symbols, r.postprocess)); });
return new Grammar(rules, start);
}n/a
function Parser(rules, start, options) {
if (rules instanceof Grammar) {
var grammar = rules;
var options = start;
} else {
var grammar = Grammar.fromCompiled(rules, start);
}
this.grammar = grammar;
// Read options
this.options = {
keepHistory: false,
// rewindable: false,
};
for (var key in (options || {})) {
this.options[key] = options[key];
}
// if (this.options.rewindable) { this.options.keepHistory = true; }
// Setup a table
var column = new Column(grammar, 0);
var table = this.table = [column];
// I could be expecting anything.
column.wants[grammar.start] = [];
column.predict(grammar.start);
// TODO what if start rule is nullable?
column.process();
this.current = 0;
}...
nearley exposes the following API:
var grammar = require("generated-code.js");
var nearley = require("nearley");
// Create a Parser object from our grammar.
var p = new nearley.Parser(grammar.ParserRules, grammar.ParserStart);
// Parse something
p.feed("1+1");
// p.results --> [ ["sum", "1", "1"] ]
The `Parser` object can be fed data in parts with `.feed(data)`. You can then
find an array of parsings with the `.results` property. If `results` is empty,
...feed = function (chunk) {
for (var chunkPos = 0; chunkPos < chunk.length; chunkPos++) {
// We add new states to table[current+1]
var column = this.table[this.current + chunkPos];
// GC unused states
if (!this.options.keepHistory) {
delete this.table[this.current + chunkPos - 1];
}
var n = this.current + chunkPos + 1;
var nextColumn = new Column(this.grammar, n);
this.table.push(nextColumn);
// Advance all tokens that expect the symbol
// So for each state in the previous row,
var token = chunk[chunkPos];
var scannable = column.scannable;
for (var w = scannable.length; w--; ) {
var state = scannable[w];
var expect = state.rule.symbols[state.dot];
// Try to consume the token
// either regex or literal
if (expect.test ? expect.test(token) : expect.literal === token) {
// Add it
var next = state.nextState(token);
nextColumn.states.push(next);
}
}
// Next, for each of the rules, we either
// (a) complete it, and try to see if the reference row expected that
// rule
// (b) predict the next nonterminal it expects by adding that
// nonterminal's start state
// To prevent duplication, we also keep track of rules we have already
// added
nextColumn.process();
// If needed, throw an error:
if (nextColumn.states.length === 0) {
// No states at all! This is not good.
var err = new Error(
"nearley: No possible parsings (@" + (this.current + chunkPos)
+ ": '" + chunk[chunkPos] + "')."
);
err.offset = this.current + chunkPos;
throw err;
}
}
this.current += chunkPos;
// Incrementally keep track of results
this.results = this.finish();
// Allow chaining, for whatever it's worth
return this;
}...
var grammar = require("generated-code.js");
var nearley = require("nearley");
// Create a Parser object from our grammar.
var p = new nearley.Parser(grammar.ParserRules, grammar.ParserStart);
// Parse something
p.feed("1+1");
// p.results --> [ ["sum", "1", "1"] ]
The `Parser` object can be fed data in parts with `.feed(data)`. You can then
find an array of parsings with the `.results` property. If `results` is empty,
then there are no parsings. If `results` contains multiple values, then that
combination is ambiguous.
...finish = function () {
// Return the possible parsings
var considerations = [];
var start = this.grammar.start;
var column = this.table[this.table.length - 1]
column.states.forEach(function (t) {
if (t.rule.name === start
&& t.dot === t.rule.symbols.length
&& t.reference === 0
&& t.data !== Parser.fail) {
considerations.push(t);
}
});
return considerations.map(function(c) {return c.data; });
}n/a
rewind = function (index) {
if (!this.options.keepHistory) {
throw new Error('set option `keepHistory` to enable rewinding')
}
if (this.current < this.index) {
// TODO: api -- consider silently succeeding?
throw new Error('cannot rewind forward!')
}
/*
* recall column (table) indicies fall between token indicies.
*
* col 0 -- token 0 -- col 1
*/
this.table.splice(index + 1);
this.current = index;
// Incrementally keep track of results
this.results = this.finish();
}n/a
function Rule(name, symbols, postprocess) {
this.id = ++Rule.highestId;
this.name = name;
this.symbols = symbols; // a list of literal | regex class | nonterminal
this.postprocess = postprocess;
return this;
}...
var tokens = [];
for (var i = 0; i < rule.tokens.length; i++) {
var token = buildToken(ruleName, rule.tokens[i], env);
if (token !== null) {
tokens.push(token);
}
}
return new nearley.Rule(
ruleName,
tokens,
rule.postprocess
);
}
function buildToken(ruleName, token, env) {
...toString = function (withCursorAt) {
function stringifySymbolSequence (e) {
return (e.literal) ? JSON.stringify(e.literal)
: e.toString();
}
var symbolSequence = (typeof withCursorAt === "undefined")
? this.symbols.map(stringifySymbolSequence).join(' ')
: ( this.symbols.slice(0, withCursorAt).map(stringifySymbolSequence).join(' ')
+ " ● "
+ this.symbols.slice(withCursorAt).map(stringifySymbolSequence).join(' ') );
return this.name + " → " + symbolSequence;
}...
)
);
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};
...generate = function (parser, exportName) {
if(!parser.config.preprocessor) {
parser.config.preprocessor = "_default";
}
if(!generate[parser.config.preprocessor]) {
throw new Error("No such preprocessor: " + parser.config.preprocessor)
}
return generate[parser.config.preprocessor](parser, exportName);
}n/a
_default = function (parser, exportName) {
var output = "// Generated automatically by nearley\n";
output += "// http://github.com/Hardmath123/nearley\n";
output += "(function () {\n";
output += "function id(x) {return x[0]; }\n";
output += parser.body.join('\n');
output += "var grammar = {\n";
output += " ParserRules: " +
serializeRules(parser.rules, generate.javascript.builtinPostprocessors)
+ "\n";
output += " , ParserStart: " + JSON.stringify(parser.start) + "\n";
output += "}\n";
output += "if (typeof module !== 'undefined'"
+ "&& typeof module.exports !== 'undefined') {\n";
output += " module.exports = grammar;\n";
output += "} else {\n";
output += " window." + exportName + " = grammar;\n";
output += "}\n";
output += "})();\n";
return output;
}n/a
coffee = function (parser, exportName) {
var output = "# Generated automatically by nearley\n";
output += "# http://github.com/Hardmath123/nearley\n";
output += "do ->\n";
output += " id = (d)->d[0]\n";
output += tabulateString(dedentFunc(parser.body.join('\n')), ' ') + '\n';
output += " grammar = {\n";
output += " ParserRules: " +
tabulateString(
serializeRules(parser.rules, generate.coffeescript.builtinPostprocessors),
' ',
{indentFirst: false})
+ ",\n";
output += " ParserStart: " + JSON.stringify(parser.start) + "\n";
output += " }\n";
output += " if typeof module != 'undefined' "
+ "&& typeof module.exports != 'undefined'\n";
output += " module.exports = grammar;\n";
output += " else\n";
output += " window." + exportName + " = grammar;\n";
return output;
}n/a
coffeescript = function (parser, exportName) {
var output = "# Generated automatically by nearley\n";
output += "# http://github.com/Hardmath123/nearley\n";
output += "do ->\n";
output += " id = (d)->d[0]\n";
output += tabulateString(dedentFunc(parser.body.join('\n')), ' ') + '\n';
output += " grammar = {\n";
output += " ParserRules: " +
tabulateString(
serializeRules(parser.rules, generate.coffeescript.builtinPostprocessors),
' ',
{indentFirst: false})
+ ",\n";
output += " ParserStart: " + JSON.stringify(parser.start) + "\n";
output += " }\n";
output += " if typeof module != 'undefined' "
+ "&& typeof module.exports != 'undefined'\n";
output += " module.exports = grammar;\n";
output += " else\n";
output += " window." + exportName + " = grammar;\n";
return output;
}n/a
cs = function (parser, exportName) {
var output = "# Generated automatically by nearley\n";
output += "# http://github.com/Hardmath123/nearley\n";
output += "do ->\n";
output += " id = (d)->d[0]\n";
output += tabulateString(dedentFunc(parser.body.join('\n')), ' ') + '\n';
output += " grammar = {\n";
output += " ParserRules: " +
tabulateString(
serializeRules(parser.rules, generate.coffeescript.builtinPostprocessors),
' ',
{indentFirst: false})
+ ",\n";
output += " ParserStart: " + JSON.stringify(parser.start) + "\n";
output += " }\n";
output += " if typeof module != 'undefined' "
+ "&& typeof module.exports != 'undefined'\n";
output += " module.exports = grammar;\n";
output += " else\n";
output += " window." + exportName + " = grammar;\n";
return output;
}n/a
javascript = function (parser, exportName) {
var output = "// Generated automatically by nearley\n";
output += "// http://github.com/Hardmath123/nearley\n";
output += "(function () {\n";
output += "function id(x) {return x[0]; }\n";
output += parser.body.join('\n');
output += "var grammar = {\n";
output += " ParserRules: " +
serializeRules(parser.rules, generate.javascript.builtinPostprocessors)
+ "\n";
output += " , ParserStart: " + JSON.stringify(parser.start) + "\n";
output += "}\n";
output += "if (typeof module !== 'undefined'"
+ "&& typeof module.exports !== 'undefined') {\n";
output += " module.exports = grammar;\n";
output += "} else {\n";
output += " window." + exportName + " = grammar;\n";
output += "}\n";
output += "})();\n";
return output;
}n/a
js = function (parser, exportName) {
var output = "// Generated automatically by nearley\n";
output += "// http://github.com/Hardmath123/nearley\n";
output += "(function () {\n";
output += "function id(x) {return x[0]; }\n";
output += parser.body.join('\n');
output += "var grammar = {\n";
output += " ParserRules: " +
serializeRules(parser.rules, generate.javascript.builtinPostprocessors)
+ "\n";
output += " , ParserStart: " + JSON.stringify(parser.start) + "\n";
output += "}\n";
output += "if (typeof module !== 'undefined'"
+ "&& typeof module.exports !== 'undefined') {\n";
output += " module.exports = grammar;\n";
output += "} else {\n";
output += " window." + exportName + " = grammar;\n";
output += "}\n";
output += "})();\n";
return output;
}n/a
ts = function (parser, exportName) {
var output = "// Generated automatically by nearley\n";
output += "// http://github.com/Hardmath123/nearley\n";
output += "function id(d:any[]):any {return d[0];}\n";
output += parser.body.join('\n');
output += "interface NearleyGrammar {ParserRules:NearleyRule[]; ParserStart:string};\n";
output += "interface NearleyRule {name:string; symbols:NearleySymbol[]; postprocess?:(d:any[],loc?:number,reject?:{})=>any};\n";
output += "type NearleySymbol = string | {literal:any} | {test:(token:any) => boolean};\n";
output += "export var grammar : NearleyGrammar = {\n";
output += " ParserRules: " + serializeRules(parser.rules, generate.typescript.builtinPostprocessors) + "\n";
output += " , ParserStart: " + JSON.stringify(parser.start) + "\n";
output += "}\n";
return output;
}n/a
typescript = function (parser, exportName) {
var output = "// Generated automatically by nearley\n";
output += "// http://github.com/Hardmath123/nearley\n";
output += "function id(d:any[]):any {return d[0];}\n";
output += parser.body.join('\n');
output += "interface NearleyGrammar {ParserRules:NearleyRule[]; ParserStart:string};\n";
output += "interface NearleyRule {name:string; symbols:NearleySymbol[]; postprocess?:(d:any[],loc?:number,reject?:{})=>any};\n";
output += "type NearleySymbol = string | {literal:any} | {test:(token:any) => boolean};\n";
output += "export var grammar : NearleyGrammar = {\n";
output += " ParserRules: " + serializeRules(parser.rules, generate.typescript.builtinPostprocessors) + "\n";
output += " , ParserStart: " + JSON.stringify(parser.start) + "\n";
output += "}\n";
return output;
}n/a
function StreamWrapper(parser) {
Writable.call(this);
this._parser = parser;
}n/a
function Writable(options) {
// Writable ctor is applied to Duplexes, too.
// `realHasInstance` is necessary because using plain `instanceof`
// would return false, as no `_writableState` property is attached.
// Trying to use the custom `instanceof` for Writable here will also break the
// Node.js LazyTransform implementation, which has a non-trivial getter for
// `_writableState` that would lead to infinite recursion.
if (!(realHasInstance.call(Writable, this)) &&
!(this instanceof Stream.Duplex)) {
return new Writable(options);
}
this._writableState = new WritableState(options, this);
// legacy.
this.writable = true;
if (options) {
if (typeof options.write === 'function')
this._write = options.write;
if (typeof options.writev === 'function')
this._writev = options.writev;
}
Stream.call(this);
}n/a
function write(chunk, encoding, callback) {
this._parser.feed(chunk.toString());
callback();
}n/a