Do not reduce quantifiers if it affects which text will be matched

Quantifier reduction when using +?)* and +?)+ should not be done
as it affects which text will be matched.

This removes the need for the RQ_PQ_Q ReduceType, so remove the
enum entry and related switch case.

Test that these are the only two patterns affected by testing all
quantifier reduction tuples for both the captured and uncaptured
cases and making sure the matched text is the same for both.

Fixes [Bug #17341]
This commit is contained in:
Jeremy Evans 2020-11-23 14:40:59 -08:00 коммит произвёл Benoit Daloze
Родитель 7546be2ca0
Коммит 9e73177d53
2 изменённых файлов: 15 добавлений и 8 удалений

Просмотреть файл

@ -2187,7 +2187,6 @@ enum ReduceType {
RQ_AQ, /* to '*?' */
RQ_QQ, /* to '??' */
RQ_P_QQ, /* to '+)??' */
RQ_PQ_Q /* to '+?)?' */
};
static enum ReduceType const ReduceTypeTable[6][6] = {
@ -2197,7 +2196,7 @@ static enum ReduceType const ReduceTypeTable[6][6] = {
{RQ_A, RQ_A, RQ_DEL, RQ_ASIS, RQ_P_QQ, RQ_DEL}, /* '+' */
{RQ_DEL, RQ_AQ, RQ_AQ, RQ_DEL, RQ_AQ, RQ_AQ}, /* '??' */
{RQ_DEL, RQ_DEL, RQ_DEL, RQ_DEL, RQ_DEL, RQ_DEL}, /* '*?' */
{RQ_ASIS, RQ_PQ_Q, RQ_DEL, RQ_AQ, RQ_AQ, RQ_DEL} /* '+?' */
{RQ_ASIS, RQ_ASIS, RQ_ASIS, RQ_AQ, RQ_AQ, RQ_DEL} /* '+?' */
};
extern void
@ -2234,12 +2233,6 @@ onig_reduce_nested_quantifier(Node* pnode, Node* cnode)
c->lower = 1; c->upper = REPEAT_INFINITE; c->greedy = 1;
return ;
break;
case RQ_PQ_Q:
p->target = cnode;
p->lower = 0; p->upper = 1; p->greedy = 1;
c->lower = 1; c->upper = REPEAT_INFINITE; c->greedy = 0;
return ;
break;
case RQ_ASIS:
p->target = cnode;
return ;

Просмотреть файл

@ -1196,6 +1196,20 @@ class TestRegexp < Test::Unit::TestCase
}
end
def test_quantifier_reduction
assert_equal('aa', eval('/(a+?)*/').match('aa')[0])
assert_equal('aa', eval('/(?:a+?)*/').match('aa')[0])
quantifiers = %w'? * + ?? *? +?'
quantifiers.each do |q1|
quantifiers.each do |q2|
r1 = eval("/(a#{q1})#{q2}/").match('aa')[0]
r2 = eval("/(?:a#{q1})#{q2}/").match('aa')[0]
assert_equal(r1, r2)
end
end
end
def test_once
pr1 = proc{|i| /#{i}/o}
assert_equal(/0/, pr1.call(0))