From 58806a3d778c784399c9fe831b92a99f9fe267c0 Mon Sep 17 00:00:00 2001 From: David Majda Date: Sun, 6 Mar 2016 17:20:19 +0100 Subject: [PATCH] Label scope specs: Add negative specs (subexpressions) Semantic predicate and action specs which verified label scope didn't exercise labels in subexpressions. This commit adds cases exercising them, including few commented-out cases which reveal #396 (these will be uncommented when the bug gets fixed). Note that added specs exercise all relevant expression types. This is needed because code that makes subexpression labels invisible to the outside is separate for each expression type so one generic test wouldn't generate enough coverage. Part of a fix of #396. --- .../generated-parser-behavior.spec.js | 177 ++++++++++++++++++ 1 file changed, 177 insertions(+) diff --git a/spec/behavior/generated-parser-behavior.spec.js b/spec/behavior/generated-parser-behavior.spec.js index ed40b02..bb73189 100644 --- a/spec/behavior/generated-parser-behavior.spec.js +++ b/spec/behavior/generated-parser-behavior.spec.js @@ -463,6 +463,65 @@ describe("generated parser behavior", function() { expect(parser).toFailToParse("a"); }); + + it("cannot access variables defined by subexpressions", function() { + var testcases = [ + // TODO: Fix #396. + // + // { + // grammar: 'start = (a:"a") &{ return a === "a"; }', + // input: "a" + // }, + { + grammar: 'start = (a:"a")? &{ return a === "a"; }', + input: "a" + }, + { + grammar: 'start = (a:"a")* &{ return a === "a"; }', + input: "a" + }, + { + grammar: 'start = (a:"a")+ &{ return a === "a"; }', + input: "a" + }, + { + grammar: 'start = $(a:"a") &{ return a === "a"; }', + input: "a" + }, + { + grammar: 'start = &(a:"a") "a" &{ return a === "a"; }', + input: "a" + }, + { + grammar: 'start = !(a:"a") "b" &{ return a === "a"; }', + input: "b" + }, + { + grammar: 'start = b:(a:"a") &{ return a === "a"; }', + input: "a" + }, + // TODO: Fix #396. + // + // { + // grammar: 'start = ("a" b:"b" "c") &{ return b === "b"; }', + // input: "abc" + // }, + { + grammar: 'start = (a:"a" { return a; }) &{ return a === "a"; }', + input: "a" + }, + { + grammar: 'start = ("a" / b:"b" / "c") &{ return b === "b"; }', + input: "b" + } + ], + parser, i; + + for (i = 0; i < testcases.length; i++) { + parser = PEG.buildParser(testcases[i].grammar, options); + expect(parser).toFailToParse(testcases[i].input); + } + }); }); describe("in outer sequence", function() { @@ -608,6 +667,65 @@ describe("generated parser behavior", function() { expect(parser).toFailToParse("a"); }); + + it("cannot access variables defined by subexpressions", function() { + var testcases = [ + // TODO: Fix #396. + // + // { + // grammar: 'start = (a:"a") !{ return a !== "a"; }', + // input: "a" + // }, + { + grammar: 'start = (a:"a")? !{ return a !== "a"; }', + input: "a" + }, + { + grammar: 'start = (a:"a")* !{ return a !== "a"; }', + input: "a" + }, + { + grammar: 'start = (a:"a")+ !{ return a !== "a"; }', + input: "a" + }, + { + grammar: 'start = $(a:"a") !{ return a !== "a"; }', + input: "a" + }, + { + grammar: 'start = &(a:"a") "a" !{ return a !== "a"; }', + input: "a" + }, + { + grammar: 'start = !(a:"a") "b" !{ return a !== "a"; }', + input: "b" + }, + { + grammar: 'start = b:(a:"a") !{ return a !== "a"; }', + input: "a" + }, + // TODO: Fix #396. + // + // { + // grammar: 'start = ("a" b:"b" "c") !{ return b !== "b"; }', + // input: "abc" + // }, + { + grammar: 'start = (a:"a" { return a; }) !{ return a !== "a"; }', + input: "a" + }, + { + grammar: 'start = ("a" / b:"b" / "c") !{ return b !== "b"; }', + input: "b" + } + ], + parser, i; + + for (i = 0; i < testcases.length; i++) { + parser = PEG.buildParser(testcases[i].grammar, options); + expect(parser).toFailToParse(testcases[i].input); + } + }); }); describe("in outer sequence", function() { @@ -931,6 +1049,65 @@ describe("generated parser behavior", function() { expect(parser).toParse("abc", ["a", "b", "c"]); }); + + it("cannot access variables defined by subexpressions", function() { + var testcases = [ + // TODO: Fix #396. + // + // { + // grammar: 'start = (a:"a") { return a; }', + // input: "a" + // }, + { + grammar: 'start = (a:"a")? { return a; }', + input: "a" + }, + { + grammar: 'start = (a:"a")* { return a; }', + input: "a" + }, + { + grammar: 'start = (a:"a")+ { return a; }', + input: "a" + }, + { + grammar: 'start = $(a:"a") { return a; }', + input: "a" + }, + { + grammar: 'start = &(a:"a") "a" { return a; }', + input: "a" + }, + { + grammar: 'start = !(a:"a") "b" { return a; }', + input: "b" + }, + { + grammar: 'start = b:(a:"a") { return a; }', + input: "a" + }, + // TODO: Fix #396. + // + // { + // grammar: 'start = ("a" b:"b" "c") { return b; }', + // input: "abc" + // }, + { + grammar: 'start = (a:"a" { return a; }) { return a; }', + input: "a" + }, + { + grammar: 'start = ("a" / b:"b" / "c") { return b; }', + input: "b" + } + ], + parser, i; + + for (i = 0; i < testcases.length; i++) { + parser = PEG.buildParser(testcases[i].grammar, options); + expect(parser).toFailToParse(testcases[i].input); + } + }); }); describe("in outer sequence", function() {