Skip to content

Auto-home bare same-package references (#4529)#5425

Merged
yegor256 merged 10 commits into
masterfrom
claude/github-issue-4529-0rb69t
Jul 14, 2026
Merged

Auto-home bare same-package references (#4529)#5425
yegor256 merged 10 commits into
masterfrom
claude/github-issue-4529-0rb69t

Conversation

@yegor256

@yegor256 yegor256 commented Jul 12, 2026

Copy link
Copy Markdown
Member

Closes #4529.

What

When a program declares a +package meta, a bare reference to an object that belongs to the same package is now resolved automatically into that package, as if a +alias had been written by hand. For example, in package foo:

+package foo

[] > x
  bar 42 > @

bar is compiled to Φ.foo.bar (previously it defaulted to the root Φ.bar), so same-package objects no longer need manual +alias foo.bar metas.

How

add-default-package.xsl takes an objects parameter — the space-separated names of the local objects that belong to a package, filled in by the eo-maven-plugin from the registered catalog. The rule for a bare name in a program with a +package meta:

  • the name is one of those local package objects → home it into the current package (Φ.<pkg>.<name>);
  • otherwise → leave it at the root Φ (treated as a global — the default behaviour).

This keeps globals correct without any allow/deny gymnastics: a bare seq (not a local package object) stays Φ.seq, and when the list is empty (e.g. the parser used stand-alone) every bare reference falls back to the root Φ. Aliased references are untouched (handled earlier in the chain).

Changes

  • add-default-package.xsl — new objects parameter and an eo:homed() function; @base/@atom bare references are homed into the current package only when the name is a local package object, otherwise into Φ.
  • Canonical (new, in eo-parser) — wraps the canonical XSL pipeline as a UnaryOperator<XML>, injecting the objects parameter into add-default-package.xsl; the pipeline is built lazily and once, thread-safely (cactoos Synced/Sticky), and reused across the concurrent parse.
  • EoSyntaxCANONICAL delegates to Canonical; a public (Input, UnaryOperator<XML>) constructor lets the plugin supply the objects-aware pipeline.
  • Parsing — builds the objects-aware pipeline once from the local package-object names and reuses it for every source; the object-set digest is part of the parse-cache key so cached XMIRs are invalidated when the set changes.
  • EoSource — accepts the shared transform.

Testing

  • eo-parser: full suite passes, incl. new EoSyntaxTest cases (bare reference homed into the package when it is a local package object; kept at root otherwise).
  • eo-maven-plugin: MjParseTest (incl. new end-to-end cases across two files in one package), CompilingTest, MjTranspileTest — all green under -Pqulice.
  • Real eo-runtime: all 113 sources parse concurrently with no error; an exact-match audit confirms no global (seq, malloc, number, …) is wrongly homed into a package, and bare seq stays Φ.seq.

Notes

  • Homing applies to the current project's local package objects known at parse time. Referencing a same-package object that lives in an external dependency still needs an explicit +alias; bare references to runtime globals are unaffected (they stay at the root).

🤖 Generated with Claude Code

https://claude.ai/code/session_01LUBw9ufavQSMDmBxnqJ9Nw

When a program declares a "+package" meta, a bare reference to an
object that exists in the same package is now resolved automatically
into that package, as if a "+alias" meta had been declared. For
example, in package "foo" the reference "bar" is compiled to
"Φ.foo.bar" when "Φ.foo.bar" is a known object, so same-package
objects no longer need manual "+alias" metas.

The decision is existence-based to stay safe: "add-default-package.xsl"
takes an "objects" parameter with the fully qualified names of all
objects the compiler is aware of. A bare reference is homed into the
current package only when such an object exists there; otherwise it
stays at the root "Φ" (so bare globals like "seq", which live at
"Φ.seq" and not at "Φ.foo.seq", are untouched). The eo-maven-plugin
fills this parameter from the registered "foreign" catalog during
parsing and includes its digest in the parse cache key so cached
XMIRs are invalidated when the set of objects changes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUBw9ufavQSMDmBxnqJ9Nw
@github-actions

github-actions Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

🚀 Performance Analysis

All benchmarks are within the acceptable range. No critical degradation detected (threshold is 100%). Please refer to the detailed report for more information.

Click to see the detailed report
Test Base Score PR Score Change % Change Unit Mode
benchmarks.XmirBench.xmirToEO 21222.902 21095.604 -127.298 -0.60% ms/op Average Time

✅ Performance gain: benchmarks.XmirBench.xmirToEO is faster by 127.298 ms/op (0.60%)

claude and others added 6 commits July 12, 2026 21:15
- Move the canonical XSL pipeline out of EoSyntax into a new
  Canonical class implementing Function<XML, XML>, to satisfy
  qulice (no public static methods, correct declaration order,
  no trailing dot in Javadoc tags).
- Thread the parsing transform and objects-digest through Parsing
  as parameters instead of mutable fields.
- Update MjParseTest.parsesWithCache to account for the objects
  digest now included in the parse cache key.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUBw9ufavQSMDmBxnqJ9Nw
- Build the canonical pipeline lazily via a cactoos Scalar so the
  Canonical constructor contains only instantiations (satisfies
  ConstructorsCodeFreeCheck).
- Suppress PMD UnnecessaryLocalRule where the pipeline/digest locals
  must be built once and captured by the parsing lambda.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUBw9ufavQSMDmBxnqJ9Nw
Parsing runs concurrently (Threaded), and the lazily-built pipeline
in Canonical was memoized with a plain Sticky scalar, which is not
thread-safe: under concurrent first access the scalar could return
null, causing a NullPointerException while parsing. Wrap it in a
Synced scalar so the pipeline is built once and safely shared across
threads.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUBw9ufavQSMDmBxnqJ9Nw
- add-default-package.xsl now takes the list of local package object
  NAMES (not all FQNs). A bare name in a program with a "+package" meta
  is homed into that package when it is one of those names; otherwise it
  stays at the root "Φ" (treated as a global). Empty list falls back to
  the root, so bare globals like "seq" and the stand-alone parser are
  untouched.
- The eo-maven-plugin fills the list with the simple names of the local
  objects that belong to a package.
- Use UnaryOperator<XML> instead of Function<XML, XML> (SonarCloud
  java:S4276).
- Remove the PMD UnnecessaryLocalRule suppressions: the parsing
  transform and digest are passed as method parameters instead of
  single-use locals, and the test computes the cache version inline via
  a helper.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUBw9ufavQSMDmBxnqJ9Nw
With same-package auto-homing in place, a bare reference to an object
of the current package no longer needs a manual "+alias". Remove the
now-redundant "+alias ms.*" metas across the ms package (abs, pi, e,
sine, power, ln, sqrt, arc-sine); those bare references are homed into
"Φ.ms.*" automatically, producing the exact same XMIR as before. This
both exercises the new feature on real code and delivers its intended
benefit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUBw9ufavQSMDmBxnqJ9Nw
@yegor256 yegor256 marked this pull request as ready for review July 13, 2026 08:45
Copilot AI review requested due to automatic review settings July 13, 2026 08:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@yegor256

Copy link
Copy Markdown
Member Author

@maxonfjvipon take a look

final String objects = sources.stream()
.map(TjForeign::identifier)
.filter(id -> id.contains("."))
.map(id -> id.substring(id.lastIndexOf('.') + 1))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This flattens every object across all packages into one set of simple names, so eo:homed homes a bare name into the current package whenever the name exists in any package. ss and tt already both define contains/index-of/last-index-of, and ss/index-of.eo uses a bare number — the day any package gains a number object, that reference silently re-homes to Φ.ss.number. Keying on the qualified name avoids this: pass the .-containing identifiers as objects unchanged, then home only when concat($package, '.', $name) matches. Same single pipeline, no simple-name collisions.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 501c5d1. add-default-package.xsl now keys on the qualified name: the plugin passes the .-containing identifiers (package.name) unchanged, and a bare name is homed only when concat($package, '.', $name) is in the list. So the simple-name collision is gone — verified against eo-runtime, the bare number in ss/index-of.eo stays Φ.number (33 occurrences, 0 Φ.ss.number).


Generated by Claude Code

.distinct()
.collect(Collectors.joining(" "));
final int total = this.parsed(
sources, new Canonical(objects), Integer.toHexString(objects.hashCode())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String.hashCode is a collidable 32-bit hash, and objects is built with distinct() over withSources(), whose order isn't guaranteed. A collision gives a stale cache hit; an order flip gives a needless miss. Sorting the names and using a real digest makes this deterministic.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 501c5d1. The qualified names are now sorted and hashed with SHA-256 (cactoos Sha256DigestOf + HexOf) instead of the order-sensitive, 32-bit String.hashCode, so the cache key is deterministic and collision-resistant.


Generated by Claude Code

Per @maxonfjvipon's review:

- add-default-package.xsl now keys on the qualified name. The plugin
  passes the "." -containing identifiers (package.name) unchanged, and
  a bare name is homed only when concat($package, '.', $name) matches.
  This removes the simple-name collision across packages: e.g. a bare
  "number" in "ss" stays "Φ.number" even though other packages may
  define objects with colliding simple names.
- The parse-cache digest is now deterministic and collision-resistant:
  the qualified names are sorted and hashed with SHA-256 (cactoos
  Sha256DigestOf + HexOf) instead of the order-sensitive, 32-bit
  String.hashCode.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUBw9ufavQSMDmBxnqJ9Nw
@yegor256

Copy link
Copy Markdown
Member Author

@maxonfjvipon take a look again please

Comment thread eo-parser/src/main/resources/org/eolang/parser/parse/add-default-package.xsl Outdated
yegor256 and others added 2 commits July 14, 2026 15:03
@sonarqubecloud

Copy link
Copy Markdown

@yegor256

Copy link
Copy Markdown
Member Author

@maxonfjvipon good now?

@yegor256 yegor256 merged commit c3bd602 into master Jul 14, 2026
25 of 26 checks passed
@yegor256 yegor256 deleted the claude/github-issue-4529-0rb69t branch July 14, 2026 14:23
@0crat

0crat commented Jul 15, 2026

Copy link
Copy Markdown

@maxonfjvipon Thanks for the review! You've earned +7 points for this: +12 as a basis; -5 for very few (2) comments. Your running score is +616; don't forget to check your Zerocracy account too).

@0crat

0crat commented Jul 15, 2026

Copy link
Copy Markdown

@yegor256 Thanks for the contribution! You've earned +4 points for this: +16 as a basis; -4 for too many hits-of-code (475 >= 100); -8 for way too many hits-of-code (475 >= 400). Please, keep them coming. Your running score is +1720; don't forget to check your Zerocracy account too).

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.

Compile-time Optimization Not Automatically Converting Local Objects into Aliases

5 participants