Say what a constant table is, so a reflection table can be one - #50
Merged
matt-edmondson merged 1 commit intoSep 11, 2026
Merged
Conversation
[minor] The target document says the other backends "become the same exercise once the vocabulary exists". They are not. A header of structs and a table of rows need different things, and a spike that tried to build the reflection table generate_reflection.cpp emits found four of them missing: there was no way to say a declaration was an array, no way to say its value was fixed where it was written, no way to write a braced list without naming a type in front of it, and no way for an element to say which member it was for. So TypeReference gains IsArray - only that it is one, with no bound, because where the brackets go is the generator's business and C++ is the one language here that puts them on the declarator rather than the type. FieldDeclaration gains IsStatic and IsConstant, the second of which is the intent rather than the keyword, since C++ says inline constexpr at namespace scope and static constexpr inside a type while C# says static readonly and Python says nothing at all. A ConstructionExpression with no type is the braced list alone, and a MemberInitialiser among its arguments is an element that names its member: a designated initialiser in C++, an object initialiser in C#, a keyword argument in Python, an object literal in JavaScript. A list whose elements are themselves lists is a table rather than a value, so it is written one element per line with a trailing comma. A table on one line is a diff nobody can read, and a generated file is read. What is still not expressible is the explicit template specialisation that sits below that table. That is C++ and only C++, and whether the AST should learn it or the generator should write it is the same question static_assert raised, with the same answer available. Also: a name may no longer swallow a bracket, or int[] would parse as a type called "int[]" rather than an array of int. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0165XQS7s11ssp36AEY8tvCF
|
matt-edmondson
deleted the
claude/holotype-cpp-schema-integration-8nzvut
branch
September 11, 2026 08:43
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.



Holotype's
docs/generated-cpp-target.mdcloses by saying the other backends "become the same exercise once the vocabulary exists". A spike that tried to build the reflection tablegenerate_reflection.cppactually emits says otherwise — a header of structs and a table of rows need different things, and four of them were missing.What was missing
FieldInfo kFields[]inline constexprFieldDeclaration= { … }.name = "mass"MemberInitialiserthrewNotSupportedExceptionoutside a constructor's initialiser listWhat this adds
TypeReference.IsArray— only that it is an array, with no bound. A bound would have to be an expression rather than a number and nothing asks for one; and where the brackets go is the generator's business, since C++ is the one language here that puts them on the declarator (T name[]) rather than on the type (T[] name).Parse/ToStringread and write[]so the round trip still holds.FieldDeclaration.IsStaticand.IsConstant— the intent rather than the keyword, because no two of these languages spell it the same way and one of them spells it differently depending on where the field sits:inline constexprstatic constexprstatic readonlystatic readonlyinlineis what makes a namespace-scope constant safe to define in a header, which is the only place a generated one appears; a static data member is already implicitly inline, so saying it inside a type would be noise. The generator tracks that with a depth rather than a flag so a type nested in a type stays balanced.A braced list. A
ConstructionExpressionwith no type is the list alone — what initialises a declaration that has already named its type, an array of rows most of all, where naming the array's type again would be wrong rather than merely redundant. AMemberInitialiseramong its arguments is an element that names its member:.name = vin C++,Name = vin C#,name=vin Python,{ name: v }in JavaScript. The last of those is the options-object convention rather than a translation — it is the only shape in that language where the names survive at all, and the remark on the method says so.Stacking. A list whose elements are themselves lists is a table, and a table written on one line is a diff nobody can read, so it goes one element per line with a trailing comma. A list of plain values is a value and stays where it is. The test is the shape of the data rather than a column count, because a generated file has no idea how wide anyone's editor is.
Result
ExemplarReflectionTableTestsbuilds that and asserts it, alongsideExemplarHeaderTests— written against the real table rather than a toy, so it fails when a generated table would.What is still not expressible
The
template<> struct Describe<T>specialisation below that table. An explicit specialisation is C++ and only C++, and whether this AST should learn it or the generator should write it is the same questionstatic_assertraised, with the same answer available. Recorded in the new test's remarks and in the Holotype plan rather than decided here.One behaviour change worth naming
IsPunctuationnow stops a name at[or], orint[]would parse as a type namedint[]rather than an array ofint. Text the grammar still cannot read whole —int[3]— falls back to a verbatim name exactly as before, so nothing becomes lossy.Testing
dotnet build -c Releaseclean, 0 warnings. Full suite 496/496 on net10.0 (this container has no .NET 9 runtime, so that leg cannot launch here — CI has both).AstFieldsgained the two flags so the editor's inspector can still edit every property a field has, and both round-trip through YAML.🤖 Generated with Claude Code
https://claude.ai/code/session_0165XQS7s11ssp36AEY8tvCF
Generated by Claude Code