From cab652169029b5910104e80bee6b6bf69b3de5ef Mon Sep 17 00:00:00 2001 From: David Majda Date: Sun, 9 Dec 2012 20:46:58 +0100 Subject: [PATCH 1/2] Test |offset|, |line| and |column| in the initializer Add a test verifying that the |offset|, |line| and |column| functions are visible and properly initialized inside the initializer. See GH-132. --- spec/generated-parser.spec.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/spec/generated-parser.spec.js b/spec/generated-parser.spec.js index 4a038e2..9686446 100644 --- a/spec/generated-parser.spec.js +++ b/spec/generated-parser.spec.js @@ -171,6 +171,24 @@ describe("generated parser", function() { expect(parser).toParse("a", 42); }); + it("can use the |offset| function to get the current parse position", function() { + var parser = PEG.buildParser([ + '{ var result = offset(); }', + 'start = "a" { return result; }' + ].join("\n"), options); + + expect(parser).toParse("a", 0); + }); + + it("can use the |line| and |column| functions to get the current line and column", function() { + var parser = PEG.buildParser([ + '{ var result = [line(), column()]; }', + 'start = "a" { return result; }' + ].join("\n"), options); + + expect(parser).toParse("a", [1, 1]); + }); + it("can use options passed to the parser", function() { var parser = PEG.buildParser([ '{ var result = options; }', From bea6b1fde74c8aebf802f9bcc3380c65b241e1b7 Mon Sep 17 00:00:00 2001 From: David Majda Date: Mon, 10 Dec 2012 21:01:30 +0100 Subject: [PATCH 2/2] Implement the |text| function When called inside an action, the |text| function returns the text matched by action's expression. It can be also called inside an initializer or a predicate where it returns an empty string. The |text| function will be useful mainly in cases where one needs a structured representation of the input and simultaneously the raw text. Until now, the only way to get the raw text in these cases was to painfully build it from the structured representation. Fixes GH-131. --- README.md | 3 +++ lib/compiler/passes/generate-code.js | 4 ++++ spec/generated-parser.spec.js | 36 ++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/README.md b/README.md index a46b4ab..59d7ed9 100644 --- a/README.md +++ b/README.md @@ -346,6 +346,9 @@ The code inside the action can access all variables and functions defined in the initializer at the beginning of the grammar. Curly braces in the action code must be balanced. +The code inside the action can also access the string matched by the expression +using the `text` function. + The code inside the action can also access the parse position at the beginning of the action's expression using the `offset` function. It returns a zero-based character index into the input string. The code can also access the line and diff --git a/lib/compiler/passes/generate-code.js b/lib/compiler/passes/generate-code.js index 5b6ec38..a858570 100644 --- a/lib/compiler/passes/generate-code.js +++ b/lib/compiler/passes/generate-code.js @@ -404,6 +404,10 @@ module.exports = function(ast, options) { ' return cachedReportedPosDetails;', ' }', ' ', + ' function text() {', + ' return input.substring(reportedPos, pos);', + ' }', + ' ', ' function offset() {', ' return reportedPos;', ' }', diff --git a/spec/generated-parser.spec.js b/spec/generated-parser.spec.js index 9686446..7c38a47 100644 --- a/spec/generated-parser.spec.js +++ b/spec/generated-parser.spec.js @@ -171,6 +171,15 @@ describe("generated parser", function() { expect(parser).toParse("a", 42); }); + it("can use the |text| function", function() { + var parser = PEG.buildParser([ + '{ var result = text(); }', + 'start = "a" { return result; }' + ].join("\n"), options); + + expect(parser).toParse("a", ""); + }); + it("can use the |offset| function to get the current parse position", function() { var parser = PEG.buildParser([ '{ var result = offset(); }', @@ -273,6 +282,15 @@ describe("generated parser", function() { expect(parser).toParse("a", "a"); }); + it("can use the |text| function to get the text matched by the expression", function() { + var parser = PEG.buildParser( + 'start = "a" "b" "c" { return text(); }', + options + ); + + expect(parser).toParse("abc", "abc"); + }); + it("can use the |offset| function to get the current parse position", function() { var parser = PEG.buildParser( 'start = "a" ("b" { return offset(); })', @@ -443,6 +461,15 @@ describe("generated parser", function() { expect(parser).toParse("a", ["a", ""]); }); + it("can use the |text| function", function() { + var parser = PEG.buildParser( + 'start = "a" &{ return text() === ""; }', + options + ); + + expect(parser).toParse("a", ["a", ""]); + }); + it("can use the |offset| function to get the current parse position", function() { var parser = PEG.buildParser( 'start = "a" &{ return offset() === 1; }', @@ -525,6 +552,15 @@ describe("generated parser", function() { expect(parser).toParse("a", ["a", ""]); }); + it("can use the |text| function", function() { + var parser = PEG.buildParser( + 'start = "a" !{ return text() !== ""; }', + options + ); + + expect(parser).toParse("a", ["a", ""]); + }); + it("can use the |offset| function to get the current parse position", function() { var parser = PEG.buildParser( 'start = "a" !{ return offset() !== 1; }',