Skip to content

Commit aa85163

Browse files
committed
Force computation of lazy capture groups before resolving group names
This is necessary now that TRegex supports named capture groups sharing the same name.
1 parent 7742b80 commit aa85163

File tree

1 file changed

+45
-21
lines changed

1 file changed

+45
-21
lines changed

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

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
import org.truffleruby.core.regexp.MatchDataNodesFactory.ValuesNodeFactory;
3737
import org.truffleruby.core.rope.Rope;
3838
import org.truffleruby.core.rope.RopeNodes;
39-
import org.truffleruby.core.rope.RopeOperations;
4039
import org.truffleruby.core.string.RubyString;
4140
import org.truffleruby.core.string.StringSupport;
4241
import org.truffleruby.core.string.StringUtils;
@@ -309,26 +308,35 @@ protected Object getIndexSymbolKnownRegexp(RubyMatchData matchData, RubySymbol s
309308
@Cached("getRegexp(matchData)") RubyRegexp cachedRegexp,
310309
@Cached("findNameEntry(cachedRegexp, cachedSymbol)") NameEntry nameEntry,
311310
@Cached("numBackRefs(nameEntry)") int backRefs,
312-
@Cached("backRefIndex(nameEntry)") int backRefIndex) {
311+
@Cached("backRefIndex(nameEntry)") int backRefIndex,
312+
@Cached ConditionProfile lazyProfile,
313+
@CachedLibrary(limit = "getInteropCacheLimit()") InteropLibrary libInterop) {
313314
if (backRefs == 1) {
314315
return executeGetIndex(matchData, backRefIndex, NotProvided.INSTANCE);
315316
} else {
316-
final int i = getBackRef(matchData, cachedRegexp, nameEntry);
317+
final int i = getBackRef(matchData, cachedRegexp, nameEntry, lazyProfile, libInterop);
317318
return executeGetIndex(matchData, i, NotProvided.INSTANCE);
318319
}
319320
}
320321

321322
@Specialization
322-
protected Object getIndexSymbol(RubyMatchData matchData, RubySymbol index, NotProvided length) {
323-
return executeGetIndex(matchData, getBackRefFromSymbol(matchData, index), NotProvided.INSTANCE);
323+
protected Object getIndexSymbol(RubyMatchData matchData, RubySymbol index, NotProvided length,
324+
@Cached ConditionProfile lazyProfile,
325+
@CachedLibrary(limit = "getInteropCacheLimit()") InteropLibrary libInterop) {
326+
return executeGetIndex(
327+
matchData,
328+
getBackRefFromSymbol(matchData, index, lazyProfile, libInterop),
329+
NotProvided.INSTANCE);
324330
}
325331

326332
@Specialization(guards = "libIndex.isRubyString(index)")
327333
protected Object getIndexString(RubyMatchData matchData, Object index, NotProvided length,
328-
@CachedLibrary(limit = "2") RubyStringLibrary libIndex) {
334+
@CachedLibrary(limit = "2") RubyStringLibrary libIndex,
335+
@Cached ConditionProfile lazyProfile,
336+
@CachedLibrary(limit = "getInteropCacheLimit()") InteropLibrary libInterop) {
329337
return executeGetIndex(
330338
matchData,
331-
getBackRefFromRope(matchData, libIndex.getRope(index)),
339+
getBackRefFromRope(matchData, libIndex.getRope(index), lazyProfile, libInterop),
332340
NotProvided.INSTANCE);
333341
}
334342

@@ -388,34 +396,50 @@ protected RubyRegexp getRegexp(RubyMatchData matchData) {
388396
return regexpNode.executeGetRegexp(matchData);
389397
}
390398

391-
@TruffleBoundary
392-
private int getBackRefFromSymbol(RubyMatchData matchData, RubySymbol index) {
393-
return getBackRefFromRope(matchData, index.getRope());
399+
private int getBackRefFromSymbol(RubyMatchData matchData, RubySymbol index, ConditionProfile lazyProfile,
400+
InteropLibrary libInterop) {
401+
return getBackRefFromRope(matchData, index.getRope(), lazyProfile, libInterop);
402+
}
403+
404+
private int getBackRefFromRope(RubyMatchData matchData, Rope value, ConditionProfile lazyProfile,
405+
InteropLibrary libInterop) {
406+
if (lazyProfile.profile(matchData.tRegexResult != null)) {
407+
// force the calculation of lazy capture group results before invoking
408+
// nameToBackrefNumber
409+
forceLazyMatchData(matchData, libInterop);
410+
}
411+
return nameToBackrefNumber(matchData, getRegexp(matchData), value.getBytes(), 0, value.byteLength());
412+
}
413+
414+
private int getBackRef(RubyMatchData matchData, RubyRegexp regexp, NameEntry name, ConditionProfile lazyProfile,
415+
InteropLibrary libInterop) {
416+
if (lazyProfile.profile(matchData.tRegexResult != null)) {
417+
// force the calculation of lazy capture group results before invoking
418+
// nameToBackrefNumber
419+
forceLazyMatchData(matchData, libInterop);
420+
}
421+
return nameToBackrefNumber(matchData, regexp, name.name, name.nameP, name.nameEnd);
394422
}
395423

396424
@TruffleBoundary
397-
private int getBackRefFromRope(RubyMatchData matchData, Rope value) {
425+
private int nameToBackrefNumber(RubyMatchData matchData, RubyRegexp regexp, byte[] name, int nameP,
426+
int nameEnd) {
398427
try {
399-
return getRegexp(matchData).regex.nameToBackrefNumber(
400-
value.getBytes(),
401-
0,
402-
value.byteLength(),
428+
return regexp.regex.nameToBackrefNumber(
429+
name,
430+
nameP,
431+
nameEnd,
403432
matchData.region);
404433
} catch (ValueException e) {
405434
throw new RaiseException(
406435
getContext(),
407436
coreExceptions().indexError(
408437
StringUtils
409-
.format("undefined group name reference: %s", RopeOperations.decodeRope(value)),
438+
.format("undefined group name reference: %s", new String(name, nameP, nameEnd)),
410439
this));
411440
}
412441
}
413442

414-
@TruffleBoundary
415-
private int getBackRef(RubyMatchData matchData, RubyRegexp regexp, NameEntry name) {
416-
return regexp.regex.nameToBackrefNumber(name.name, name.nameP, name.nameEnd, matchData.region);
417-
}
418-
419443
@TruffleBoundary
420444
protected static int numBackRefs(NameEntry nameEntry) {
421445
return nameEntry == null ? 0 : nameEntry.getBackRefs().length;

0 commit comments

Comments
 (0)