diff --git a/spec/generated-parser.spec.js b/spec/generated-parser.spec.js index 316efe8..aac6e8b 100644 --- a/spec/generated-parser.spec.js +++ b/spec/generated-parser.spec.js @@ -91,6 +91,65 @@ describe("generated parser", function() { }); }); + describe("semantic not code", function() { + varyAll(function(options) { + it("causes successful match by returning |false|", function() { + var parser = PEG.buildParser('start = !{ return false; }', options); + + expect(parser).toParse("", ""); + }); + + 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 + ); + + expect(parser).toParse("a", ["a", ""]); + }); + + it("can use the |offset| variable to get the current parse position", function() { + var parser = PEG.buildParser( + 'start = "a" !{ return offset !== 1; }', + options + ); + + expect(parser).toParse("a", ["a", ""]); + }); + + if (options.trackLineAndColumn) { + it("can use the |line| and |column| variables 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); + + expect(parser).toParse("1\n2\n\n3\n\n\n4 5 x", [7, 5]); + + /* 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 + + /* Strange newlines */ + expect(parser).toParse("1\u2028x", [2, 1]); // line separator + expect(parser).toParse("1\u2029x", [2, 1]); // paragraph separator + }); + } + }); + }); + describe("optional matching", function() { varyAll(function(options) { it("matches correctly", function() { diff --git a/test/compiler-test.js b/test/compiler-test.js index 0cf4c9c..f6cec8d 100644 --- a/test/compiler-test.js +++ b/test/compiler-test.js @@ -251,184 +251,6 @@ test("semantic and (with trackLineAndColumn: true)", function() { parses(digitsParser, "1\u2029x", [2, 1]); // paragraph separator }); -test("semantic not (with trackLineAndColumn: false)", function() { - var options = { trackLineAndColumn: false }; - - var acceptingParser = PEG.buildParser( - 'start = "a" !{ return false; } "b"', - options - ); - parses(acceptingParser, "ab", ["a", "", "b"]); - - var rejectingParser = PEG.buildParser( - 'start = "a" !{ return true; } "b"', - options - ); - doesNotParse(rejectingParser, "ab"); - - var singleElementUnlabeledParser = PEG.buildParser( - 'start = "a" !{ return arguments.length !== 1 || offset !== 1; }', - options - ); - parses(singleElementUnlabeledParser, "a", ["a", ""]); - - var singleElementLabeledParser = PEG.buildParser([ - 'start = a:"a" !{', - ' return arguments.length !== 2', - ' || offset !== 1', - ' || a !== "a";', - ' }' - ].join("\n"), options); - parses(singleElementLabeledParser, "a", ["a", ""]); - - var multiElementUnlabeledParser = PEG.buildParser( - 'start = "a" "b" "c" !{ return arguments.length !== 1 || offset !== 3; }', - options - ); - parses(multiElementUnlabeledParser, "abc", ["a", "b", "c", ""]); - - var multiElementLabeledParser = PEG.buildParser([ - 'start = a:"a" "b" c:"c" !{', - ' return arguments.length !== 3', - ' || offset !== 3', - ' || a !== "a"', - ' || c !== "c";', - ' }' - ].join("\n"), options); - parses(multiElementLabeledParser, "abc", ["a", "b", "c", ""]); - - var innerElementsUnlabeledParser = PEG.buildParser([ - 'start = "a"', - ' ("b" "c" "d" !{ return arguments.length !== 1 || offset !== 4; })', - ' "e"' - ].join("\n"), options); - parses(innerElementsUnlabeledParser, "abcde", ["a", ["b", "c", "d", ""], "e"]); - - var innerElementsLabeledParser = PEG.buildParser([ - 'start = "a"', - ' (', - ' b:"b" "c" d:"d" !{', - ' return arguments.length !== 3', - ' || offset !== 4', - ' || b !== "b"', - ' || d !== "d";', - ' }', - ' )', - ' "e"' - ].join("\n"), options); - parses(innerElementsLabeledParser, "abcde", ["a", ["b", "c", "d", ""], "e"]); -}); - -test("semantic not (with trackLineAndColumn: true)", function() { - var options = { trackLineAndColumn: true }; - - var acceptingParser = PEG.buildParser( - 'start = "a" !{ return false; } "b"', - options - ); - parses(acceptingParser, "ab", ["a", "", "b"]); - - var rejectingParser = PEG.buildParser( - 'start = "a" !{ return true; } "b"', - options - ); - doesNotParse(rejectingParser, "ab"); - - var singleElementUnlabeledParser = PEG.buildParser([ - 'start = "a" !{', - ' return arguments.length !== 3', - ' || offset !== 1', - ' || line !== 1', - ' || column !== 2;', - ' }' - ].join("\n"), options); - parses(singleElementUnlabeledParser, "a", ["a", ""]); - - var singleElementLabeledParser = PEG.buildParser([ - 'start = a:"a" !{', - ' return arguments.length !== 4', - ' || offset !== 1', - ' || line !== 1', - ' || column !== 2', - ' || a !== "a";', - ' }' - ].join("\n"), options); - parses(singleElementLabeledParser, "a", ["a", ""]); - - var multiElementUnlabeledParser = PEG.buildParser([ - 'start = "a" "b" "c" !{', - ' return arguments.length !== 3', - ' || offset !== 3', - ' || line !== 1', - ' || column !== 4;', - ' }' - ].join("\n"), options); - parses(multiElementUnlabeledParser, "abc", ["a", "b", "c", ""]); - - var multiElementLabeledParser = PEG.buildParser([ - 'start = a:"a" "b" c:"c" !{', - ' return arguments.length !== 5', - ' || offset !== 3', - ' || line !== 1', - ' || column !== 4', - ' || a !== "a"', - ' || c !== "c";', - ' }' - ].join("\n"), options); - parses(multiElementLabeledParser, "abc", ["a", "b", "c", ""]); - - var innerElementsUnlabeledParser = PEG.buildParser([ - 'start = "a"', - ' (', - ' "b" "c" "d" !{', - ' return arguments.length !== 3', - ' || offset !== 4', - ' || line !== 1', - ' || column !== 5;', - ' }', - ' )', - ' "e"' - ].join("\n"), options); - parses(innerElementsUnlabeledParser, "abcde", ["a", ["b", "c", "d", ""], "e"]); - - var innerElementsLabeledParser = PEG.buildParser([ - 'start = "a"', - ' (', - ' b:"b" "c" d:"d" !{', - ' return arguments.length !== 5', - ' || offset !== 4', - ' || line !== 1', - ' || column !== 5', - ' || b !== "b"', - ' || d !== "d";', - ' }', - ' )', - ' "e"' - ].join("\n"), options); - parses(innerElementsLabeledParser, "abcde", ["a", ["b", "c", "d", ""], "e"]); - - var digitsParser = 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); - - parses(digitsParser, "1\n2\n\n3\n\n\n4 5 x", [7, 5]); - - /* Non-Unix newlines */ - parses(digitsParser, "1\rx", [2, 1]); // Old Mac - parses(digitsParser, "1\r\nx", [2, 1]); // Windows - parses(digitsParser, "1\n\rx", [3, 1]); // mismatched - - /* Strange newlines */ - parses(digitsParser, "1\u2028x", [2, 1]); // line separator - parses(digitsParser, "1\u2029x", [2, 1]); // paragraph separator -}); - testWithVaryingTrackLineAndColumn("initializer", function(options) { var variableInActionParser = PEG.buildParser( '{ a = 42; }; start = "a" { return a; }',