Skip to content

Commit b483338

Browse files
Perl::Critic support: add English.pm and fix foreach my @array scoping (#452) (#454)
* Perl::Critic support: add English.pm and fix foreach my @array scoping Phase 1 of Perl::Critic support plan (see dev/modules/perl_critic.md): 1. Add English.pm core module - provides human-readable aliases for Perl punctuation special variables. Required by Perl::Critic's Build.PL via inc/Perl/Critic/BuildUtilities.pm. 2. Fix foreach statement modifier scoping bug - in 'EXPR foreach my @v = LIST', the my @v declaration was trapped inside inner scopes (BlockNode for local and For1Node loop scope) instead of being visible in the enclosing scope. Fix applied at two levels: - StatementResolver: hoist my declarations from the foreach list expression before the BlockNode wrapper - EmitForeach: pre-evaluate list expression before enterScope() This fixes List::SomeUtils::PP::apply() which uses this pattern. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Update Perl::Critic plan with Phase 2 blockers; use perl5/ English.pm via sync.pl - Switch English.pm source from system Perl (v1.11) to perl5/ tree (v1.12) - Register English.pm in dev/import-perl5/config.yaml for sync.pl - Document Phase 2 blockers found during jcpan test: Readonly (Module::Build::Tiny/DynaLoader), Params::Util XS, Pod-Parser script generation, Pod::Spell Encode Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * docs: add detailed Phase 2 blocker plan to perl_critic.md Root-cause analysis and recommended fixes for: - 2a: DynaLoader.pm stub (unblocks Readonly via Module::Build::Tiny) - 2b: XSLoader PP-companion detection (unblocks PPI via Params::Util) - 2c: MakeMaker PL_FILES non-fatal (unblocks Pod-Parser) - 2d: Pod::Spell/Encode (deferred, optional) Includes dependency chain install order and verification steps. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix: unblock Perl::Critic Phase 2 dependencies - Add DynaLoader.pm stub so `require DynaLoader` succeeds and CPAN can resolve version dependencies (unblocks Module::Build::Tiny → Readonly) - Set $DynaLoader::VERSION in DynaLoader.java initialize() - Detect ::PP companion modules in XSLoader.java before dying, so modules like Params::Util that pre-load a PP fallback before calling XSLoader::load can proceed (unblocks PPI) - Prefix PL_FILES commands with `-` in MakeMaker.pm so script generation failures are non-fatal (unblocks Pod-Parser) Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix: @{[expr]} whitespace parsing, tied array iteration, autodie/Fatal import - Fix @{ [expr] } parsing in string/regex interpolation when whitespace appears between { and [. The tokenIndex backup used decrement-by-1 which landed on a WHITESPACE token instead of the opening brace. Now uses savedIndex to restore to the correct position. Unblocks Perl::Critic::Document. - Fix tied array iteration in RuntimeArray: getList(), addToArray(), and toString() now check for TIED_ARRAY and use size()/get(i) instead of ArrayList iterator (which uses private size field, always 0 for TieArray). Fixes Readonly::Array behavior. - Import Fatal.pm, autodie, Tie::RefHash from perl5/ tree via sync.pl - Add Config.pm startperl (was undefined, caused Module::Build::Tiny make_executable() to die under FATAL => all) - Update TAP::Parser::Multiplexer and _charnames.pm from perl5/ sync With all fixes, use Perl::Critic loads and runs successfully. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix: (??{}) in groups, interpreter local list assignment, Encode improvements - Fix (??{...}) recursive regex failing when nested inside groups (e.g., (?:abc|(??{42}))). The handler was consuming the closing ')' and returning past it, but handleParentheses convention is to return offset AT ')' and let the caller's offset++ move past it. Removed the early return and let the code fall through to common '' handling. - Fix interpreter ClassCastException for local(,)=(val1,val2). ARRAY_GET expects a register containing the index, but code was passing a raw integer. Fixed by allocating a register and loading the index with LOAD_INT first. - Encode.java: resolve_alias() now returns canonical charset name instead of undef. define_encoding() registers encoding objects in %Encode::Encoding hash, fixing Encode::Guess add_suspects. - Add Encode::Encoding and Encode::Unicode stub modules. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> EOF ) * fix: fork-open emulation returns lines in list context The fork-open emulation (open FH, "-|" + exec) returned the captured command output as a single string, even in list context. This broke Module::Build's _default_INC which expects individual lines from _backticks. The fix splits output into lines (preserving newlines, like Perl's <FH> in list context when callContext is LIST. This fixes PERL5LIB construction in Module::Build which was including jar:PERL5LIB (a virtual @inc entry with a colon) that got corrupted when split by the path separator. Now _default_INC properly identifies default @inc entries, so only real added paths go into PERL5LIB. Unblocks Perl::Critic test suite (2708/2708 tests pass in t/00_modules.t). Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> EOF ) * fix: 5 bugs blocking Perl::Critic test suite (99.5% pass rate) - List::Util::reduce: use coderef's packageName for $a/$b instead of hardcoded "main::" (fixes reduce/pairmap/pairgrep/pairfirst) - caller(): default null package names to "main" in stack traces, preventing Devel::StackTrace crashes when filtering frames - local *glob: create new empty replacement objects instead of calling dynamicSaveState on existing ones, fixing corruption of blessed objects when localizing typeglobs (Pod::Parser pattern) - \N{CARRIAGE RETURN}: add all C0/C1 control character name aliases to UnicodeResolver (NUL, SOH, CR, LF, TAB, etc.) since ICU4J doesn't support Unicode Name Aliases - state variable hoisting: suppress false "redeclared" warnings when EmitBlock hoists state declarations to enclosing scope Perl::Critic test results: 34/40 files pass, 5389/5416 subtests (99.5%). Remaining 27 failures are from a deep eval-string closure capture bug (Bug 6) and unrelated Perl::Tidy/charnames issues. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix: reduce aliasing bug, caller null package, Exception::Class aliases - List::Util::reduce: clone accumulator before finally block restores $a/$b, preventing the result from being corrupted when the code block returns $a or $b directly (same RuntimeScalar object as varA/varB) - caller(): ensure package name is never null (defaults to "main") in both scalar and list context return paths - ExceptionFormatter: null-check package name in runSpecialBlock handler Perl-side workarounds (in ~/.perlonjava/lib/): - Exception::Class: replace alias closure with eval-string to avoid eval-string closure capture bug corrupting $subclass - Devel::StackTrace: guard against undef package in frame filter Perl::Critic: 37/40 files pass, 5406/5416 subtests (99.8%) Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix: charnames::viacode, ref(*{$fh}{IO}), Perl::Critic 99.9% pass rate - Wire _charnames::viacode() to Java-backed ICU4J lookup via _java_viacode, bypassing missing unicore/Name.pl. Add C0/C1 control character name table to Charnames.java. - Fix populate_txt() in _charnames.pm to not crash when unicore/Name.pl is unavailable. - Fix ref(*{$fh}{IO}) to return "IO::Handle" instead of "GLOB" by checking for RuntimeIO in ReferenceOperators.java. - Perl::Critic test suite: 39/40 files, 5411/5416 subtests (99.9%) Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix: add ClassFormatError to interpreter fallback Perl::Tidy's Formatter module has subroutines with 113+ hash key accesses that exceed JVM's 255-argument method signature limit, causing ClassFormatError. This catch enables graceful fallback to the interpreter backend for such cases. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * perf: selective closure variable capture, fix BIPUSH overflow Closures now only capture variables actually referenced in their body, instead of all visible lexical variables. This prevents JVM 255 constructor argument limit from being hit in modules like Perl::Tidy where subroutines have 200+ lexicals in scope. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix: selective closure capture for named subs, fix Perl::Tidy re-entry hang SubroutineParser: Apply VariableCollectorVisitor-based selective capture filtering to named subs (matching anonymous subs in EmitSubroutine). Prevents hitting JVM 255 constructor argument limit for large modules. Perl::Tidy workaround: Fix infinite loop in _decrement_count() while _increment_count() > 1 pattern in Formatter.pm and Tokenizer.pm. Replaced with correct peek-reset-set pattern for missing DESTROY. Unblocks t/20_policy_require_tidy_code.t (6/6 tests now pass). Generated with Devin (https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix: VariableCollectorVisitor missing TryNode.finallyBlock and ListNode.handle The selective closure capture visitor was not traversing: - TryNode.finallyBlock: variables used only in finally blocks were not collected, causing 'Global symbol requires explicit package name' errors under use strict (broke op/try.t) - ListNode.handle: variables used in indirect object syntax like 'exec $prog "hello"' were not collected (broke op/taint.t) Generated with Devin (https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix: local *glob now properly saves/restores pinned code refs When `local *glob` was used, dynamicSaveState() replaced the globalCodeRefs entry with a new empty object, but pinnedCodeRefs still pointed to the saved (original) object. Since getGlobalCodeRef() checks pinnedCodeRefs first, assignments during the local scope (e.g. `*foo = sub { ... }`) would mutate the saved snapshot object instead of the new empty one, making dynamicRestoreState() a no-op. Fix: Added GlobalVariable.replacePinnedCodeRef() to redirect the pinned ref during local scope and restore it on scope exit. This fixes method_caching.t tests 7, 9, 10, 11 and method_caching_utf8.t tests 7, 9. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix: constant-fold (??{...}) with simple constants in regex patterns For simple constant expressions like (??{1}) or (??{"[x]"}), inline the evaluated value directly as a regex pattern: (?:1) or (?:[x]). This avoids the empty-group issue where (??{}) produced an empty match. Non-constant or complex expressions still fall through to the existing runtime eval path. Fixes 8 test failures in re/regexp.t and related re_tests variants. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix: kv-slice closure capture and tied array CLEAR-during-assign Two fixes for branch regressions: 1. VariableCollectorVisitor: %a[@i] and @A[@i] now correctly capture @A (the array), not just %a. The selective closure capture was only handling $a[idx] -> @A, missing the % and @ sigil variants used in kv-slices and array slices. Fixes kvaslice.t test 23. 2. RuntimeArray.setFromList (TIED_ARRAY): return materializedList instead of `this` after assignment. When CLEAR replaces the glob (e.g. *a = []), the old tied array becomes invalid. Returning it caused getList() to call FETCHSIZE on the dead tied object. Fixes tie.t test 55. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix: preprocess (??{const}) output through handleRegex The constant-folded value from (??{"[x]"}) may contain regex constructs like (?[...]) from regex_sets_compat.t transformation. Run the value through handleRegex() so these get converted to Java-compatible patterns. Fixes regex_sets_compat.t test 1709; net +1 over master (2089 vs 2088). 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>
1 parent 8bd6e15 commit b483338

42 files changed

Lines changed: 6021 additions & 171 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

dev/import-perl5/config.yaml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,43 @@ imports:
341341
target: perl5_t/Attribute-Handlers
342342
type: directory
343343

344+
# English - Human-readable aliases for punctuation special variables
345+
- source: perl5/lib/English.pm
346+
target: src/main/perl/lib/English.pm
347+
348+
# Fatal / autodie - Make builtins throw exceptions on failure
349+
# Required by Perl::Critic test data generation (.run.PL files)
350+
- source: perl5/cpan/autodie/lib/Fatal.pm
351+
target: src/main/perl/lib/Fatal.pm
352+
353+
- source: perl5/cpan/autodie/lib/autodie.pm
354+
target: src/main/perl/lib/autodie.pm
355+
356+
- source: perl5/cpan/autodie/lib/autodie/Util.pm
357+
target: src/main/perl/lib/autodie/Util.pm
358+
359+
- source: perl5/cpan/autodie/lib/autodie/exception.pm
360+
target: src/main/perl/lib/autodie/exception.pm
361+
362+
- source: perl5/cpan/autodie/lib/autodie/exception/system.pm
363+
target: src/main/perl/lib/autodie/exception/system.pm
364+
365+
- source: perl5/cpan/autodie/lib/autodie/hints.pm
366+
target: src/main/perl/lib/autodie/hints.pm
367+
368+
- source: perl5/cpan/autodie/lib/autodie/skip.pm
369+
target: src/main/perl/lib/autodie/skip.pm
370+
371+
- source: perl5/cpan/autodie/lib/autodie/Scope/Guard.pm
372+
target: src/main/perl/lib/autodie/Scope/Guard.pm
373+
374+
- source: perl5/cpan/autodie/lib/autodie/Scope/GuardStack.pm
375+
target: src/main/perl/lib/autodie/Scope/GuardStack.pm
376+
377+
# Tie::RefHash - Hash with references as keys (required by Fatal.pm)
378+
- source: perl5/lib/Tie/RefHash.pm
379+
target: src/main/perl/lib/Tie/RefHash.pm
380+
344381
# From core distribution
345382
- source: perl5/dist/Env/lib/Env.pm
346383
target: src/main/perl/lib/Env.pm

0 commit comments

Comments
 (0)