Allow an empty cgp_namespace! body to omit its braces - #265
Merged
Merged
Conversation
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>
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.
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 ascgp_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-bodystarts frommainatdb07fa9. Commit8de907a("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 thecgp,cgp-knowledge-base, andcgp-skillscheckouts.Behavior
An inheriting namespace can now express its complete definition in the header. A definition such as
new Child: Parentemits 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_namespaceon the branch produced the following results:new Foo: Emits only__FooComponentsandtrait Foo<__Table__>.new Foo: Bar: Emits the struct, trait, and inheritance implementation, with output identical tonew Foo: Bar { }.<T> new Foo<T>: Bar<T>: Emits the same items with the generic parameter carried through the trait and implementation.Foo: Bar(withoutnew): Emits only the inheritance implementation. The trait and marker struct must be declared elsewhere.The form without
newretains its existing declaration requirement. Its expansion references__FooComponentswithout 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 existingexpected curly braceserror. This change applies only tocgp_namespace!:delegate_components!,delegate_and_check_components!, nestedWrapper<new Inner { … }>tables, andfor … 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
cgpcheckout:crates/macros/cgp-macro-core/src/types/namespace/table.rs:NamespaceTable::parsechecksinput.is_empty()after the optional: parentclause. When the input ends there, it usesDelegateEntries::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:DelegateEntriesgains#[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:channelchanges from1.96.1to1.98.1.Expansion remains unchanged for existing inputs because the
evalpipeline is untouched. EmptyDelegateEntriesproduce neither entry implementations nor lifted inner tables. A header without a body therefore expands exactly like the same header followed by{ }.The
Defaultimplementation is also an additive public API change.DelegateEntriesis public incgp-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 fornew HeaderOnlyNamespaceandnew HeaderOnlyExtendedNamespace: DefaultNamespacewithout 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 aCheckAppbundle 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
/cgpskill 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 withoutnew, 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 theParsedescription 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.mdandcgp-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 withoutnew.