From 39084496ca9c9c6ff5aef4f7e2a79cb923a251fd Mon Sep 17 00:00:00 2001 From: David Majda Date: Sat, 19 Apr 2014 18:14:12 +0200 Subject: [PATCH] Expose the parser object in action/predicate code The action/predicate code didn't have access to the parser object. This was mostly a side effect actions/predicates being implemented as nested functions, in which |this| is a reference to the global object (an ugly JavaScript quirk). The initializer, being implemented differently, had access to the parser object via |this|, but this was not documented. Because having access to the parser object can be useful, this commits introduces a new |parser| variable which holds a reference to it, is visible in action/predicate/initializer code, and is properly documented. See also: https://groups.google.com/forum/#!topic/pegjs/Na7YWnz6Bmg --- README.md | 19 ++++++------ lib/compiler/passes/generate-javascript.js | 1 + lib/parser.js | 1 + spec/generated-parser.spec.js | 36 ++++++++++++++++++++++ 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index faee1b1..61f3aa1 100644 --- a/README.md +++ b/README.md @@ -186,9 +186,10 @@ Rules can be preceded by an *initializer* — a piece of JavaScript code in curl braces (“{” and “}”). This code is executed before the generated parser starts parsing. All variables and functions defined in the initializer are accessible in rule actions and semantic predicates. The code inside the initializer can -access options passed to the parser using the `options` variable. Curly braces -in the initializer code must be balanced. Let's look at the example grammar -from above using a simple initializer. +access the parser object using the `parser` variable and options passed to the +parser using the `options` variable. Curly braces in the initializer code must +be balanced. Let's look at the example grammar from above using a simple +initializer. { function makeInteger(o) { @@ -321,8 +322,8 @@ the `offset` function. It returns a zero-based character index into the input string. The code can also access the current line and column using the `line` and `column` functions. Both return one-based indexes. -The code inside the predicate can also access options passed to the parser using -the `options` variable. +The code inside the predicate can also access the parser object using the +`parser` variable and options passed to the parser using the `options` variable. Note that curly braces in the predicate code must be balanced. @@ -343,8 +344,8 @@ the `offset` function. It returns a zero-based character index into the input string. The code can also access the current line and column using the `line` and `column` functions. Both return one-based indexes. -The code inside the predicate can also access options passed to the parser using -the `options` variable. +The code inside the predicate can also access the parser object using the +`parser` variable and options passed to the parser using the `options` variable. Note that curly braces in the predicate code must be balanced. @@ -398,8 +399,8 @@ character index into the input string. The code can also access the line and column at the beginning of the action's expression using the `line` and `column` functions. Both return one-based indexes. -The code inside the action can also access options passed to the parser using -the `options` variable. +The code inside the action can also access the parser object using the `parser` +variable and options passed to the parser using the `options` variable. Note that curly braces in the action code must be balanced. diff --git a/lib/compiler/passes/generate-javascript.js b/lib/compiler/passes/generate-javascript.js index 16087e6..3e68abc 100644 --- a/lib/compiler/passes/generate-javascript.js +++ b/lib/compiler/passes/generate-javascript.js @@ -692,6 +692,7 @@ module.exports = function(ast, options) { '', ' function peg$parse(input) {', ' var options = arguments.length > 1 ? arguments[1] : {},', + ' parser = this,', '', ' peg$FAILED = {},', '' diff --git a/lib/parser.js b/lib/parser.js index d7d8b88..de84adf 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -26,6 +26,7 @@ module.exports = (function() { function peg$parse(input) { var options = arguments.length > 1 ? arguments[1] : {}, + parser = this, peg$FAILED = {}, diff --git a/spec/generated-parser.spec.js b/spec/generated-parser.spec.js index daa7f35..4ec57f8 100644 --- a/spec/generated-parser.spec.js +++ b/spec/generated-parser.spec.js @@ -211,6 +211,15 @@ describe("generated parser", function() { expect(parser).toParse("a", [1, 1]); }); + it("can use the |parser| variable to access the parser object", function() { + var parser = PEG.buildParser([ + '{ var result = parser; }', + 'start = "a" { return result; }' + ].join("\n"), options); + + expect(parser).toParse("a", parser); + }); + it("can use options passed to the parser", function() { var parser = PEG.buildParser([ '{ var result = options; }', @@ -382,6 +391,15 @@ describe("generated parser", function() { expect(parser).toParse("a", 42); }); + it("can use the |parser| variable to access the parser object", function() { + var parser = PEG.buildParser( + 'start = "a" { return parser; }', + options + ); + + expect(parser).toParse("a", parser); + }); + it("can use options passed to the parser", function() { var parser = PEG.buildParser( 'start = "a" { return options; }', @@ -546,6 +564,15 @@ describe("generated parser", function() { expect(parser).toParse("a", ["a", undefined]); }); + it("can use the |parser| variable to access the parser object", function() { + var parser = PEG.buildParser([ + '{ var result; }', + 'start = "a" &{ result = parser; return true; } { return result; }' + ].join("\n"), options); + + expect(parser).toParse("a", parser); + }); + it("can use options passed to the parser", function() { var parser = PEG.buildParser([ '{ var result; }', @@ -637,6 +664,15 @@ describe("generated parser", function() { expect(parser).toParse("a", ["a", undefined]); }); + it("can use the |parser| variable to access the parser object", function() { + var parser = PEG.buildParser([ + '{ var result; }', + 'start = "a" !{ result = parser; return false; } { return result; }' + ].join("\n"), options); + + expect(parser).toParse("a", parser); + }); + it("can use options passed to the parser", function() { var parser = PEG.buildParser([ '{ var result; }',