Skip to content

Commit

Permalink
Ranges (pegjs/pegjs#30): Add testcases for ranges and regenerate parser
Browse files Browse the repository at this point in the history
  • Loading branch information
Mingun committed Feb 19, 2023
1 parent 4f9a16a commit e447b5a
Show file tree
Hide file tree
Showing 10 changed files with 1,091 additions and 306 deletions.
2 changes: 1 addition & 1 deletion examples/fizzbuzz.peggy
Expand Up @@ -10,7 +10,7 @@ const NUMS = [3, 5];
let currentNumber = (options.start == null) ? 1 : options.start|0;
}

top = c:count* { return c.filter(fb => fb) }
top = c:count|..| { return c.filter(fb => fb) }

count
= end_comment "\n" { return }
Expand Down
774 changes: 469 additions & 305 deletions lib/parser.js

Large diffs are not rendered by default.

199 changes: 199 additions & 0 deletions test/behavior/generated-parser-behavior.spec.js
Expand Up @@ -499,6 +499,38 @@ describe("generated parser behavior", () => {
grammar: "start = (a:'a')+ &{ return a === 'a'; }",
input: "a",
},
{
grammar: "start = (a:'a')| .. | &{ return a === 'a'; }",
input: "a",
},
{
grammar: "start = (a:'a')|0.. | &{ return a === 'a'; }",
input: "a",
},
{
grammar: "start = (a:'a')|1.. | &{ return a === 'a'; }",
input: "a",
},
{
grammar: "start = (a:'a')|2.. | &{ return a === 'a'; }",
input: "aa",
},
{
grammar: "start = (a:'a')| ..1| &{ return a === 'a'; }",
input: "a",
},
{
grammar: "start = (a:'a')| ..3| &{ return a === 'a'; }",
input: "a",
},
{
grammar: "start = (a:'a')|2..3| &{ return a === 'a'; }",
input: "aa",
},
{
grammar: "start = (a:'a')|3| &{ return a === 'a'; }",
input: "aaa",
},
{
grammar: "start = $(a:'a') &{ return a === 'a'; }",
input: "a",
Expand Down Expand Up @@ -717,6 +749,38 @@ describe("generated parser behavior", () => {
grammar: "start = (a:'a')+ !{ return a !== 'a'; }",
input: "a",
},
{
grammar: "start = (a:'a')| .. | !{ return a !== 'a'; }",
input: "a",
},
{
grammar: "start = (a:'a')|0.. | !{ return a !== 'a'; }",
input: "a",
},
{
grammar: "start = (a:'a')|1.. | !{ return a !== 'a'; }",
input: "a",
},
{
grammar: "start = (a:'a')|2.. | !{ return a !== 'a'; }",
input: "aa",
},
{
grammar: "start = (a:'a')| ..1| !{ return a !== 'a'; }",
input: "a",
},
{
grammar: "start = (a:'a')| ..3| !{ return a !== 'a'; }",
input: "a",
},
{
grammar: "start = (a:'a')|2..3| !{ return a !== 'a'; }",
input: "aa",
},
{
grammar: "start = (a:'a')|3| !{ return a !== 'a'; }",
input: "aaa",
},
{
grammar: "start = $(a:'a') !{ return a !== 'a'; }",
input: "a",
Expand Down Expand Up @@ -913,6 +977,109 @@ describe("generated parser behavior", () => {
});
});

describe("repeated", () => {
describe("without delimiter", () => {
describe("with constant boundaries", () => {
it("| .. | matches correctly", () => {
const parser = peg.generate("start = 'a'|..|", options);

expect(parser).to.parse("", []);
expect(parser).to.parse("a", ["a"]);
expect(parser).to.parse("aa", ["a", "a"]);
expect(parser).to.parse("aaa", ["a", "a", "a"]);
});

it("|0.. | matches correctly", () => {
const parser = peg.generate("start = 'a'|0..|", options);

expect(parser).to.parse("", []);
expect(parser).to.parse("a", ["a"]);
expect(parser).to.parse("aa", ["a", "a"]);
expect(parser).to.parse("aaa", ["a", "a", "a"]);
});

it("|1.. | matches correctly", () => {
const parser = peg.generate("start = 'a'|1..|", options);

expect(parser).to.failToParse("");
expect(parser).to.parse("a", ["a"]);
expect(parser).to.parse("aa", ["a", "a"]);
expect(parser).to.parse("aaa", ["a", "a", "a"]);
});

it("|2.. | matches correctly", () => {
const parser = peg.generate("start = 'a'|2..|", options);

expect(parser).to.failToParse("");
expect(parser).to.failToParse("a");
expect(parser).to.parse("aa", ["a", "a"]);
expect(parser).to.parse("aaa", ["a", "a", "a"]);
});

it("| ..1| matches correctly", () => {
const parser = peg.generate("start = 'a'|..1|", options);

expect(parser).to.parse("", []);
expect(parser).to.parse("a", ["a"]);
expect(parser).to.failToParse("aa");
expect(parser).to.failToParse("aaa");
});

it("| ..2| matches correctly", () => {
const parser = peg.generate("start = 'a'|..2|", options);

expect(parser).to.parse("", []);
expect(parser).to.parse("a", ["a"]);
expect(parser).to.parse("aa", ["a", "a"]);
expect(parser).to.failToParse("aaa");
});

it("|2..3| matches correctly", () => {
const parser = peg.generate("start = 'a'|2..3|", options);

expect(parser).to.failToParse("");
expect(parser).to.failToParse("a");
expect(parser).to.parse("aa", ["a", "a"]);
expect(parser).to.parse("aaa", ["a", "a", "a"]);
expect(parser).to.failToParse("aaaa");
});

it("|2..2| matches correctly", () => {
const parser = peg.generate("start = 'a'|2..2|", options);

expect(parser).to.failToParse("");
expect(parser).to.failToParse("a");
expect(parser).to.parse("aa", ["a", "a"]);
expect(parser).to.failToParse("aaa");
});

it("| 2 | matches correctly", () => {
const parser = peg.generate("start = 'a'|2|", options);

expect(parser).to.failToParse("");
expect(parser).to.failToParse("a");
expect(parser).to.parse("aa", ["a", "a"]);
expect(parser).to.failToParse("aaa");
});

it("|3..2| matches correctly", () => {
const parser = peg.generate("start = 'a'|3..2|", options);

expect(parser).to.failToParse("");
expect(parser).to.failToParse("a");
expect(parser).to.failToParse("aa");
expect(parser).to.failToParse("aaa");
});

it("does not consume input on failure", () => {
const parser = peg.generate("start = 'a'|3| / 'a'|2| { return 42; }", options);

expect(parser).to.parse("aa", 42);
});
});
});
});

describe("text", () => {
describe("when the expression matches", () => {
it("returns the matched text", () => {
Expand Down Expand Up @@ -1134,6 +1301,38 @@ describe("generated parser behavior", () => {
grammar: "start = (a:'a')+ { return a; }",
input: "a",
},
{
grammar: "start = (a:'a')| .. | { return a; }",
input: "a",
},
{
grammar: "start = (a:'a')|0.. | { return a; }",
input: "a",
},
{
grammar: "start = (a:'a')|1.. | { return a; }",
input: "a",
},
{
grammar: "start = (a:'a')|2.. | { return a; }",
input: "aa",
},
{
grammar: "start = (a:'a')| ..1| { return a; }",
input: "a",
},
{
grammar: "start = (a:'a')| ..3| { return a; }",
input: "a",
},
{
grammar: "start = (a:'a')|2..3| { return a; }",
input: "aa",
},
{
grammar: "start = (a:'a')|3| { return a; }",
input: "aaa",
},
{
grammar: "start = $(a:'a') { return a; }",
input: "a",
Expand Down
12 changes: 12 additions & 0 deletions test/types/peg.test-d.ts
Expand Up @@ -347,6 +347,17 @@ describe("peg.d.ts", () => {
expectType<peggy.ast.Primary>(node.expression);
visit(node.expression);
},
repeated(node) {
add(node.type);
expectType<peggy.ast.Repeated>(node);
expectType<"repeated">(node.type);
expect(node.type).toBe("repeated");
expectType<peggy.LocationRange>(node.location);
expectType<peggy.ast.RepeatedBoundary | null>(node.min);
expectType<peggy.ast.RepeatedBoundary>(node.max);
expectType<peggy.ast.Primary>(node.expression);
visit(node.expression);
},
group(node) {
add(node.type);
expectType<peggy.ast.Group>(node);
Expand Down Expand Up @@ -420,6 +431,7 @@ describe("peg.d.ts", () => {
"named",
"one_or_more",
"optional",
"repeated",
"rule",
"rule_ref",
"semantic_and",
Expand Down

0 comments on commit e447b5a

Please sign in to comment.