diff --git a/docs/reference/feature-matrix.md b/docs/reference/feature-matrix.md index e8e7c819e..59e4cadba 100644 --- a/docs/reference/feature-matrix.md +++ b/docs/reference/feature-matrix.md @@ -663,7 +663,8 @@ The `:encoding()` layer supports all encodings provided by Java's `Charset.forNa - ✅ Implemented: `<=>`, `cmp`, `<`, `<=`, `>`, `>=`, `==`, `!=`, `lt`, `le`, `gt`, `ge`, `eq`, `ne`. - ✅ Implemented: `qr`. - ✅ Implemented: `+=`, `-=`, `*=`, `/=`, `%=`. - - ❌ Missing: `++`, `--`, `=`, `<>`. + - ✅ Implemented: `<>`. + - ❌ Missing: `++`, `--`, `=`. - ❌ Missing: `&`, `|`, `^`, `~`, `<<`, `>>`, `&.`, `|.`, `^.`, `~.`, `x`, `.`. - ❌ Missing: `**=`, `<<=`, `>>=`, `x=`, `.=`, `&=`, `|=`, `^=`, `&.=`, `|.=`, `^.=`. - ❌ Missing: `-X`. diff --git a/src/main/java/org/perlonjava/backend/bytecode/OpcodeHandlerExtended.java b/src/main/java/org/perlonjava/backend/bytecode/OpcodeHandlerExtended.java index c218df163..60918e057 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/OpcodeHandlerExtended.java +++ b/src/main/java/org/perlonjava/backend/bytecode/OpcodeHandlerExtended.java @@ -837,8 +837,13 @@ public static int executeReadline(int[] bytecode, int pc, RuntimeBase[] register RuntimeScalar fh = (RuntimeScalar) registers[fhReg]; // Diamond operator <> passes a plain string scalar (not a glob/IO). // Route to DiamondIO.readline which manages @ARGV / STDIN iteration. + // But blessed objects may have <> overload, so route those to Readline. if (fh.getRuntimeIO() == null) { - registers[rd] = DiamondIO.readline(fh, ctx); + if (RuntimeScalarType.blessedId(fh) < 0) { + registers[rd] = Readline.readline(fh, ctx); + } else { + registers[rd] = DiamondIO.readline(fh, ctx); + } } else { registers[rd] = Readline.readline(fh, ctx); } diff --git a/src/main/java/org/perlonjava/core/Configuration.java b/src/main/java/org/perlonjava/core/Configuration.java index 7fd7161c1..11f1db198 100644 --- a/src/main/java/org/perlonjava/core/Configuration.java +++ b/src/main/java/org/perlonjava/core/Configuration.java @@ -33,7 +33,7 @@ public final class Configuration { * Automatically populated by Gradle/Maven during build. * DO NOT EDIT MANUALLY - this value is replaced at build time. */ - public static final String gitCommitId = "7bf93f44f"; + public static final String gitCommitId = "0d83f6c7e"; /** * Git commit date of the build (ISO format: YYYY-MM-DD). @@ -48,7 +48,7 @@ public final class Configuration { * Parsed by App::perlbrew and other tools via: perl -V | grep "Compiled at" * DO NOT EDIT MANUALLY - this value is replaced at build time. */ - public static final String buildTimestamp = "Apr 13 2026 14:15:09"; + public static final String buildTimestamp = "Apr 13 2026 14:49:28"; // Prevent instantiation private Configuration() { diff --git a/src/main/java/org/perlonjava/runtime/operators/Readline.java b/src/main/java/org/perlonjava/runtime/operators/Readline.java index a4b02a21a..a4d95863e 100644 --- a/src/main/java/org/perlonjava/runtime/operators/Readline.java +++ b/src/main/java/org/perlonjava/runtime/operators/Readline.java @@ -20,6 +20,18 @@ public static RuntimeBase readline(RuntimeScalar fileHandle, int ctx) { RuntimeIO fh = fileHandle.getRuntimeIO(); if (fh == null) { + // Check for <> overload before warning about unopened filehandle + int blessId = RuntimeScalarType.blessedId(fileHandle); + if (blessId < 0) { + OverloadContext overloadCtx = OverloadContext.prepare(blessId); + if (overloadCtx != null) { + RuntimeScalar result = overloadCtx.tryOverload("(<>", new RuntimeArray(fileHandle)); + if (result != null) { + return result; + } + } + } + // Perl warns and returns undef for unopened filehandle, doesn't die WarnDie.warn(new RuntimeScalar("readline() on unopened filehandle"), new RuntimeScalar("\n")); return ctx == RuntimeContextType.LIST ? new RuntimeList() : scalarUndef;