From e9d038547d42796ca857fcaa4bfb7466b0d35718 Mon Sep 17 00:00:00 2001 From: David Majda Date: Mon, 26 Jan 2015 09:37:20 +0100 Subject: [PATCH] Behavior specs cleanup: Improve semantic predicate specs Note that use of |text| inside semantic predicate code is no longer tested and officially supported. --- .../generated-parser-behavior.spec.js | 284 +++++++++--------- 1 file changed, 134 insertions(+), 150 deletions(-) diff --git a/spec/behavior/generated-parser-behavior.spec.js b/spec/behavior/generated-parser-behavior.spec.js index 6d072fe..fc7a13c 100644 --- a/spec/behavior/generated-parser-behavior.spec.js +++ b/spec/behavior/generated-parser-behavior.spec.js @@ -415,202 +415,186 @@ describe("generated parser behavior", function() { }); describe("positive semantic predicate", function() { - it("causes successful match by returning |true|", function() { - var parser = PEG.buildParser('start = &{ return true; }', options); - - expect(parser).toParse("", undefined); - }); - - it("causes match failure by returning |false|", function() { - var parser = PEG.buildParser('start = &{ return false; }', options); - - expect(parser).toFailToParse(""); - }); - - it("can use label variables", function() { - var parser = PEG.buildParser( - 'start = a:"a" &{ return a === "a"; }', - options - ); + describe("when the code returns a truthy value", function() { + it("returns |undefined|", function() { + var parser = PEG.buildParser('start = &{ return true; }', options); - expect(parser).toParse("a", ["a", undefined]); + expect(parser).toParse("", undefined); + }); }); - it("can use the |text| function", function() { - var parser = PEG.buildParser( - 'start = "a" &{ return text() === ""; }', - options - ); + describe("when the code returns a falsey value", function() { + it("reports match failure", function() { + var parser = PEG.buildParser('start = &{ return false; }', options); - expect(parser).toParse("a", ["a", undefined]); + expect(parser).toFailToParse(""); + }); }); - it("can use the |offset| function to get the current parse position", function() { - var parser = PEG.buildParser( - 'start = "a" &{ return offset() === 1; }', - options - ); + describe("label variables", function() { + it("can access label variables from preceding labeled elements in a sequence", function() { + var parser = PEG.buildParser( + 'start = a:"a" b:"b" c:"c" &{ return a === "a" && b === "b" && c === "c"; }', + options + ); - expect(parser).toParse("a", ["a", undefined]); + expect(parser).toParse("abc"); + }); }); - it("can use the |line| and |column| functions to get the current line and column", function() { - var parser = PEG.buildParser([ - '{ var result; }', - 'start = line (nl+ line)* { return result; }', - 'line = thing (" "+ thing)*', - 'thing = digit / mark', - 'digit = [0-9]', - 'mark = &{ result = [line(), column()]; return true; } "x"', - 'nl = ("\\r" / "\\n" / "\\u2028" / "\\u2029")' - ].join("\n"), options); + describe("initializer variables & functions", function() { + it("can access variables defined in the initializer", function() { + var parser = PEG.buildParser([ + '{ var v = 42 }', + 'start = &{ return v === 42; }' + ].join("\n"), options); - expect(parser).toParse("1\n2\n\n3\n\n\n4 5 x", [7, 5]); + expect(parser).toParse(""); + }); - /* Non-Unix newlines */ - expect(parser).toParse("1\rx", [2, 1]); // Old Mac - expect(parser).toParse("1\r\nx", [2, 1]); // Windows - expect(parser).toParse("1\n\rx", [3, 1]); // mismatched + it("can access functions defined in the initializer", function() { + var parser = PEG.buildParser([ + '{ function f() { return 42; } }', + 'start = &{ return f() === 42; }' + ].join("\n"), options); - /* Strange newlines */ - expect(parser).toParse("1\u2028x", [2, 1]); // line separator - expect(parser).toParse("1\u2029x", [2, 1]); // paragraph separator + expect(parser).toParse(""); + }); }); - it("can use variables defined in the initializer", function() { - var parser = PEG.buildParser([ - '{ var v = 42 }', - 'start = "a" &{ return v === 42; }' - ].join("\n"), options); + describe("available variables & functions", function() { + it("|parser| contains the parser object", function() { + var parser = PEG.buildParser([ + '{ var result; }', + 'start = &{ result = parser; return true; } { return result; }' + ].join("\n"), options); - expect(parser).toParse("a", ["a", undefined]); - }); + expect(parser).toParse("", parser); + }); - it("can use functions defined in the initializer", function() { - var parser = PEG.buildParser([ - '{ function f() { return 42; } }', - 'start = "a" &{ return f() === 42; }' - ].join("\n"), options); + it("|options| contains options", function() { + var parser = PEG.buildParser([ + '{ var result; }', + 'start = &{ result = options; return true; } { return result; }' + ].join("\n"), options); - expect(parser).toParse("a", ["a", undefined]); - }); + expect(parser).toParse("", { a: 42 }, { a: 42 }); + }); - 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); + it("|offset|, |line|, and |column| return current parse position, line, and column", function() { + var parser = PEG.buildParser([ + '{ var result; }', + 'start = line (nl+ line)* { return result; }', + 'line = thing (" "+ thing)*', + 'thing = digit / mark', + 'digit = [0-9]', + 'mark = &{ result = [offset(), line(), column()]; return true; } "x"', + 'nl = [\\r"\\n\\u2028\\u2029]' + ].join("\n"), options); - expect(parser).toParse("a", parser); - }); + expect(parser).toParse("1\n2\n\n3\n\n\n4 5 x", [13, 7, 5]); - it("can use options passed to the parser", function() { - var parser = PEG.buildParser([ - '{ var result; }', - 'start = "a" &{ result = options; return true; } { return result; }' - ].join("\n"), options); + /* Non-Unix newlines */ + expect(parser).toParse("1\rx", [2, 2, 1]); // Old Mac + expect(parser).toParse("1\r\nx", [3, 2, 1]); // Windows + expect(parser).toParse("1\n\rx", [3, 3, 1]); // mismatched - expect(parser).toParse("a", { a: 42 }, { a: 42 }); + /* Strange newlines */ + expect(parser).toParse("1\u2028x", [2, 2, 1]); // line separator + expect(parser).toParse("1\u2029x", [2, 2, 1]); // paragraph separator + }); }); }); describe("negative semantic predicate", function() { - it("causes successful match by returning |false|", function() { - var parser = PEG.buildParser('start = !{ return false; }', options); - - expect(parser).toParse("", undefined); - }); - - it("causes match failure by returning |true|", function() { - var parser = PEG.buildParser('start = !{ return true; }', options); - - expect(parser).toFailToParse(); - }); - - it("can use label variables", function() { - var parser = PEG.buildParser( - 'start = a:"a" !{ return a !== "a"; }', - options - ); + describe("when the code returns a falsey value", function() { + it("returns |undefined|", function() { + var parser = PEG.buildParser('start = !{ return false; }', options); - expect(parser).toParse("a", ["a", undefined]); + expect(parser).toParse("", undefined); + }); }); - it("can use the |text| function", function() { - var parser = PEG.buildParser( - 'start = "a" !{ return text() !== ""; }', - options - ); + describe("when the code returns a truthy value", function() { + it("reports match failure", function() { + var parser = PEG.buildParser('start = !{ return true; }', options); - expect(parser).toParse("a", ["a", undefined]); + expect(parser).toFailToParse(""); + }); }); - it("can use the |offset| function to get the current parse position", function() { - var parser = PEG.buildParser( - 'start = "a" !{ return offset() !== 1; }', - options - ); + describe("label variables", function() { + it("can access label variables from preceding labeled elements in a sequence", function() { + var parser = PEG.buildParser( + 'start = a:"a" b:"b" c:"c" !{ return a !== "a" || b !== "b" || c !== "c"; }', + options + ); - expect(parser).toParse("a", ["a", undefined]); + expect(parser).toParse("abc"); + }); }); - it("can use the |line| and |column| functions to get the current line and column", function() { - var parser = PEG.buildParser([ - '{ var result; }', - 'start = line (nl+ line)* { return result; }', - 'line = thing (" "+ thing)*', - 'thing = digit / mark', - 'digit = [0-9]', - 'mark = !{ result = [line(), column()]; return false; } "x"', - 'nl = ("\\r" / "\\n" / "\\u2028" / "\\u2029")' - ].join("\n"), options); + describe("initializer variables & functions", function() { + it("can access variables defined in the initializer", function() { + var parser = PEG.buildParser([ + '{ var v = 42 }', + 'start = !{ return v !== 42; }' + ].join("\n"), options); - expect(parser).toParse("1\n2\n\n3\n\n\n4 5 x", [7, 5]); + expect(parser).toParse(""); + }); - /* Non-Unix newlines */ - expect(parser).toParse("1\rx", [2, 1]); // Old Mac - expect(parser).toParse("1\r\nx", [2, 1]); // Windows - expect(parser).toParse("1\n\rx", [3, 1]); // mismatched + it("can access functions defined in the initializer", function() { + var parser = PEG.buildParser([ + '{ function f() { return 42; } }', + 'start = !{ return f() !== 42; }' + ].join("\n"), options); - /* Strange newlines */ - expect(parser).toParse("1\u2028x", [2, 1]); // line separator - expect(parser).toParse("1\u2029x", [2, 1]); // paragraph separator + expect(parser).toParse(""); + }); }); - it("can use variables defined in the initializer", function() { - var parser = PEG.buildParser([ - '{ var v = 42 }', - 'start = "a" !{ return v !== 42; }' - ].join("\n"), options); + describe("available variables & functions", function() { + it("|parser| contains the parser object", function() { + var parser = PEG.buildParser([ + '{ var result; }', + 'start = !{ result = parser; return false; } { return result; }' + ].join("\n"), options); - expect(parser).toParse("a", ["a", undefined]); - }); + expect(parser).toParse("", parser); + }); - it("can use functions defined in the initializer", function() { - var parser = PEG.buildParser([ - '{ function f() { return 42; } }', - 'start = "a" !{ return f() !== 42; }' - ].join("\n"), options); + it("|options| contains options", function() { + var parser = PEG.buildParser([ + '{ var result; }', + 'start = !{ result = options; return false; } { return result; }' + ].join("\n"), options); - expect(parser).toParse("a", ["a", undefined]); - }); + expect(parser).toParse("", { a: 42 }, { a: 42 }); + }); - 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); + it("|offset|, |line|, and |column| return current parse position, line, and column", function() { + var parser = PEG.buildParser([ + '{ var result; }', + 'start = line (nl+ line)* { return result; }', + 'line = thing (" "+ thing)*', + 'thing = digit / mark', + 'digit = [0-9]', + 'mark = !{ result = [offset(), line(), column()]; return false; } "x"', + 'nl = [\\r"\\n\\u2028\\u2029]' + ].join("\n"), options); - expect(parser).toParse("a", parser); - }); + expect(parser).toParse("1\n2\n\n3\n\n\n4 5 x", [13, 7, 5]); - it("can use options passed to the parser", function() { - var parser = PEG.buildParser([ - '{ var result; }', - 'start = "a" !{ result = options; return false; } { return result; }' - ].join("\n"), options); + /* Non-Unix newlines */ + expect(parser).toParse("1\rx", [2, 2, 1]); // Old Mac + expect(parser).toParse("1\r\nx", [3, 2, 1]); // Windows + expect(parser).toParse("1\n\rx", [3, 3, 1]); // mismatched - expect(parser).toParse("a", { a: 42 }, { a: 42 }); + /* Strange newlines */ + expect(parser).toParse("1\u2028x", [2, 2, 1]); // line separator + expect(parser).toParse("1\u2029x", [2, 2, 1]); // paragraph separator + }); }); });