parent
95ce20ed92
commit
d7fc0b5c3b
@ -0,0 +1,27 @@
|
|||||||
|
var GrammarError = require("../../grammar-error"),
|
||||||
|
asts = require("../asts"),
|
||||||
|
visitor = require("../visitor");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reports expressions that don't consume any input inside |*| or |+| in the
|
||||||
|
* grammar, which prevents infinite loops in the generated parser.
|
||||||
|
*/
|
||||||
|
function reportInfiniteLoops(ast) {
|
||||||
|
var check = visitor.build({
|
||||||
|
zero_or_more: function(node) {
|
||||||
|
if (asts.matchesEmpty(ast, node.expression)) {
|
||||||
|
throw new GrammarError("Infinite loop detected.");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
one_or_more: function(node) {
|
||||||
|
if (asts.matchesEmpty(ast, node.expression)) {
|
||||||
|
throw new GrammarError("Infinite loop detected.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
check(ast);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = reportInfiniteLoops;
|
@ -0,0 +1,71 @@
|
|||||||
|
describe("compiler pass |reportLeftRecursion|", function() {
|
||||||
|
var pass = PEG.compiler.passes.check.reportInfiniteLoops;
|
||||||
|
|
||||||
|
it("reports infinite loops for zero_or_more", function() {
|
||||||
|
expect(pass).toReportError('start = ("")*', {
|
||||||
|
message: "Infinite loop detected."
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("reports infinite loops for one_or_more", function() {
|
||||||
|
expect(pass).toReportError('start = ("")+', {
|
||||||
|
message: "Infinite loop detected."
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("computes empty string matching correctly", function() {
|
||||||
|
expect(pass).toReportError('start = ("" / "a" / "b")*');
|
||||||
|
expect(pass).toReportError('start = ("a" / "" / "b")*');
|
||||||
|
expect(pass).toReportError('start = ("a" / "b" / "")*');
|
||||||
|
expect(pass).not.toReportError('start = ("a" / "b" / "c")*');
|
||||||
|
|
||||||
|
expect(pass).toReportError('start = ("" { })*');
|
||||||
|
expect(pass).not.toReportError('start = ("a" { })*');
|
||||||
|
|
||||||
|
expect(pass).toReportError('start = ("" "" "")*');
|
||||||
|
expect(pass).not.toReportError('start = ("a" "" "")*');
|
||||||
|
expect(pass).not.toReportError('start = ("" "a" "")*');
|
||||||
|
expect(pass).not.toReportError('start = ("" "" "a")*');
|
||||||
|
|
||||||
|
expect(pass).toReportError('start = (a:"")*');
|
||||||
|
expect(pass).not.toReportError('start = (a:"a")*');
|
||||||
|
|
||||||
|
expect(pass).toReportError('start = ($"")*');
|
||||||
|
expect(pass).not.toReportError('start = ($"a")*');
|
||||||
|
|
||||||
|
expect(pass).toReportError('start = (&"")*');
|
||||||
|
expect(pass).toReportError('start = (&"a")*');
|
||||||
|
|
||||||
|
expect(pass).toReportError('start = (!"")*');
|
||||||
|
expect(pass).toReportError('start = (!"a")*');
|
||||||
|
|
||||||
|
expect(pass).toReportError('start = (""?)*');
|
||||||
|
expect(pass).toReportError('start = ("a"?)*');
|
||||||
|
|
||||||
|
expect(pass).toReportError('start = (""*)*');
|
||||||
|
expect(pass).toReportError('start = ("a"*)*');
|
||||||
|
|
||||||
|
expect(pass).toReportError('start = (""+)*');
|
||||||
|
expect(pass).not.toReportError('start = ("a"+)*');
|
||||||
|
|
||||||
|
expect(pass).toReportError('start = (&{ })*');
|
||||||
|
|
||||||
|
expect(pass).toReportError('start = (!{ })*');
|
||||||
|
|
||||||
|
expect(pass).toReportError([
|
||||||
|
'start = a*',
|
||||||
|
'a = ""'
|
||||||
|
].join('\n'));
|
||||||
|
expect(pass).not.toReportError([
|
||||||
|
'start = a*',
|
||||||
|
'a = "a"'
|
||||||
|
].join('\n'));
|
||||||
|
|
||||||
|
expect(pass).toReportError('start = ""*');
|
||||||
|
expect(pass).not.toReportError('start = "a"*');
|
||||||
|
|
||||||
|
expect(pass).not.toReportError('start = [a-d]*');
|
||||||
|
|
||||||
|
expect(pass).not.toReportError('start = "."*');
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue