diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fa30a4bc51..e95e3f352d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: - '3.1' - '3.2' - debug - - jruby-head + - jruby-9.4.1.0 - truffleruby - truffleruby-head include: diff --git a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java index 60385905ae..0b4d6338ff 100644 --- a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java +++ b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java @@ -51,7 +51,6 @@ import org.jruby.ast.util.ArgsUtil; import org.jruby.common.IRubyWarnings.ID; import org.jruby.exceptions.RaiseException; -import org.jruby.runtime.Block; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.util.ByteList; @@ -62,7 +61,9 @@ import static org.jruby.runtime.Visibility.PRIVATE; /** - * @author kscott + * JRuby implementation of the strscan library from Ruby. + * + * Original implementation by Kelly Nawrocke. Currently a loose port of the C implementation from CRuby. */ @JRubyClass(name = "StringScanner") public class RubyStringScanner extends RubyObject { @@ -73,7 +74,7 @@ public class RubyStringScanner extends RubyObject { private Region regs; private Regex pattern; - private int scannerFlags; + private boolean matched; private boolean fixedAnchor; private static final int MATCHED_STR_SCN_F = 1 << 11; @@ -195,15 +196,15 @@ public int getNumRegs(Region region) { } private void clearMatched() { - scannerFlags &= ~MATCHED_STR_SCN_F; + matched = false; } private void setMatched() { - scannerFlags |= MATCHED_STR_SCN_F; + matched = true; } private boolean isMatched() { - return (scannerFlags & MATCHED_STR_SCN_F) != 0; + return matched; } private void check(ThreadContext context) { @@ -244,7 +245,7 @@ public IRubyObject initialize_copy(ThreadContext context, IRubyObject other) { str = otherScanner.str; curr = otherScanner.curr; prev = otherScanner.prev; - scannerFlags = otherScanner.scannerFlags; + matched = otherScanner.matched; regs = otherScanner.regs.clone(); pattern = otherScanner.pattern; @@ -350,20 +351,6 @@ private IRubyObject extractBegLen(Ruby runtime, int beg, int len) { return str.makeSharedString(runtime, beg, len); } - final ThreadLocal currentMatcher = new ThreadLocal<>(); - final RubyThread.Task task = new RubyThread.Task() { - @Override - public Integer run(ThreadContext context, RubyStringScanner rubyStringScanner) throws InterruptedException { - ByteList value = str.getByteList(); - return currentMatcher.get().matchInterruptible(value.begin() + curr, value.begin() + value.realSize(), Option.NONE); - } - - @Override - public void wakeup(RubyThread thread, RubyStringScanner rubyStringScanner) { - thread.getNativeThread().interrupt(); - } - }; - // MRI: strscan_do_scan private IRubyObject scan(ThreadContext context, IRubyObject regex, boolean succptr, boolean getstr, boolean headonly) { final Ruby runtime = context.runtime; @@ -625,8 +612,9 @@ public IRubyObject peek(ThreadContext context, IRubyObject length) { } ByteList value = str.getByteList(); - if (curr >= value.getRealSize()) return RubyString.newEmptyString(context.runtime); - if (curr + len > value.getRealSize()) len = value.getRealSize() - curr; + int realSize = value.getRealSize(); + if (curr >= realSize) return RubyString.newEmptyString(context.runtime); + if (curr + len > realSize) len = realSize - curr; return extractBegLen(context.runtime, curr, len); } @@ -647,7 +635,7 @@ public IRubyObject unscan(ThreadContext context) { if (!isMatched()) { Ruby runtime = context.runtime; - RubyClass errorClass = runtime.getClass("StringScanner").getClass("Error"); + RubyClass errorClass = (RubyClass) runtime.getClassFromPath("StringScanner::Error"); throw RaiseException.from(runtime, errorClass, "unscan failed: previous match had failed"); } @@ -716,7 +704,7 @@ public IRubyObject matchedsize(ThreadContext context) { if (runtime.isVerbose()) { runtime.getWarnings().warning(ID.DEPRECATED_METHOD, "StringScanner#matchedsize is obsolete; use #matched_size instead"); } - return matched_size(); + return matched_size(context); } @JRubyMethod(name = "[]") @@ -779,12 +767,13 @@ public IRubyObject rest(ThreadContext context) { Ruby runtime = context.runtime; ByteList value = str.getByteList(); + int realSize = value.getRealSize(); - if (curr >= value.getRealSize()) { + if (curr >= realSize) { return RubyString.newEmptyString(runtime); } - return extractRange(runtime, curr, value.getRealSize()); + return extractRange(runtime, curr, realSize); } @JRubyMethod(name = "rest_size") @@ -793,10 +782,11 @@ public RubyFixnum rest_size(ThreadContext context) { Ruby runtime = context.runtime; ByteList value = str.getByteList(); + int realSize = value.getRealSize(); - if (curr >= value.getRealSize()) return RubyFixnum.zero(runtime); + if (curr >= realSize) return RubyFixnum.zero(runtime); - return RubyFixnum.newFixnum(runtime, value.getRealSize() - curr); + return RubyFixnum.newFixnum(runtime, realSize - curr); } @JRubyMethod(name = "restsize") @@ -812,9 +802,15 @@ public RubyFixnum restsize(ThreadContext context) { @Override public IRubyObject inspect() { if (str == null) return inspect("(uninitialized)"); - if (curr >= str.getByteList().getRealSize()) return inspect("fin"); - if (curr == 0) return inspect(curr + "/" + str.getByteList().getRealSize() + " @ " + inspect2()); - return inspect(curr + "/" + str.getByteList().getRealSize() + " " + inspect1() + " @ " + inspect2()); + + ByteList byteList = str.getByteList(); + int realSize = byteList.getRealSize(); + + if (curr >= realSize) return inspect("fin"); + + if (curr == 0) return inspect(curr + "/" + realSize + " @ " + inspect2()); + + return inspect(curr + "/" + realSize + " " + inspect1() + " @ " + inspect2()); } @JRubyMethod(name = "fixed_anchor?") @@ -859,20 +855,30 @@ private IRubyObject inspect(String msg) { private IRubyObject inspect1() { final Ruby runtime = getRuntime(); + if (curr == 0) return RubyString.newEmptyString(runtime); + if (curr > INSPECT_LENGTH) { return RubyString.newStringNoCopy(runtime, DOT_BYTES).append(str.substr(runtime, curr - INSPECT_LENGTH, INSPECT_LENGTH)).inspect(); } + return str.substr(runtime, 0, curr).inspect(); } private IRubyObject inspect2() { final Ruby runtime = getRuntime(); - if (curr >= str.getByteList().getRealSize()) return RubyString.newEmptyString(runtime); - int len = str.getByteList().getRealSize() - curr; + + ByteList byteList = str.getByteList(); + int realSize = byteList.getRealSize(); + + if (curr >= realSize) return RubyString.newEmptyString(runtime); + + int len = realSize - curr; + if (len > INSPECT_LENGTH) { return ((RubyString) str.substr(runtime, curr, INSPECT_LENGTH)).cat(DOT_BYTES).inspect(); } + return str.substr(runtime, curr, len).inspect(); } @@ -921,65 +927,32 @@ public IRubyObject values_at(ThreadContext context, IRubyObject[] args) { return newAry; } - @Deprecated - public IRubyObject initialize(IRubyObject[] args, Block unusedBlock) { - str = args[0].convertToString(); - return this; - } - - @Deprecated - public IRubyObject initialize_copy(IRubyObject other) { - return initialize_copy(getRuntime().getCurrentContext(), other); - } - - @Deprecated - public IRubyObject concat(IRubyObject obj) { - return concat(getRuntime().getCurrentContext(), obj); - } - - @Deprecated - public RubyFixnum pos() { - return pos(getRuntime().getCurrentContext()); - } - - @Deprecated - public IRubyObject set_pos(IRubyObject pos) { - return set_pos(getRuntime().getCurrentContext(), pos); - } + @JRubyMethod(name = "values_at") + public IRubyObject values_at(ThreadContext context) { + if (!isMatched()) return context.nil; - @Deprecated - public IRubyObject getch19(ThreadContext context) { - return getch(context); + return RubyArray.newEmptyArray(context.runtime); } - @Deprecated - public IRubyObject reset() { - return reset(getRuntime().getCurrentContext()); - } + @JRubyMethod(name = "values_at") + public IRubyObject values_at(ThreadContext context, IRubyObject index) { + if (!isMatched()) return context.nil; - @Deprecated - public IRubyObject unscan() { - return unscan(getRuntime().getCurrentContext()); + return RubyArray.newArray(context.runtime, op_aref(context, index)); } - @Deprecated - public IRubyObject matched_size() { - return matched_size(getRuntime().getCurrentContext()); - } + @JRubyMethod(name = "values_at") + public IRubyObject values_at(ThreadContext context, IRubyObject index1, IRubyObject index2) { + if (!isMatched()) return context.nil; - @Deprecated - public IRubyObject bol_p() { - return bol_p(getRuntime().getCurrentContext()); + return RubyArray.newArray(context.runtime, op_aref(context, index1), op_aref(context, index2)); } - @Deprecated - public RubyFixnum rest_size() { - return rest_size(getRuntime().getCurrentContext()); - } + @JRubyMethod(name = "values_at") + public IRubyObject values_at(ThreadContext context, IRubyObject index1, IRubyObject index2, IRubyObject index3) { + if (!isMatched()) return context.nil; - @Deprecated - public IRubyObject getchCommon(ThreadContext context, boolean is1_9) { - return getchCommon(context); + return RubyArray.newArray(context.runtime, op_aref(context, index1), op_aref(context, index2), op_aref(context, index3)); } /**