From f5b323b40124e9ebe1336b509af0716d5a31ce55 Mon Sep 17 00:00:00 2001 From: Futago-za Ryuu Date: Thu, 18 Jan 2018 01:24:34 +0000 Subject: [PATCH] Report consistent errors on look ahead + cached results This should resolve issue #452, and is based entirely on a fix @nikku did on a local branch of PEG.js v0.10.0 (Currently at https://github.com/nikku/pegjs/tree/452-peg-js-0.10-fix). Also his test case from #555 is included. Fixes #452, Closes #555 --- lib/compiler/passes/generate-js.js | 29 ++- lib/parser/index.js | 194 +++++++++++++++--- .../generated-parser-behavior.spec.js | 51 +++++ 3 files changed, 235 insertions(+), 39 deletions(-) diff --git a/lib/compiler/passes/generate-js.js b/lib/compiler/passes/generate-js.js index 10dedae..76166cd 100644 --- a/lib/compiler/passes/generate-js.js +++ b/lib/compiler/passes/generate-js.js @@ -143,7 +143,11 @@ function generateJS( ast, options ) { const parts = []; - parts.push( "" ); + parts.push( [ + "", + "var rule$expects = peg$expect;", + "" + ].join( "\n" ) ); if ( options.trace ) { @@ -163,9 +167,20 @@ function generateJS( ast, options ) { parts.push( [ "var key = peg$currPos * " + ast.rules.length + " + " + ruleIndexCode + ";", "var cached = peg$resultsCache[key];", + "var rule$expectations = [];", + "", + "rule$expects = function (expected) {", + " if (peg$silentFails === 0) peg$expect(expected);", + " rule$expectations.push(expected);", + "}", "", "if (cached) {", " peg$currPos = cached.nextPos;", + "", + " rule$expectations = cached.expectations;", + " if (peg$silentFails === 0) {", + " rule$expectations.map(peg$expect);", + " }", "" ].join( "\n" ) ); @@ -211,7 +226,11 @@ function generateJS( ast, options ) { parts.push( [ "", - "peg$resultsCache[key] = { nextPos: peg$currPos, result: " + resultCode + " };" + "peg$resultsCache[key] = {", + " nextPos: peg$currPos,", + " result: " + resultCode + ",", + " expectations: rule$expectations", + "};" ].join( "\n" ) ); } @@ -479,9 +498,7 @@ function generateJS( ast, options ) { " break;", "", " case " + op.EXPECT + ":", // EXPECT e - " if (peg$silentFails === 0) {", - " peg$expect(peg$expectations[bc[ip + 1]]);", - " }", + " rule$expects(peg$expectations[bc[ip + 1]]);", " ip += 2;", " break;", "", @@ -840,7 +857,7 @@ function generateJS( ast, options ) { break; case op.EXPECT: // EXPECT e - parts.push( "if (peg$silentFails === 0) { peg$expect(" + e( bc[ ip + 1 ] ) + "); }" ); + parts.push( "rule$expects(" + e( bc[ ip + 1 ] ) + ");" ); ip += 2; break; diff --git a/lib/parser/index.js b/lib/parser/index.js index 76ff0c7..ea349dc 100644 --- a/lib/parser/index.js +++ b/lib/parser/index.js @@ -540,6 +540,8 @@ function peg$parse(input, options) { function peg$parseGrammar() { var s0, s1, s2, s3, s4, s5, s6; + var rule$expects = peg$expect; + s0 = peg$currPos; s1 = peg$parse__(); s2 = peg$currPos; @@ -597,6 +599,8 @@ function peg$parse(input, options) { function peg$parseInitializer() { var s0, s1, s2; + var rule$expects = peg$expect; + s0 = peg$currPos; s1 = peg$parseCodeBlock(); if (s1 !== peg$FAILED) { @@ -619,6 +623,8 @@ function peg$parse(input, options) { function peg$parseRule() { var s0, s1, s2, s3, s4, s5, s6, s7; + var rule$expects = peg$expect; + s0 = peg$currPos; s1 = peg$parseIdentifierName(); if (s1 !== peg$FAILED) { @@ -636,7 +642,7 @@ function peg$parse(input, options) { if (s3 === peg$FAILED) { s3 = null; } - if (peg$silentFails === 0) { peg$expect(peg$e0); } + rule$expects(peg$e0); if (input.charCodeAt(peg$currPos) === 61) { s4 = peg$c0; peg$currPos++; @@ -674,13 +680,15 @@ function peg$parse(input, options) { function peg$parseChoiceExpression() { var s0, s1, s2, s3, s4, s5, s6, s7; + var rule$expects = peg$expect; + s0 = peg$currPos; s1 = peg$parseActionExpression(); if (s1 !== peg$FAILED) { s2 = []; s3 = peg$currPos; s4 = peg$parse__(); - if (peg$silentFails === 0) { peg$expect(peg$e1); } + rule$expects(peg$e1); if (input.charCodeAt(peg$currPos) === 47) { s5 = peg$c1; peg$currPos++; @@ -705,7 +713,7 @@ function peg$parse(input, options) { s2.push(s3); s3 = peg$currPos; s4 = peg$parse__(); - if (peg$silentFails === 0) { peg$expect(peg$e1); } + rule$expects(peg$e1); if (input.charCodeAt(peg$currPos) === 47) { s5 = peg$c1; peg$currPos++; @@ -740,6 +748,8 @@ function peg$parse(input, options) { function peg$parseActionExpression() { var s0, s1, s2, s3, s4; + var rule$expects = peg$expect; + s0 = peg$currPos; s1 = peg$parseSequenceExpression(); if (s1 !== peg$FAILED) { @@ -769,6 +779,8 @@ function peg$parse(input, options) { function peg$parseSequenceExpression() { var s0, s1, s2, s3, s4, s5; + var rule$expects = peg$expect; + s0 = peg$currPos; s1 = peg$parseLabeledExpression(); if (s1 !== peg$FAILED) { @@ -809,11 +821,13 @@ function peg$parse(input, options) { function peg$parseLabeledExpression() { var s0, s1, s2, s3, s4, s5; + var rule$expects = peg$expect; + s0 = peg$currPos; s1 = peg$parseIdentifier(); if (s1 !== peg$FAILED) { s2 = peg$parse__(); - if (peg$silentFails === 0) { peg$expect(peg$e2); } + rule$expects(peg$e2); if (input.charCodeAt(peg$currPos) === 58) { s3 = peg$c2; peg$currPos++; @@ -848,6 +862,8 @@ function peg$parse(input, options) { function peg$parsePrefixedExpression() { var s0, s1, s2, s3; + var rule$expects = peg$expect; + s0 = peg$currPos; s1 = peg$parsePrefixedOperator(); if (s1 !== peg$FAILED) { @@ -874,7 +890,9 @@ function peg$parse(input, options) { function peg$parsePrefixedOperator() { var s0; - if (peg$silentFails === 0) { peg$expect(peg$e3); } + var rule$expects = peg$expect; + + rule$expects(peg$e3); if (input.charCodeAt(peg$currPos) === 36) { s0 = peg$c3; peg$currPos++; @@ -882,7 +900,7 @@ function peg$parse(input, options) { s0 = peg$FAILED; } if (s0 === peg$FAILED) { - if (peg$silentFails === 0) { peg$expect(peg$e4); } + rule$expects(peg$e4); if (input.charCodeAt(peg$currPos) === 38) { s0 = peg$c4; peg$currPos++; @@ -890,7 +908,7 @@ function peg$parse(input, options) { s0 = peg$FAILED; } if (s0 === peg$FAILED) { - if (peg$silentFails === 0) { peg$expect(peg$e5); } + rule$expects(peg$e5); if (input.charCodeAt(peg$currPos) === 33) { s0 = peg$c5; peg$currPos++; @@ -906,6 +924,8 @@ function peg$parse(input, options) { function peg$parseSuffixedExpression() { var s0, s1, s2, s3; + var rule$expects = peg$expect; + s0 = peg$currPos; s1 = peg$parsePrimaryExpression(); if (s1 !== peg$FAILED) { @@ -932,7 +952,9 @@ function peg$parse(input, options) { function peg$parseSuffixedOperator() { var s0; - if (peg$silentFails === 0) { peg$expect(peg$e6); } + var rule$expects = peg$expect; + + rule$expects(peg$e6); if (input.charCodeAt(peg$currPos) === 63) { s0 = peg$c6; peg$currPos++; @@ -940,7 +962,7 @@ function peg$parse(input, options) { s0 = peg$FAILED; } if (s0 === peg$FAILED) { - if (peg$silentFails === 0) { peg$expect(peg$e7); } + rule$expects(peg$e7); if (input.charCodeAt(peg$currPos) === 42) { s0 = peg$c7; peg$currPos++; @@ -948,7 +970,7 @@ function peg$parse(input, options) { s0 = peg$FAILED; } if (s0 === peg$FAILED) { - if (peg$silentFails === 0) { peg$expect(peg$e8); } + rule$expects(peg$e8); if (input.charCodeAt(peg$currPos) === 43) { s0 = peg$c8; peg$currPos++; @@ -964,6 +986,8 @@ function peg$parse(input, options) { function peg$parsePrimaryExpression() { var s0, s1, s2, s3, s4, s5; + var rule$expects = peg$expect; + s0 = peg$parseLiteralMatcher(); if (s0 === peg$FAILED) { s0 = peg$parseCharacterClassMatcher(); @@ -975,7 +999,7 @@ function peg$parse(input, options) { s0 = peg$parseSemanticPredicateExpression(); if (s0 === peg$FAILED) { s0 = peg$currPos; - if (peg$silentFails === 0) { peg$expect(peg$e9); } + rule$expects(peg$e9); if (input.charCodeAt(peg$currPos) === 40) { s1 = peg$c9; peg$currPos++; @@ -987,7 +1011,7 @@ function peg$parse(input, options) { s3 = peg$parseChoiceExpression(); if (s3 !== peg$FAILED) { s4 = peg$parse__(); - if (peg$silentFails === 0) { peg$expect(peg$e10); } + rule$expects(peg$e10); if (input.charCodeAt(peg$currPos) === 41) { s5 = peg$c10; peg$currPos++; @@ -1021,6 +1045,8 @@ function peg$parse(input, options) { function peg$parseRuleReferenceExpression() { var s0, s1, s2, s3, s4, s5, s6, s7; + var rule$expects = peg$expect; + s0 = peg$currPos; s1 = peg$parseIdentifierName(); if (s1 !== peg$FAILED) { @@ -1041,7 +1067,7 @@ function peg$parse(input, options) { if (s5 === peg$FAILED) { s5 = null; } - if (peg$silentFails === 0) { peg$expect(peg$e0); } + rule$expects(peg$e0); if (input.charCodeAt(peg$currPos) === 61) { s6 = peg$c0; peg$currPos++; @@ -1080,6 +1106,8 @@ function peg$parse(input, options) { function peg$parseSemanticPredicateExpression() { var s0, s1, s2, s3; + var rule$expects = peg$expect; + s0 = peg$currPos; s1 = peg$parseSemanticPredicateOperator(); if (s1 !== peg$FAILED) { @@ -1103,7 +1131,9 @@ function peg$parse(input, options) { function peg$parseSemanticPredicateOperator() { var s0; - if (peg$silentFails === 0) { peg$expect(peg$e4); } + var rule$expects = peg$expect; + + rule$expects(peg$e4); if (input.charCodeAt(peg$currPos) === 38) { s0 = peg$c4; peg$currPos++; @@ -1111,7 +1141,7 @@ function peg$parse(input, options) { s0 = peg$FAILED; } if (s0 === peg$FAILED) { - if (peg$silentFails === 0) { peg$expect(peg$e5); } + rule$expects(peg$e5); if (input.charCodeAt(peg$currPos) === 33) { s0 = peg$c5; peg$currPos++; @@ -1126,7 +1156,9 @@ function peg$parse(input, options) { function peg$parseSourceCharacter() { var s0; - if (peg$silentFails === 0) { peg$expect(peg$e11); } + var rule$expects = peg$expect; + + rule$expects(peg$e11); if (input.length > peg$currPos) { s0 = input.charAt(peg$currPos); peg$currPos++; @@ -1140,7 +1172,9 @@ function peg$parse(input, options) { function peg$parseWhiteSpace() { var s0; - if (peg$silentFails === 0) { peg$expect(peg$e12); } + var rule$expects = peg$expect; + + rule$expects(peg$e12); peg$silentFails++; if (input.charCodeAt(peg$currPos) === 9) { s0 = peg$c11; @@ -1199,7 +1233,9 @@ function peg$parse(input, options) { function peg$parseLineTerminator() { var s0; - if (peg$silentFails === 0) { peg$expect(peg$e13); } + var rule$expects = peg$expect; + + rule$expects(peg$e13); if (peg$r0.test(input.charAt(peg$currPos))) { s0 = input.charAt(peg$currPos); peg$currPos++; @@ -1213,7 +1249,9 @@ function peg$parse(input, options) { function peg$parseLineTerminatorSequence() { var s0; - if (peg$silentFails === 0) { peg$expect(peg$e14); } + var rule$expects = peg$expect; + + rule$expects(peg$e14); peg$silentFails++; if (input.charCodeAt(peg$currPos) === 10) { s0 = peg$c17; @@ -1261,7 +1299,9 @@ function peg$parse(input, options) { function peg$parseComment() { var s0; - if (peg$silentFails === 0) { peg$expect(peg$e15); } + var rule$expects = peg$expect; + + rule$expects(peg$e15); peg$silentFails++; s0 = peg$parseMultiLineComment(); if (s0 === peg$FAILED) { @@ -1275,6 +1315,8 @@ function peg$parse(input, options) { function peg$parseMultiLineComment() { var s0, s1, s2, s3, s4, s5; + var rule$expects = peg$expect; + s0 = peg$currPos; if (input.substr(peg$currPos, 2) === peg$c22) { s1 = peg$c22; @@ -1369,8 +1411,10 @@ function peg$parse(input, options) { function peg$parseMultiLineCommentNoLineTerminator() { var s0, s1, s2, s3, s4, s5; + var rule$expects = peg$expect; + s0 = peg$currPos; - if (peg$silentFails === 0) { peg$expect(peg$e16); } + rule$expects(peg$e16); if (input.substr(peg$currPos, 2) === peg$c22) { s1 = peg$c22; peg$currPos += 2; @@ -1382,7 +1426,7 @@ function peg$parse(input, options) { s3 = peg$currPos; s4 = peg$currPos; peg$begin(); - if (peg$silentFails === 0) { peg$expect(peg$e17); } + rule$expects(peg$e17); if (input.substr(peg$currPos, 2) === peg$c23) { s5 = peg$c23; peg$currPos += 2; @@ -1417,7 +1461,7 @@ function peg$parse(input, options) { s3 = peg$currPos; s4 = peg$currPos; peg$begin(); - if (peg$silentFails === 0) { peg$expect(peg$e17); } + rule$expects(peg$e17); if (input.substr(peg$currPos, 2) === peg$c23) { s5 = peg$c23; peg$currPos += 2; @@ -1448,7 +1492,7 @@ function peg$parse(input, options) { s3 = peg$FAILED; } } - if (peg$silentFails === 0) { peg$expect(peg$e17); } + rule$expects(peg$e17); if (input.substr(peg$currPos, 2) === peg$c23) { s3 = peg$c23; peg$currPos += 2; @@ -1473,8 +1517,10 @@ function peg$parse(input, options) { function peg$parseSingleLineComment() { var s0, s1, s2, s3, s4, s5; + var rule$expects = peg$expect; + s0 = peg$currPos; - if (peg$silentFails === 0) { peg$expect(peg$e18); } + rule$expects(peg$e18); if (input.substr(peg$currPos, 2) === peg$c24) { s1 = peg$c24; peg$currPos += 2; @@ -1547,6 +1593,8 @@ function peg$parse(input, options) { function peg$parseIdentifier() { var s0, s1; + var rule$expects = peg$expect; + s0 = peg$currPos; s1 = peg$parseIdentifierName(); if (s1 !== peg$FAILED) { @@ -1561,7 +1609,9 @@ function peg$parse(input, options) { function peg$parseIdentifierName() { var s0, s1, s2, s3; - if (peg$silentFails === 0) { peg$expect(peg$e19); } + var rule$expects = peg$expect; + + rule$expects(peg$e19); peg$silentFails++; s0 = peg$currPos; s1 = peg$parseIdentifierStart(); @@ -1586,6 +1636,8 @@ function peg$parse(input, options) { function peg$parseIdentifierStart() { var s0, s1, s2; + var rule$expects = peg$expect; + s0 = peg$parseUnicodeLetter(); if (s0 === peg$FAILED) { if (input.charCodeAt(peg$currPos) === 36) { @@ -1632,6 +1684,8 @@ function peg$parse(input, options) { function peg$parseIdentifierPart() { var s0; + var rule$expects = peg$expect; + s0 = peg$parseIdentifierStart(); if (s0 === peg$FAILED) { s0 = peg$parseUnicodeCombiningMark(); @@ -1665,6 +1719,8 @@ function peg$parse(input, options) { function peg$parseUnicodeLetter() { var s0; + var rule$expects = peg$expect; + s0 = peg$parseLu(); if (s0 === peg$FAILED) { s0 = peg$parseLl(); @@ -1688,6 +1744,8 @@ function peg$parse(input, options) { function peg$parseUnicodeCombiningMark() { var s0; + var rule$expects = peg$expect; + s0 = peg$parseMn(); if (s0 === peg$FAILED) { s0 = peg$parseMc(); @@ -1699,7 +1757,9 @@ function peg$parse(input, options) { function peg$parseLiteralMatcher() { var s0, s1, s2; - if (peg$silentFails === 0) { peg$expect(peg$e20); } + var rule$expects = peg$expect; + + rule$expects(peg$e20); peg$silentFails++; s0 = peg$currPos; s1 = peg$parseStringLiteral(); @@ -1727,7 +1787,9 @@ function peg$parse(input, options) { function peg$parseStringLiteral() { var s0, s1, s2, s3; - if (peg$silentFails === 0) { peg$expect(peg$e21); } + var rule$expects = peg$expect; + + rule$expects(peg$e21); peg$silentFails++; s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 34) { @@ -1801,6 +1863,8 @@ function peg$parse(input, options) { function peg$parseDoubleStringCharacter() { var s0, s1, s2; + var rule$expects = peg$expect; + s0 = peg$currPos; s1 = peg$currPos; peg$begin(); @@ -1873,6 +1937,8 @@ function peg$parse(input, options) { function peg$parseSingleStringCharacter() { var s0, s1, s2; + var rule$expects = peg$expect; + s0 = peg$currPos; s1 = peg$currPos; peg$begin(); @@ -1945,7 +2011,9 @@ function peg$parse(input, options) { function peg$parseCharacterClassMatcher() { var s0, s1, s2, s3, s4, s5; - if (peg$silentFails === 0) { peg$expect(peg$e22); } + var rule$expects = peg$expect; + + rule$expects(peg$e22); peg$silentFails++; s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 91) { @@ -2010,6 +2078,8 @@ function peg$parse(input, options) { function peg$parseClassCharacterRange() { var s0, s1, s2, s3; + var rule$expects = peg$expect; + s0 = peg$currPos; s1 = peg$parseClassCharacter(); if (s1 !== peg$FAILED) { @@ -2043,6 +2113,8 @@ function peg$parse(input, options) { function peg$parseClassCharacter() { var s0, s1, s2; + var rule$expects = peg$expect; + s0 = peg$currPos; s1 = peg$currPos; peg$begin(); @@ -2115,6 +2187,8 @@ function peg$parse(input, options) { function peg$parseLineContinuation() { var s0, s1, s2; + var rule$expects = peg$expect; + s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 92) { s1 = peg$c26; @@ -2142,6 +2216,8 @@ function peg$parse(input, options) { function peg$parseEscapeSequence() { var s0, s1, s2, s3; + var rule$expects = peg$expect; + s0 = peg$parseCharacterEscapeSequence(); if (s0 === peg$FAILED) { s0 = peg$currPos; @@ -2187,6 +2263,8 @@ function peg$parse(input, options) { function peg$parseCharacterEscapeSequence() { var s0; + var rule$expects = peg$expect; + s0 = peg$parseSingleEscapeCharacter(); if (s0 === peg$FAILED) { s0 = peg$parseNonEscapeCharacter(); @@ -2198,6 +2276,8 @@ function peg$parse(input, options) { function peg$parseSingleEscapeCharacter() { var s0, s1; + var rule$expects = peg$expect; + if (input.charCodeAt(peg$currPos) === 39) { s0 = peg$c31; peg$currPos++; @@ -2311,6 +2391,8 @@ function peg$parse(input, options) { function peg$parseNonEscapeCharacter() { var s0, s1, s2; + var rule$expects = peg$expect; + s0 = peg$currPos; s1 = peg$currPos; peg$begin(); @@ -2345,6 +2427,8 @@ function peg$parse(input, options) { function peg$parseEscapeCharacter() { var s0; + var rule$expects = peg$expect; + s0 = peg$parseSingleEscapeCharacter(); if (s0 === peg$FAILED) { s0 = peg$parseDecimalDigit(); @@ -2372,6 +2456,8 @@ function peg$parse(input, options) { function peg$parseHexEscapeSequence() { var s0, s1, s2, s3, s4, s5; + var rule$expects = peg$expect; + s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 120) { s1 = peg$c43; @@ -2419,6 +2505,8 @@ function peg$parse(input, options) { function peg$parseUnicodeEscapeSequence() { var s0, s1, s2, s3, s4, s5, s6, s7; + var rule$expects = peg$expect; + s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 117) { s1 = peg$c44; @@ -2478,6 +2566,8 @@ function peg$parse(input, options) { function peg$parseDecimalDigit() { var s0; + var rule$expects = peg$expect; + if (peg$r1.test(input.charAt(peg$currPos))) { s0 = input.charAt(peg$currPos); peg$currPos++; @@ -2491,6 +2581,8 @@ function peg$parse(input, options) { function peg$parseHexDigit() { var s0; + var rule$expects = peg$expect; + if (peg$r2.test(input.charAt(peg$currPos))) { s0 = input.charAt(peg$currPos); peg$currPos++; @@ -2504,8 +2596,10 @@ function peg$parse(input, options) { function peg$parseAnyMatcher() { var s0, s1; + var rule$expects = peg$expect; + s0 = peg$currPos; - if (peg$silentFails === 0) { peg$expect(peg$e23); } + rule$expects(peg$e23); if (input.charCodeAt(peg$currPos) === 46) { s1 = peg$c45; peg$currPos++; @@ -2524,7 +2618,9 @@ function peg$parse(input, options) { function peg$parseCodeBlock() { var s0, s1, s2, s3; - if (peg$silentFails === 0) { peg$expect(peg$e24); } + var rule$expects = peg$expect; + + rule$expects(peg$e24); peg$silentFails++; s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 123) { @@ -2574,6 +2670,8 @@ function peg$parse(input, options) { function peg$parseCode() { var s0, s1, s2, s3, s4, s5; + var rule$expects = peg$expect; + s0 = peg$currPos; s1 = []; s2 = []; @@ -2775,6 +2873,8 @@ function peg$parse(input, options) { function peg$parseLl() { var s0; + var rule$expects = peg$expect; + if (peg$r4.test(input.charAt(peg$currPos))) { s0 = input.charAt(peg$currPos); peg$currPos++; @@ -2788,6 +2888,8 @@ function peg$parse(input, options) { function peg$parseLm() { var s0; + var rule$expects = peg$expect; + if (peg$r5.test(input.charAt(peg$currPos))) { s0 = input.charAt(peg$currPos); peg$currPos++; @@ -2801,6 +2903,8 @@ function peg$parse(input, options) { function peg$parseLo() { var s0; + var rule$expects = peg$expect; + if (peg$r6.test(input.charAt(peg$currPos))) { s0 = input.charAt(peg$currPos); peg$currPos++; @@ -2814,6 +2918,8 @@ function peg$parse(input, options) { function peg$parseLt() { var s0; + var rule$expects = peg$expect; + if (peg$r7.test(input.charAt(peg$currPos))) { s0 = input.charAt(peg$currPos); peg$currPos++; @@ -2827,6 +2933,8 @@ function peg$parse(input, options) { function peg$parseLu() { var s0; + var rule$expects = peg$expect; + if (peg$r8.test(input.charAt(peg$currPos))) { s0 = input.charAt(peg$currPos); peg$currPos++; @@ -2840,6 +2948,8 @@ function peg$parse(input, options) { function peg$parseMc() { var s0; + var rule$expects = peg$expect; + if (peg$r9.test(input.charAt(peg$currPos))) { s0 = input.charAt(peg$currPos); peg$currPos++; @@ -2853,6 +2963,8 @@ function peg$parse(input, options) { function peg$parseMn() { var s0; + var rule$expects = peg$expect; + if (peg$r10.test(input.charAt(peg$currPos))) { s0 = input.charAt(peg$currPos); peg$currPos++; @@ -2866,6 +2978,8 @@ function peg$parse(input, options) { function peg$parseNd() { var s0; + var rule$expects = peg$expect; + if (peg$r11.test(input.charAt(peg$currPos))) { s0 = input.charAt(peg$currPos); peg$currPos++; @@ -2879,6 +2993,8 @@ function peg$parse(input, options) { function peg$parseNl() { var s0; + var rule$expects = peg$expect; + if (peg$r12.test(input.charAt(peg$currPos))) { s0 = input.charAt(peg$currPos); peg$currPos++; @@ -2892,6 +3008,8 @@ function peg$parse(input, options) { function peg$parsePc() { var s0; + var rule$expects = peg$expect; + if (peg$r13.test(input.charAt(peg$currPos))) { s0 = input.charAt(peg$currPos); peg$currPos++; @@ -2905,6 +3023,8 @@ function peg$parse(input, options) { function peg$parseZs() { var s0; + var rule$expects = peg$expect; + if (peg$r14.test(input.charAt(peg$currPos))) { s0 = input.charAt(peg$currPos); peg$currPos++; @@ -2918,6 +3038,8 @@ function peg$parse(input, options) { function peg$parse__() { var s0, s1; + var rule$expects = peg$expect; + s0 = []; s1 = peg$parseWhiteSpace(); if (s1 === peg$FAILED) { @@ -2943,6 +3065,8 @@ function peg$parse(input, options) { function peg$parse_() { var s0, s1; + var rule$expects = peg$expect; + s0 = []; s1 = peg$parseWhiteSpace(); if (s1 === peg$FAILED) { @@ -2962,9 +3086,11 @@ function peg$parse(input, options) { function peg$parseEOS() { var s0, s1, s2, s3; + var rule$expects = peg$expect; + s0 = peg$currPos; s1 = peg$parse__(); - if (peg$silentFails === 0) { peg$expect(peg$e25); } + rule$expects(peg$e25); if (input.charCodeAt(peg$currPos) === 59) { s2 = peg$c48; peg$currPos++; @@ -3013,9 +3139,11 @@ function peg$parse(input, options) { function peg$parseEOF() { var s0, s1; + var rule$expects = peg$expect; + s0 = peg$currPos; peg$begin(); - if (peg$silentFails === 0) { peg$expect(peg$e11); } + rule$expects(peg$e11); if (input.length > peg$currPos) { s1 = input.charAt(peg$currPos); peg$currPos++; diff --git a/test/spec/behavior/generated-parser-behavior.spec.js b/test/spec/behavior/generated-parser-behavior.spec.js index 90aec2f..0ad8627 100644 --- a/test/spec/behavior/generated-parser-behavior.spec.js +++ b/test/spec/behavior/generated-parser-behavior.spec.js @@ -1782,6 +1782,57 @@ describe( "generated parser behavior", function () { } ); + it( "reports expectations correctly with look ahead", function () { + + // Case 1, by https://github.com/dmajda + + let parser = peg.generate( [ + "Statement = '{' __ !Statement Statement __ '}'", + "__ = [ ]*" + ].join( "\n" ), options ); + + expect( parser ).to.failToParse( "{x}", { + expected: [ + { type: "class", parts: [ " " ], inverted: false, ignoreCase: false }, + { type: "not", expected: { type: "literal", text: "{", ignoreCase: false } }, + { type: "literal", text: "{", ignoreCase: false } + ] + } ); + + // Case 2, by https://github.com/nikku + + parser = peg.generate( [ + "Start = Char+ End", + "End = 'e'", + "Char = !End [a-z]" + ].join( "\n" ), options ); + + expect( parser ).to.failToParse( "a", { + expected: [ + { type: "class", parts: [ [ "a", "z" ] ], inverted: false, ignoreCase: false }, + { type: "literal", text: "e", ignoreCase: false } + ] + } ); + + } ); + + it( "reports expectations correctly with look ahead + grouped names", function () { + + const parser = peg.generate( [ + "Start = Char+ End", + "End 'end' = 'e'", + "Char = !End [a-z]" + ].join( "\n" ), options ); + + expect( parser ).to.failToParse( "a", { + expected: [ + { type: "class", parts: [ [ "a", "z" ] ], inverted: false, ignoreCase: false }, + { type: "other", description: "end" } + ] + } ); + + } ); + } ); describe( "found string reporting", function () {