diff --git a/core/src/main/java/org/jruby/RubyComplex.java b/core/src/main/java/org/jruby/RubyComplex.java index 19e05a48580..691bf783570 100644 --- a/core/src/main/java/org/jruby/RubyComplex.java +++ b/core/src/main/java/org/jruby/RubyComplex.java @@ -1289,8 +1289,8 @@ static IRubyObject[] str_to_c_internal(ThreadContext context, RubyString str) { if (m != nil) { RubyMatchData match = (RubyMatchData)m; - sr = match.at(1); - si = match.at(2); + sr = match.at(context, 1); + si = match.at(context, 2); re = match.post_match(context); po = true; } @@ -1301,9 +1301,9 @@ static IRubyObject[] str_to_c_internal(ThreadContext context, RubyString str) { if (m != nil) { RubyMatchData match = (RubyMatchData)m; sr = nil; - si = match.at(1); + si = match.at(context, 1); if (si == nil) si = runtime.newString(); - IRubyObject t = match.at(2); + IRubyObject t = match.at(context, 2); if (t == nil) t = runtime.newString(RubyInteger.singleCharByteList((byte) '1')); ((RubyString) (si = si.convertToString())).cat(t.convertToString()); re = match.post_match(context); @@ -1315,12 +1315,12 @@ static IRubyObject[] str_to_c_internal(ThreadContext context, RubyString str) { m = RubyRegexp.newDummyRegexp(runtime, Numeric.ComplexPatterns.comp_pat2).match_m(context, str, false); if (m == nil) return new IRubyObject[] { context.nil, str }; RubyMatchData match = (RubyMatchData) m; - sr = match.at(1); - if (match.at(2) == nil) { + sr = match.at(context, 1); + if (match.at(context, 2) == nil) { si = context.nil; } else { - si = match.at(3); - IRubyObject t = match.at(4); + si = match.at(context, 3); + IRubyObject t = match.at(context, 4); if (t == nil) t = runtime.newString(RubyInteger.singleCharByteList((byte) '1')); ((RubyString) (si = si.convertToString())).cat(t.convertToString()); } diff --git a/core/src/main/java/org/jruby/RubyGlobal.java b/core/src/main/java/org/jruby/RubyGlobal.java index c1db1859d2f..fae5d88b7e6 100644 --- a/core/src/main/java/org/jruby/RubyGlobal.java +++ b/core/src/main/java/org/jruby/RubyGlobal.java @@ -918,7 +918,8 @@ public PreMatchGlobalVariable(Ruby runtime, String name) { @Override public IRubyObject get() { - return RubyRegexp.match_pre(runtime.getCurrentContext().getBackRef()); + var context = runtime.getCurrentContext(); + return RubyRegexp.match_pre(context, context.getBackRef()); } } @@ -940,7 +941,8 @@ public LastMatchGlobalVariable(Ruby runtime, String name) { @Override public IRubyObject get() { - return RubyRegexp.match_last(runtime.getCurrentContext().getBackRef()); + var context = runtime.getCurrentContext(); + return RubyRegexp.match_last(context, context.getBackRef()); } } diff --git a/core/src/main/java/org/jruby/RubyMatchData.java b/core/src/main/java/org/jruby/RubyMatchData.java index a249c1a22ee..57ef9f804c9 100644 --- a/core/src/main/java/org/jruby/RubyMatchData.java +++ b/core/src/main/java/org/jruby/RubyMatchData.java @@ -34,11 +34,6 @@ package org.jruby; -import java.util.Arrays; -import java.util.Iterator; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - import org.jcodings.Encoding; import org.joni.Matcher; import org.joni.NameEntry; @@ -46,8 +41,8 @@ import org.joni.Region; import org.joni.exception.JOniException; import org.joni.exception.ValueException; -import org.jruby.anno.JRubyMethod; import org.jruby.anno.JRubyClass; +import org.jruby.anno.JRubyMethod; import org.jruby.ast.util.ArgsUtil; import org.jruby.runtime.Arity; import org.jruby.runtime.Block; @@ -60,11 +55,22 @@ import org.jruby.util.RegexpOptions; import org.jruby.util.StringSupport; +import java.util.Arrays; +import java.util.Iterator; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + import static org.jruby.api.Convert.asFixnum; import static org.jruby.api.Convert.asSymbol; -import static org.jruby.api.Create.*; +import static org.jruby.api.Create.newArray; +import static org.jruby.api.Create.newEmptyArray; +import static org.jruby.api.Create.newEmptyString; +import static org.jruby.api.Create.newRawArray; +import static org.jruby.api.Create.newSmallHash; +import static org.jruby.api.Create.newString; import static org.jruby.api.Define.defineClass; import static org.jruby.api.Error.argumentError; +import static org.jruby.api.Error.indexError; import static org.jruby.api.Error.typeError; import static org.jruby.util.RubyStringBuilder.str; @@ -281,29 +287,29 @@ public final boolean used() { return (flags & MATCH_BUSY) != 0; } - final void check() { - if (str == null) throw typeError(getRuntime().getCurrentContext(), "uninitialized Match"); + final void check(ThreadContext context) { + if (str == null) throw typeError(context, "uninitialized Match"); } - final Regex getPattern() { + final Regex getPattern(ThreadContext context) { final Object pattern = this.pattern; - if (pattern instanceof Regex) return (Regex) pattern; - if (pattern == null) throw typeError(getRuntime().getCurrentContext(), "uninitialized Match (missing pattern)"); + if (pattern instanceof Regex regex) return regex; + if (pattern == null) throw typeError(context, "uninitialized Match (missing pattern)"); // when a regexp is avoided for matching we lazily instantiate one from the unquoted string : - Regex regexPattern = RubyRegexp.getQuotedRegexpFromCache(metaClass.runtime, (RubyString) pattern, RegexpOptions.NULL_OPTIONS); + Regex regexPattern = RubyRegexp.getQuotedRegexpFromCache(context, (RubyString) pattern, RegexpOptions.NULL_OPTIONS); this.pattern = regexPattern; return regexPattern; } - private RubyRegexp getRegexp() { + private RubyRegexp getRegexp(ThreadContext context) { RubyRegexp regexp = this.regexp; if (regexp != null) return regexp; - final Regex pattern = getPattern(); - return this.regexp = RubyRegexp.newRegexp(metaClass.runtime, (ByteList) pattern.getUserObject(), pattern); + final Regex pattern = getPattern(context); + return this.regexp = RubyRegexp.newRegexp(context.runtime, (ByteList) pattern.getUserObject(), pattern); } private RubyArray match_array(ThreadContext context, int start) { - check(); + check(context); if (regs == null) { if (start != 0) return newEmptyArray(context); @@ -323,27 +329,40 @@ private RubyArray match_array(ThreadContext context, int start) { return arr.finishRawArray(context); } + @Deprecated(since = "10.0") public IRubyObject group(long n) { - return RubyRegexp.nth_match((int)n, this); + return group(getCurrentContext(), (int) n); } + @Deprecated(since = "10.0") public IRubyObject group(int n) { - return RubyRegexp.nth_match(n, this); + return group(getCurrentContext(), n); } + public IRubyObject group(ThreadContext context, int n) { + return RubyRegexp.nth_match(context, n, this); + } + + @Deprecated(since = "10.0") public int getNameToBackrefNumber(String name) { + return getNameToBackrefNumber(getCurrentContext(), name); + } + + public int getNameToBackrefNumber(ThreadContext context, String name) { try { byte[] bytes = name.getBytes(); - return getPattern().nameToBackrefNumber(bytes, 0, bytes.length, regs); + return getPattern(context).nameToBackrefNumber(bytes, 0, bytes.length, regs); } catch (JOniException je) { - throw metaClass.runtime.newIndexError(je.getMessage()); + throw indexError(context, je.getMessage()); } } // This returns a list of values in the order the names are defined (named capture local var // feature uses this). + @Deprecated(since = "10.0") public IRubyObject[] getNamedBackrefValues(Ruby runtime) { - final Regex pattern = getPattern(); + var context = runtime.getCurrentContext(); + final Regex pattern = getPattern(context); if (pattern.numberOfNames() == 0) return NULL_ARRAY; IRubyObject[] values = new IRubyObject[pattern.numberOfNames()]; @@ -353,7 +372,7 @@ public IRubyObject[] getNamedBackrefValues(Ruby runtime) { NameEntry e = i.next(); int nth = pattern.nameToBackrefNumber(e.name, e.nameP, e.nameEnd, regs); - values[j++] = RubyRegexp.nth_match(nth, this); + values[j++] = RubyRegexp.nth_match(context, nth, this); } return values; @@ -361,7 +380,7 @@ public IRubyObject[] getNamedBackrefValues(Ruby runtime) { @JRubyMethod public IRubyObject byteoffset(ThreadContext context, IRubyObject group) { - int index = backrefNumber(context.runtime, group); + int index = backrefNumber(context, group); Region regs = this.regs; backrefNumberCheck(context, index); @@ -382,7 +401,7 @@ public RubyString inspect(ThreadContext context) { NameEntry[] names = new NameEntry[regs == null ? 1 : regs.getNumRegs()]; - final Regex pattern = getPattern(); + final Regex pattern = getPattern(context); for (Iterator i = pattern.namedBackrefIterator(); i.hasNext();) { NameEntry e = i.next(); for (int num : e.getBackRefs()) names[num] = e; @@ -399,7 +418,7 @@ public RubyString inspect(ThreadContext context) { } result.cat((byte)':'); } - IRubyObject v = RubyRegexp.nth_match(i, this); + IRubyObject v = RubyRegexp.nth_match(context, i, this); if (v.isNil()) { result.cat(RubyNil.nilBytes); // "nil" } else { @@ -412,14 +431,14 @@ public RubyString inspect(ThreadContext context) { @JRubyMethod public RubyRegexp regexp(ThreadContext context, Block block) { - check(); - return getRegexp(); + check(context); + return getRegexp(context); } @JRubyMethod public IRubyObject names(ThreadContext context, Block block) { - check(); - return getRegexp().names(context); + check(context); + return getRegexp(context).names(context); } /** match_to_a @@ -433,17 +452,17 @@ public RubyArray to_a(ThreadContext context) { @JRubyMethod(rest = true) public IRubyObject values_at(ThreadContext context, IRubyObject[] args) { - check(); + check(context); var result = newRawArray(context, args.length); for (IRubyObject arg : args) { - if (arg instanceof RubyFixnum) { - result.append(context, RubyRegexp.nth_match(arg.convertToInteger().getIntValue(), this)); + if (arg instanceof RubyFixnum fix) { + result.append(context, RubyRegexp.nth_match(context, fix.getIntValue(), this)); } else { int num = namevToBackrefNumber(context, arg); if (num >= 0) { - result.append(context, RubyRegexp.nth_match(num, this)); + result.append(context, RubyRegexp.nth_match(context, num, this)); } else { matchAryAref(context, arg, result); } @@ -453,8 +472,9 @@ public IRubyObject values_at(ThreadContext context, IRubyObject[] args) { return result.finishRawArray(context); } + @Deprecated(since = "10.0") public IRubyObject values_at(IRubyObject[] args) { - return values_at(metaClass.runtime.getCurrentContext(), args); + return values_at(getCurrentContext(), args); } /** match_captures @@ -465,22 +485,22 @@ public IRubyObject captures(ThreadContext context) { return match_array(context, 1); } - private int nameToBackrefNumber(RubyString str) { - check(); - return nameToBackrefNumber(metaClass.runtime, getPattern(), regs, str); + private int nameToBackrefNumber(ThreadContext context, RubyString str) { + check(context); + return nameToBackrefNumber(context, getPattern(context), regs, str); } - private static int nameToBackrefNumber(Ruby runtime, Regex pattern, Region regs, ByteListHolder str) { + private static int nameToBackrefNumber(ThreadContext context, Regex pattern, Region regs, ByteListHolder str) { assert pattern != null; ByteList value = str.getByteList(); try { return pattern.nameToBackrefNumber(value.getUnsafeBytes(), value.getBegin(), value.getBegin() + value.getRealSize(), regs); } catch (JOniException je) { if (je instanceof ValueException) { - throw runtime.newIndexError(str(runtime, "undefined group name reference: ", runtime.newString(value))); + throw context.runtime.newIndexError(str(context.runtime, "undefined group name reference: ", newString(context, value))); } // FIXME: I think we could only catch ValueException here, but someone needs to audit that. - throw runtime.newIndexError(je.getMessage()); + throw context.runtime.newIndexError(je.getMessage()); } } @@ -492,16 +512,24 @@ private static int nameToBackrefNumber(Regex pattern, Region regs, ByteList name } } + @Deprecated(since = "10.0") public final int backrefNumber(Ruby runtime, IRubyObject obj) { - check(); - return backrefNumber(runtime, getPattern(), regs, obj); + return backrefNumber(runtime.getCurrentContext(), obj); } + public final int backrefNumber(ThreadContext context, IRubyObject obj) { + check(context); + return backrefNumber(context, getPattern(context), regs, obj); + } + + @Deprecated(since = "10.0") public static int backrefNumber(Ruby runtime, Regex pattern, Region regs, IRubyObject obj) { - if (obj instanceof RubySymbol sym) { - return nameToBackrefNumber(runtime, pattern, regs, (RubyString) sym.to_s(runtime.getCurrentContext())); - } - if (obj instanceof RubyString str) return nameToBackrefNumber(runtime, pattern, regs, str); + return backrefNumber(runtime.getCurrentContext(), pattern, regs, obj); + } + + public static int backrefNumber(ThreadContext context, Regex pattern, Region regs, IRubyObject obj) { + if (obj instanceof RubySymbol sym) return nameToBackrefNumber(context, pattern, regs, (RubyString) sym.to_s(context)); + if (obj instanceof RubyString str) return nameToBackrefNumber(context, pattern, regs, str); return RubyNumeric.num2int(obj); } @@ -516,8 +544,8 @@ private int namevToBackrefNumber(ThreadContext context, IRubyObject name) { case STRING: Ruby runtime = context.runtime; if (regexp.isNil() || RubyEncoding.areCompatible(regexp, name) == null || - (num = nameToBackrefNumber(runtime, regexp.getPattern(), regs, name.convertToString())) < 1) { - nameToBackrefError(runtime, name.toString()); + (num = nameToBackrefNumber(context, regexp.getPattern(context), regs, name.convertToString())) < 1) { + nameToBackrefError(context, name.toString()); } return num; @@ -526,8 +554,8 @@ private int namevToBackrefNumber(ThreadContext context, IRubyObject name) { } } - private int nameToBackrefError(Ruby runtime, String name) { - throw runtime.newIndexError("undefined group name reference " + name); + private int nameToBackrefError(ThreadContext context, String name) { + throw context.runtime.newIndexError("undefined group name reference " + name); } // MRI: match_ary_subseq @@ -541,7 +569,7 @@ private IRubyObject matchArySubseq(ThreadContext context, int beg, int len, Ruby if (len == 0) return result; for (j = beg; j < end; j++) { - result.append(context, RubyRegexp.nth_match(j, this)); + result.append(context, RubyRegexp.nth_match(context, j, this)); } // if not enough groups, force length to be as wide as desired by setting last value to nil @@ -564,7 +592,7 @@ private IRubyObject matchAryAref(ThreadContext context, IRubyObject index, RubyA if (isRange.isNil()) return context.nil; if (!isRange.isTrue()) { - IRubyObject nthMatch = RubyRegexp.nth_match(index.convertToInteger().getIntValue(), this); + IRubyObject nthMatch = RubyRegexp.nth_match(context, index.convertToInteger().getIntValue(), this); // this should never happen here, but MRI allows any VALUE for result // if (result.isNil()) return nthMatch; @@ -580,7 +608,7 @@ private IRubyObject matchAryAref(ThreadContext context, IRubyObject index, RubyA */ @JRubyMethod(name = "[]") public IRubyObject op_aref(ThreadContext context, IRubyObject idx) { - check(); + check(context); IRubyObject result = op_arefCommon(context, idx); return result == null ? to_a(context).aref(context, idx) : result; } @@ -598,20 +626,22 @@ public IRubyObject op_aref(ThreadContext context, IRubyObject idx, IRubyObject r private IRubyObject op_arefCommon(ThreadContext context, IRubyObject idx) { if (idx instanceof RubyFixnum) { int num = RubyNumeric.fix2int(idx); - if (num >= 0) return RubyRegexp.nth_match(num, this); - } else { - if (idx instanceof RubySymbol) { - return RubyRegexp.nth_match(nameToBackrefNumber((RubyString) ((RubySymbol) idx).to_s(context)), this); - } - if (idx instanceof RubyString) { - return RubyRegexp.nth_match(nameToBackrefNumber((RubyString) idx), this); - } + if (num >= 0) return RubyRegexp.nth_match(context, num, this); + } else if (idx instanceof RubySymbol index) { + return RubyRegexp.nth_match(context, nameToBackrefNumber(context, (RubyString) index.to_s(context)), this); + } else if (idx instanceof RubyString index) { + return RubyRegexp.nth_match(context, nameToBackrefNumber(context, index), this); } return null; } + @Deprecated(since = "10.0") public final IRubyObject at(final int nth) { - return RubyRegexp.nth_match(nth, this); + return at(getCurrentContext(), nth); + } + + public final IRubyObject at(ThreadContext context, final int nth) { + return RubyRegexp.nth_match(context, nth, this); } /** match_size @@ -619,7 +649,7 @@ public final IRubyObject at(final int nth) { */ @JRubyMethod(name = {"size", "length"}) public IRubyObject size(ThreadContext context) { - check(); + check(context); return regs == null ? RubyFixnum.one(context.runtime) : asFixnum(context, regs.getNumRegs()); } @@ -628,8 +658,8 @@ public IRubyObject size(ThreadContext context) { */ @JRubyMethod public IRubyObject begin(ThreadContext context, IRubyObject index) { - check(); - final int i = backrefNumber(context.runtime, index); + check(context); + final int i = backrefNumber(context, index); backrefNumberCheck(context, i); @@ -646,9 +676,9 @@ public IRubyObject begin(ThreadContext context, IRubyObject index) { */ @JRubyMethod public IRubyObject end(ThreadContext context, IRubyObject index) { - check(); + check(context); - final int i = backrefNumber(context.runtime, index); + final int i = backrefNumber(context, index); backrefNumberCheck(context, i); @@ -673,9 +703,9 @@ public IRubyObject offset19(ThreadContext context, IRubyObject index) { */ @JRubyMethod(name = "offset") public IRubyObject offset(ThreadContext context, IRubyObject index) { - check(); + check(context); - final int i = backrefNumber(context.runtime, index); + final int i = backrefNumber(context, index); backrefNumberCheck(context, i); int b, e; @@ -703,10 +733,8 @@ public IRubyObject offset(ThreadContext context, IRubyObject index) { */ @JRubyMethod public IRubyObject pre_match(ThreadContext context) { - check(); - if (begin == -1) return context.nil; - - return str.makeSharedString(context.runtime, 0, begin); + check(context); + return begin == -1 ? context.nil : str.makeSharedString(context.runtime, 0, begin); } @JRubyMethod @@ -768,11 +796,10 @@ private void backrefNumberCheck(ThreadContext context, int i) { */ @JRubyMethod public IRubyObject post_match(ThreadContext context) { - check(); - if (begin == -1) return context.nil; + check(context); - final int strLen = str.getByteList().length(); - return str.makeSharedString(context.runtime, end, strLen - end); + return begin == -1 ? + context.nil : str.makeSharedString(context.runtime, end, str.getByteList().length() - end); } /** match_to_s @@ -781,17 +808,21 @@ public IRubyObject post_match(ThreadContext context) { @JRubyMethod @Override public IRubyObject to_s(ThreadContext context) { - check(); + check(context); IRubyObject ss = RubyRegexp.last_match(this); return ss.isNil() ? newEmptyString(context) : ss; } + @Deprecated(since = "10.0") + public IRubyObject string() { + return string(getCurrentContext()); + } /** match_string * */ @JRubyMethod - public IRubyObject string() { - check(); + public IRubyObject string(ThreadContext context) { + check(context); return str; //str is frozen } @@ -813,8 +844,10 @@ public boolean equals(Object other) { if (this == other) return true; if (!(other instanceof RubyMatchData that)) return false; + var context = getRuntime().getCurrentContext(); + return (this.str == that.str || (this.str != null && this.str.equals(that.str))) && - (this.regexp == that.regexp || (this.getRegexp().equals(that.getRegexp()))) && + (this.regexp == that.regexp || (this.getRegexp(context).equals(that.getRegexp(context)))) && (this.charOffsets == that.charOffsets || (this.charOffsets != null && this.charOffsets.equals(that.charOffsets))) && this.charOffsetUpdated == that.charOffsetUpdated && this.begin == that.begin && this.end == that.end; @@ -827,8 +860,9 @@ public IRubyObject eql_p(ThreadContext context, IRubyObject obj) { @Override public int hashCode() { - check(); - return getPattern().hashCode() ^ str.hashCode(); + var context = getRuntime().getCurrentContext(); + check(context); + return getPattern(context).hashCode() ^ str.hashCode(); } @JRubyMethod @@ -838,7 +872,7 @@ public RubyFixnum hash(ThreadContext context) { @JRubyMethod(keywords = true, optional = 1) public RubyHash named_captures(ThreadContext context, IRubyObject[] args) { - check(); + check(context); int argc = Arity.checkArgumentCount(context, args.length, 0, 0, true); RubyHash hash = newSmallHash(context); @@ -846,8 +880,8 @@ public RubyHash named_captures(ThreadContext context, IRubyObject[] args) { final boolean symbolizeNames; if (argc == 1) { - if (!(args[0] instanceof RubyHash)) throw argumentError(context, 1, 0); - IRubyObject value = ArgsUtil.extractKeywordArg(context, (RubyHash) args[0], "symbolize_names"); + if (!(args[0] instanceof RubyHash opts)) throw argumentError(context, 1, 0); + IRubyObject value = ArgsUtil.extractKeywordArg(context, opts, "symbolize_names"); symbolizeNames = value != null && value.isTrue(); } else { symbolizeNames = false; @@ -858,7 +892,7 @@ public RubyHash named_captures(ThreadContext context, IRubyObject[] args) { boolean found = false; for (int b : entry.getBackRefs()) { - IRubyObject value = RubyRegexp.nth_match(b, this); + IRubyObject value = RubyRegexp.nth_match(context, b, this); if (value.isTrue()) { hash.op_aset(context, key, value); @@ -886,12 +920,12 @@ public IRubyObject deconstruct_keys(ThreadContext context, IRubyObject what) { RubySymbol key = symbolFromNameEntry(context, entry); for (int b : entry.getBackRefs()) { - IRubyObject value = RubyRegexp.nth_match(b, this); + IRubyObject value = RubyRegexp.nth_match(context, b, this); if (value.isTrue()) hash.op_aset(context, key, value); } }); } else if (what instanceof RubyArray arr) { - if (getPattern().numberOfNames() < arr.size()) return hash; + if (getPattern(context).numberOfNames() < arr.size()) return hash; Iterable iterable = () -> arr.rubyStream().iterator(); for (IRubyObject obj : iterable) { @@ -899,10 +933,10 @@ public IRubyObject deconstruct_keys(ThreadContext context, IRubyObject what) { throw typeError(context, str(context.runtime, "wrong argument type ", obj.getMetaClass(), " (expected Symbol)")); } - int index = nameToBackrefNumber(getPattern(), regs, requestedKey.getBytes()); + int index = nameToBackrefNumber(getPattern(context), regs, requestedKey.getBytes()); if (index == -1) break; - IRubyObject value = RubyRegexp.nth_match(index, this); + IRubyObject value = RubyRegexp.nth_match(context, index, this); if (!value.isTrue()) break; hash.op_aset(context, requestedKey, value); @@ -914,7 +948,7 @@ public IRubyObject deconstruct_keys(ThreadContext context, IRubyObject what) { } private Stream getNamedBackrefKeys(ThreadContext context) { - Iterable iterable = () -> getPattern().namedBackrefIterator(); + Iterable iterable = () -> getPattern(context).namedBackrefIterator(); return StreamSupport.stream(iterable.spliterator(), false); } @@ -972,17 +1006,17 @@ public int numRegs() { @Deprecated @Override public RubyArray to_a() { - return match_array(getRuntime().getCurrentContext(), 0); + return match_array(getCurrentContext(), 0); } @Deprecated public IRubyObject op_aref(IRubyObject idx) { - return op_aref(getRuntime().getCurrentContext(), idx); + return op_aref(getCurrentContext(), idx); } @Deprecated public IRubyObject op_aref(IRubyObject idx, IRubyObject rest) { - return op_aref(getRuntime().getCurrentContext(), idx, rest); + return op_aref(getCurrentContext(), idx, rest); } } diff --git a/core/src/main/java/org/jruby/RubyRational.java b/core/src/main/java/org/jruby/RubyRational.java index f61da07a417..0725478dc66 100644 --- a/core/src/main/java/org/jruby/RubyRational.java +++ b/core/src/main/java/org/jruby/RubyRational.java @@ -1422,9 +1422,9 @@ static IRubyObject[] str_to_r_internal(final ThreadContext context, final RubySt } if (m != nil) { RubyMatchData match = (RubyMatchData) m; - IRubyObject si = match.at(1); - RubyString nu = (RubyString) match.at(2); - IRubyObject de = match.at(3); + IRubyObject si = match.at(context, 1); + RubyString nu = (RubyString) match.at(context, 2); + IRubyObject de = match.at(context, 3); IRubyObject re = match.post_match(context); var a = nu.split(context, RubyRegexp.newDummyRegexp(context.runtime, Numeric.RationalPatterns.an_e_pat)); diff --git a/core/src/main/java/org/jruby/RubyRegexp.java b/core/src/main/java/org/jruby/RubyRegexp.java index 2e2ca4ea47a..632bdf7f4e2 100755 --- a/core/src/main/java/org/jruby/RubyRegexp.java +++ b/core/src/main/java/org/jruby/RubyRegexp.java @@ -37,10 +37,6 @@ package org.jruby; -import static org.jruby.RubyNumeric.fix2int; -import static org.jruby.anno.FrameField.BACKREF; -import static org.jruby.anno.FrameField.LASTLINE; - import org.jcodings.Encoding; import org.jcodings.specific.ASCIIEncoding; import org.jcodings.specific.USASCIIEncoding; @@ -56,7 +52,6 @@ import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; import org.jruby.api.Convert; -import org.jruby.common.IRubyWarnings.ID; import org.jruby.exceptions.RaiseException; import org.jruby.parser.ReOptions; import org.jruby.runtime.Block; @@ -76,14 +71,27 @@ import org.jruby.util.StringSupport; import org.jruby.util.TypeConverter; import org.jruby.util.cli.Options; -import org.jruby.util.io.EncodingUtils; import org.jruby.util.collections.WeakValuedMap; +import org.jruby.util.io.EncodingUtils; + +import java.util.Iterator; +import static org.jruby.RubyNumeric.fix2int; +import static org.jruby.anno.FrameField.BACKREF; +import static org.jruby.anno.FrameField.LASTLINE; import static org.jruby.api.Access.instanceConfig; -import static org.jruby.api.Convert.*; -import static org.jruby.api.Create.*; +import static org.jruby.api.Convert.asBoolean; +import static org.jruby.api.Convert.asFixnum; +import static org.jruby.api.Convert.asFloat; +import static org.jruby.api.Convert.asSymbol; +import static org.jruby.api.Create.dupString; +import static org.jruby.api.Create.newEmptyArray; +import static org.jruby.api.Create.newHash; +import static org.jruby.api.Create.newString; import static org.jruby.api.Define.defineClass; -import static org.jruby.api.Error.*; +import static org.jruby.api.Error.argumentError; +import static org.jruby.api.Error.runtimeError; +import static org.jruby.api.Error.typeError; import static org.jruby.api.Warn.warn; import static org.jruby.api.Warn.warning; import static org.jruby.runtime.ThreadContext.resetCallInfo; @@ -91,8 +99,6 @@ import static org.jruby.util.StringSupport.CR_7BIT; import static org.jruby.util.StringSupport.EMPTY_STRING_ARRAY; -import java.util.Iterator; - @JRubyClass(name="Regexp") public class RubyRegexp extends RubyObject implements ReOptions, EncodingCapable, MarshalEncoding { Regex pattern; @@ -184,13 +190,13 @@ public static Regex getRegexpFromCache(Ruby runtime, ByteList bytes, Encoding en return regex; } - static Regex getQuotedRegexpFromCache(Ruby runtime, RubyString str, RegexpOptions options) { + static Regex getQuotedRegexpFromCache(ThreadContext context, RubyString str, RegexpOptions options) { final ByteList bytes = str.getByteList(); Regex regex = quotedPatternCache.get(bytes); Encoding enc = str.isAsciiOnly() ? USASCIIEncoding.INSTANCE : bytes.getEncoding(); if (regex != null && regex.getEncoding() == enc && regex.getOptions() == options.toJoniOptions()) return regex; final ByteList quoted = quote(str); - regex = makeRegexp(runtime, quoted, options, quoted.getEncoding()); + regex = makeRegexp(context.runtime, quoted, options, quoted.getEncoding()); regex.setUserObject(quoted); quotedPatternCache.put(bytes, regex); return regex; @@ -376,26 +382,36 @@ public static RubyRegexp newRegexpFromStr(Ruby runtime, RubyString s, int option return re; } + @Deprecated(since = "10.0") + public final RegexpOptions getOptions() { + return getOptions(getCurrentContext()); + } + /** rb_reg_options */ - public final RegexpOptions getOptions() { - check(); + public final RegexpOptions getOptions(ThreadContext context) { + check(context); return options; } + @Deprecated(since = "10.0") public final Regex getPattern() { - check(); + return getPattern(getCurrentContext()); + } + + public final Regex getPattern(ThreadContext context) { + check(context); return pattern; } - final Encoding checkEncoding(RubyString other) { + Encoding checkEncoding(ThreadContext context, RubyString other) { Encoding enc = other.isCompatibleWith(this); - if (enc == null) encodingMatchError(getRuntime(), pattern, other.getEncoding()); + if (enc == null) encodingMatchError(context, pattern, other.getEncoding()); return enc; } - private static void encodingMatchError(Ruby runtime, Regex pattern, Encoding strEnc) { - throw runtime.newEncodingCompatibilityError("incompatible encoding regexp match (" + + private static void encodingMatchError(ThreadContext context, Regex pattern, Encoding strEnc) { + throw context.runtime.newEncodingCompatibilityError("incompatible encoding regexp match (" + pattern.getEncoding() + " regexp with " + strEnc + " string)"); } @@ -404,17 +420,17 @@ private Encoding prepareEncoding(ThreadContext context, RubyString str, boolean int cr = str.scanForCodeRange(); if (cr == StringSupport.CR_BROKEN) throw argumentError(context, "invalid byte sequence in " + enc); - check(); + check(context); Encoding patternEnc = pattern.getEncoding(); if (patternEnc == enc) { } else if (cr == StringSupport.CR_7BIT && patternEnc == USASCIIEncoding.INSTANCE) { enc = patternEnc; } else if (!enc.isAsciiCompatible()) { - encodingMatchError(getRuntime(), pattern, enc); + encodingMatchError(context, pattern, enc); } else if (options.isFixed()) { if (enc != patternEnc && (!patternEnc.isAsciiCompatible() || - cr != StringSupport.CR_7BIT)) encodingMatchError(getRuntime(), pattern, enc); + cr != StringSupport.CR_7BIT)) encodingMatchError(context, pattern, enc); enc = patternEnc; } if (warn && isEncodingNone() && enc != ASCIIEncoding.INSTANCE && cr != StringSupport.CR_7BIT) { @@ -630,8 +646,8 @@ private static Encoding processDRegexpElement(ThreadContext context, RegexpOptio return regexpEnc; } - private void check() { - if (pattern == null) throw typeError(getRuntime().getCurrentContext(),"uninitialized Regexp"); + private void check(ThreadContext context) { + if (pattern == null) throw typeError(context, "uninitialized Regexp"); } @JRubyMethod(meta = true) @@ -781,12 +797,9 @@ public static IRubyObject last_match_s(ThreadContext context, IRubyObject recv) */ @JRubyMethod(name = "last_match", meta = true, reads = BACKREF) public static IRubyObject last_match_s(ThreadContext context, IRubyObject recv, IRubyObject nth) { - IRubyObject backref = context.getBackRef(); - if (backref instanceof RubyMatchData) { - RubyMatchData match = ((RubyMatchData) backref); - return nth_match(match.backrefNumber(context.runtime, nth), match); - } - return backref; // nil + return context.getBackRef() instanceof RubyMatchData match ? + nth_match(context, match.backrefNumber(context, nth), match) : + context.nil; } /** rb_reg_s_union @@ -829,7 +842,7 @@ public static IRubyObject union(ThreadContext context, IRubyObject recv, IRubyOb } else if (hasAsciiIncompat != enc) { // n kcode doesn't match first one throw argumentError(context, "incompatible encodings: " + hasAsciiIncompat + " and " + enc); } - } else if (regex.getOptions().isFixed()) { + } else if (regex.getOptions(context).isFixed()) { if (hasAsciiCompatFixed == null) { // First regexp of union sets kcode. hasAsciiCompatFixed = enc; } else if (hasAsciiCompatFixed != enc) { // n kcode doesn't match first one @@ -897,23 +910,18 @@ public IRubyObject initialize_copy(ThreadContext context, IRubyObject re) { } RubyRegexp regexp = (RubyRegexp)re; - regexp.check(); + regexp.check(context); - return regexpInitialize(regexp.str, regexp.str.getEncoding(), regexp.getOptions(), regexp.timeout); + return regexpInitialize(regexp.str, regexp.str.getEncoding(), regexp.getOptions(context), regexp.timeout); } private static int objectAsJoniOptions(ThreadContext context, IRubyObject arg) { - Ruby runtime = arg.getRuntime(); if (arg instanceof RubyFixnum) return fix2int(arg); - if (arg instanceof RubyString) return RegexpOptions.fromByteList(runtime, ((RubyString) arg).getByteList()).toJoniOptions(); - if (arg instanceof RubyBoolean) { - if (arg.isTrue()) return RE_OPTION_IGNORECASE; - - return 0; - } + if (arg instanceof RubyString str) return RegexpOptions.fromByteList(context, str.getByteList()).toJoniOptions(); + if (arg instanceof RubyBoolean) return arg.isTrue() ? RE_OPTION_IGNORECASE : 0; if (arg.isNil()) return 0; - warning(context, str(runtime, "expected true or false as ignorecase: ", arg)); + warning(context, str(context.runtime, "expected true or false as ignorecase: ", arg)); return RE_OPTION_IGNORECASE; } @@ -926,7 +934,7 @@ public IRubyObject initialize_m(IRubyObject arg) { @JRubyMethod(name = "initialize", visibility = Visibility.PRIVATE) public IRubyObject initialize_m(ThreadContext context, IRubyObject arg) { return arg instanceof RubyRegexp regexp ? - initializeByRegexp(regexp, null) : + initializeByRegexp(context, regexp, null) : regexpInitializeString(context, arg.convertToString(), new RegexpOptions(), null); } @@ -944,11 +952,11 @@ public IRubyObject initialize_m(ThreadContext context, IRubyObject arg0, IRubyOb if (keywords) { regexpOptions = new RegexpOptions(); timeout = timeoutFromArg(context, arg1); - if (arg0 instanceof RubyRegexp regexp) return initializeByRegexp(regexp, timeout); + if (arg0 instanceof RubyRegexp regexp) return initializeByRegexp(context, regexp, timeout); } else { if (arg0 instanceof RubyRegexp && Options.PARSER_WARN_FLAGS_IGNORED.load()) { warn(context, "flags ignored"); - return initializeByRegexp((RubyRegexp)arg0, null); + return initializeByRegexp(context, (RubyRegexp)arg0, null); } regexpOptions = RegexpOptions.fromJoniOptions(objectAsJoniOptions(context, arg1)); timeout = null; @@ -975,7 +983,7 @@ public IRubyObject initialize_m(ThreadContext context, IRubyObject arg0, IRubyOb if (arg0 instanceof RubyRegexp && Options.PARSER_WARN_FLAGS_IGNORED.load()) { warn(context, "flags ignored"); - return initializeByRegexp((RubyRegexp)arg0, timeoutFromArg(context, arg2)); + return initializeByRegexp(context, (RubyRegexp)arg0, timeoutFromArg(context, arg2)); } RegexpOptions newOptions = RegexpOptions.fromJoniOptions(objectAsJoniOptions(context, arg1)); @@ -988,10 +996,10 @@ private IRubyObject timeoutFromArg(ThreadContext context, IRubyObject arg) { return Convert.castAsHash(context, arg).fastARef(asSymbol(context, "timeout")); } - private IRubyObject initializeByRegexp(RubyRegexp regexp, IRubyObject timeoutProvided) { + private IRubyObject initializeByRegexp(ThreadContext context, RubyRegexp regexp, IRubyObject timeoutProvided) { // Clone and toggle flags since this is no longer a literal regular expression // but it did come from one. - RegexpOptions newOptions = regexp.getOptions().clone(); + RegexpOptions newOptions = regexp.getOptions(context).clone(); newOptions.setLiteral(false); return regexpInitialize(regexp.str, regexp.getEncoding(), newOptions, timeoutProvided != null ? timeoutProvided : regexp.timeout); } @@ -1054,7 +1062,7 @@ public final RubyRegexp regexpInitialize(ByteList bytes, Encoding enc, RegexpOpt @JRubyMethod public RubyFixnum hash(ThreadContext context) { - check(); + check(context); int hash = pattern.getOptions(); int len = str.getRealSize(); int p = str.getBegin(); @@ -1069,12 +1077,10 @@ public RubyFixnum hash(ThreadContext context) { @Override public IRubyObject op_equal(ThreadContext context, IRubyObject other) { if (this == other) return context.tru; - if (!(other instanceof RubyRegexp)) return context.fals; + if (!(other instanceof RubyRegexp otherRegex)) return context.fals; - RubyRegexp otherRegex = (RubyRegexp) other; - - check(); - otherRegex.check(); + check(context); + otherRegex.check(context); return asBoolean(context, str.equal(otherRegex.str) && options.equals(otherRegex.options)); } @@ -1394,7 +1400,7 @@ static RubyMatchData createMatchData(ThreadContext context, RubyString str, int @JRubyMethod public IRubyObject options(ThreadContext context) { - return asFixnum(context, getOptions().toOptions()); + return asFixnum(context, getOptions(context).toOptions()); } @Deprecated @@ -1404,7 +1410,7 @@ public IRubyObject options() { @JRubyMethod(name = "casefold?") public IRubyObject casefold_p(ThreadContext context) { - return asBoolean(context, getOptions().isIgnorecase()); + return asBoolean(context, getOptions(context).isIgnorecase()); } /** rb_reg_source @@ -1412,7 +1418,7 @@ public IRubyObject casefold_p(ThreadContext context) { */ @JRubyMethod public IRubyObject source(ThreadContext context) { - check(); + check(context); var enc = pattern == null ? str.getEncoding() : pattern.getEncoding(); ByteList newStr = str.dup(); newStr.setEncoding(enc); @@ -1448,7 +1454,7 @@ public IRubyObject inspect(ThreadContext context) { @Override @JRubyMethod public RubyString to_s(ThreadContext context) { - check(); + check(context); RegexpOptions newOptions = options.clone(); int p = str.getBegin(); @@ -1555,7 +1561,7 @@ public String[] getNames() { */ @JRubyMethod public IRubyObject names(ThreadContext context) { - check(); + check(context); if (pattern.numberOfNames() == 0) return newEmptyArray(context); @@ -1574,7 +1580,7 @@ public IRubyObject names(ThreadContext context) { */ @JRubyMethod public IRubyObject named_captures(ThreadContext context) { - check(); + check(context); RubyHash hash = newHash(context); if (pattern.numberOfNames() == 0) return hash; @@ -1643,83 +1649,106 @@ public static IRubyObject linear_time_p(ThreadContext context, IRubyObject recv, return pattern != null && pattern.isLinear() ? context.tru : context.fals; } + @Deprecated(since = "10.0") + public static IRubyObject nth_match(int nth, IRubyObject match) { + return nth_match(((RubyBasicObject) match).getCurrentContext(), nth, match); + } + /** rb_reg_nth_match * */ - public static IRubyObject nth_match(int nth, IRubyObject match) { - if (match.isNil()) return match; - return nth_match(nth, (RubyMatchData) match); + public static IRubyObject nth_match(ThreadContext context, int nth, IRubyObject matchArg) { + return matchArg instanceof RubyMatchData match ? + nth_match(context, nth, match) : context.nil; } - static IRubyObject nth_match(int nth, RubyMatchData match) { - match.check(); + static IRubyObject nth_match(ThreadContext context, int nth, RubyMatchData match) { + match.check(context); final int start, end; if (match.regs == null) { - if (nth >= 1 || (nth < 0 && ++nth <= 0)) return match.getRuntime().getNil(); + if (nth >= 1 || (nth < 0 && ++nth <= 0)) return context.nil; start = match.begin; end = match.end; } else { if (nth >= match.regs.getNumRegs() || (nth < 0 && (nth+=match.regs.getNumRegs()) <= 0)) { - return match.getRuntime().getNil(); + return context.nil; } start = match.regs.getBeg(nth); end = match.regs.getEnd(nth); } - if (start == -1) return match.getRuntime().getNil(); + return start == -1 ? + context.nil : match.str.makeSharedString(context.runtime, start, end - start); + } - return match.str.makeSharedString(match.metaClass.runtime, start, end - start); + @Deprecated(since = "10.0") + public static IRubyObject last_match(IRubyObject match) { + return last_match(((RubyBasicObject) match).getCurrentContext(), match); } /** rb_reg_last_match * */ - public static IRubyObject last_match(IRubyObject match) { - return nth_match(0, match); + public static IRubyObject last_match(ThreadContext context, IRubyObject match) { + return nth_match(context, 0, match); + } + + + @Deprecated(since = "10.0") + public static IRubyObject match_pre(IRubyObject match) { + return match_pre(((RubyBasicObject) match).getCurrentContext(), match); } /** rb_reg_match_pre * */ - public static IRubyObject match_pre(IRubyObject match) { - if (match.isNil()) return match; - RubyMatchData m = (RubyMatchData)match; - m.check(); + public static IRubyObject match_pre(ThreadContext context, IRubyObject matchArg) { + if (!(matchArg instanceof RubyMatchData match)) return context.nil; + + match.check(context); + + return match.begin == -1 ? + context.nil : match.str.makeShared(context.runtime, 0, match.begin); + } - Ruby runtime = m.getRuntime(); - if (m.begin == -1) return runtime.getNil(); - return m.str.makeShared(runtime, 0, m.begin); + @Deprecated(since = "10.0") + public static IRubyObject match_post(IRubyObject match) { + return match_post(((RubyBasicObject) match).getCurrentContext(), match); } /** rb_reg_match_post * */ - public static IRubyObject match_post(IRubyObject match) { - if (match.isNil()) return match; - RubyMatchData m = (RubyMatchData)match; - m.check(); + public static IRubyObject match_post(ThreadContext context, IRubyObject matchArg) { + if (!(matchArg instanceof RubyMatchData match)) return context.nil; + + match.check(context); - Ruby runtime = m.getRuntime(); - if (m.begin == -1) return runtime.getNil(); - return m.str.makeShared(runtime, m.end, m.str.getByteList().getRealSize() - m.end); + return match.begin != -1 ? + match.str.makeShared(context.runtime, match.end, match.str.getByteList().getRealSize() - match.end) : + context.nil; + } + + @Deprecated(since = "10.0") + public static IRubyObject match_last(IRubyObject match) { + return match_last(((RubyBasicObject) match).getCurrentContext(), match); } /** rb_reg_match_last * */ - public static IRubyObject match_last(IRubyObject match) { - if (match.isNil()) return match; - RubyMatchData m = (RubyMatchData) match; - m.check(); + public static IRubyObject match_last(ThreadContext context, IRubyObject matchArg) { + if (!(matchArg instanceof RubyMatchData match)) return matchArg; - if (m.regs == null || m.regs.getBeg(0) == -1) return m.getRuntime().getNil(); + match.check(context); + + if (match.regs == null || match.regs.getBeg(0) == -1) return context.nil; int i; - for (i = m.regs.getNumRegs() - 1; m.regs.getBeg(i) == -1 && i > 0; i--); - if (i == 0) return m.getRuntime().getNil(); + for (i = match.regs.getNumRegs() - 1; match.regs.getBeg(i) == -1 && i > 0; i--); - return nth_match(i, m); + return i == 0 ? context.nil : nth_match(context, i, match); } // MRI: ASCGET macro from rb_reg_regsub @@ -1852,8 +1881,8 @@ static RubyString regsub(ThreadContext context, RubyString str, RubyString src, return val; } - final int adjustStartPos(RubyString str, int pos, boolean reverse) { - check(); + final int adjustStartPos(ThreadContext context, RubyString str, int pos, boolean reverse) { + check(context); return adjustStartPosInternal(str, pattern.getEncoding(), pos, reverse); } @@ -1897,7 +1926,7 @@ public static void marshalTo(RubyRegexp regexp, MarshalStream output) throws jav int options = regexp.pattern.getOptions() & EMBEDDABLE; - if (regexp.getOptions().isFixed()) options |= RE_FIXED; + if (regexp.getOptions(regexp.getRuntime().getCurrentContext()).isFixed()) options |= RE_FIXED; output.writeByte(options); } @@ -1908,7 +1937,7 @@ public static void marshalTo(RubyRegexp regexp, NewMarshal output, NewMarshal.Ru int options = regexp.pattern.getOptions() & EMBEDDABLE; - if (regexp.getOptions().isFixed()) options |= RE_FIXED; + if (regexp.getOptions(regexp.getRuntime().getCurrentContext()).isFixed()) options |= RE_FIXED; output.writeByte(out, options); } @@ -1929,16 +1958,20 @@ public static IRubyObject getBackRef(ThreadContext context) { return context.getBackRef(); } + @Deprecated(since = "10.0") + public boolean isSimpleString() { + return isSimpleString(getCurrentContext()); + } /** * Is the pattern itself a simple US-ASCII string which can be used in simple string searches and * can be used outside of the regexp engine? * */ - public boolean isSimpleString() { + public boolean isSimpleString(ThreadContext context) { return isLiteral() && getEncoding().isAsciiCompatible() && RubyString.scanForCodeRange(str) == CR_7BIT && - !getOptions().isIgnorecase() && + !getOptions(context).isIgnorecase() && ((str.realSize() == 1 && str.charAt(0) != '.' && str.charAt(0) != '^' && diff --git a/core/src/main/java/org/jruby/RubyString.java b/core/src/main/java/org/jruby/RubyString.java index 3b63fe264e5..90460f1f7f3 100644 --- a/core/src/main/java/org/jruby/RubyString.java +++ b/core/src/main/java/org/jruby/RubyString.java @@ -3018,7 +3018,7 @@ private IRubyObject subBangIter(ThreadContext context, RubyString pattern, RubyH } private IRubyObject subBangIter(ThreadContext context, RubyRegexp regexp, RubyHash hash, Block block) { - Regex pattern = regexp.getPattern(); + Regex pattern = regexp.getPattern(context); Regex prepared = regexp.preparePattern(context, this); int begin = value.getBegin(); @@ -3118,7 +3118,7 @@ public final IRubyObject subBangFast(ThreadContext context, RubyRegexp regexp, R } private RubyMatchData subBangMatch(ThreadContext context, RubyRegexp regexp, RubyString repl) { - Regex pattern = regexp.getPattern(); + Regex pattern = regexp.getPattern(context); Regex prepared = regexp.preparePattern(context, this); int begin = value.getBegin(); @@ -3352,7 +3352,7 @@ private IRubyObject gsubCommon(ThreadContext context, Block block, RubyString re private IRubyObject gsubCommon(ThreadContext context, Block block, RubyString repl, RubyHash hash, RubyRegexp regexp, final boolean bang, int tuFlags, boolean useBackref) { - Regex pattern = regexp.getPattern(); + Regex pattern = regexp.getPattern(context); Regex prepared = regexp.preparePattern(context, this); final byte[] spBytes = value.getUnsafeBytes(); @@ -3491,8 +3491,9 @@ private IRubyObject indexCommon(ThreadContext context, IRubyObject sub, int pos) return context.nil; } - pos = singleByteOptimizable() ? pos : StringSupport.nth(regexp.checkEncoding(this), value, pos) - value.getBegin(); - pos = regexp.adjustStartPos(this, pos, false); + pos = singleByteOptimizable() ? + pos : StringSupport.nth(regexp.checkEncoding(context, this), value, pos) - value.getBegin(); + pos = regexp.adjustStartPos(context, this, pos, false); pos = regexp.search(context, this, pos, false); if (pos >= 0) pos = subLength(context.getLocalMatch().begin(0)); } else { @@ -4099,7 +4100,7 @@ private void subpatSet(ThreadContext context, RubyRegexp regexp, IRubyObject bac // this cast should be ok, since nil matchdata will be < 0 above RubyMatchData match = context.getLocalMatch(); - int nth = backref == null ? 0 : subpatSetCheck(context, match.backrefNumber(context.runtime, backref), match.regs); + int nth = backref == null ? 0 : subpatSetCheck(context, match.backrefNumber(context, backref), match.regs); final int start, end; if (match.regs == null) { @@ -4129,7 +4130,7 @@ private IRubyObject subpat(ThreadContext context, RubyRegexp regex, IRubyObject // set backref for user context.setBackRef(match); - return RubyRegexp.nth_match(match.backrefNumber(context.runtime, backref), match); + return RubyRegexp.nth_match(context, match.backrefNumber(context, backref), match); } context.clearBackRef(); @@ -4146,7 +4147,7 @@ private IRubyObject subpat(ThreadContext context, RubyRegexp regex) { // set backref for user context.setBackRef(match); - return RubyRegexp.nth_match(0, match); + return RubyRegexp.nth_match(context, 0, match); } // set backref for user @@ -4703,7 +4704,7 @@ private Object determineSplitPattern(ThreadContext context, IRubyObject pat) { } if (pattern instanceof RubyRegexp regexp) { - if (regexp.isSimpleString()) return regexp.rawSource(); // Simple string-only regexp use Optimized String split + if (regexp.isSimpleString(context)) return regexp.rawSource(); // Simple string-only regexp use Optimized String split return regexp; } @@ -4729,7 +4730,7 @@ private RubyArray regexSplit(ThreadContext context, RubyRegexp pattern, boolean byte[] bytes = value.getUnsafeBytes(); Encoding enc = value.getEncoding(); - boolean captures = pattern.getPattern().numberOfCaptures() != 0; + boolean captures = pattern.getPattern(context).numberOfCaptures() != 0; int end, beg = 0; boolean lastNull = false; @@ -5084,12 +5085,12 @@ private static IRubyObject scanOnce(ThreadContext context, RubyString str, IRuby startp[0] = matchEnd; } if (match.numRegs() == 1) { - return RubyRegexp.nth_match(0, match); + return RubyRegexp.nth_match(context, 0, match); } int size = match.numRegs(); RubyArray result = RubyArray.newBlankArrayInternal(context.runtime, size - 1); for (int i = 1; i < size; i++) { - result.eltInternalSet(i - 1, RubyRegexp.nth_match(i, match)); + result.eltInternalSet(i - 1, RubyRegexp.nth_match(context, i, match)); } result.realLength = size - 1; @@ -5561,7 +5562,7 @@ public IRubyObject rpartition(ThreadContext context, IRubyObject arg) { IRubyObject tmp = rindex(context, arg); if (tmp.isNil()) return rpartitionMismatch(context); pos = tmp.convertToInteger().getIntValue(); - sep = (RubyString)RubyRegexp.nth_match(0, context.getLocalMatchOrNil()); + sep = (RubyString)RubyRegexp.nth_match(context, 0, context.getLocalMatchOrNil()); } else { IRubyObject tmp = arg.checkStringType(); if (tmp.isNil()) throw typeError(context, "type mismatch: ", arg, " given"); diff --git a/core/src/main/java/org/jruby/ext/date/RubyDate.java b/core/src/main/java/org/jruby/ext/date/RubyDate.java index 5559256905d..ad0e15a098f 100644 --- a/core/src/main/java/org/jruby/ext/date/RubyDate.java +++ b/core/src/main/java/org/jruby/ext/date/RubyDate.java @@ -1780,44 +1780,41 @@ static IRubyObject _parse_time(ThreadContext context, IRubyObject self, RubyStri RubyRegexp re = newRegexpFromCache(context, _parse_time, RE_OPTION_IGNORECASE | RE_OPTION_EXTENDED); IRubyObject sub = subSpace(context, str, re); - if (sub != context.nil) { - RubyMatchData match = (RubyMatchData) sub; - final RubyString s1 = (RubyString) match.at(1); - final RubyString s2 = matchOrNull(context, match, 2); - - if (s2 != null) hash.fastASet(asSymbol(context, "zone"), s2); - - re = newRegexpFromCache(context, _parse_time2, RE_OPTION_IGNORECASE | RE_OPTION_EXTENDED); - sub = re.match_m(context, s1, false); - if (sub != context.nil) { - match = (RubyMatchData) sub; - RubyInteger hour; - RubyString m = (RubyString) match.at(1); - hash.fastASet(asSymbol(context, "hour"), hour = (RubyInteger) m.to_i(context)); - m = matchOrNull(context, match, 2); - if (m != null) hash.fastASet(asSymbol(context, "min"), m.to_i(context)); - m = matchOrNull(context, match, 3); - if (m != null) hash.fastASet(asSymbol(context, "sec"), m.to_i(context)); - m = matchOrNull(context, match, 4); - if (m != null) { - RubyInteger den = (RubyInteger) asFixnum(context, 10).op_pow(context, m.length()); - hash.fastASet(asSymbol(context, "sec_fraction"), RubyRational.newInstance(context, (RubyInteger) m.to_i(context), den)); - } - m = matchOrNull(context, match, 5); - if (m != null) { - hour = (RubyInteger) hour.op_mod(context, 12); - if (m.length() == 1 && strPtr(m, 'p') || strPtr(m, 'P')) { - hour = (RubyInteger) hour.op_plus(context, 12); - } - hash.fastASet(asSymbol(context, "hour"), hour); + if (!(sub instanceof RubyMatchData match)) return context.nil; + + final RubyString s1 = (RubyString) match.at(context, 1); + final RubyString s2 = matchOrNull(context, match, 2); + + if (s2 != null) hash.fastASet(asSymbol(context, "zone"), s2); + + re = newRegexpFromCache(context, _parse_time2, RE_OPTION_IGNORECASE | RE_OPTION_EXTENDED); + sub = re.match_m(context, s1, false); + if (sub instanceof RubyMatchData match2) { + RubyInteger hour; + RubyString m = (RubyString) match2.at(context, 1); + hash.fastASet(asSymbol(context, "hour"), hour = (RubyInteger) m.to_i(context)); + m = matchOrNull(context, match2, 2); + if (m != null) hash.fastASet(asSymbol(context, "min"), m.to_i(context)); + m = matchOrNull(context, match2, 3); + if (m != null) hash.fastASet(asSymbol(context, "sec"), m.to_i(context)); + m = matchOrNull(context, match2, 4); + if (m != null) { + RubyInteger den = (RubyInteger) asFixnum(context, 10).op_pow(context, m.length()); + hash.fastASet(asSymbol(context, "sec_fraction"), RubyRational.newInstance(context, (RubyInteger) m.to_i(context), den)); + } + m = matchOrNull(context, match2, 5); + if (m != null) { + hour = (RubyInteger) hour.op_mod(context, 12); + if (m.length() == 1 && strPtr(m, 'p') || strPtr(m, 'P')) { + hour = (RubyInteger) hour.op_plus(context, 12); } - } else { - hash.fastASet(asSymbol(context, "hour"), asFixnum(context, 0)); + hash.fastASet(asSymbol(context, "hour"), hour); } - - return context.tru; + } else { + hash.fastASet(asSymbol(context, "hour"), asFixnum(context, 0)); } - return sub; // nil + + return context.tru; } private static final ByteList[] ABBR_MONTHS = new ByteList[] { @@ -1853,12 +1850,11 @@ private static int mon_num(RubyString s) { static IRubyObject _parse_day(ThreadContext context, IRubyObject self, RubyString str, RubyHash hash) { RubyRegexp re = newRegexpFromCache(context, _parse_day, RE_OPTION_IGNORECASE); IRubyObject sub = subSpace(context, str, re); - if (sub != context.nil) { - int day = day_num((RubyString) ((RubyMatchData) sub).at(1)); - hash.fastASet(asSymbol(context, "wday"), asFixnum(context, day)); - return context.tru; - } - return sub; // nil + if (!(sub instanceof RubyMatchData match)) return context.nil; + + int day = day_num((RubyString) match.at(context, 1)); + hash.fastASet(asSymbol(context, "wday"), asFixnum(context, day)); + return context.tru; } private static final ByteList _parse_mon; @@ -1869,13 +1865,12 @@ static IRubyObject _parse_day(ThreadContext context, IRubyObject self, RubyStrin static IRubyObject _parse_mon(ThreadContext context, IRubyObject self, RubyString str, RubyHash hash) { RubyRegexp re = newRegexpFromCache(context, _parse_mon, RE_OPTION_IGNORECASE); - IRubyObject sub = subSpace(context, (RubyString) str, re); - if (sub != context.nil) { - int mon = mon_num((RubyString) ((RubyMatchData) sub).at(1)); - hash.fastASet(asSymbol(context, "mon"), asFixnum(context, mon)); - return context.tru; - } - return sub; // nil + IRubyObject sub = subSpace(context, str, re); + if (!(sub instanceof RubyMatchData match)) return context.nil; + + int mon = mon_num((RubyString) match.at(context, 1)); + hash.fastASet(asSymbol(context, "mon"), asFixnum(context, mon)); + return context.tru; } private static final ByteList _parse_year; @@ -1887,9 +1882,9 @@ static IRubyObject _parse_mon(ThreadContext context, IRubyObject self, RubyStrin static IRubyObject _parse_year(ThreadContext context, IRubyObject self, RubyString str, RubyHash hash) { RubyRegexp re = RubyRegexp.newRegexp(context.runtime, _parse_year); IRubyObject sub = subSpace(context, str, re); - if (sub == context.nil) return context.nil; + if (!(sub instanceof RubyMatchData match)) return context.nil; - hash.fastASet(asSymbol(context, "year"), ((RubyString) ((RubyMatchData) sub).at(1)).to_i(context)); + hash.fastASet(asSymbol(context, "year"), ((RubyString) match.at(context, 1)).to_i(context)); return context.tru; } @@ -1902,9 +1897,9 @@ static IRubyObject _parse_year(ThreadContext context, IRubyObject self, RubyStri static IRubyObject _parse_mday(ThreadContext context, IRubyObject self, RubyString str, RubyHash hash) { RubyRegexp re = newRegexpFromCache(context, _parse_mday, RE_OPTION_IGNORECASE); IRubyObject sub = subSpace(context, str, re); - if (sub == context.nil) return context.nil; + if (!(sub instanceof RubyMatchData match)) return context.nil; - hash.fastASet(asSymbol(context, "mday"), ((RubyString) ((RubyMatchData) sub).at(1)).to_i(context)); + hash.fastASet(asSymbol(context, "mday"), ((RubyString) match.at(context, 1)).to_i(context)); return context.tru; } @@ -1926,21 +1921,18 @@ static IRubyObject _parse_mday(ThreadContext context, IRubyObject self, RubyStri static IRubyObject _parse_eu(ThreadContext context, IRubyObject self, RubyString str, RubyHash hash) { RubyRegexp re = newRegexpFromCache(context, _parse_eu, RE_OPTION_IGNORECASE); - IRubyObject sub = subSpace(context, (RubyString) str, re); - if (sub != context.nil) { - final RubyMatchData match = (RubyMatchData) sub; + IRubyObject sub = subSpace(context, str, re); + if (!(sub instanceof RubyMatchData match)) return context.nil; - RubyString d = (RubyString) match.at(1); - RubyString mon = (RubyString) match.at(2); - mon = RubyString.newStringShared(context.runtime, ConvertBytes.byteToSharedByteList((short) mon_num(mon))); - RubyString b = matchOrNull(context, match, 3); - RubyString y = matchOrNull(context, match, 4); + RubyString d = (RubyString) match.at(context, 1); + RubyString mon = (RubyString) match.at(context, 2); + mon = RubyString.newStringShared(context.runtime, ConvertBytes.byteToSharedByteList((short) mon_num(mon))); + RubyString b = matchOrNull(context, match, 3); + RubyString y = matchOrNull(context, match, 4); - s3e(context, hash, y, mon, d, b != null && b.length() > 1 && (b.charAt(0) == 'B' || b.charAt(0) == 'b')); + s3e(context, hash, y, mon, d, b != null && b.length() > 1 && (b.charAt(0) == 'B' || b.charAt(0) == 'b')); - return context.tru; - } - return sub; // nil + return context.tru; } private static final ByteList _parse_us; @@ -1963,13 +1955,11 @@ static IRubyObject _parse_eu(ThreadContext context, IRubyObject self, RubyString static IRubyObject _parse_us(ThreadContext context, IRubyObject self, RubyString str, RubyHash hash) { RubyRegexp re = newRegexpFromCache(context, _parse_us, RE_OPTION_IGNORECASE); IRubyObject sub = subSpace(context, str, re); - if (sub == context.nil) return context.nil; + if (!(sub instanceof RubyMatchData match)) return context.nil; - final RubyMatchData match = (RubyMatchData) sub; - - RubyString mon = (RubyString) match.at(1); + RubyString mon = (RubyString) match.at(context, 1); mon = RubyString.newStringShared(context.runtime, ConvertBytes.byteToSharedByteList((short) mon_num(mon))); - RubyString d = (RubyString) match.at(2); + RubyString d = (RubyString) match.at(context, 2); RubyString b = matchOrNull(context, match, 3); RubyString y = matchOrNull(context, match, 4); @@ -1986,7 +1976,7 @@ private static RubyRegexp newRegexpFromCache(ThreadContext context, ByteList str } private static RubyString matchOrNull(ThreadContext context, final RubyMatchData match, int i) { - IRubyObject val = match.at(i); + IRubyObject val = match.at(context, i); return val == context.nil ? null : (RubyString) val; } @@ -1997,15 +1987,13 @@ private static RubyString matchOrNull(ThreadContext context, final RubyMatchData } static IRubyObject _parse_iso(ThreadContext context, IRubyObject self, RubyString str, RubyHash hash) { - final Ruby runtime = context.runtime; - RubyRegexp re = RubyRegexp.newRegexp(runtime, _parse_iso); - IRubyObject sub = subSpace(context, (RubyString) str, re); - if (sub != context.nil) { - final RubyMatchData match = (RubyMatchData) sub; - s3e(context, hash, (RubyString) match.at(1), (RubyString) match.at(2), (RubyString) match.at(3), false); - return context.tru; - } - return sub; // nil + RubyRegexp re = RubyRegexp.newRegexp(context.runtime, _parse_iso); + IRubyObject sub = subSpace(context, str, re); + if (!(sub instanceof RubyMatchData match)) return context.nil; + + s3e(context, hash, (RubyString) match.at(context, 1), (RubyString) match.at(context, 2), + (RubyString) match.at(context, 3), false); + return context.tru; } private static final ByteList _parse_sla; @@ -2080,9 +2068,9 @@ static void parse_frag(ThreadContext context, IRubyObject self, RubyString str, if (hashGet(context, hash, "hour") != null && hashGet(context, hash, "mday") == null) { RubyRegexp re = newRegexpFromCache(context, _parse_frag, RE_OPTION_IGNORECASE); - sub = subSpace(context, (RubyString) str, re); - if (sub != context.nil) { - RubyInteger v = (RubyInteger) ((RubyString) ((RubyMatchData) sub).at(1)).to_i(context); + sub = subSpace(context, str, re); + if (sub instanceof RubyMatchData match) { + RubyInteger v = (RubyInteger) ((RubyString) match.at(context, 1)).to_i(context); long vi = v.getLongValue(); if (1 <= vi && vi <= 31) hash.fastASet(asSymbol(context, "mday"), v); } @@ -2093,8 +2081,8 @@ static void parse_frag(ThreadContext context, IRubyObject self, RubyString str, RubyRegexp re = newRegexpFromCache(context, _parse_frag, RE_OPTION_IGNORECASE); sub = subSpace(context, str, re); } - if (sub != context.nil) { - RubyInteger v = (RubyInteger) ((RubyString) ((RubyMatchData) sub).at(1)).to_i(context); + if (sub instanceof RubyMatchData match) { + RubyInteger v = (RubyInteger) ((RubyString) match.at(context, 1)).to_i(context); long vi = v.getLongValue(); if (0 <= vi && vi <= 24) hash.fastASet(asSymbol(context, "hour"), v); } diff --git a/core/src/main/java/org/jruby/ir/instructions/BuildBackrefInstr.java b/core/src/main/java/org/jruby/ir/instructions/BuildBackrefInstr.java index e3708c0a1e3..fab661d113b 100644 --- a/core/src/main/java/org/jruby/ir/instructions/BuildBackrefInstr.java +++ b/core/src/main/java/org/jruby/ir/instructions/BuildBackrefInstr.java @@ -51,9 +51,9 @@ public Object interpret(ThreadContext context, StaticScope currScope, DynamicSco switch (type) { case '&' : return RubyRegexp.last_match(backref); - case '`' : return RubyRegexp.match_pre(backref); + case '`' : return RubyRegexp.match_pre(context, backref); case '\'': return RubyRegexp.match_post(backref); - case '+' : return RubyRegexp.match_last(backref); + case '+' : return RubyRegexp.match_last(context, backref); default: assert false: "backref with invalid type"; return null; diff --git a/core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java b/core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java index 50da76ede21..dba1b11a07b 100644 --- a/core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java +++ b/core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java @@ -1000,13 +1000,8 @@ public static IRubyObject isDefinedGlobal(ThreadContext context, String name, IR public static IRubyObject isDefinedNthRef(ThreadContext context, int matchNumber, IRubyObject definedMessage) { IRubyObject backref = context.getBackRef(); - if (backref instanceof RubyMatchData) { - if (!((RubyMatchData) backref).group(matchNumber).isNil()) { - return definedMessage; - } - } - - return context.nil; + return backref instanceof RubyMatchData match && !match.group(context, matchNumber).isNil() ? + definedMessage : context.nil; } @JIT @Interp @@ -1070,7 +1065,7 @@ public static IRubyObject isDefinedSuper(ThreadContext context, IRubyObject rece } public static IRubyObject nthMatch(ThreadContext context, int matchNumber) { - return RubyRegexp.nth_match(matchNumber, context.getBackRef()); + return RubyRegexp.nth_match(context, matchNumber, context.getBackRef()); } public static void defineAlias(ThreadContext context, IRubyObject self, DynamicScope currDynScope, @@ -1342,9 +1337,9 @@ public static IRubyObject receiveKeywordRestArg(ThreadContext context, IRubyObje public static IRubyObject setCapturedVar(ThreadContext context, IRubyObject matchRes, String id) { if (matchRes.isNil()) return context.nil; - IRubyObject backref = context.getBackRef(); + RubyMatchData backref = (RubyMatchData) context.getBackRef(); - return RubyRegexp.nth_match(((RubyMatchData) backref).getNameToBackrefNumber(id), backref); + return RubyRegexp.nth_match(context, backref.getNameToBackrefNumber(context, id), backref); } @JIT // for JVM6 diff --git a/core/src/main/java/org/jruby/runtime/Helpers.java b/core/src/main/java/org/jruby/runtime/Helpers.java index bd46d0d6119..2b12a7a018d 100644 --- a/core/src/main/java/org/jruby/runtime/Helpers.java +++ b/core/src/main/java/org/jruby/runtime/Helpers.java @@ -1076,30 +1076,22 @@ public static Block getBlockFromBlockPassBody(IRubyObject proc, Block currentBlo @Deprecated public static IRubyObject backrefLastMatch(ThreadContext context) { - IRubyObject backref = context.getBackRef(); - - return RubyRegexp.last_match(backref); + return RubyRegexp.last_match(context.getBackRef()); } @Deprecated public static IRubyObject backrefMatchPre(ThreadContext context) { - IRubyObject backref = context.getBackRef(); - - return RubyRegexp.match_pre(backref); + return RubyRegexp.match_pre(context, context.getBackRef()); } @Deprecated public static IRubyObject backrefMatchPost(ThreadContext context) { - IRubyObject backref = context.getBackRef(); - - return RubyRegexp.match_post(backref); + return RubyRegexp.match_post(context.getBackRef()); } @Deprecated public static IRubyObject backrefMatchLast(ThreadContext context) { - IRubyObject backref = context.getBackRef(); - - return RubyRegexp.match_last(backref); + return RubyRegexp.match_last(context, context.getBackRef()); } public static IRubyObject[] appendToObjectArray(IRubyObject[] array, IRubyObject add) { diff --git a/core/src/main/java/org/jruby/runtime/ThreadContext.java b/core/src/main/java/org/jruby/runtime/ThreadContext.java index 0fa4edd3386..c7dc841d820 100644 --- a/core/src/main/java/org/jruby/runtime/ThreadContext.java +++ b/core/src/main/java/org/jruby/runtime/ThreadContext.java @@ -640,21 +640,23 @@ public IRubyObject getBackRef() { /** * MRI: rb_reg_last_match */ + @JIT public IRubyObject last_match() { - return RubyRegexp.nth_match(0, frameStack[frameIndex].getBackRef(nil)); + return RubyRegexp.nth_match(this, 0, frameStack[frameIndex].getBackRef(nil)); } /** * MRI: rb_reg_match_pre */ + @JIT public IRubyObject match_pre() { - return RubyRegexp.match_pre(frameStack[frameIndex].getBackRef(nil)); + return RubyRegexp.match_pre(this, frameStack[frameIndex].getBackRef(nil)); } - /** * MRI: rb_reg_match_post */ + @JIT public IRubyObject match_post() { return RubyRegexp.match_post(frameStack[frameIndex].getBackRef(nil)); } @@ -662,8 +664,9 @@ public IRubyObject match_post() { /** * MRI: rb_reg_match_last */ + @JIT public IRubyObject match_last() { - return RubyRegexp.match_last(frameStack[frameIndex].getBackRef(nil)); + return RubyRegexp.match_last(this, frameStack[frameIndex].getBackRef(nil)); } /** diff --git a/core/src/main/java/org/jruby/util/RegexpOptions.java b/core/src/main/java/org/jruby/util/RegexpOptions.java index ff75c97abca..cb682ee36ad 100644 --- a/core/src/main/java/org/jruby/util/RegexpOptions.java +++ b/core/src/main/java/org/jruby/util/RegexpOptions.java @@ -11,6 +11,7 @@ import org.jcodings.specific.UTF8Encoding; import org.jruby.Ruby; import org.jruby.RubyRegexp; +import org.jruby.runtime.ThreadContext; import static org.jruby.api.Create.newString; import static org.jruby.api.Error.argumentError; @@ -236,8 +237,12 @@ public static RegexpOptions fromJoniOptions(int joniOptions) { return options; } - // This is the options Regexp#new supports. It is not all valid suffixes. public static RegexpOptions fromByteList(Ruby runtime, ByteList string) { + return fromByteList(runtime.getCurrentContext(), string); + } + + // This is the options Regexp#new supports. It is not all valid suffixes. + public static RegexpOptions fromByteList(ThreadContext context, ByteList string) { RegexpOptions options = new RegexpOptions(); byte[] bytes = string.unsafeBytes(); int length = string.realSize(); @@ -258,8 +263,7 @@ public static RegexpOptions fromByteList(Ruby runtime, ByteList string) { options.setOnce(true); break; default: - throw argumentError(runtime.getCurrentContext(), - str(runtime, "unknown regexp option: ", newString(runtime.getCurrentContext(), string))); + throw argumentError(context, str(context.runtime, "unknown regexp option: ", newString(context, string))); } } diff --git a/core/src/test/java/org/jruby/TestRegexpCache.java b/core/src/test/java/org/jruby/TestRegexpCache.java index f4eb986594c..5d5ee886424 100644 --- a/core/src/test/java/org/jruby/TestRegexpCache.java +++ b/core/src/test/java/org/jruby/TestRegexpCache.java @@ -22,11 +22,11 @@ public void testCacheRetention() { //assertSame(regex, RubyRegexp.getQuotedRegexpFromCache(runtime, GH2078_TEST_BYTELIST.dup(), RegexpOptions.NULL_OPTIONS, false)); RubyString str = newString(context, ByteList.create("GH2078")); - Regex regex = RubyRegexp.getQuotedRegexpFromCache(context.runtime, str, RegexpOptions.NULL_OPTIONS); - assertSame(regex, RubyRegexp.getQuotedRegexpFromCache(context.runtime, str, RegexpOptions.NULL_OPTIONS)); - assertSame(regex, RubyRegexp.getQuotedRegexpFromCache(context.runtime, (RubyString) str.dup(), RegexpOptions.NULL_OPTIONS)); - assertSame(regex, RubyRegexp.getQuotedRegexpFromCache(context.runtime, newString(context, "GH2078"), RegexpOptions.NULL_OPTIONS)); - assertSame(regex, RubyRegexp.getQuotedRegexpFromCache(context.runtime, str.newFrozen(), RegexpOptions.NULL_OPTIONS)); + Regex regex = RubyRegexp.getQuotedRegexpFromCache(context, str, RegexpOptions.NULL_OPTIONS); + assertSame(regex, RubyRegexp.getQuotedRegexpFromCache(context, str, RegexpOptions.NULL_OPTIONS)); + assertSame(regex, RubyRegexp.getQuotedRegexpFromCache(context, (RubyString) str.dup(), RegexpOptions.NULL_OPTIONS)); + assertSame(regex, RubyRegexp.getQuotedRegexpFromCache(context, newString(context, "GH2078"), RegexpOptions.NULL_OPTIONS)); + assertSame(regex, RubyRegexp.getQuotedRegexpFromCache(context, str.newFrozen(), RegexpOptions.NULL_OPTIONS)); // Should only have one entry assertEquals(1, RubyRegexp.quotedPatternCache.size());