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:
parent
7546be2ca0
commit
9e73177d53
Notes:
git
2020-12-03 02:42:32 +09:00
2 changed files with 15 additions and 8 deletions
|
@ -2187,7 +2187,6 @@ enum ReduceType {
|
||||||
RQ_AQ, /* to '*?' */
|
RQ_AQ, /* to '*?' */
|
||||||
RQ_QQ, /* to '??' */
|
RQ_QQ, /* to '??' */
|
||||||
RQ_P_QQ, /* to '+)??' */
|
RQ_P_QQ, /* to '+)??' */
|
||||||
RQ_PQ_Q /* to '+?)?' */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum ReduceType const ReduceTypeTable[6][6] = {
|
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_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_AQ, RQ_AQ, RQ_DEL, RQ_AQ, RQ_AQ}, /* '??' */
|
||||||
{RQ_DEL, RQ_DEL, RQ_DEL, RQ_DEL, RQ_DEL, RQ_DEL}, /* '*?' */
|
{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
|
extern void
|
||||||
|
@ -2234,12 +2233,6 @@ onig_reduce_nested_quantifier(Node* pnode, Node* cnode)
|
||||||
c->lower = 1; c->upper = REPEAT_INFINITE; c->greedy = 1;
|
c->lower = 1; c->upper = REPEAT_INFINITE; c->greedy = 1;
|
||||||
return ;
|
return ;
|
||||||
break;
|
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:
|
case RQ_ASIS:
|
||||||
p->target = cnode;
|
p->target = cnode;
|
||||||
return ;
|
return ;
|
||||||
|
|
|
@ -1196,6 +1196,20 @@ class TestRegexp < Test::Unit::TestCase
|
||||||
}
|
}
|
||||||
end
|
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
|
def test_once
|
||||||
pr1 = proc{|i| /#{i}/o}
|
pr1 = proc{|i| /#{i}/o}
|
||||||
assert_equal(/0/, pr1.call(0))
|
assert_equal(/0/, pr1.call(0))
|
||||||
|
|
Loading…
Reference in a new issue