Optional single-child slots return T? with a real null instead of a role
null-object, taking the C# grammar as the oracle for which slots are optional.
The generator emits the property type as T? and matches it with MatchOptional,
and consumers move from .IsNull to is null / ?.. This covers the optional
statement, member, try-catch, creation-initializer and pattern slots and the
optional NameSlot tokens. A few slots the grammar marks required but the
decompiler legitimately leaves empty (the implicit-element-access target, an
implicitly-typed lambda parameter's type) are flipped to nullable as well.
Assisted-by: Claude:claude-opus-4-8:Claude Code
The token writers and the UI syntax highlighter only need a token's identity (to
single out structural braces, the constructor this/base keyword, the override
modifier, and to colour keywords) -- not the AST child-role machinery. Make
TokenRole a standalone printer-side descriptor instead of a Role, turn the
modifier marker into a TokenRole, and change the WriteKeyword/WriteToken
signatures from Role to TokenRole across the writer hierarchy and the highlighter.
This lets the child Role hierarchy be removed without disturbing token output.
The dead OptionalComma/OptionalSemicolon bodies (no comma/semicolon/whitespace
children exist since the token drop) become no-ops, and the few sites that handed
the writer a child role for a keyword now pass none. Output is unchanged across
the decompiler suite, and the UI builds.
Assisted-by: Claude:claude-opus-4-8:Claude Code
Comments and preprocessor directives were positional children interleaved
into the child list, and punctuation, keywords and operators were token-node
children. Add a leading/trailing trivia side-channel for comments and
directives, emit it from the output visitor, and re-home every comment
receiver onto it (including inside-block comments as comment-only empty
statements and undecodable attribute arguments as an ErrorExpression). With
locations and sequence points no longer sourced from token nodes, stop
reconstructing them on the locations path and delete CSharpTokenNode,
CSharpModifierToken and InsertSpecialsDecorator. The AST no longer carries
token children or positional comments; output is byte-identical.
Assisted-by: Claude:claude-opus-4-8:Claude Code