"use strict"; var peg = require("../../../../lib/peg"); describe("compiler pass |reportInfiniteRecursion|", function() { var pass = peg.compiler.passes.check.reportInfiniteRecursion; it("reports direct left recursion", function() { expect(pass).toReportError('start = start', { message: 'Possible infinite loop when parsing (left recursion: start -> start).', location: { start: { offset: 8, line: 1, column: 9 }, end: { offset: 13, line: 1, column: 14 } } }); }); it("reports indirect left recursion", function() { expect(pass).toReportError([ 'start = stop', 'stop = start' ].join("\n"), { message: 'Possible infinite loop when parsing (left recursion: start -> stop -> start).', location: { start: { offset: 21, line: 2, column: 9 }, end: { offset: 26, line: 2, column: 14 } } }); }); describe("in sequences", function() { it("reports left recursion if all preceding elements match empty string", function() { expect(pass).toReportError('start = "" "" "" start'); }); it("doesn't report left recursion if some preceding element doesn't match empty string", function() { expect(pass).not.toReportError('start = "a" "" "" start'); expect(pass).not.toReportError('start = "" "a" "" start'); expect(pass).not.toReportError('start = "" "" "a" start'); }); /* Regression test for #359. */ it("reports left recursion when rule reference is wrapped in an expression", function() { expect(pass).toReportError('start = "" start?'); }); it("computes expressions that always consume input on success correctly", function() { expect(pass).toReportError([ 'start = a start', 'a "a" = ""' ].join('\n')); expect(pass).not.toReportError([ 'start = a start', 'a "a" = "a"' ].join('\n')); expect(pass).toReportError('start = ("" / "a" / "b") start'); expect(pass).toReportError('start = ("a" / "" / "b") start'); expect(pass).toReportError('start = ("a" / "b" / "") start'); expect(pass).not.toReportError('start = ("a" / "b" / "c") start'); expect(pass).toReportError('start = ("" { }) start'); expect(pass).not.toReportError('start = ("a" { }) start'); expect(pass).toReportError('start = ("" "" "") start'); expect(pass).not.toReportError('start = ("a" "" "") start'); expect(pass).not.toReportError('start = ("" "a" "") start'); expect(pass).not.toReportError('start = ("" "" "a") start'); expect(pass).toReportError('start = a:"" start'); expect(pass).not.toReportError('start = a:"a" start'); expect(pass).toReportError('start = $"" start'); expect(pass).not.toReportError('start = $"a" start'); expect(pass).toReportError('start = &"" start'); expect(pass).toReportError('start = &"a" start'); expect(pass).toReportError('start = !"" start'); expect(pass).toReportError('start = !"a" start'); expect(pass).toReportError('start = ""? start'); expect(pass).toReportError('start = "a"? start'); expect(pass).toReportError('start = ""* start'); expect(pass).toReportError('start = "a"* start'); expect(pass).toReportError('start = ""+ start'); expect(pass).not.toReportError('start = "a"+ start'); expect(pass).toReportError('start = ("") start'); expect(pass).not.toReportError('start = ("a") start'); expect(pass).toReportError('start = &{ } start'); expect(pass).toReportError('start = !{ } start'); expect(pass).toReportError([ 'start = a start', 'a = ""' ].join('\n')); expect(pass).not.toReportError([ 'start = a start', 'a = "a"' ].join('\n')); expect(pass).toReportError('start = "" start'); expect(pass).not.toReportError('start = "a" start'); expect(pass).not.toReportError('start = [a-d] start'); expect(pass).not.toReportError('start = . start'); }); }); });