Skip to content

Commit 9d84b28

Browse files
fglockcodex
andcommitted
fix: preserve print operands after bareword handle fix
Avoid treating core operators, v-string prefixes, and immediate bareword function calls after print as autovivified filehandles. This keeps the DateTime::Calendar::Hebrew Dumper case working without regressing Perl core tests that print qq(), v-strings, or B::svref_2object(...). Generated with [Codex](https://openai.com/codex) Co-Authored-By: Codex <codex@openai.com>
1 parent 33a4931 commit 9d84b28

2 files changed

Lines changed: 74 additions & 1 deletion

File tree

src/main/java/org/perlonjava/frontend/parser/FileHandle.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,23 @@ private static boolean isDoubleUnderscoreMagicBareword(String name) {
332332
return name.length() >= 4 && name.startsWith("__") && name.endsWith("__");
333333
}
334334

335+
private static boolean isVStringBarewordPrefix(String name) {
336+
if (name.length() < 2 || name.charAt(0) != 'v') {
337+
return false;
338+
}
339+
for (int i = 1; i < name.length(); i++) {
340+
if (!Character.isDigit(name.charAt(i))) {
341+
return false;
342+
}
343+
}
344+
return true;
345+
}
346+
347+
private static boolean isImmediatelyFollowedByOpenParen(Parser parser) {
348+
return parser.tokenIndex < parser.tokens.size()
349+
&& "(".equals(parser.tokens.get(parser.tokenIndex).text);
350+
}
351+
335352
private static boolean shouldAutovivifyBarewordHandle(Parser parser, String name, boolean autovivifyUnknownBareword) {
336353
// Do not treat compile-time magic like __PACKAGE__ as print filehandles:
337354
// they match ^[A-Z_][A-Z0-9_]*$ but must fall through to the expression list
@@ -340,6 +357,20 @@ private static boolean shouldAutovivifyBarewordHandle(Parser parser, String name
340357
return false;
341358
}
342359

360+
if (isVStringBarewordPrefix(name)) {
361+
return false;
362+
}
363+
364+
// Perl treats `print foo("x")` as printing the result of foo(), while
365+
// `print foo ("x")` can be a print to filehandle foo.
366+
if (isImmediatelyFollowedByOpenParen(parser)) {
367+
return false;
368+
}
369+
370+
if (ParserTables.CORE_PROTOTYPES.containsKey(name)) {
371+
return false;
372+
}
373+
343374
String normalizedName = normalizeBarewordHandle(parser, name);
344375
if (GlobalVariable.existsGlobalCodeRefAsScalar(normalizedName).getBoolean()) {
345376
return false;

src/test/resources/unit/print_bareword_filehandle.t

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use strict;
22
use warnings;
3-
use Test::More tests => 3;
3+
use Test::More tests => 8;
44

55
package PrintBarewordTarget;
66

@@ -31,6 +31,48 @@ sub KnownPrintArg {
3131
print KnownPrintArg $object;
3232
is($known_called, 1, 'known bareword after print remains a subroutine call');
3333

34+
{
35+
my $buffer = '';
36+
open my $capture, '>', \$buffer or die $!;
37+
my $old = select $capture;
38+
my $ok = eval {
39+
print q(a);
40+
print qq(b);
41+
print join('', 'c');
42+
1;
43+
};
44+
my $error = $@;
45+
select $old;
46+
close $capture;
47+
ok($ok, 'core operators after print are not bareword filehandles') or diag $error;
48+
is($buffer, 'abc', 'print parses q, qq, and join as core operators');
49+
}
50+
51+
{
52+
my $buffer = '';
53+
open my $capture, '>', \$buffer or die $!;
54+
my $old = select $capture;
55+
my $ok = eval {
56+
print v65.66;
57+
1;
58+
};
59+
my $error = $@;
60+
select $old;
61+
close $capture;
62+
ok($ok, 'v-string after print is not a bareword filehandle') or diag $error;
63+
is($buffer, 'AB', 'print parses v-string operands');
64+
}
65+
66+
{
67+
my $ok = eval {
68+
print UnknownPrintFunction("x");
69+
1;
70+
};
71+
my $error = $@;
72+
ok(!$ok && $error =~ /Undefined subroutine .*UnknownPrintFunction/,
73+
'bareword immediately followed by parens remains a subroutine call');
74+
}
75+
3476
sub DeclaredOnly;
3577

3678
{

0 commit comments

Comments
 (0)