From a933d7ce4081bf5b6744978ae7025f2b3abfbd41 Mon Sep 17 00:00:00 2001 From: "Flavio S. Glock" Date: Thu, 27 Aug 2026 16:24:39 +0200 Subject: [PATCH] fix: honor imported chmod and lock overrides Add chmod and lock to the parser's overridable core built-in set so Exporter-style imports dispatch to the imported subroutine. Keep explicit CORE:: calls on the built-in path and add regression coverage for both execution backends. Generated with [Codex](https://openai.com/codex/) Co-Authored-By: Codex --- docs/about/changelog.md | 1 + .../frontend/parser/ParserTables.java | 4 +- .../unit/imported_core_builtin_override.t | 41 +++++++++++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 src/test/resources/unit/imported_core_builtin_override.t diff --git a/docs/about/changelog.md b/docs/about/changelog.md index b389c5e7b1..1afdfb7b4f 100644 --- a/docs/about/changelog.md +++ b/docs/about/changelog.md @@ -19,6 +19,7 @@ Release history of PerlOnJava. See [Roadmap](roadmap.md) for future plans. CFB128, OFB, and CTR compatibility. - Preserve string-compatible scalar channels for arithmetic results derived from string operands on both execution backends. +- Honor imported overrides of the core `chmod` and `lock` built-ins. ## v5.44.1: Regex, Threads, Async/Await, and CPAN Compatibility diff --git a/src/main/java/org/perlonjava/frontend/parser/ParserTables.java b/src/main/java/org/perlonjava/frontend/parser/ParserTables.java index 160eabf043..7985d187ae 100644 --- a/src/main/java/org/perlonjava/frontend/parser/ParserTables.java +++ b/src/main/java/org/perlonjava/frontend/parser/ParserTables.java @@ -27,13 +27,13 @@ public class ParserTables { public static final Set OVERRIDABLE_OP = Set.of( "bless", "atan2", - "caller", "chdir", "close", "connect", + "caller", "chdir", "chmod", "close", "connect", "die", "do", "dump", "exec", "exit", "fork", "getgrgid", "gethostbyname", "getpwuid", "glob", "hex", - "kill", + "kill", "lock", "localtime", "log", "oct", "open", "rand", "readline", "readpipe", "rename", "require", diff --git a/src/test/resources/unit/imported_core_builtin_override.t b/src/test/resources/unit/imported_core_builtin_override.t new file mode 100644 index 0000000000..9c714621b4 --- /dev/null +++ b/src/test/resources/unit/imported_core_builtin_override.t @@ -0,0 +1,41 @@ +use strict; +use warnings; +use Test::More; + +# Model the way a pure-Perl module exports a subroutine: assigning its CODE +# slot into the caller's package during import must make the imported sub win +# over a same-named core builtin. +BEGIN { + package ImportedCoreBuiltins; + + sub chmod { + return 'imported chmod'; + } + + sub lock { + return 'imported lock'; + } + + sub import { + my ($class, $caller) = @_; + $caller //= caller; + no strict 'refs'; + *{"${caller}::chmod"} = \&chmod; + *{"${caller}::lock"} = \&lock; + } + + __PACKAGE__->import('main'); +} + +is(chmod('+r', 'unused'), 'imported chmod', + 'imported chmod overrides the core builtin'); +my $lock_name = 'unused'; +is(lock($lock_name), 'imported lock', + 'imported lock overrides the core builtin'); +is(CORE::chmod(0, 'unused'), 0, + 'CORE::chmod still selects the core builtin'); +my $lock_target = 'unused'; +is(CORE::lock($lock_target), 'unused', + 'CORE::lock still selects the core builtin'); + +done_testing();