From 78cc56dc46b92ff8562c751e187cf84516d4862c Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Sun, 29 Jun 2014 17:39:24 -0700 Subject: [PATCH] Make ZeroOrMore non-greedy to make it nestable without exponential behavior. --- grammars/mediawiki.js | 2 +- recentrunes.js | 18 +++++++++--------- test.js | 5 +++-- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/grammars/mediawiki.js b/grammars/mediawiki.js index 02675b1..63e63aa 100644 --- a/grammars/mediawiki.js +++ b/grammars/mediawiki.js @@ -23,5 +23,5 @@ var mediawiki = { rr.Ref('nowiki'), rr.Ref('text') ), - 'wikidoc': rr.Node('wikidoc', rr.ZeroOrMore(rr.Ref('wikichunk'))), + 'wikidoc': rr.Node('wikidoc', rr.Sequence(rr.ZeroOrMore(rr.Ref('wikichunk')), rr.EndOfText())), }; diff --git a/recentrunes.js b/recentrunes.js index 5f45b22..bab93bb 100644 --- a/recentrunes.js +++ b/recentrunes.js @@ -493,22 +493,18 @@ rr.ZeroOrMore_ = function(child) { */ rr.ZeroOrMore_.prototype.match = function(context) { // Yield: - // 1) The results of SequentialPair(child, this) - // 2) An empty result + // 1) An empty result + // 2) The results of SequentialPair(child, this) // 3) Done // - // We must check for results from 1 that don't reduce context.remaining(); + // We must check for results from 2 that don't reduce context.remaining(); // that means infinite recursion. - var iterator = this.pair_.match(context); + var iterator = null; return { 'next': function() { if (!iterator) { - return { 'done': true }; - } - var next = iterator.next(); - if (next['done']) { - iterator = null; + iterator = this.pair_.match(context); return { 'done': false, 'value': { @@ -517,6 +513,10 @@ rr.ZeroOrMore_.prototype.match = function(context) { } }; } + var next = iterator.next(); + if (next['done']) { + return { 'done': true }; + } if (next['value']['context'].remaining() == context.remaining()) { throw "Child of ZeroOrMore didn't consume input; grammar bug?"; } diff --git a/test.js b/test.js index 89500fd..0dcb8a5 100644 --- a/test.js +++ b/test.js @@ -8,7 +8,7 @@ QUnit.test('Simple', function(assert) { var iterable = context.rules['wikidoc'].match(context); assert.equal(iterable.next().value.nodes[0].innerHTML, '

Heading

This is a wiki doc.\n' + - 'How about some bold and <i>bold italic</i>.\n' + + "How about some bold and ''bold italic''.\n" + 'I would also love some nowiki <b>foo</b>'); }); @@ -16,7 +16,8 @@ QUnit.test('Simple', function(assert) { QUnit.test('ZeroOrMore', function(assert) { assert.expect(1); var rules = { - 'test': rr.Node('test', rr.ZeroOrMore(rr.MultiLineText())) + 'test': rr.Node('test', + rr.Sequence(rr.ZeroOrMore(rr.MultiLineText()), rr.EndOfText())) }; var context = new rr.Context(rules, 'foobar'); var iterable = context.rules['test'].match(context);