Replace Java Exporter with pure Perl implementation#347
Merged
Conversation
- Remove Exporter.java and use Exporter.pm from Perl 5 core - Add generic inheritFrom() method to PerlModuleBase for loading and inheriting from any Perl module on-demand - Add Exporter.pm and Exporter/Heavy.pm to import config - Update GlobalContext to not initialize Java Exporter Known issue: Lexical override of builtins (e.g., `use Time::HiRes 'time'`) not yet implemented - documented in dev/design/pure-perl-exporter.md Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Parser now checks if subroutine exists (via existsGlobalCodeRef) in addition to checking isSubs flag. This allows imported subs like Time::HiRes::time to override builtins when called without & prefix. Since use statements run at BEGIN time before subsequent code is parsed, imported subs are visible to the parser when it encounters calls to them. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
When taking a reference to a constant subroutine (\&name), return the
CODE reference instead of a reference to the constant value. This fixes
Exporter which does `*{$pkg::$sym} = \&{$src::$sym}` - the glob
assignment expects a CODE reference to work correctly.
This fixes regressions in op/do.t, io/scalar.t, op/stat_errors.t and
other tests that use Errno constants like ENOENT.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…balCodeRef existsGlobalCodeRef returns true even for undefined stub subs, which caused false positives when checking if an overridable builtin (like open, readline) should be treated as a user-defined sub. Use isGlobalCodeRefDefined which properly checks if the sub is actually defined (has methodHandle or constantValue). Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
d42447b to
6294edd
Compare
When initializeGlobals() is called, modules are initialized, which may call require() to load other modules (like Exporter.pm). This triggers re-entrant calls to initializeGlobals() with different compilerOptions, overwriting special variables like $0, $/, and $\ with the module's values. Fix by only setting these variables if they haven't been set yet, using containsKey() checks before the first assignment. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
fglock
added a commit
that referenced
this pull request
Mar 21, 2026
Two fixes for run/switches.t regression introduced in PR #347: 1. Backticks now preserve exact output by reading raw bytes instead of using BufferedReader.readLine() which added extra trailing newlines 2. $^I is now initialized from compilerOptions.inPlaceExtension so the -i switch properly enables in-place editing with backup files Test results: run/switches.t improved from 8/107 to 38/142 (baseline was 29/142) Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
fglock
added a commit
that referenced
this pull request
Mar 22, 2026
…ame (#349) * Fix ClassCastException when CORE::GLOBAL::require is overridden The bug occurred when: 1. CORE::GLOBAL::require was overridden 2. A file was loaded via do/require 3. That file contained a use statement The parser assumed requireOp.operand was always a ListNode, but it could be a NumberNode (e.g., for version requirements like 'use 5.008'). Added defensive instanceof checks in: - ParsePrimary.java (root cause) - EmitControlFlow.java - EmitOperator.java - EmitRegex.java - CompileOperator.java Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Add bundled Try::Tiny implementation and fix substr negative offset Try::Tiny: - Pure Perl implementation compatible with Try::Tiny 0.32 - All essential tests pass: basic.t (25/25), finally.t (30/30), context.t (25/25), erroneous_usage.t (8/8) - Supports nested try/catch/finally, multiple finally blocks - Properly re-throws if catch block dies (after finally runs) - Warning format matches original for fatal finally blocks Operator.java (substr): - Fix negative offset behavior to match Perl 5 semantics - Without explicit length: clip negative offsets to 0 (no warning) - With explicit length: warn and return undef if offset is too negative - Fixes unit/warnings.t test Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Fix caller() to honor set_subname() for JVM-compiled code - Add callerWithSub() method that takes __SUB__ parameter - JVM backend now passes __SUB__ to caller() via handleCallerOperator - For caller(0), if __SUB__ has a subName set by set_subname(), use it - Interpreter already worked via InterpreterState tracking code.subName Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Fix backticks trailing newline and -i switch regression Two fixes for run/switches.t regression introduced in PR #347: 1. Backticks now preserve exact output by reading raw bytes instead of using BufferedReader.readLine() which added extra trailing newlines 2. $^I is now initialized from compilerOptions.inPlaceExtension so the -i switch properly enables in-place editing with backup files Test results: run/switches.t improved from 8/107 to 38/142 (baseline was 29/142) Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR replaces the Java implementation of Exporter with the pure Perl version from Perl 5 core.
Changes
Exporter.java- Java implementation no longer neededExporter.pmandExporter/Heavy.pmfrom Perl 5 distinheritFrom(String parentModule)method toPerlModuleBase.java:requireif not already loaded@ISAinitializeExporter()now callsinheritFrom("Exporter")GlobalContext.javato not initialize Java Exporterdev/design/pure-perl-exporter.mdHow It Works
Java modules that need Exporter functionality call
initializeExporter()which:Exporter.pmif not loadedExporterto the module's@ISAExporter::importfrom pure PerlKnown Issue
Lexical override of builtins (e.g.,
use Time::HiRes 'time') is not yet implemented. Thetime_hires_override.ttest fails because the parser doesn't know to treattimeas a subroutine call after import. This is documented in the design doc for Phase 2 implementation.Test Plan
use File::Basename qw(dirname)use Carp qw(:DEFAULT)use constant X => 42use Time::HiRes 'time'- deferred to Phase 2Generated with Devin