Skip to content

Email::Stuff dependency chain: 5 PerlOnJava bug fixes#633

Merged
fglock merged 2 commits intomasterfrom
fix/email-stuff-build
Apr 30, 2026
Merged

Email::Stuff dependency chain: 5 PerlOnJava bug fixes#633
fglock merged 2 commits intomasterfrom
fix/email-stuff-build

Conversation

@fglock
Copy link
Copy Markdown
Owner

@fglock fglock commented Apr 30, 2026

Summary

Five real PerlOnJava bugs fixed while running ./jcpan -t Email::Stuff. The
distribution chain (MailToolsMail::InternetEmail::Send
Email::Stuff) is full of older Perl idioms; each failure exposed a
distinct bug in the parser, runtime, or build glue.

System-perl baseline: 60/61 tests pass (the 1 failure is an unrelated
upstream Email::MIME header-quoting change).

# File Bug
1 ExtUtils/MakeMaker.pm Missing ppd:: target — MailTools/Makefile.PL's MY::postamble adds all:: ppd, which made make die before anything was built. Added a no-op rule + .PHONY entry.
2 SubroutineParser my $x = new Foo or print "..." produced syntax error ... near "or print ". Indirect-object branch backtracked past the class on infix-op lookahead. Now parses as Foo->new() and lets the outer parser consume the operator.
3 ParserTables send was not in OVERRIDABLE_OP, so Email::Send's exported send() was rejected with the socket builtin's prototype *$$;$ (Not enough arguments for send). Added send to the override set.
4 Base.java use base 'IO::Handle' skipped require IO::Handle because the Java backend pre-registers a few bridge stubs (IO::Handle::_sync etc.), which made isPackageLoaded return true. Realigned with real base.pm: only @ISA or $VERSION counts as loaded; otherwise require. If require fails with Can't locate / not found AND code refs exist, accept the in-memory package (preserves the existing DBIC eval-class fix). Fixes Mail::Mailer's $class->SUPER::new.
5 StringDoubleQuoted s/\b(\w+)/\L\u$1/g produced lc(ucfirst($1)) (lowercases the freshly-uppercased first char) instead of ucfirst(lc($1)). Real Perl applies modifiers per-character left-to-right — for \L\u the first char gets \u, the rest get \L. Fixed applyCaseModifier to pre-wrap with the outer's case function before the single-char wrap. Fixes 6 subtests in MailTools/t/extract.t (Mail::Address->name uses this idiom for title-casing).

Net effect on ./jcpan -t Email::Stuff

Distribution Before After
MailTools make crashed at ppd target PASS 109/109
Return::Value PASS PASS
Email::Send most test files crashed 89/90 (1 sub fails — see below)
File::Type PASS PASS
prefork PASS PASS
Email::Stuff cascade fail cascade fail (blocked by 1 below)

Remaining blocker (out of scope, documented)

Email::Send/t/sendmail.t writes a fake sendmail with #!$^X (the path to
the jperl bash wrapper) and execs it. macOS does not support
multi-level shebang — the kernel returns ENOEXEC and the calling shell
falls back to interpreting the temp file as bash, producing
syntax error near unexpected token ;. Linux behaviour is similar.
Fix requires replacing the bash wrapper with a small native binary
launcher (jpackage / C / Rust). Documented as item 6 in
dev/modules/email_stuff.md with future-proofing options.

This single subtest failure cascades — CPAN.pm marks Email::Send as
make_test => NO and does not add its blib/lib to @INC for
Email::Stuff's tests, which then fail with Can't locate Email/Send.pm in @INC.

Test plan

  • make (full unit-test suite) passes.
  • ./jperl -e 'package Foo; sub new {...}; my $x = new Foo or die' no longer fails to parse.
  • ./jperl -e 'BEGIN { *send = sub {...} } send;' calls the override.
  • ./jperl -e 'package Foo; ... use base "Foo"' still works for in-memory base classes (DBIC pattern).
  • ./jperl -MIO::Handle -e 'use base "IO::Handle"; print Foo->new' works.
  • ./jperl -e '$_ = "spickett"; s/(\w+)/\L\u$1/; print' prints Spickett.
  • ./jcpan -t Email::Stuff reaches each distribution and the only remaining failure in MailTools / Email::Send test suites is t/sendmail.t (item 6).

Files

  • src/main/perl/lib/ExtUtils/MakeMaker.pmppd:: target
  • src/main/java/org/perlonjava/frontend/parser/SubroutineParser.java — indirect object + infix
  • src/main/java/org/perlonjava/frontend/parser/ParserTables.javasend override
  • src/main/java/org/perlonjava/runtime/perlmodule/Base.javause base require semantics
  • src/main/java/org/perlonjava/frontend/parser/StringDoubleQuoted.java — nested case modifiers
  • dev/modules/email_stuff.md — full plan / progress doc
  • src/main/java/org/perlonjava/core/Configuration.java — auto-updated commit info

Generated with Devin

@fglock fglock force-pushed the fix/email-stuff-build branch 3 times, most recently from d7017dd to 075a9b7 Compare April 30, 2026 08:31
fglock and others added 2 commits April 30, 2026 10:41
Two unrelated fixes uncovered while running `./jcpan -t Email::Stuff`:

1. ExtUtils/MakeMaker.pm: emit a no-op `ppd::` rule. Some Makefile.PLs
   (notably MailTools' postamble) declare `all:: ppd`, which previously
   broke MailTools' build with `make: *** No rule to make target 'ppd'`.
   Real ExtUtils::MakeMaker generates a Win32 PPM .ppd descriptor; we
   don't need PPM, but the target must exist so postambles work.

2. SubroutineParser: indirect-object syntax `new Class` followed by an
   infix operator (`or`, `and`, `||`, `&&`, `==`, ...) or a statement
   terminator (`;`, `)`, `}`, `]`, `,`, `?`, `:`) was being backtracked,
   making the call collapse to a bare `new` identifier and producing a
   confusing `syntax error ... near "or print ..."`. We now parse it as
   a zero-argument `Class->new()` call and let the outer parser consume
   the trailing operator. This fixes idioms like:

       my $msg = new Mail::Send  or print "not ";
       my $m   = new Mail::Mailer or warn;

   which appear verbatim in MailTools' t/mailer.t and t/send.t.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…///)

Continuation of fix/email-stuff-build. Three additional real PerlOnJava
bugs found while running ./jcpan -t Email::Stuff:

1. ParserTables.OVERRIDABLE_OP: add `send`.
   Email::Send exports a sub named `send` that real Perl honours via
   typeglob assignment. PerlOnJava was rejecting `send(Test => $msg)`
   with "Not enough arguments for send" because it always enforced the
   socket builtin's prototype `*$$;$`. Adding `send` to OVERRIDABLE_OP
   makes the imported sub win, unblocking 5 Email::Send test files.

2. Base.importBase: tighten "already loaded" detection.
   `use base 'IO::Handle'` was skipping `require IO::Handle` because the
   Java backend pre-registers a few bridge stubs (IO::Handle::_sync etc.)
   in the global code-ref map, which made isPackageLoaded() return true.
   Realigned with real Perl's base.pm: only @isa or $VERSION counts as
   loaded; otherwise require. If require fails with "Can't locate" /
   "not found" AND the package has code refs in its stash, accept it
   (preserves the DBIC eval-package fix from before).

   Fixes Mail::Mailer's `$class->SUPER::new` which was failing because
   IO::Handle::new was never defined.

3. StringDoubleQuoted.applyCaseModifier: nested \L\u ordering.
   `s/\b(\w+)/\L\u$1/g` on "spickett" was producing "spickett" instead of
   "Spickett". The outer \L was being applied AFTER the inner \u, so
   the AST was lc(ucfirst($1)) — which lowercases the freshly-uppercased
   first char. Real Perl applies case modifiers per-character left-to-
   right; for `\L\u` the first char gets \u, the rest get \L, equivalent
   to ucfirst(lc($1)).

   Fix: when a single-char modifier (\u/\l) is applied inside a region
   modifier (\L/\U/\F/\Q), pre-wrap the segment with the outer's case
   function before wrapping with the single-char function, and remove
   the segment from the outer's tracking so it isn't re-wrapped.

   Fixes 6 subtests in MailTools/t/extract.t (Mail::Address->name uses
   `s/\b(\w+)/\L\u$1/igo` to title-case extracted names).

Status with these fixes:
  MailTools   make test: PASS (109/109; was crashing)
  Email::Send make test: 89/90 (1 subtest fails: chained shebang)
  Email::Stuff: still blocked by the chained shebang cascade —
    needs a native binary launcher for jperl. Documented in
    dev/modules/email_stuff.md as item 6.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@fglock fglock force-pushed the fix/email-stuff-build branch from 075a9b7 to fd6a580 Compare April 30, 2026 08:42
@fglock fglock merged commit f83cf21 into master Apr 30, 2026
2 checks passed
@fglock fglock deleted the fix/email-stuff-build branch April 30, 2026 08:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant