From 6d06d1490059e79884c5202edd06261d17e65c76 Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Sat, 28 Jun 2014 17:30:21 -0700 Subject: [PATCH] Fix rr.Or matcher inifite loop bug. --- recentrunes.js | 47 ++++++++++++++++++++++++++++++++--------------- test.js | 2 +- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/recentrunes.js b/recentrunes.js index 693d805..ecda247 100644 --- a/recentrunes.js +++ b/recentrunes.js @@ -56,6 +56,7 @@ rr.Literal_ = function(value) { * @return {rr.typeIterator} */ rr.Literal_.prototype.match = function(context) { + console.log('Literal.match:', this.value_); if (context.stringAfter(this.value_.length) == this.value_) { return rr.iterableFromArray_([{ 'context': context.advance(this.value_.length), @@ -101,6 +102,7 @@ rr.Ref_ = function(key) { * @return {rr.typeIterator} */ rr.Ref_.prototype.match = function(context) { + console.log('Ref.match:', this.key_); return context.rules[this.key_].match(context); }; @@ -141,9 +143,11 @@ rr.Node_ = function(name, child) { * @return {rr.typeIterator} */ rr.Node_.prototype.match = function(context) { + console.log('Node.match'); var iterator = this.child_.match(context); return { 'next': function() { + console.log('Node.next'); var next = iterator.next(); if (next['done']) { return { 'done': true }; @@ -191,6 +195,7 @@ rr.EndOfLine_ = function() { * @return {rr.typeIterator} */ rr.EndOfLine_.prototype.match = function(context) { + console.log('EndOfLine.match'); if (context.atEnd()) { return rr.iterableFromArray_([{ 'context': context, @@ -243,6 +248,7 @@ rr.EndOfText_ = function() { * @return {rr.typeIterator} */ rr.EndOfText_.prototype.match = function(context) { + console.log('EndOfText.match'); if (context.atEnd()) { return rr.iterableFromArray_([{ 'context': context, @@ -284,9 +290,11 @@ rr.MultiLineText_ = function() { * @return {rr.typeIterator} */ rr.MultiLineText_.prototype.match = function(context) { + console.log('MultiLineText.match'); var i = 1; return { 'next': function() { + console.log('MultiLineText.next:', i); if (i <= context.remaining()) { var newNode = document.createTextNode(context.stringAfter(i)); var ret = { @@ -338,27 +346,28 @@ rr.Or_ = function(options) { * @return {rr.typeIterator} */ rr.Or_.prototype.match = function(context) { - var i = 0; + console.log('Or.match'); + var optionIndex = 0; var lastIterator = null; return { 'next': function() { - if (lastIterator) { - var next = lastIterator.next(); - if (!next['done']) { - return next; + console.log('Or.next'); + while (true) { + if (lastIterator) { + console.log('Or.next: still consuming child iterator', optionIndex); + var next = lastIterator.next(); + if (!next['done']) { + return next; + } + } + console.log('Or.next: moving on to next option', optionIndex); + var option = this.options_[optionIndex++]; + if (!option) { + console.log('Or.next: returning done'); + return { 'done': true }; } - } - for (; i < this.options_.length; i++) { - var option = this.options_[i]; lastIterator = option.match(context); - var next = lastIterator.next(); - if (next['done']) { - continue; - } else { - return next; - } } - return { 'done': true }; }.bind(this) }; }; @@ -387,9 +396,11 @@ rr.SingleLineText_ = function() { * @return {rr.typeIterator} */ rr.SingleLineText_.prototype.match = function(context) { + console.log('SingleLineText.match'); var i = 1; return { 'next': function() { + console.log('SingleLineText.next'); if (i <= context.remaining()) { var newString = context.stringAfter(i); if (newString.indexOf('\n') != -1) { @@ -443,6 +454,7 @@ rr.StartOfLine_ = function() { * @return {rr.typeIterator} */ rr.StartOfLine_.prototype.match = function(context) { + console.log('StartOfLine.match'); if (context.atStart()) { return rr.iterableFromArray_([{ 'context': context, @@ -497,6 +509,7 @@ rr.ZeroOrMore_ = function(child) { * @return {rr.typeIterator} */ rr.ZeroOrMore_.prototype.match = function(context) { + console.log('ZeroOrMore.match'); // Yield: // 1) The results of SequentialPair(child, this) // 2) An empty result @@ -508,6 +521,7 @@ rr.ZeroOrMore_.prototype.match = function(context) { var iterator = this.pair_.match(context); return { 'next': function() { + console.log('ZeroOrMore.next'); if (!iterator) { return { 'done': true }; } @@ -559,11 +573,13 @@ rr.SequentialPair_ = function(child1, child2) { * @return {rr.typeIterator} */ rr.SequentialPair_.prototype.match = function(context) { + console.log('SequentialPair.match'); var child1Iterator = this.child1_.match(context); var child1Value = null; var child2Iterator = null; return { 'next': function() { + console.log('SequentialPair.next'); while (true) { if (!child1Value) { child1Value = child1Iterator.next(); @@ -702,5 +718,6 @@ rr.Context.prototype.advance = function(numChars) { } var context = this.copy(); context.inputIndex += numChars; + console.log('New context: ', context.stringAfter()); return context; }; diff --git a/test.js b/test.js index b264202..5609a3d 100644 --- a/test.js +++ b/test.js @@ -3,7 +3,7 @@ QUnit.test('Simple', function(assert) { var context = new rr.Context(mediawiki, '=== Heading ===\n' + 'This is a wiki doc.\n' + - "How about some '''bold and bold italic'''.\n" + + "How about some '''bold and ''bold italic'''''.\n" + 'I would also love some nowiki foo'); var iterable = context.rules['wikidoc'].match(context); assert.equal(iterable.next().value.nodes[0].innerHTML,