Kill the |toSource| method, introduce the |output| option

Before this commit, |PEG.buildParser| always returned a parser object.
The only way to get its source code was to call the |toSource| method on
it. While this method worked for parsers produced by |PEG.buildParser|
directly, it didn't work for parsers instantiated by executing their
source code. In other words, it was unreliable.

This commit remvoes the |toSource| method on generated parsers and
introduces a new |output| option to |PEG.buildParser|. It allows callers
to specify whether they want to get back the parser object
(|options.output === "parser"|) or its source code (|options.output ===
"source"|). This is much better and more reliable API.
redux
David Majda 12 years ago
parent 3629d880d3
commit 05a6bad989

@ -94,11 +94,10 @@ a parameter:
var parser = PEG.buildParser("start = ('a' / 'b')+"); var parser = PEG.buildParser("start = ('a' / 'b')+");
The method will return generated parser object or throw an exception if the The method will return generated parser object or its source code as a string
grammar is invalid. The exception will contain `message` property with more (depending on the value of the `output` option — see below). It will throw an
details about the error. exception if the grammar is invalid. The exception will contain `message`
property with more details about the error.
To get parsers source code, call the `toSource` method on the parser.
You can tweak the generated parser by passing a second parameter with an options You can tweak the generated parser by passing a second parameter with an options
object to `PEG.buildParser`. The following options are supported: object to `PEG.buildParser`. The following options are supported:
@ -111,6 +110,9 @@ object to `PEG.buildParser`. The following options are supported:
(default: `false`) (default: `false`)
* `allowedStartRules` — rules the parser will be allowed to start parsing from * `allowedStartRules` — rules the parser will be allowed to start parsing from
(default: the first rule in the grammar) (default: the first rule in the grammar)
* `output` — if set to `"parser"`, the method will return generated parser
object; if set to `"source"`, it will return parser source code as a string
(default: `"parser"`)
Using the Parser Using the Parser
---------------- ----------------

@ -73,7 +73,8 @@ function readStream(inputStream, callback) {
var exportVar = "module.exports"; var exportVar = "module.exports";
var options = { var options = {
cache: false, cache: false,
trackLineAndColumn: false trackLineAndColumn: false,
output: "source"
}; };
while (args.length > 0 && isOption(args[0])) { while (args.length > 0 && isOption(args[0])) {
@ -158,7 +159,7 @@ switch (args.length) {
readStream(inputStream, function(input) { readStream(inputStream, function(input) {
try { try {
var parser = PEG.buildParser(input, options); var source = PEG.buildParser(input, options);
} catch (e) { } catch (e) {
if (e.line !== undefined && e.column !== undefined) { if (e.line !== undefined && e.column !== undefined) {
abort(e.line + ":" + e.column + ": " + e.message); abort(e.line + ":" + e.column + ": " + e.message);
@ -167,7 +168,7 @@ readStream(inputStream, function(input) {
} }
} }
outputStream.write(exportVar + " = " + parser.toSource() + ";\n"); outputStream.write(exportVar + " = " + source + ";\n");
if (outputStream !== process.stdout) { if (outputStream !== process.stdout) {
outputStream.end(); outputStream.end();
} }

@ -24,16 +24,16 @@ module.exports = {
compile: function(ast, options) { compile: function(ast, options) {
if (options === undefined) { options = {}; } if (options === undefined) { options = {}; }
var that = this; var that = this,
output = options.output !== undefined ? options.output : "parser";
utils.each(this.appliedPassNames, function(passName) { utils.each(this.appliedPassNames, function(passName) {
that.passes[passName](ast, options); that.passes[passName](ast, options);
}); });
var source = ast.code; switch (output) {
var result = eval(source); case "parser": return eval(ast.code);
result._source = source; case "source": return ast.code;
}
return result;
} }
}; };

@ -516,10 +516,7 @@ module.exports = function(ast, options) {
' }', ' }',
' ', ' ',
' return result;', ' return result;',
' },', ' }',
' ',
' /* Returns the parser source code. */',
' toSource: function() { return this._source; }',
' };', ' };',
' ', ' ',
' /* Thrown when a parser encounters a syntax error. */', ' /* Thrown when a parser encounters a syntax error. */',

@ -2840,10 +2840,7 @@ module.exports = (function(){
} }
return result; return result;
}, }
/* Returns the parser source code. */
toSource: function() { return this._source; }
}; };
/* Thrown when a parser encounters a syntax error. */ /* Thrown when a parser encounters a syntax error. */

@ -934,6 +934,37 @@ describe("generated parser", function() {
}); });
}); });
describe("output", function() {
var grammar = 'start = "a"';
describe("without the |output| option", function() {
it("returns a parser object", function() {
var parser = PEG.buildParser(grammar);
expect(typeof parser).toBe("object");
expect(parser).toParse("a", "a");
});
});
describe("when the |output| option is set to \"parser\"", function() {
it("returns a parser object", function() {
var parser = PEG.buildParser(grammar, { output: "parser" });
expect(typeof parser).toBe("object");
expect(parser).toParse("a", "a");
});
});
describe("when the |output| option is set to \"source\"", function() {
it("returns a parser source code", function() {
var source = PEG.buildParser(grammar, { output: "source" });
expect(typeof source).toBe("string");
expect(eval(source)).toParse("a", "a");
});
});
});
/* /*
* Following examples are from Wikipedia, see * Following examples are from Wikipedia, see
* http://en.wikipedia.org/w/index.php?title=Parsing_expression_grammar&oldid=335106938. * http://en.wikipedia.org/w/index.php?title=Parsing_expression_grammar&oldid=335106938.

Loading…
Cancel
Save