From 3b259fa1e0f4baf57b4f2deed0ad4a4a95ec850c Mon Sep 17 00:00:00 2001 From: "Flavio S. Glock" Date: Wed, 29 Apr 2026 17:30:09 +0200 Subject: [PATCH] fix(): treat as diamond operator iterating @ARGV In Perl, behaves identically to the null filehandle <>: it iterates over files named in @ARGV (falling back to STDIN when @ARGV was initially empty), rather than reading from a single named ARGV filehandle. Previously the parser treated like or , emitting a plain readline against the (closed) ARGV filehandle. That made code like Slurp's local( $/, @ARGV ) = ( wantarray ? $/ : undef, @_ ); return ; fail with "readline() on unopened filehandle" and return nothing, breaking jcpan -t Slurp (2/6 subtests). Special-case in parseDiamondOperator so it produces the same OperatorNode("<>", ...) that <> does, routing through DiamondIO which already handles @ARGV iteration, STDIN fallback, and aliased *ARGV globs correctly. Verified with `./jcpan -t Slurp` (now PASSes 6/6) and `make`. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../java/org/perlonjava/core/Configuration.java | 4 ++-- .../frontend/parser/OperatorParser.java | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/perlonjava/core/Configuration.java b/src/main/java/org/perlonjava/core/Configuration.java index 2b54aa0f2..533c0d3f5 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 = "b7b7d29d3"; + public static final String gitCommitId = "8acc9ffd5"; /** * 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 29 2026 17:16:43"; + public static final String buildTimestamp = "Apr 29 2026 17:29:18"; // Prevent instantiation private Configuration() { diff --git a/src/main/java/org/perlonjava/frontend/parser/OperatorParser.java b/src/main/java/org/perlonjava/frontend/parser/OperatorParser.java index 1edc622ad..d3fc32a5d 100644 --- a/src/main/java/org/perlonjava/frontend/parser/OperatorParser.java +++ b/src/main/java/org/perlonjava/frontend/parser/OperatorParser.java @@ -124,6 +124,21 @@ static Node parseDiamondOperator(Parser parser, LexerToken token) { LexerToken operand = parser.tokens.get(parser.tokenIndex); String tokenText = operand.text; + // is special: it behaves like the diamond operator <>, + // iterating over @ARGV (or STDIN if @ARGV is empty), rather than + // reading from a single named filehandle. Treat it as <> so it + // routes through DiamondIO. + if (operand.type == IDENTIFIER && tokenText.equals("ARGV") + && parser.tokens.get(parser.tokenIndex + 1).text.equals(">")) { + parser.tokenIndex += 2; // consume ARGV and > + OperatorNode diamond = new OperatorNode( + "<>", + new ListNode(currentTokenIndex), + currentTokenIndex); + diamond.setAnnotation("handleName", "ARGV"); + return diamond; + } + // Check if the token looks like a Bareword file handle if (operand.type == IDENTIFIER) { Node fileHandle = FileHandle.parseFileHandle(parser);