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