[major] Model visibility, constants and entry points in the AST - #32
Merged
Conversation
Closes three gaps where the AST could not say something every target language can spell. Visibility (#25) becomes an enumeration — Public, Protected, Internal, Private, and Unspecified for "however the language would write it anyway" — carried by ClassDeclaration, FunctionDeclaration and VariableDeclaration through IHasVisibility. It replaces the free-text AccessModifier that ClassDeclaration and VariableDeclaration carried, which could only ever be right for whichever language it was typed for. Each generator spells it its own way: C# writes the keyword, C++ groups members under access labels, JavaScript gives a private member the # prefix that is its own private syntax, and Python writes nothing at all, because its leading-underscore convention renames the declaration and would leave every reference to it naming something that no longer exists. Documents written with accessModifier still load. Constants (#26) are a VariableDeclaration marked IsConstant with a literal value, and now come out right wherever they sit: C++ writes static constexpr for a class member rather than a per-instance const, JavaScript writes static for one rather than a const that is a syntax error in a class body, and the palette offers a constant already holding a literal. EntryPoint (#27) is a node of its own rather than a function named main, since only some languages spell the entry point as a function at all. It carries the two things that vary — whether the program reads its arguments and whether it returns an exit code — and each generator writes what its language looks for: C#'s static Main, C++'s free int main, Python's main with the __main__ guard and the import its arguments need, and JavaScript's main with the call that runs it. The schema, the inspector, the palette and the YAML round trip carry all three, with 41 tests over the four generators and both directions of serialization. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FMNNvzNnuLErq96R4NjYUi
|
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.



Closes #25, closes #26, closes #27.
Three gaps where the AST could not say something every target language can spell. All three go the whole way along the path a node feature has to work: the AST, the schema the editor walks, the inspector, the palette, the four generators and both directions of YAML.
Visibility (#25)
Visibilityis an enumeration —Public,Protected,Internal,Private, andUnspecifiedmeaning "however the language would write it anyway".ClassDeclaration,FunctionDeclarationandVariableDeclarationcarry it throughIHasVisibility.It replaces the free-text
string? AccessModifierthatClassDeclarationandVariableDeclarationcarried. That text could only ever be right for whichever language it was typed for —internalmeans nothing in C++, and Python has no keyword at all — so it could not be spelled per language. Hence the[major]tag.publicpublic:,protected:,private:) the members are grouped under;Internalbecomespublic:, since C++ has no assembly to be internal to#prefix — JavaScript's own private syntax, enforced by the runtime; nothing for the restPython is deliberate rather than unfinished: its convention for a non-public member is a leading underscore on the identifier, and renaming a declaration in the generator would leave every
VariableReferenceto it naming something that no longer exists. It is dropped the same wayJavaScriptGeneratoralready drops the types the AST carries, and the class's remarks say so.Documents saved with the old
accessModifierkey still load — the deserializer reads both spellings.Constants (#26)
A
VariableDeclarationmarkedIsConstantwith a literalInitialValue. The AST already had the flag; what was missing was it coming out right where it sits:static constexprfor a class member. A plainconstmember is a per-instance value initialised once per object, which is not what a constant means. A member with no initialiser staysconst, sinceconstexprwithout one does not compile.staticfor a class member.constdeclares a binding in a scope and a class body is not one, so the previous output was a syntax error waiting to happen. Combines with#for a private constant:static #MAX = 10;.The palette now offers a constant that already holds a literal, so it is a node you edit rather than one you have to wire a value into first.
Entry point (#27)
EntryPointis a node of its own rather than aFunctionDeclarationnamedmain, because only some languages spell the entry point as a function at all and none of them spell it the same way. It carries the two things that actually vary —AcceptsArgumentsandReturnsExitCode— and each generator writes what its language looks for:public static int Main(string[] args), or a barevoid Main()int main(int argc, char* argv[]);inteither way, since that is what the standard namesdef main(args):plus theif __name__ == "__main__":guard that runs it, and theimport sysits arguments and exit code need — emitted only when neededfunction main(args)plusprocess.exit(main(process.argv.slice(2)));, since a module that only definesmaindoes nothingAn entry point is accepted as a class member (which is where C# puts
Main) but refused as a statement inside a body — a program does not start running part-way through a function.Testing
dotnet test— 370 passed, 0 failed (41 new). Release build clean, no new warnings. The new tests cover each generator's own spelling rather than asserting one shape four times, both directions of YAML including the oldaccessModifierkey, the schema's slots and what they accept, the inspector's reads and writes, and the palette entries.🤖 Generated with Claude Code
https://claude.ai/code/session_01FMNNvzNnuLErq96R4NjYUi
Generated by Claude Code