Skip to content

Commit 351b0ea

Browse files
committed
Add Regex.linear_time? method
1 parent 2f0565d commit 351b0ea

File tree

4 files changed

+49
-5
lines changed

4 files changed

+49
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ Bug fixes:
99

1010
Compatibility:
1111
* Move `IO#wait_readable`, `IO#wait_writable`, `IO#wait_priority` and `IO#wait` into core library (@andrykonchin).
12-
1312
* Change assignment evaluation order for fully qualified constant and evaluate left-hand-side before right-hand-side (#3039, @andrykonchin).
1413
* Fix evaluation order for multi-assignment and evaluate left-hand-side before right-hand-side (@andrykonchin).
14+
* Add `Regexp.linear_time?` method (#3039, @andrykonchin).
1515

1616
Performance:
1717

spec/tags/core/regexp/linear_time_tags.txt

Lines changed: 0 additions & 4 deletions
This file was deleted.

src/main/java/org/truffleruby/core/regexp/TruffleRegexpNodes.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,38 @@ private static Object dupString(Object string, DispatchNode stringDupNode) {
10561056
}
10571057
}
10581058

1059+
@CoreMethod(names = "linear_time?", onSingleton = true, required = 1)
1060+
public abstract static class IsLinearTimeNode extends CoreMethodArrayArgumentsNode {
1061+
1062+
@Specialization
1063+
Object isLinearTime(RubyRegexp regexp,
1064+
@Cached InlinedConditionProfile tRegexCouldNotCompileProfile,
1065+
@Cached TRegexCompileNode tRegexCompileNode,
1066+
@CachedLibrary(limit = "getInteropCacheLimit()") InteropLibrary regexInterop,
1067+
@Cached TranslateInteropExceptionNode translateInteropExceptionNode,
1068+
@Bind("this") Node node) {
1069+
final Object compiledRegex = tRegexCompileNode.executeTRegexCompile(regexp, false, regexp.encoding);
1070+
1071+
if (tRegexCouldNotCompileProfile.profile(node, compiledRegex == nil)) {
1072+
return nil;
1073+
}
1074+
1075+
Object isBacktracking = readMember(node, regexInterop, compiledRegex, "isBacktracking",
1076+
translateInteropExceptionNode);
1077+
return !(boolean) isBacktracking;
1078+
}
1079+
1080+
private static Object readMember(Node node, InteropLibrary interop, Object receiver, String name,
1081+
TranslateInteropExceptionNode translateInteropExceptionNode) {
1082+
try {
1083+
return interop.readMember(receiver, name);
1084+
} catch (InteropException e) {
1085+
throw translateInteropExceptionNode.execute(node, e);
1086+
}
1087+
}
1088+
}
1089+
1090+
10591091
public abstract static class MatchNode extends RubyBaseNode {
10601092

10611093
@Child private DispatchNode dupNode = DispatchNode.create();

src/main/ruby/truffleruby/core/regexp.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,22 @@ def self.last_match(index = nil)
9898
end
9999
end
100100

101+
def self.linear_time?(regexp, options = undefined)
102+
if Primitive.is_a?(regexp, Regexp)
103+
unless Primitive.undefined?(options)
104+
warn('flags ignored', uplevel: 1)
105+
end
106+
else
107+
if Primitive.undefined?(options)
108+
options = 0
109+
end
110+
111+
regexp = Regexp.new(regexp, options) # expect String source to be passed
112+
end
113+
114+
Truffle::RegexpOperations.linear_time?(regexp)
115+
end
116+
101117
def self.union(*patterns)
102118
case patterns.size
103119
when 0

0 commit comments

Comments
 (0)