After the Role and TokenRole hierarchies were removed, the Roles class no
longer held any roles -- only the punctuation and keyword text the output
visitor writes (LPar, Arrow, ClassKeyword, ...). The name was a misleading
vestige of the deleted system. Rename it to Tokens, which is what it now
is; the constants and their values are unchanged.
Also refresh the CSharpSlotInfo doc, which still described slot identity as
the successor to the removed node.Role == Roles.X comparison.
Assisted-by: Claude:claude-opus-4-8:Claude Code
The slot kind is now the canonical typed CSharpSlotInfo<T> in Slots, matched by
object identity (the IL SlotInfo model), instead of a parallel SlotKind enum.
CSharpSlotInfo.Kind points at the canonical shared slot; a Slots constant is its
own kind (null Kind, never read -- only per-node slots are asked for their kind),
so there is no self-reference. Child access (GetChild/GetChildren/SetChild,
GetCollectionByKind, AddChild/InsertChild) and the polymorphic
node.Slot.Kind == Slots.X comparisons key on the canonical reference; the
generated SlotKind enum is removed. No behavior change.
Assisted-by: Claude:claude-opus-4-8:Claude Code
Add a generic CSharpSlotInfo<T> (T is the child type, the element type for a
collection) and have the generator emit each per-node slot field as the typed
variant. This lets the typed child accessors infer the result type from the slot,
so the explicit type argument can drop out of the SlotKind-based child API in the
following steps. No behavior change -- the typed slots are still consumed through
the non-generic CSharpSlotInfo base.
Assisted-by: Claude:claude-opus-4-8:Claude Code
A DEBUG-only structural check, the analog of ILInstruction.CheckInvariant, run
after every AST transform in RunTransforms. It recursively asserts that each
required (non-optional) single slot holds a child, every child's Parent points
back, the stored flattened index matches the slot position, and the runtime type
fits the slot, so a transform that corrupts the tree fails at that transform
instead of as a downstream output diff. CSharpSlotInfo gains an IsOptional flag
(emitted by the generator) so the check can tell required from optional slots.
Assisted-by: Claude:claude-opus-4-8:Claude Code
Nodes use nullable reference types now, so the generated null-object
node and its hasNullNode / NeedsNullNode / NullNodeBaseCtorParamCount
plumbing are dead. Drop them and reword the affected comments.
Introduce the successor to node.Role for child-slot identity: the generator
emits a CSharpSlotInfo per [Slot], exposed as node.Slot, plus a shared SlotKind
enum for the polymorphic "is this node in an embedded-statement / condition /
base-type slot?" comparisons a per-node identity cannot express. Migrate the
printer and transform position checks from node.Role to node.Slot and
node.Slot.Kind, and read identifier children and role-keyed writes through the
typed properties. Role is still present and is removed later; output is
unchanged.
Assisted-by: Claude:claude-opus-4-8:Claude Code