Make ZeroOrMore non-greedy to make it nestable without exponential behavior.
This commit is contained in:
@@ -23,5 +23,5 @@ var mediawiki = {
|
|||||||
rr.Ref('nowiki'),
|
rr.Ref('nowiki'),
|
||||||
rr.Ref('text')
|
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())),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -493,22 +493,18 @@ rr.ZeroOrMore_ = function(child) {
|
|||||||
*/
|
*/
|
||||||
rr.ZeroOrMore_.prototype.match = function(context) {
|
rr.ZeroOrMore_.prototype.match = function(context) {
|
||||||
// Yield:
|
// Yield:
|
||||||
// 1) The results of SequentialPair(child, this)
|
// 1) An empty result
|
||||||
// 2) An empty result
|
// 2) The results of SequentialPair(child, this)
|
||||||
// 3) Done
|
// 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.
|
// that means infinite recursion.
|
||||||
|
|
||||||
var iterator = this.pair_.match(context);
|
var iterator = null;
|
||||||
return {
|
return {
|
||||||
'next': function() {
|
'next': function() {
|
||||||
if (!iterator) {
|
if (!iterator) {
|
||||||
return { 'done': true };
|
iterator = this.pair_.match(context);
|
||||||
}
|
|
||||||
var next = iterator.next();
|
|
||||||
if (next['done']) {
|
|
||||||
iterator = null;
|
|
||||||
return {
|
return {
|
||||||
'done': false,
|
'done': false,
|
||||||
'value': {
|
'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()) {
|
if (next['value']['context'].remaining() == context.remaining()) {
|
||||||
throw "Child of ZeroOrMore didn't consume input; grammar bug?";
|
throw "Child of ZeroOrMore didn't consume input; grammar bug?";
|
||||||
}
|
}
|
||||||
|
|||||||
5
test.js
5
test.js
@@ -8,7 +8,7 @@ QUnit.test('Simple', function(assert) {
|
|||||||
var iterable = context.rules['wikidoc'].match(context);
|
var iterable = context.rules['wikidoc'].match(context);
|
||||||
assert.equal(iterable.next().value.nodes[0].innerHTML,
|
assert.equal(iterable.next().value.nodes[0].innerHTML,
|
||||||
'<h3>Heading</h3>This is a wiki doc.\n' +
|
'<h3>Heading</h3>This is a wiki doc.\n' +
|
||||||
'How about some <b>bold and <i>bold italic</i></b>.\n' +
|
"How about some <b>bold and ''bold italic</b>''.\n" +
|
||||||
'I would also love some nowiki <b>foo</b>');
|
'I would also love some nowiki <b>foo</b>');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -16,7 +16,8 @@ QUnit.test('Simple', function(assert) {
|
|||||||
QUnit.test('ZeroOrMore', function(assert) {
|
QUnit.test('ZeroOrMore', function(assert) {
|
||||||
assert.expect(1);
|
assert.expect(1);
|
||||||
var rules = {
|
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 context = new rr.Context(rules, 'foobar');
|
||||||
var iterable = context.rules['test'].match(context);
|
var iterable = context.rules['test'].match(context);
|
||||||
|
|||||||
Reference in New Issue
Block a user