fix(jcpan): unblock ActiveResource dependency chain (Encode tags, SAX undef parity)#568
Merged
fix(jcpan): unblock ActiveResource dependency chain (Encode tags, SAX undef parity)#568
Conversation
Document the dependency-chain failures uncovered while running
`jcpan -t ActiveResource`:
ActiveResource
├── Class::Accessor::Lvalue (XS dep "Want" — no Java port)
└── XML::Hash
└── Test::XML
└── XML::SemanticDiff (2 fails in t/16zero_to_empty_str_cmp.t)
Identifies three independent issues with priority order:
1. Encode %EXPORT_TAGS missing :all / :default (cheap, broad impact)
2. SAX empty-element text reported as '' instead of undef (medium)
3. Want XS module needed by Class::Accessor::Lvalue (deferred)
This PR will land #1 and (if scoped small) #2; #3 is tracked as a
follow-up because it requires either a Pure-Perl Want shim or a full
Java port.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Core Encode.pm exposes four export tags:
all, default, fallbacks, fallback_all
PerlOnJava only registered :fallbacks and :fallback_all, so any module
doing `use Encode qw(:all)` or `qw(:default)` died at import with:
"all" is not defined in %Encode::EXPORT_TAGS at (eval N) line 1.
This bit at least Test::XML's t/sax.t and t/basic.t (and is the kind of
thing many CPAN modules trip over).
Add a small reusable helper `defineDefaultAndAllTags()` in
PerlModuleBase that builds :default = @export and :all = @export +
@EXPORT_OK from the EXPORT/EXPORT_OK arrays already populated. Call it
from Encode.initialize() after all defineExport(...) calls so the tag
arrays capture the final lists.
Adds a regression test that asserts both the tag presence and that
`use Encode qw(:all)` / qw(:default) succeed.
Verified parity with system perl:
keys %Encode::EXPORT_TAGS = (all, default, fallback_all, fallbacks)
Refs dev/modules/active_resource.md (issue #1).
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
XML::Parser::Expat's current_element() returns $self->{Context}->[-1].
Real libexpat updates Context AFTER the user Start handler returns and
BEFORE the user End handler runs, so:
- inside StartTag: current_element returns the *parent* element
(or undef at the root)
- inside EndTag: current_element returns the parent element
(or undef at the root)
PerlOnJava had the opposite timing — pushed before Start and popped
after End — so current_element returned the just-started/closing
element instead. This broke XML::SemanticDiff: Style::Stream's doText
fires Text from inside Start/End, and XML::SemanticDiff::Text uses
current_element to attribute accumulated text. With the wrong parent,
empty-element text was attributed to the new child element, turning
its CData from undef into ''.
Fix: in XMLParserExpat.java, move the Context push to the end of
startElement() (after the user start handler) and the pop to before
the user end handler. Also factor the push/pop into small helpers
(pushContext / popContext) for the skip-path balancing.
Verified empirically against system perl with Style => 'Stream':
[Start root] cur=undef depth=0
[Text] cur=root
[Start el2] cur=root depth=1
[End el2] cur=root depth=1
[Text] cur=root
[End root] cur=undef depth=0
Test results:
- XML::Parser bundled suite: 45 files / 434 tests still pass
- XML::SemanticDiff: 2 previously-failing subtests in
t/16zero_to_empty_str_cmp.t now pass; full suite green (47/47)
- Adds src/test/resources/unit/xml_parser_current_element.t with
12 subtests covering Start/Text/End attribution at root and nested
Refs dev/modules/active_resource.md (issue #2).
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Scopes a port of CPAN's Want module (the XS dep that blocks Class::Accessor::Lvalue and therefore ActiveResource). Covers: - What Want's API actually does and why wantarray isn't enough. - Why it's hard on PerlOnJava (no op tree at runtime). - Three options (Pure-Perl shim, Java port of subset, full parity) and a recommendation to start with Option A1: a runtime lvalue-context flag plus a Perl-side shim covering LVALUE/RVALUE/ASSIGN/LIST/SCALAR/VOID + rreturn/lnoreturn. - Acceptance tests, implementation checklist, and risks (re-entrancy, interpreter parity, perf). Refs dev/modules/active_resource.md (issue #3).
395a26e to
218a431
Compare
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
Investigates and fixes two of the three failures uncovered by
jcpan -t ActiveResource.ActiveResourceitself never reaches its own test suite — it fails because of achain of dependencies, each broken for a different reason:
See
dev/modules/active_resource.md(added inthis PR) for the full breakdown.
What this PR does
dev/modules/active_resource.md— full diagnosis of all three blockers.dev/modules/want.md— detailed port plan for the deferredWantblocker (see "Out of scope" below).
returninside a literal can break JVM stack #1:Encode%EXPORT_TAGS— was missing:alland:default, souse Encode qw(:all)died with"all" is not defined in %Encode::EXPORT_TAGS.Adds a reusable
defineDefaultAndAllTags()helper inPerlModuleBaseandwires it up in
Encode.java. Now matches core perl exactly:keys %Encode::EXPORT_TAGS = (all, default, fallback_all, fallbacks).XML::Parser::Expatcurrent_elementpush/pop timing — reallibexpat updates
ContextAFTER the user Start handler returns and BEFOREthe user End handler runs. PerlOnJava had the opposite timing, so
current_element()returned the wrong element from inside Start/End. Thisbroke
XML::SemanticDiff(itsTextaccumulator misattributed text to thejust-started child, turning empty-element CData from
undefinto'').Fixed by reordering the Context push/pop in
XMLParserExpat.java.Out of scope (follow-up)
WantXS module (large, separate PR). Without it,Class::Accessor::Lvalueand thereforeActiveResourceitself remainunreachable. Detailed port plan in
dev/modules/want.md— recommends starting withOption A1: a runtime lvalue-context flag in PerlOnJava plus a Pure-Perl
Wantshim covering LVALUE/RVALUE/ASSIGN/LIST/SCALAR/VOID andrreturn/lnoreturn. That subset is enough to unblockClass::Accessor::Lvalueand thereforeActiveResource; the more exoticOBJECT('Pkg')/CHAIN(N)introspection is left for later.Test plan
makepasses locally (all unit tests).src/test/resources/unit/encode_export_tags.t— 8 subtestssrc/test/resources/unit/xml_parser_current_element.t— 12 subtestsXML::Parsersuite (src/test/resources/module/XML-Parser/t/*.t):45 files / 434 tests, all pass (no regression from the Context timing change).
XML::SemanticDiffstandalone: 18 files / 47 tests, all pass; the 2previously-failing subtests in
t/16zero_to_empty_str_cmp.tnow pass.keys %Encode::EXPORT_TAGSnow matches system perl.Generated with Devin