What's wrong
CSharpGenerator.GenerateNamespace writes every member of a namespace directly into the braced namespace: CSharpGenerator.cs#L319-L336.
Two generators then write ordinary members there:
C# has no namespace-scope fields or methods. Every other target has somewhere to put these declarations:
- C++:
inline constexpr and free functions
- C, Rust and Go: module items
- Python and JavaScript: module scope
Reproduction
var ns = new NamespaceDeclaration("Geometry");
ns.Members.Add(new FieldDeclaration { Name = "Origins", Type = "int", IsConstant = true, InitialValue = new LiteralExpression<int>(2) });
var f = new FunctionDeclaration("twice") { ReturnType = "int" };
f.Parameters.Add(new Parameter("n", "int"));
f.Body.Add(new ReturnStatement(new BinaryExpression(new VariableReference("n"), BinaryOperator.Multiply, new LiteralExpression<int>(2))));
ns.Members.Add(f);
Output:
namespace Geometry
{
public static readonly int Origins = 2;
public int twice(int n)
{
return (n * 2);
}
}
Building this gives error CS0116: A namespace cannot directly contain members such as fields, methods or statements. Putting the same members directly in a SourceFile, with no namespace, gives error CS0106: The modifier 'public' is not valid for this item instead.
The repo's own reflection-table exemplar has this shape. ExemplarReflectionTableTests.CSharp_WritesAnObjectInitialiserAndAStaticReadonlyField asserts static readonly for a FieldDeclaration inside NamespaceDeclaration("holo::components::reflection"), so the C# output that test pins does not compile (L62, L147-L153). C# has no compile test, unlike C, C++, Rust and Go, which is why this went unnoticed.
Suggested fix
- Collect a namespace's (and a file's) non-type members into a generated
public static class, and mark them static. Non-type members are FieldDeclaration, FunctionDeclaration and VariableDeclaration.
- Name the class after the namespace's last segment, or use a fixed name such as
Globals. Any naming convention works as long as the output compiles.
- Leave types, enums, aliases and nested namespaces where they are.
Acceptance criteria
- C# output for a namespace containing a constant table and a free function compiles.
- Add a
CSharpGeneratedSourceCompilesTests, matching the C/C++/Rust/Go ones, that builds the compiled exemplar with Roslyn or dotnet build.
What's wrong
CSharpGenerator.GenerateNamespacewrites every member of a namespace directly into the braced namespace: CSharpGenerator.cs#L319-L336.Two generators then write ordinary members there:
GenerateField: L582-L608GenerateFunctionwithenclosingType: null: L641-L660C# has no namespace-scope fields or methods. Every other target has somewhere to put these declarations:
inline constexprand free functionsReproduction
Output:
Building this gives
error CS0116: A namespace cannot directly contain members such as fields, methods or statements. Putting the same members directly in aSourceFile, with no namespace, giveserror CS0106: The modifier 'public' is not valid for this iteminstead.The repo's own reflection-table exemplar has this shape.
ExemplarReflectionTableTests.CSharp_WritesAnObjectInitialiserAndAStaticReadonlyFieldassertsstatic readonlyfor aFieldDeclarationinsideNamespaceDeclaration("holo::components::reflection"), so the C# output that test pins does not compile (L62, L147-L153). C# has no compile test, unlike C, C++, Rust and Go, which is why this went unnoticed.Suggested fix
public static class, and mark themstatic. Non-type members areFieldDeclaration,FunctionDeclarationandVariableDeclaration.Globals. Any naming convention works as long as the output compiles.Acceptance criteria
CSharpGeneratedSourceCompilesTests, matching the C/C++/Rust/Go ones, that builds the compiled exemplar with Roslyn ordotnet build.