feat(parser): admit slash-separated module paths (v2 grammar, step 1 of #43)#46
Merged
Conversation
First slice of the v2-grammar work in #43. The pest grammar's `qualified_name` rule was dot-separated only — `Foo.Bar.Baz`. The downstream `hypatia/ui/bridge` style used by `hyperpolymath/hypatia`'s `bridge.eph` would not parse, which is the first concrete error any consumer of the v2 grammar hits. Two changes: 1. **`ephapax.pest`** — `qualified_name` now admits `/` alongside `.` and `_`. Both separators are accepted at the grammar level; the path is stored verbatim in `Module.name`. No canonicalisation yet — that comes when the import resolver lands. 2. **`parse_surface_module`** — previously walked only `Rule::declaration`, silently dropping the `module Foo` header. Now extracts the module name from `Rule::module_decl` when present, falling back to the filename otherwise. Matches the pre-existing behaviour of `parse_module` (core parser). Tests added in both `surface::tests` and `tests::`: * `parse_module_with_slash_path` — `module hypatia/ui/bridge` parses; name preserved. * `parse_module_with_dot_path` — `module Foo.Bar.Baz` continues to parse; covers regression of the historical form. * `parse_module_without_decl_uses_filename` (surface only) — the filename-fallback path the parser already supported. Out of scope for this commit: * `extern "abi" { ... }` blocks — separate grammar + AST work, the second-largest gap behind `bridge.eph`. Tracked in #43. * `Rule::match_expr` dispatch in `parse_single_expr_core` (core parser only; surface parser already routes it correctly via `parse_match_expr`). Tracked in #43. * `Decl::Data` variant — `data` decls currently piggy-back on `parse_type_decl` in the core parser; the surface parser models them properly. Cleanup tracked in #43. After this lands, `bridge.eph`'s `module hypatia/ui/bridge` line parses; the next blocker the parser hits on that file is the `extern "gossamer" { ... }` block, which is the natural next PR. Hypatia's `build-gossamer-gui.yml` probe order is unchanged — the `::warning::` is still emitted while `extern` remains unsupported, since the workflow greps for `Parse error|expected EOI` which the `extern` rule still produces. Closes part of #43 (item 1 in the re-scoped ordering). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This was referenced May 14, 2026
This was referenced May 15, 2026
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
First slice of the v2-grammar work in #43. Admits slash-separated module paths in the pest grammar so files like
hypatia/ui/bridgecan name themselves withmodule hypatia/ui/bridge.This unblocks the first concrete parse error on
hyperpolymath/hypatia'sbridge.eph. The next blocker the file hits isextern "gossamer" { ... }, which is the natural follow-up PR (also tracked in #43).Changes
ephapax.pest—qualified_nameadmits/alongside.and_. Both separators are accepted at grammar level; the path is stored verbatim inModule.name.parse_surface_module— previously walked onlyRule::declaration, silently droppingmodule Fooheaders. Now extracts the module name fromRule::module_declwhen present, falling back to the filename otherwise (matchesparse_modulein the core parser).Tests
parse_module_with_slash_path(both surface + core) —module hypatia/ui/bridgeparses; name preserved.parse_module_with_dot_path(both surface + core) — regression cover for the historicalFoo.Bar.Bazform.parse_module_without_decl_uses_filename(surface) — filename-fallback path.cargo test -p ephapax-parser→ 47 passed, 0 failed.cargo check --workspace→ clean.Out of scope
extern "abi" { ... }blocks (separate grammar + AST work; next slice of Implement v2 grammar (module/import/extern/data/match/let!) in Rust + Idris2 parsers #43).Rule::match_exprdispatch inparse_single_expr_core(core parser only; surface parser already handles match correctly viaparse_match_expr).Decl::Datavariant —datadecls currently piggy-back onparse_type_declin the core parser; the surface parser models them properly. Cleanup tracked in Implement v2 grammar (module/import/extern/data/match/let!) in Rust + Idris2 parsers #43.Hypatia's
build-gossamer-gui.ymlprobe order is unchanged — the::warning::is still emitted whileexternremains unsupported, since the workflow greps forParse error|expected EOIwhich theexternrule still produces.Closes part of #43 (item 1 in the re-scoped ordering on that ticket).
Test plan
cargo test -p ephapax-parser(47/47 passed)cargo check --workspace(clean)bridge.ephparses past the module decl and fails next onextern.