Repository navigation
[patch] Let functions write module-level fields in Rust and Python - #319
Open
matt-edmondson wants to merge 3 commits into
Open
matt-edmondson wants to merge 3 commits into
matt-edmondson wants to merge 3 commits into
Conversation
) A function that assigned to a module-level field produced code that did not work. Rust refused to compile it, because an immutable static cannot be assigned to. Python raised UnboundLocalError, because the assignment made the name local to the function. Rust now makes a written field a `static mut` and reaches it through `unsafe`. Python now declares it `global` in each function that writes it. A local or a parameter with the same name still shadows the field. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L1CFbhzg3saCCjeDAZC7Pd
Comment on lines
+531
to
+537
| foreach (FieldDeclaration field in members.OfType<FieldDeclaration>()) | ||
| { | ||
| if (!field.IsConstant && !string.IsNullOrEmpty(field.Name)) | ||
| { | ||
| fields.Add(field.Name); | ||
| } | ||
| } |
Comment on lines
+545
to
+556
| foreach (AssignmentStatement assignment in SelfAndDescendants(GenerationRoot).OfType<AssignmentStatement>()) | ||
| { | ||
| if (assignment.Target is VariableReference { Name: string name }) | ||
| { | ||
| int dot = name.IndexOf('.', StringComparison.Ordinal); | ||
| string root = dot < 0 ? name : name[..dot]; | ||
| if (fields.Contains(root)) | ||
| { | ||
| written.Add(root); | ||
| } | ||
| } | ||
| } |
Comment on lines
+522
to
+538
| foreach (AstNode node in SelfAndDescendants(GenerationRoot)) | ||
| { | ||
| IEnumerable<AstNode> members = node switch | ||
| { | ||
| SourceFile file => file.Members, | ||
| NamespaceDeclaration space => space.Members, | ||
| _ => [], | ||
| }; | ||
|
|
||
| foreach (FieldDeclaration field in members.OfType<FieldDeclaration>()) | ||
| { | ||
| if (!field.IsConstant && !string.IsNullOrEmpty(field.Name)) | ||
| { | ||
| fields.Add(field.Name); | ||
| } | ||
| } | ||
| } |
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018tZnrna9oooMZHDaLyXumk
Resolves the RustGenerator conflict by keeping both the bound-locals tracking this branch uses to tell a static mut from a local and main's reserved-word escaping. The new GenerateVariableReference dispatch now escapes reserved-word segments too, as TryGenerateCommonNode does on main, so static mut reads and ordinary references both come out escaped. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018tZnrna9oooMZHDaLyXumk
|
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.



Fixes #296.
Before: a function that assigned to a module-level field broke in two targets. In Rust,
rustcrejected the program because an immutablestaticcannot be assigned to. In Python, the program raisedUnboundLocalErrorthe first time the function ran, because assigning to the name made it local to the function.After: both programs run and the writes persist. The new tests call
bump()twice and the program exits with 2.How:
StandardLanguageGenerator.WrittenFileScopeFields()finds every non-constant file-level field that some assignment writes to.static mutinstead ofstatic. Each assignment to it is wrapped in anunsafeblock, and so is each read outside one. Parameters and locals with the same name are tracked, so they still shadow the field.global name. A parameter or local with the same name is left alone.RustGeneratedSourceCompilesTestscompiles and runs the program, andPythonGeneratedSourceImportsTestsruns it. Reverting the generator changes makes both tests fail:rustcrejects the program and Python raisesUnboundLocalError.Generated by Claude Code