diff --git a/CHANGELOG.md b/CHANGELOG.md index ac4cfa10..9b4ec619 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ Released: TBD - [#280](https://github.com/peggyjs/peggy/issues/280) Add inline examples to the documentation, from @hildjj +- [#291](https://github.com/peggyjs/peggy/pull/291): Add support for repetition + operator `expression|min .. max, delimiter|`, from @Mingun ### Minor Changes diff --git a/docs/documentation.html b/docs/documentation.html index 6345af4f..daea678c 100644 --- a/docs/documentation.html +++ b/docs/documentation.html @@ -832,6 +832,63 @@

Parsing Expressio +
expression |count| +
expression |min..max| +
expression |count, delimiter| +
expression |min..max, delimiter|
+ +
+

Match exact count repetitions of expression. + If the match succeeds, return their match results in an array.

+ +

-or-

+ +

Match expression at least min but not more then max times. + If the match succeeds, return their match results in an array. Both min + and max may be omitted. If min is omitted, then it is assumed + to be 0. If max is omitted, then it is assumed to be infinity. + Hence

+ + + +

Optionally, delimiter expression can be specified. Delimiter must appear + between expressions exactly once and it is not included in the final array.

+ +

count, min and max can be represented as:

+ + + +
+
+
Example: repetition = "a"|2..3, ","|
+
Matches: "a,a", "a,a,a"
+
Does not match: "a", "b,b", + "a,a,a,", "a,a,a,a"
+
+
+ Try it: + +
+
+
+
+
expression ?
diff --git a/docs/js/examples.js b/docs/js/examples.js index 88ab373a..bef1ec65 100644 --- a/docs/js/examples.js +++ b/docs/js/examples.js @@ -170,16 +170,17 @@ function peg$parse(input, options) { var peg$FAILED = {}; var peg$source = options.grammarSource; - var peg$startRuleFunctions = { literal: peg$parseliteral, literal_i: peg$parseliteral_i, any: peg$parseany, class: peg$parseclass, class_i: peg$parseclass_i, rule: peg$parserule, child: peg$parsechild, paren: peg$parseparen, star: peg$parsestar, plus: peg$parseplus, maybe: peg$parsemaybe, posAssertion: peg$parseposAssertion, negAssertion: peg$parsenegAssertion, posPredicate: peg$parseposPredicate, negPredicate: peg$parsenegPredicate, dollar: peg$parsedollar, label: peg$parselabel, pluck_1: peg$parsepluck_1, pluck_2: peg$parsepluck_2, sequence: peg$parsesequence, action: peg$parseaction, alt: peg$parsealt, rest: peg$parserest }; + var peg$startRuleFunctions = { literal: peg$parseliteral, literal_i: peg$parseliteral_i, any: peg$parseany, class: peg$parseclass, class_i: peg$parseclass_i, rule: peg$parserule, child: peg$parsechild, paren: peg$parseparen, star: peg$parsestar, plus: peg$parseplus, repetition: peg$parserepetition, maybe: peg$parsemaybe, posAssertion: peg$parseposAssertion, negAssertion: peg$parsenegAssertion, posPredicate: peg$parseposPredicate, negPredicate: peg$parsenegPredicate, dollar: peg$parsedollar, label: peg$parselabel, pluck_1: peg$parsepluck_1, pluck_2: peg$parsepluck_2, sequence: peg$parsesequence, action: peg$parseaction, alt: peg$parsealt, rest: peg$parserest }; var peg$startRuleFunction = peg$parseliteral; var peg$c0 = "foo"; var peg$c1 = "1"; var peg$c2 = "a"; - var peg$c3 = "b"; - var peg$c4 = "bar"; - var peg$c5 = " "; - var peg$c6 = "c"; + var peg$c3 = ","; + var peg$c4 = "b"; + var peg$c5 = "bar"; + var peg$c6 = " "; + var peg$c7 = "c"; var peg$r0 = /^[a-z]/; var peg$r1 = /^[^a-z]/i; @@ -192,12 +193,13 @@ function peg$parse(input, options) { var peg$e4 = peg$classExpectation([["a", "z"]], true, true); var peg$e5 = peg$literalExpectation("1", false); var peg$e6 = peg$literalExpectation("a", false); - var peg$e7 = peg$literalExpectation("b", false); - var peg$e8 = peg$classExpectation([["0", "9"]], false, false); - var peg$e9 = peg$literalExpectation("bar", true); - var peg$e10 = peg$literalExpectation(" ", false); - var peg$e11 = peg$literalExpectation("c", false); - var peg$e12 = peg$otherExpectation("The rest of the input"); + var peg$e7 = peg$literalExpectation(",", false); + var peg$e8 = peg$literalExpectation("b", false); + var peg$e9 = peg$classExpectation([["0", "9"]], false, false); + var peg$e10 = peg$literalExpectation("bar", true); + var peg$e11 = peg$literalExpectation(" ", false); + var peg$e12 = peg$literalExpectation("c", false); + var peg$e13 = peg$otherExpectation("The rest of the input"); var peg$f0 = function(match, rest) { return {match, rest}; }; var peg$f1 = function(match, rest) { return {match, rest}; }; @@ -212,19 +214,20 @@ function peg$parse(input, options) { var peg$f10 = function(match, rest) { return {match, rest}; }; var peg$f11 = function(match, rest) { return {match, rest}; }; var peg$f12 = function(match, rest) { return {match, rest}; }; - var peg$f13 = function(match) { return parseInt(match, 10) < 100 }; - var peg$f14 = function(match, rest) { return {match, rest}; }; - var peg$f15 = function(match) { return parseInt(match, 10) < 100 }; - var peg$f16 = function(match, rest) { return {match, rest}; }; + var peg$f13 = function(match, rest) { return {match, rest}; }; + var peg$f14 = function(match) { return parseInt(match, 10) < 100 }; + var peg$f15 = function(match, rest) { return {match, rest}; }; + var peg$f16 = function(match) { return parseInt(match, 10) < 100 }; var peg$f17 = function(match, rest) { return {match, rest}; }; - var peg$f18 = function(foo) { return {foo}; }; - var peg$f19 = function(match, rest) { return {match, rest}; }; + var peg$f18 = function(match, rest) { return {match, rest}; }; + var peg$f19 = function(foo) { return {foo}; }; var peg$f20 = function(match, rest) { return {match, rest}; }; var peg$f21 = function(match, rest) { return {match, rest}; }; var peg$f22 = function(match, rest) { return {match, rest}; }; - var peg$f23 = function() { return location(); }; - var peg$f24 = function(match, rest) { return {match, rest}; }; + var peg$f23 = function(match, rest) { return {match, rest}; }; + var peg$f24 = function() { return location(); }; var peg$f25 = function(match, rest) { return {match, rest}; }; + var peg$f26 = function(match, rest) { return {match, rest}; }; var peg$currPos = 0; var peg$savedPos = 0; var peg$posDetailsCache = [{ line: 1, column: 1 }]; @@ -643,6 +646,69 @@ function peg$parse(input, options) { return s0; } + function peg$parserepetition() { + var s0, s1, s2, s3, s4; + + s0 = peg$currPos; + s1 = peg$currPos; + s2 = []; + if (input.charCodeAt(peg$currPos) === 97) { + s3 = peg$c2; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e6); } + } + while (s3 !== peg$FAILED) { + s2.push(s3); + if (s2.length >= 3) { + s3 = peg$FAILED; + } else { + s3 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 44) { + s4 = peg$c3; + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e7); } + } + if (s4 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 97) { + s4 = peg$c2; + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e6); } + } + if (s4 === peg$FAILED) { + peg$currPos = s3; + s3 = peg$FAILED; + } else { + s3 = s4; + } + } else { + s3 = s4; + } + } + } + if (s2.length < 2) { + peg$currPos = s1; + s1 = peg$FAILED; + } else { + s1 = s2; + } + if (s1 !== peg$FAILED) { + s2 = peg$parserest(); + peg$savedPos = s0; + s0 = peg$f10(s1, s2); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + return s0; + } + function peg$parsemaybe() { var s0, s1, s2; @@ -659,7 +725,7 @@ function peg$parse(input, options) { } s2 = peg$parserest(); peg$savedPos = s0; - s0 = peg$f10(s1, s2); + s0 = peg$f11(s1, s2); return s0; } @@ -679,11 +745,11 @@ function peg$parse(input, options) { s2 = peg$currPos; peg$silentFails++; if (input.charCodeAt(peg$currPos) === 98) { - s3 = peg$c3; + s3 = peg$c4; peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e7); } + if (peg$silentFails === 0) { peg$fail(peg$e8); } } peg$silentFails--; if (s3 !== peg$FAILED) { @@ -695,7 +761,7 @@ function peg$parse(input, options) { if (s2 !== peg$FAILED) { s3 = peg$parserest(); peg$savedPos = s0; - s0 = peg$f11(s1, s3); + s0 = peg$f12(s1, s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -723,11 +789,11 @@ function peg$parse(input, options) { s2 = peg$currPos; peg$silentFails++; if (input.charCodeAt(peg$currPos) === 98) { - s3 = peg$c3; + s3 = peg$c4; peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e7); } + if (peg$silentFails === 0) { peg$fail(peg$e8); } } peg$silentFails--; if (s3 === peg$FAILED) { @@ -739,7 +805,7 @@ function peg$parse(input, options) { if (s2 !== peg$FAILED) { s3 = peg$parserest(); peg$savedPos = s0; - s0 = peg$f12(s1, s3); + s0 = peg$f13(s1, s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -763,7 +829,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e8); } + if (peg$silentFails === 0) { peg$fail(peg$e9); } } if (s3 !== peg$FAILED) { while (s3 !== peg$FAILED) { @@ -773,7 +839,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e8); } + if (peg$silentFails === 0) { peg$fail(peg$e9); } } } } else { @@ -786,7 +852,7 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = peg$currPos; - s2 = peg$f13(s1); + s2 = peg$f14(s1); if (s2) { s2 = undefined; } else { @@ -795,7 +861,7 @@ function peg$parse(input, options) { if (s2 !== peg$FAILED) { s3 = peg$parserest(); peg$savedPos = s0; - s0 = peg$f14(s1, s3); + s0 = peg$f15(s1, s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -819,7 +885,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e8); } + if (peg$silentFails === 0) { peg$fail(peg$e9); } } if (s3 !== peg$FAILED) { while (s3 !== peg$FAILED) { @@ -829,7 +895,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e8); } + if (peg$silentFails === 0) { peg$fail(peg$e9); } } } } else { @@ -842,7 +908,7 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = peg$currPos; - s2 = peg$f15(s1); + s2 = peg$f16(s1); if (s2) { s2 = peg$FAILED; } else { @@ -851,7 +917,7 @@ function peg$parse(input, options) { if (s2 !== peg$FAILED) { s3 = peg$parserest(); peg$savedPos = s0; - s0 = peg$f16(s1, s3); + s0 = peg$f17(s1, s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -899,7 +965,7 @@ function peg$parse(input, options) { if (s1 !== peg$FAILED) { s2 = peg$parserest(); peg$savedPos = s0; - s0 = peg$f17(s1, s2); + s0 = peg$f18(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -913,22 +979,22 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = peg$currPos; - if (input.substr(peg$currPos, 3).toLowerCase() === peg$c4) { + if (input.substr(peg$currPos, 3).toLowerCase() === peg$c5) { s2 = input.substr(peg$currPos, 3); peg$currPos += 3; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e9); } + if (peg$silentFails === 0) { peg$fail(peg$e10); } } if (s2 !== peg$FAILED) { peg$savedPos = s1; - s2 = peg$f18(s2); + s2 = peg$f19(s2); } s1 = s2; if (s1 !== peg$FAILED) { s2 = peg$parserest(); peg$savedPos = s0; - s0 = peg$f19(s1, s2); + s0 = peg$f20(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -973,21 +1039,21 @@ function peg$parse(input, options) { if (s2 !== peg$FAILED) { s3 = []; if (input.charCodeAt(peg$currPos) === 32) { - s4 = peg$c5; + s4 = peg$c6; peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e10); } + if (peg$silentFails === 0) { peg$fail(peg$e11); } } if (s4 !== peg$FAILED) { while (s4 !== peg$FAILED) { s3.push(s4); if (input.charCodeAt(peg$currPos) === 32) { - s4 = peg$c5; + s4 = peg$c6; peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e10); } + if (peg$silentFails === 0) { peg$fail(peg$e11); } } } } else { @@ -1006,7 +1072,7 @@ function peg$parse(input, options) { if (s1 !== peg$FAILED) { s2 = peg$parserest(); peg$savedPos = s0; - s0 = peg$f20(s1, s2); + s0 = peg$f21(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1051,21 +1117,21 @@ function peg$parse(input, options) { if (s2 !== peg$FAILED) { s3 = []; if (input.charCodeAt(peg$currPos) === 32) { - s4 = peg$c5; + s4 = peg$c6; peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e10); } + if (peg$silentFails === 0) { peg$fail(peg$e11); } } if (s4 !== peg$FAILED) { while (s4 !== peg$FAILED) { s3.push(s4); if (input.charCodeAt(peg$currPos) === 32) { - s4 = peg$c5; + s4 = peg$c6; peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e10); } + if (peg$silentFails === 0) { peg$fail(peg$e11); } } } } else { @@ -1075,21 +1141,21 @@ function peg$parse(input, options) { s4 = peg$currPos; s5 = []; if (input.charCodeAt(peg$currPos) === 98) { - s6 = peg$c3; + s6 = peg$c4; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e7); } + if (peg$silentFails === 0) { peg$fail(peg$e8); } } if (s6 !== peg$FAILED) { while (s6 !== peg$FAILED) { s5.push(s6); if (input.charCodeAt(peg$currPos) === 98) { - s6 = peg$c3; + s6 = peg$c4; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e7); } + if (peg$silentFails === 0) { peg$fail(peg$e8); } } } } else { @@ -1117,7 +1183,7 @@ function peg$parse(input, options) { if (s1 !== peg$FAILED) { s2 = peg$parserest(); peg$savedPos = s0; - s0 = peg$f21(s1, s2); + s0 = peg$f22(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1140,19 +1206,19 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 98) { - s3 = peg$c3; + s3 = peg$c4; peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e7); } + if (peg$silentFails === 0) { peg$fail(peg$e8); } } if (s3 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 99) { - s4 = peg$c6; + s4 = peg$c7; peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e11); } + if (peg$silentFails === 0) { peg$fail(peg$e12); } } if (s4 !== peg$FAILED) { s2 = [s2, s3, s4]; @@ -1172,7 +1238,7 @@ function peg$parse(input, options) { if (s1 !== peg$FAILED) { s2 = peg$parserest(); peg$savedPos = s0; - s0 = peg$f22(s1, s2); + s0 = peg$f23(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1188,21 +1254,21 @@ function peg$parse(input, options) { s1 = peg$currPos; s2 = []; if (input.charCodeAt(peg$currPos) === 32) { - s3 = peg$c5; + s3 = peg$c6; peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e10); } + if (peg$silentFails === 0) { peg$fail(peg$e11); } } if (s3 !== peg$FAILED) { while (s3 !== peg$FAILED) { s2.push(s3); if (input.charCodeAt(peg$currPos) === 32) { - s3 = peg$c5; + s3 = peg$c6; peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e10); } + if (peg$silentFails === 0) { peg$fail(peg$e11); } } } } else { @@ -1218,7 +1284,7 @@ function peg$parse(input, options) { } if (s3 !== peg$FAILED) { peg$savedPos = s1; - s1 = peg$f23(); + s1 = peg$f24(); } else { peg$currPos = s1; s1 = peg$FAILED; @@ -1230,7 +1296,7 @@ function peg$parse(input, options) { if (s1 !== peg$FAILED) { s2 = peg$parserest(); peg$savedPos = s0; - s0 = peg$f24(s1, s2); + s0 = peg$f25(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1252,26 +1318,26 @@ function peg$parse(input, options) { } if (s1 === peg$FAILED) { if (input.charCodeAt(peg$currPos) === 98) { - s1 = peg$c3; + s1 = peg$c4; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e7); } + if (peg$silentFails === 0) { peg$fail(peg$e8); } } if (s1 === peg$FAILED) { if (input.charCodeAt(peg$currPos) === 99) { - s1 = peg$c6; + s1 = peg$c7; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e11); } + if (peg$silentFails === 0) { peg$fail(peg$e12); } } } } if (s1 !== peg$FAILED) { s2 = peg$parserest(); peg$savedPos = s0; - s0 = peg$f25(s1, s2); + s0 = peg$f26(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1306,7 +1372,7 @@ function peg$parse(input, options) { s0 = input.substring(s0, peg$currPos); peg$silentFails--; s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e12); } + if (peg$silentFails === 0) { peg$fail(peg$e13); } return s0; } diff --git a/docs/js/examples.peggy b/docs/js/examples.peggy index 92a0b575..2a2337ae 100644 --- a/docs/js/examples.peggy +++ b/docs/js/examples.peggy @@ -16,6 +16,8 @@ star = match:"a"* rest:rest { return {match, rest}; } plus = match:"a"+ rest:rest { return {match, rest}; } +repetition = match:"a"|2..3, ","| rest:rest { return {match, rest}; } + maybe = match:"a"? rest:rest { return {match, rest}; } posAssertion = match:"a" &"b" rest:rest { return {match, rest}; }