Skip to content

Allow an empty cgp_namespace! body to omit its braces - #265

Merged
soareschen merged 2 commits into
mainfrom
empty-namespace-body
Sep 15, 2026
Merged

soareschen merged 2 commits into
mainfrom
empty-namespace-body

Conversation

@soareschen

@soareschen soareschen commented Sep 15, 2026

Copy link
Copy Markdown
Collaborator

AI Summary

This PR lets cgp_namespace! omit the body braces when a namespace has no entries of its own. For example, cgp_namespace! { new ExtendedNamespace: DefaultNamespace } produces the same expansion as cgp_namespace! { new ExtendedNamespace: DefaultNamespace { } }. The PR also updates the pinned stable toolchain from 1.96.1 to 1.98.1. The parser change does not require that update.

The implementation, tests, and documentation are ready in the working tree, but the changelog and toolchain descriptions still need updates. The checks reported below passed under 1.98.1, though the full workspace test run preceded the new tests. The expanded test targets passed separately after the additions.

This overview covers both the committed change and uncommitted supporting work. Branch empty-namespace-body starts from main at db07fa9. Commit 8de907a ("Allow empty namespace body to omit braces") changes three files, with 7 insertions and 3 deletions. The working tree adds tests, documentation, and parser formatting in the cgp, cgp-knowledge-base, and cgp-skills checkouts.

Behavior

An inheriting namespace can now express its complete definition in the header. A definition such as new Child: Parent emits a marker struct, a lookup trait, and a blanket implementation that forwards every key the parent resolves. When the child has no entries of its own, an empty body adds nothing to that definition. The parser now treats the omitted body as an empty table.

The relaxation also applies to other forms that end at the header. Passing these forms through cgp_macro_lib::cgp_namespace on the branch produced the following results:

  • new Foo: Emits only __FooComponents and trait Foo<__Table__>.
  • new Foo: Bar: Emits the struct, trait, and inheritance implementation, with output identical to new Foo: Bar { }.
  • <T> new Foo<T>: Bar<T>: Emits the same items with the generic parameter carried through the trait and implementation.
  • Foo: Bar (without new): Emits only the inheritance implementation. The trait and marker struct must be declared elsewhere.

The form without new retains its existing declaration requirement. Its expansion references __FooComponents without declaring it. Omitting the braces makes this form easier to write accidentally, so the reference document now states the requirement beside the new syntax.

The body is optional only when the input ends immediately after the header. A stray token still reaches the braced! call and fails with the existing expected curly braces error. This change applies only to cgp_namespace!: delegate_components!, delegate_and_check_components!, nested Wrapper<new Inner { … }> tables, and for … in … { … } loops still require braces. The namespace and delegation macros continue to share a body grammar, but their header grammars now differ.

Implementation

The committed implementation changes the namespace parser, its shared table-body type, and the toolchain pin. Paths below are relative to the cgp checkout:

  • crates/macros/cgp-macro-core/src/types/namespace/table.rs: NamespaceTable::parse checks input.is_empty() after the optional : parent clause. When the input ends there, it uses DelegateEntries::default() instead of requiring a braced body. The working tree also removes two blank lines that rustfmt rejected in the commit.
  • crates/macros/cgp-macro-core/src/types/delegate_component/entries.rs: DelegateEntries gains #[derive(Default)], producing an empty table without statements or mappings. The working tree documents its use for a namespace whose body is omitted.
  • rust-toolchain.toml: channel changes from 1.96.1 to 1.98.1.

Expansion remains unchanged for existing inputs because the eval pipeline is untouched. Empty DelegateEntries produce neither entry implementations nor lifted inner tables. A header without a body therefore expands exactly like the same header followed by { }.

The Default implementation is also an additive public API change. DelegateEntries is public in cgp-macro-core, so direct users of that crate can use the new implementation. Its doc comment and the AST document now describe the default value.

Tests and documentation

The working tree adds expansion, wiring, and rejection coverage in the targets required by the test-suite conventions. These additions cover both the usable namespace and the boundary of the new syntax:

  • crates/tests/cgp-tests/tests/namespaces/namespace_header_only.rs: Adds and registers snapshots for new HeaderOnlyNamespace and new HeaderOnlyExtendedNamespace: DefaultNamespace without body braces. It also joins a context to the inheriting namespace, wires the inherited error type and raiser components under their full paths, and uses a CheckApp bundle to assert that each capability resolves.
  • crates/tests/cgp-macro-tests/tests/parser_rejections/cgp_namespace.rs: Adds rejection cases for a semicolon after the parent and a stray identifier after the name. Both ensure that omitting the body requires the input to end at the header.

The documentation updates keep the source, tests and snapshots, reference, implementation documents, and /cgp skill consistent, as required by the AGENTS instructions. The sibling checkouts contain these changes:

  • cgp-knowledge-base/cgp/reference/macros/cgp_namespace.md: Adds an example without body braces, documents the declaration requirement for forms without new, makes the braced table optional in the EBNF grammar, and states that only { or end of input may follow the header.
  • cgp-knowledge-base/cgp/implementation/asts/namespace.md: Updates the Parse description to explain the optional table and default entries.
  • cgp-knowledge-base/cgp/implementation/entrypoints/cgp_namespace.md: Updates the parse step, corner-case explanation, inheritance example comment, snapshot and test entries, and rejection description.
  • cgp-skills/cgp/references/macro-grammar.md and cgp-skills/cgp/references/namespaces.md: Document the optional table in the EBNF grammar and the inheritance syntax without body braces.

The documentation also explains the limits of the change. It identifies the optional body as specific to cgp_namespace!, preserves the brace requirements for delegation macros and nested constructs, and states the declarations needed by the form without new.

soareschen and others added 2 commits September 15, 2026 09:31
Pin the braceless header with snapshots for `new Ns` and `new Child: Parent`,
wire a context through the braceless inheriting namespace, and reject a stray
token after the header in `cgp-macro-tests`. Document the `Default` on
`DelegateEntries` and remove the blank lines rustfmt rejected.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@soareschen
soareschen merged commit 0bf713d into main Sep 15, 2026
3 checks passed
@soareschen
soareschen deleted the empty-namespace-body branch September 15, 2026 13:32
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