Skip to content

Commit f98cab6

Browse files
andrykonchineregon
authored andcommitted
[GR-45621] Add Regex.linear_time? method
PullRequest: truffleruby/4209
2 parents 06edfb7 + 0f96178 commit f98cab6

File tree

4 files changed

+44
-26
lines changed

4 files changed

+44
-26
lines changed

CHANGELOG.md

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

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

1717
Performance:
1818

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: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import com.oracle.truffle.api.dsl.GenerateInline;
3131
import com.oracle.truffle.api.dsl.ImportStatic;
3232
import com.oracle.truffle.api.dsl.NeverDefault;
33-
import com.oracle.truffle.api.interop.InteropException;
3433
import com.oracle.truffle.api.interop.InteropLibrary;
3534
import com.oracle.truffle.api.library.CachedLibrary;
3635
import com.oracle.truffle.api.profiles.InlinedBranchProfile;
@@ -68,6 +67,7 @@
6867
import org.truffleruby.core.string.StringNodes.StringAppendPrimitiveNode;
6968
import org.truffleruby.core.string.StringOperations;
7069
import org.truffleruby.core.string.StringUtils;
70+
import org.truffleruby.interop.InteropNodes;
7171
import org.truffleruby.interop.TranslateInteropExceptionNode;
7272
import org.truffleruby.language.LazyWarnNode;
7373
import org.truffleruby.language.RubyBaseNode;
@@ -965,16 +965,18 @@ static Object matchInRegionTRegex(
965965
tstringToMatch = tstring;
966966
execMethod = "execBoolean";
967967
}
968-
final Object result = invoke(node, regexInterop, tRegex, execMethod, translateInteropExceptionNode,
969-
tstringToMatch, fromIndex);
968+
969+
final Object[] arguments = new Object[]{ tstringToMatch, fromIndex };
970+
final Object result = InteropNodes.invokeMember(node, regexInterop, tRegex, execMethod, arguments,
971+
translateInteropExceptionNode);
970972

971973
if (createMatchDataProfile.profile(node, createMatchData)) {
972-
final boolean isMatch = (boolean) readMember(node, resultInterop, result, "isMatch",
974+
final boolean isMatch = (boolean) InteropNodes.readMember(node, resultInterop, result, "isMatch",
973975
translateInteropExceptionNode);
974976

975977
if (matchFoundProfile.profile(node, isMatch)) {
976978
final int groupCount = groupCountProfile
977-
.profile(node, (int) readMember(node, regexInterop, tRegex, "groupCount",
979+
.profile(node, (int) InteropNodes.readMember(node, regexInterop, tRegex, "groupCount",
978980
translateInteropExceptionNode));
979981
final Region region = new Region(groupCount);
980982

@@ -1033,26 +1035,30 @@ private static Object createMatchData(Node node, RubyRegexp regexp, Object strin
10331035
return matchData;
10341036
}
10351037

1036-
private static Object readMember(Node node, InteropLibrary interop, Object receiver, String name,
1037-
TranslateInteropExceptionNode translateInteropExceptionNode) {
1038-
try {
1039-
return interop.readMember(receiver, name);
1040-
} catch (InteropException e) {
1041-
throw translateInteropExceptionNode.execute(node, e);
1042-
}
1038+
private static Object dupString(Object string, DispatchNode stringDupNode) {
1039+
return stringDupNode.call(string, "dup");
10431040
}
1041+
}
10441042

1045-
private static Object invoke(Node node, InteropLibrary interop, Object receiver, String member,
1046-
TranslateInteropExceptionNode translateInteropExceptionNode, Object... args) {
1047-
try {
1048-
return interop.invokeMember(receiver, member, args);
1049-
} catch (InteropException e) {
1050-
throw translateInteropExceptionNode.executeInInvokeMember(node, e, receiver, args);
1043+
@CoreMethod(names = "linear_time?", onSingleton = true, required = 1)
1044+
public abstract static class IsLinearTimeNode extends CoreMethodArrayArgumentsNode {
1045+
1046+
@Specialization
1047+
Object isLinearTime(RubyRegexp regexp,
1048+
@Cached InlinedConditionProfile tRegexCouldNotCompileProfile,
1049+
@Cached TRegexCompileNode tRegexCompileNode,
1050+
@CachedLibrary(limit = "getInteropCacheLimit()") InteropLibrary regexInterop,
1051+
@Cached TranslateInteropExceptionNode translateInteropExceptionNode,
1052+
@Bind("this") Node node) {
1053+
final Object compiledRegex = tRegexCompileNode.executeTRegexCompile(regexp, false, regexp.encoding);
1054+
1055+
if (tRegexCouldNotCompileProfile.profile(node, compiledRegex == nil)) {
1056+
return nil;
10511057
}
1052-
}
10531058

1054-
private static Object dupString(Object string, DispatchNode stringDupNode) {
1055-
return stringDupNode.call(string, "dup");
1059+
boolean isBacktracking = (boolean) InteropNodes.readMember(node, regexInterop, compiledRegex,
1060+
"isBacktracking", translateInteropExceptionNode);
1061+
return !isBacktracking;
10561062
}
10571063
}
10581064

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)