1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

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 committed by Benoit Daloze
parent 7546be2ca0
commit 9e73177d53
Notes: git 2020-12-03 02:42:32 +09:00
2 changed files with 15 additions and 8 deletions

View file

@ -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 ;

View file

@ -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))