Skip to content

Commit 5459731

Browse files
committed
Expand Regexp.linear_time? specs and clearly categorize specs which only pass on some Regexp engines
1 parent ed5da28 commit 5459731

1 file changed

Lines changed: 37 additions & 8 deletions

File tree

core/regexp/linear_time_spec.rb

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,48 @@
3333
Regexp.linear_time?(/a*(?:(?<=a)a*)*b/).should == true
3434
end
3535

36-
it "returns true for negative lookahead" do
37-
Regexp.linear_time?(/a*(?:(?!a*)a*)*b/).should == true
38-
end
39-
4036
it "returns true for negative lookbehind" do
4137
Regexp.linear_time?(/a*(?:(?<!a)a*)*b/).should == true
4238
end
4339

44-
it "returns true for atomic groups" do
45-
Regexp.linear_time?(/a*(?:(?>a)a*)*b/).should == true
40+
# There are two known ways to make Regexp linear:
41+
# * Using a DFA (deterministic finite-state automaton) Regexp engine, which always matches in linear time (e.g. TruffleRuby with TRegex)
42+
# * Caching position and state to avoid catastrophic backtracking (e.g. CRuby: https://bugs.ruby-lang.org/issues/19104)
43+
#
44+
# Both approach should be allowed and given that DFA Regexp engines
45+
# are much faster there should be no specs preventing using them.
46+
uses_regexp_caching = RUBY_ENGINE == 'ruby'
47+
uses_dfa_regexp_engine = !uses_regexp_caching
48+
49+
# The following specs should not be relied upon,
50+
# they are here only to illustrate differences between Regexp engines.
51+
guard -> { uses_regexp_caching } do
52+
it "returns true for negative lookahead" do
53+
Regexp.linear_time?(/a*(?:(?!a*)a*)*b/).should == true
54+
end
55+
56+
it "returns true for atomic groups" do
57+
Regexp.linear_time?(/a*(?:(?>a)a*)*b/).should == true
58+
end
59+
60+
it "returns true for possessive quantifiers" do
61+
Regexp.linear_time?(/a*(?:(?:a)?+a*)*b/).should == true
62+
end
63+
64+
it "returns true for positive lookbehind with capture group" do
65+
Regexp.linear_time?(/.(?<=(a))/).should == true
66+
end
4667
end
4768

48-
it "returns true for possessive quantifiers" do
49-
Regexp.linear_time?(/a*(?:(?:a)?+a*)*b/).should == true
69+
# The following specs should not be relied upon,
70+
# they are here only to illustrate differences between Regexp engines.
71+
guard -> { uses_dfa_regexp_engine } do
72+
it "returns true for non-recursive subexpression call" do
73+
Regexp.linear_time?(/(?<a>a){0}\g<a>/).should == true
74+
end
75+
76+
it "returns true for positive lookahead with capture group" do
77+
Regexp.linear_time?(/x+(?=(a))/).should == true
78+
end
5079
end
5180
end

0 commit comments

Comments
 (0)