@tsonic/emitter 0.0.73 → 0.0.74

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/adapter-generator.d.ts.map +1 -1
  3. package/dist/adapter-generator.js +2 -1
  4. package/dist/adapter-generator.js.map +1 -1
  5. package/dist/constants.d.ts +3 -2
  6. package/dist/constants.d.ts.map +1 -1
  7. package/dist/constants.js +15 -6
  8. package/dist/constants.js.map +1 -1
  9. package/dist/core/format/attributes.d.ts.map +1 -1
  10. package/dist/core/format/attributes.js +5 -56
  11. package/dist/core/format/attributes.js.map +1 -1
  12. package/dist/core/format/attributes.test.js +1 -1
  13. package/dist/core/format/attributes.test.js.map +1 -1
  14. package/dist/core/format/backend-ast/builders.d.ts +13 -0
  15. package/dist/core/format/backend-ast/builders.d.ts.map +1 -0
  16. package/dist/core/format/backend-ast/builders.js +169 -0
  17. package/dist/core/format/backend-ast/builders.js.map +1 -0
  18. package/dist/core/format/backend-ast/builders.test.d.ts +2 -0
  19. package/dist/core/format/backend-ast/builders.test.d.ts.map +1 -0
  20. package/dist/core/format/backend-ast/builders.test.js +258 -0
  21. package/dist/core/format/backend-ast/builders.test.js.map +1 -0
  22. package/dist/core/format/backend-ast/index.d.ts +3 -2
  23. package/dist/core/format/backend-ast/index.d.ts.map +1 -1
  24. package/dist/core/format/backend-ast/index.js +2 -1
  25. package/dist/core/format/backend-ast/index.js.map +1 -1
  26. package/dist/core/format/backend-ast/invariants.test.d.ts +2 -0
  27. package/dist/core/format/backend-ast/invariants.test.d.ts.map +1 -0
  28. package/dist/core/format/backend-ast/invariants.test.js +72 -0
  29. package/dist/core/format/backend-ast/invariants.test.js.map +1 -0
  30. package/dist/core/format/backend-ast/printer.d.ts +1 -1
  31. package/dist/core/format/backend-ast/printer.d.ts.map +1 -1
  32. package/dist/core/format/backend-ast/printer.js +362 -119
  33. package/dist/core/format/backend-ast/printer.js.map +1 -1
  34. package/dist/core/format/backend-ast/printer.test.d.ts +2 -0
  35. package/dist/core/format/backend-ast/printer.test.d.ts.map +1 -0
  36. package/dist/core/format/backend-ast/printer.test.js +796 -0
  37. package/dist/core/format/backend-ast/printer.test.js.map +1 -0
  38. package/dist/core/format/backend-ast/types.d.ts +66 -14
  39. package/dist/core/format/backend-ast/types.d.ts.map +1 -1
  40. package/dist/core/format/backend-ast/utils.d.ts +12 -8
  41. package/dist/core/format/backend-ast/utils.d.ts.map +1 -1
  42. package/dist/core/format/backend-ast/utils.js +222 -19
  43. package/dist/core/format/backend-ast/utils.js.map +1 -1
  44. package/dist/core/format/backend-ast/utils.test.d.ts +2 -0
  45. package/dist/core/format/backend-ast/utils.test.d.ts.map +1 -0
  46. package/dist/core/format/backend-ast/utils.test.js +142 -0
  47. package/dist/core/format/backend-ast/utils.test.js.map +1 -0
  48. package/dist/core/format/module-emitter/assembly.d.ts +2 -2
  49. package/dist/core/format/module-emitter/assembly.d.ts.map +1 -1
  50. package/dist/core/format/module-emitter/assembly.js +7 -3
  51. package/dist/core/format/module-emitter/assembly.js.map +1 -1
  52. package/dist/core/format/module-emitter/header.d.ts +2 -1
  53. package/dist/core/format/module-emitter/header.d.ts.map +1 -1
  54. package/dist/core/format/module-emitter/header.js +2 -2
  55. package/dist/core/format/module-emitter/header.js.map +1 -1
  56. package/dist/core/format/module-emitter/orchestrator.js +1 -1
  57. package/dist/core/format/module-emitter/orchestrator.js.map +1 -1
  58. package/dist/core/format/module-emitter/static-container.d.ts.map +1 -1
  59. package/dist/core/format/module-emitter/static-container.js +3 -5
  60. package/dist/core/format/module-emitter/static-container.js.map +1 -1
  61. package/dist/core/module-emitter.test.js +1 -0
  62. package/dist/core/module-emitter.test.js.map +1 -1
  63. package/dist/core/semantic/boolean-context.d.ts.map +1 -1
  64. package/dist/core/semantic/boolean-context.js +45 -49
  65. package/dist/core/semantic/boolean-context.js.map +1 -1
  66. package/dist/core/semantic/imports.d.ts.map +1 -1
  67. package/dist/core/semantic/imports.js +16 -15
  68. package/dist/core/semantic/imports.js.map +1 -1
  69. package/dist/core/semantic/imports.test.js.map +1 -1
  70. package/dist/core/semantic/type-resolution.js +1 -2
  71. package/dist/core/semantic/type-resolution.js.map +1 -1
  72. package/dist/emitter-types/core.d.ts +19 -10
  73. package/dist/emitter-types/core.d.ts.map +1 -1
  74. package/dist/emitter.d.ts.map +1 -1
  75. package/dist/emitter.js +124 -44
  76. package/dist/emitter.js.map +1 -1
  77. package/dist/expression-emitter.d.ts.map +1 -1
  78. package/dist/expression-emitter.js +24 -43
  79. package/dist/expression-emitter.js.map +1 -1
  80. package/dist/expressions/access.d.ts.map +1 -1
  81. package/dist/expressions/access.js +11 -28
  82. package/dist/expressions/access.js.map +1 -1
  83. package/dist/expressions/calls/call-analysis.d.ts +0 -10
  84. package/dist/expressions/calls/call-analysis.d.ts.map +1 -1
  85. package/dist/expressions/calls/call-analysis.js +3 -62
  86. package/dist/expressions/calls/call-analysis.js.map +1 -1
  87. package/dist/expressions/calls/call-emitter.d.ts.map +1 -1
  88. package/dist/expressions/calls/call-emitter.js +89 -151
  89. package/dist/expressions/calls/call-emitter.js.map +1 -1
  90. package/dist/expressions/calls/new-emitter.d.ts.map +1 -1
  91. package/dist/expressions/calls/new-emitter.js +36 -69
  92. package/dist/expressions/calls/new-emitter.js.map +1 -1
  93. package/dist/expressions/collections.d.ts +3 -0
  94. package/dist/expressions/collections.d.ts.map +1 -1
  95. package/dist/expressions/collections.js +43 -70
  96. package/dist/expressions/collections.js.map +1 -1
  97. package/dist/expressions/functions.d.ts.map +1 -1
  98. package/dist/expressions/functions.js +1 -7
  99. package/dist/expressions/functions.js.map +1 -1
  100. package/dist/expressions/identifiers.d.ts.map +1 -1
  101. package/dist/expressions/identifiers.js +23 -44
  102. package/dist/expressions/identifiers.js.map +1 -1
  103. package/dist/expressions/index.test.js +128 -0
  104. package/dist/expressions/index.test.js.map +1 -1
  105. package/dist/expressions/literals.d.ts.map +1 -1
  106. package/dist/expressions/literals.js +9 -41
  107. package/dist/expressions/literals.js.map +1 -1
  108. package/dist/expressions/operators/assignment-emitter.d.ts.map +1 -1
  109. package/dist/expressions/operators/assignment-emitter.js +2 -6
  110. package/dist/expressions/operators/assignment-emitter.js.map +1 -1
  111. package/dist/expressions/operators/binary-emitter.d.ts.map +1 -1
  112. package/dist/expressions/operators/binary-emitter.js +16 -32
  113. package/dist/expressions/operators/binary-emitter.js.map +1 -1
  114. package/dist/expressions/operators/logical-emitter.d.ts.map +1 -1
  115. package/dist/expressions/operators/logical-emitter.js +1 -3
  116. package/dist/expressions/operators/logical-emitter.js.map +1 -1
  117. package/dist/expressions/operators/unary-emitter.d.ts.map +1 -1
  118. package/dist/expressions/operators/unary-emitter.js +9 -20
  119. package/dist/expressions/operators/unary-emitter.js.map +1 -1
  120. package/dist/expressions/other.d.ts.map +1 -1
  121. package/dist/expressions/other.js +6 -11
  122. package/dist/expressions/other.js.map +1 -1
  123. package/dist/generator-exchange.d.ts.map +1 -1
  124. package/dist/generator-exchange.js +3 -2
  125. package/dist/generator-exchange.js.map +1 -1
  126. package/dist/generator-wrapper.d.ts.map +1 -1
  127. package/dist/generator-wrapper.js +27 -56
  128. package/dist/generator-wrapper.js.map +1 -1
  129. package/dist/integration.test.js +1 -1
  130. package/dist/integration.test.js.map +1 -1
  131. package/dist/json-aot-generic.test.js +3 -0
  132. package/dist/json-aot-generic.test.js.map +1 -1
  133. package/dist/patterns.d.ts.map +1 -1
  134. package/dist/patterns.js +19 -40
  135. package/dist/patterns.js.map +1 -1
  136. package/dist/statements/classes/members/methods.d.ts.map +1 -1
  137. package/dist/statements/classes/members/methods.js +3 -9
  138. package/dist/statements/classes/members/methods.js.map +1 -1
  139. package/dist/statements/classes/parameters.d.ts.map +1 -1
  140. package/dist/statements/classes/parameters.js +2 -1
  141. package/dist/statements/classes/parameters.js.map +1 -1
  142. package/dist/statements/classes/properties.d.ts.map +1 -1
  143. package/dist/statements/classes/properties.js +5 -16
  144. package/dist/statements/classes/properties.js.map +1 -1
  145. package/dist/statements/control/conditionals/guard-analysis.d.ts +2 -1
  146. package/dist/statements/control/conditionals/guard-analysis.d.ts.map +1 -1
  147. package/dist/statements/control/conditionals/guard-analysis.js +19 -6
  148. package/dist/statements/control/conditionals/guard-analysis.js.map +1 -1
  149. package/dist/statements/control/conditionals/if-emitter.d.ts.map +1 -1
  150. package/dist/statements/control/conditionals/if-emitter.js +14 -9
  151. package/dist/statements/control/conditionals/if-emitter.js.map +1 -1
  152. package/dist/statements/control/exceptions.d.ts.map +1 -1
  153. package/dist/statements/control/exceptions.js +2 -4
  154. package/dist/statements/control/exceptions.js.map +1 -1
  155. package/dist/statements/control/loops.d.ts.map +1 -1
  156. package/dist/statements/control/loops.js +3 -5
  157. package/dist/statements/control/loops.js.map +1 -1
  158. package/dist/statements/declarations/classes.d.ts.map +1 -1
  159. package/dist/statements/declarations/classes.js +2 -4
  160. package/dist/statements/declarations/classes.js.map +1 -1
  161. package/dist/statements/declarations/functions.d.ts.map +1 -1
  162. package/dist/statements/declarations/functions.js +36 -66
  163. package/dist/statements/declarations/functions.js.map +1 -1
  164. package/dist/statements/declarations/interfaces-mutable-storage.test.js +10 -2
  165. package/dist/statements/declarations/interfaces-mutable-storage.test.js.map +1 -1
  166. package/dist/statements/declarations/interfaces.d.ts.map +1 -1
  167. package/dist/statements/declarations/interfaces.js +4 -12
  168. package/dist/statements/declarations/interfaces.js.map +1 -1
  169. package/dist/statements/declarations/type-aliases.d.ts.map +1 -1
  170. package/dist/statements/declarations/type-aliases.js +3 -8
  171. package/dist/statements/declarations/type-aliases.js.map +1 -1
  172. package/dist/statements/declarations/variables.d.ts.map +1 -1
  173. package/dist/statements/declarations/variables.js +39 -37
  174. package/dist/statements/declarations/variables.js.map +1 -1
  175. package/dist/statements/index.test.js +94 -8
  176. package/dist/statements/index.test.js.map +1 -1
  177. package/dist/types/dictionaries.d.ts.map +1 -1
  178. package/dist/types/dictionaries.js +5 -5
  179. package/dist/types/dictionaries.js.map +1 -1
  180. package/dist/types/functions.d.ts.map +1 -1
  181. package/dist/types/functions.js +5 -25
  182. package/dist/types/functions.js.map +1 -1
  183. package/dist/types/primitives.d.ts.map +1 -1
  184. package/dist/types/primitives.js.map +1 -1
  185. package/dist/types/references.d.ts.map +1 -1
  186. package/dist/types/references.js +65 -132
  187. package/dist/types/references.js.map +1 -1
  188. package/dist/types/references.test.js +63 -51
  189. package/dist/types/references.test.js.map +1 -1
  190. package/dist/types/tuples.d.ts.map +1 -1
  191. package/dist/types/tuples.js +7 -17
  192. package/dist/types/tuples.js.map +1 -1
  193. package/dist/types/unions.d.ts.map +1 -1
  194. package/dist/types/unions.js +2 -5
  195. package/dist/types/unions.js.map +1 -1
  196. package/package.json +2 -2
  197. package/dist/expressions/parentheses.d.ts +0 -4
  198. package/dist/expressions/parentheses.d.ts.map +0 -1
  199. package/dist/expressions/parentheses.js +0 -91
  200. package/dist/expressions/parentheses.js.map +0 -1
@@ -7,6 +7,203 @@
7
7
  * Parenthesization is derived from operator precedence tables,
8
8
  * not from advisory metadata on fragments.
9
9
  */
10
+ const escapeCSharpStringLiteral = (value) => value
11
+ .replace(/\\/g, "\\\\")
12
+ .replace(/"/g, '\\"')
13
+ .replace(/\n/g, "\\n")
14
+ .replace(/\r/g, "\\r")
15
+ .replace(/\t/g, "\\t");
16
+ const escapeCSharpCharLiteral = (value) => {
17
+ switch (value) {
18
+ case "'":
19
+ return "\\'";
20
+ case "\\":
21
+ return "\\\\";
22
+ case "\n":
23
+ return "\\n";
24
+ case "\r":
25
+ return "\\r";
26
+ case "\t":
27
+ return "\\t";
28
+ case "\0":
29
+ return "\\0";
30
+ default:
31
+ return value;
32
+ }
33
+ };
34
+ const printTrivia = (trivia) => {
35
+ switch (trivia.kind) {
36
+ case "singleLineCommentTrivia":
37
+ return `// ${trivia.text}`;
38
+ case "blankLineTrivia":
39
+ return "";
40
+ default: {
41
+ const exhaustive = trivia;
42
+ throw new Error(`ICE: Unhandled trivia kind '${exhaustive.kind}' in printTrivia`);
43
+ }
44
+ }
45
+ };
46
+ const nameMayPrintColon = (name) => name.aliasQualifier !== undefined;
47
+ const typeMayPrintColon = (type) => {
48
+ switch (type.kind) {
49
+ case "predefinedType":
50
+ case "varType":
51
+ return false;
52
+ case "identifierType":
53
+ return type.typeArguments?.some(typeMayPrintColon) === true;
54
+ case "qualifiedIdentifierType":
55
+ return (nameMayPrintColon(type.name) ||
56
+ type.typeArguments?.some(typeMayPrintColon) === true);
57
+ case "nullableType":
58
+ return typeMayPrintColon(type.underlyingType);
59
+ case "arrayType":
60
+ return typeMayPrintColon(type.elementType);
61
+ case "pointerType":
62
+ return typeMayPrintColon(type.elementType);
63
+ case "tupleType":
64
+ return type.elements.some((element) => typeMayPrintColon(element.type));
65
+ default: {
66
+ const exhaustive = type;
67
+ throw new Error(`ICE: Unhandled type AST kind '${exhaustive.kind}' in typeMayPrintColon`);
68
+ }
69
+ }
70
+ };
71
+ const patternMayPrintColon = (pattern) => {
72
+ switch (pattern.kind) {
73
+ case "typePattern":
74
+ case "declarationPattern":
75
+ return typeMayPrintColon(pattern.type);
76
+ case "varPattern":
77
+ case "discardPattern":
78
+ return false;
79
+ case "constantPattern":
80
+ return expressionMayPrintColon(pattern.expression);
81
+ case "negatedPattern":
82
+ return patternMayPrintColon(pattern.pattern);
83
+ default: {
84
+ const exhaustive = pattern;
85
+ throw new Error(`ICE: Unhandled pattern AST kind '${exhaustive.kind}' in patternMayPrintColon`);
86
+ }
87
+ }
88
+ };
89
+ const expressionMayPrintColon = (expr) => {
90
+ switch (expr.kind) {
91
+ case "conditionalExpression":
92
+ return true;
93
+ case "identifierExpression":
94
+ return false;
95
+ case "qualifiedIdentifierExpression":
96
+ return nameMayPrintColon(expr.name);
97
+ case "typeReferenceExpression":
98
+ return typeMayPrintColon(expr.type);
99
+ case "parenthesizedExpression":
100
+ case "awaitExpression":
101
+ case "throwExpression":
102
+ case "suppressNullableWarningExpression":
103
+ case "argumentModifierExpression":
104
+ return expressionMayPrintColon(expr.expression);
105
+ case "prefixUnaryExpression":
106
+ case "postfixUnaryExpression":
107
+ return expressionMayPrintColon(expr.operand);
108
+ case "memberAccessExpression":
109
+ case "conditionalMemberAccessExpression":
110
+ return expressionMayPrintColon(expr.expression);
111
+ case "elementAccessExpression":
112
+ case "conditionalElementAccessExpression":
113
+ return (expressionMayPrintColon(expr.expression) ||
114
+ expr.arguments.some(expressionMayPrintColon));
115
+ case "implicitElementAccessExpression":
116
+ return expr.arguments.some(expressionMayPrintColon);
117
+ case "invocationExpression":
118
+ return (expressionMayPrintColon(expr.expression) ||
119
+ expr.arguments.some(expressionMayPrintColon) ||
120
+ expr.typeArguments?.some(typeMayPrintColon) === true);
121
+ case "objectCreationExpression":
122
+ return (typeMayPrintColon(expr.type) ||
123
+ expr.arguments.some(expressionMayPrintColon) ||
124
+ expr.initializer?.some(expressionMayPrintColon) === true);
125
+ case "arrayCreationExpression":
126
+ return (typeMayPrintColon(expr.elementType) ||
127
+ (expr.sizeExpression
128
+ ? expressionMayPrintColon(expr.sizeExpression)
129
+ : false) ||
130
+ expr.initializer?.some(expressionMayPrintColon) === true);
131
+ case "stackAllocArrayCreationExpression":
132
+ return (typeMayPrintColon(expr.elementType) ||
133
+ expressionMayPrintColon(expr.sizeExpression));
134
+ case "assignmentExpression":
135
+ case "binaryExpression":
136
+ return (expressionMayPrintColon(expr.left) ||
137
+ expressionMayPrintColon(expr.right));
138
+ case "castExpression":
139
+ return (typeMayPrintColon(expr.type) || expressionMayPrintColon(expr.expression));
140
+ case "asExpression":
141
+ return (typeMayPrintColon(expr.type) || expressionMayPrintColon(expr.expression));
142
+ case "isExpression":
143
+ return (expressionMayPrintColon(expr.expression) ||
144
+ patternMayPrintColon(expr.pattern));
145
+ case "defaultExpression":
146
+ return expr.type ? typeMayPrintColon(expr.type) : false;
147
+ case "sizeOfExpression":
148
+ case "typeofExpression":
149
+ return typeMayPrintColon(expr.type);
150
+ case "lambdaExpression":
151
+ return expr.parameters.some((p) => p.type ? typeMayPrintColon(p.type) : false);
152
+ case "interpolatedStringExpression":
153
+ return expr.parts.some((part) => part.kind === "interpolation" &&
154
+ expressionMayPrintColon(part.expression));
155
+ case "switchExpression":
156
+ return (expressionMayPrintColon(expr.governingExpression) ||
157
+ expr.arms.some((arm) => patternMayPrintColon(arm.pattern) ||
158
+ (arm.whenClause
159
+ ? expressionMayPrintColon(arm.whenClause)
160
+ : false) ||
161
+ expressionMayPrintColon(arm.expression)));
162
+ case "tupleExpression":
163
+ return expr.elements.some(expressionMayPrintColon);
164
+ case "nullLiteralExpression":
165
+ case "booleanLiteralExpression":
166
+ case "stringLiteralExpression":
167
+ case "charLiteralExpression":
168
+ case "numericLiteralExpression":
169
+ return false;
170
+ default: {
171
+ const exhaustive = expr;
172
+ throw new Error(`ICE: Unhandled expression AST kind '${exhaustive.kind}' in expressionMayPrintColon`);
173
+ }
174
+ }
175
+ };
176
+ const needsPrefixUnarySeparator = (operatorToken, operand) => {
177
+ if (operatorToken !== "-" && operatorToken !== "+") {
178
+ return false;
179
+ }
180
+ const unwrapped = operand.kind === "parenthesizedExpression" ? operand.expression : operand;
181
+ return (unwrapped.kind === "prefixUnaryExpression" &&
182
+ unwrapped.operatorToken === operatorToken);
183
+ };
184
+ const printNumericLiteral = (expr) => {
185
+ const suffix = expr.suffix ?? "";
186
+ const hasRealParts = expr.fractionalPart !== undefined || expr.exponentDigits !== undefined;
187
+ if (hasRealParts) {
188
+ const fractional = expr.fractionalPart !== undefined ? `.${expr.fractionalPart}` : "";
189
+ const exponent = expr.exponentDigits !== undefined
190
+ ? `e${expr.exponentSign ?? ""}${expr.exponentDigits}`
191
+ : "";
192
+ return `${expr.wholePart}${fractional}${exponent}${suffix}`;
193
+ }
194
+ switch (expr.base) {
195
+ case "decimal":
196
+ return `${expr.wholePart}${suffix}`;
197
+ case "hexadecimal":
198
+ return `0x${expr.wholePart}${suffix}`;
199
+ case "binary":
200
+ return `0b${expr.wholePart}${suffix}`;
201
+ default: {
202
+ const exhaustive = expr.base;
203
+ throw new Error(`ICE: Unhandled numeric literal base '${exhaustive}'`);
204
+ }
205
+ }
206
+ };
10
207
  // ============================================================
11
208
  // C# reserved keywords for identifier escaping
12
209
  // ============================================================
@@ -115,21 +312,16 @@ const PREDEFINED_TYPE_KEYWORDS = new Set([
115
312
  */
116
313
  const escapeIdentifier = (name) => CSHARP_KEYWORDS.has(name) ? `@${name}` : name;
117
314
  /**
118
- * Escape segments in a qualified name (e.g. "global::Foo.stackalloc.Bar").
119
- * The "global::" prefix and predefined type keywords are preserved.
315
+ * Escape segments in a qualified name AST.
120
316
  */
121
317
  const escapeQualifiedName = (name, preservePredefinedTypeKeywords = false) => {
122
- const globalPrefix = "global::";
123
- const hasGlobal = name.startsWith(globalPrefix);
124
- const body = hasGlobal ? name.slice(globalPrefix.length) : name;
125
- const escaped = body
126
- .split(".")
318
+ const escaped = [...name.segments]
127
319
  .map((segment) => CSHARP_KEYWORDS.has(segment) &&
128
320
  !(preservePredefinedTypeKeywords && PREDEFINED_TYPE_KEYWORDS.has(segment))
129
321
  ? `@${segment}`
130
322
  : segment)
131
323
  .join(".");
132
- return hasGlobal ? `${globalPrefix}${escaped}` : escaped;
324
+ return name.aliasQualifier ? `${name.aliasQualifier}::${escaped}` : escaped;
133
325
  };
134
326
  // ============================================================
135
327
  // Operator precedence for parenthesization
@@ -224,13 +416,20 @@ const getExpressionPrecedence = (expr) => {
224
416
  case "awaitExpression":
225
417
  return 14; // Await is at unary level
226
418
  // Primary expressions (highest precedence)
227
- case "literalExpression":
419
+ case "nullLiteralExpression":
420
+ case "booleanLiteralExpression":
421
+ case "stringLiteralExpression":
422
+ case "charLiteralExpression":
423
+ case "numericLiteralExpression":
228
424
  case "identifierExpression":
425
+ case "qualifiedIdentifierExpression":
426
+ case "typeReferenceExpression":
229
427
  case "parenthesizedExpression":
230
428
  case "memberAccessExpression":
231
429
  case "conditionalMemberAccessExpression":
232
430
  case "elementAccessExpression":
233
431
  case "conditionalElementAccessExpression":
432
+ case "implicitElementAccessExpression":
234
433
  case "invocationExpression":
235
434
  case "objectCreationExpression":
236
435
  case "arrayCreationExpression":
@@ -289,8 +488,8 @@ const needsParensInBinary = (child, parentPrecedence, isRightOperand) => {
289
488
  /**
290
489
  * Wrap expression text in parens if needed for the given context.
291
490
  */
292
- const parenthesizeIfNeeded = (expr, parentPrecedence, isRightOperand) => {
293
- const text = printExpression(expr);
491
+ const parenthesizeIfNeeded = (expr, parentPrecedence, isRightOperand, indent) => {
492
+ const text = printExpression(expr, indent);
294
493
  return needsParensInBinary(expr, parentPrecedence, isRightOperand)
295
494
  ? `(${text})`
296
495
  : text;
@@ -303,6 +502,17 @@ export const printType = (type) => {
303
502
  case "predefinedType":
304
503
  return type.keyword;
305
504
  case "identifierType": {
505
+ if (type.name.includes(".") || type.name.includes("::")) {
506
+ throw new Error(`ICE: Simple identifierType '${type.name}' contains qualification. Use qualifiedIdentifierType AST instead.`);
507
+ }
508
+ const name = escapeIdentifier(type.name);
509
+ if (!type.typeArguments || type.typeArguments.length === 0) {
510
+ return name;
511
+ }
512
+ const args = type.typeArguments.map(printType).join(", ");
513
+ return `${name}<${args}>`;
514
+ }
515
+ case "qualifiedIdentifierType": {
306
516
  const name = escapeQualifiedName(type.name, true);
307
517
  if (!type.typeArguments || type.typeArguments.length === 0) {
308
518
  return name;
@@ -339,39 +549,68 @@ export const printType = (type) => {
339
549
  // ============================================================
340
550
  // Expression Printer
341
551
  // ============================================================
342
- export const printExpression = (expr) => {
552
+ export const printExpression = (expr, indent = "") => {
343
553
  switch (expr.kind) {
344
- case "literalExpression":
345
- return expr.text;
554
+ case "nullLiteralExpression":
555
+ return "null";
556
+ case "booleanLiteralExpression":
557
+ return expr.value ? "true" : "false";
558
+ case "stringLiteralExpression":
559
+ return `"${escapeCSharpStringLiteral(expr.value)}"`;
560
+ case "charLiteralExpression":
561
+ return `'${escapeCSharpCharLiteral(expr.value)}'`;
562
+ case "numericLiteralExpression":
563
+ return printNumericLiteral(expr);
346
564
  case "identifierExpression":
565
+ if (expr.identifier.includes(".") || expr.identifier.includes("::")) {
566
+ throw new Error(`ICE: Simple identifierExpression '${expr.identifier}' contains qualification. Use qualifiedIdentifierExpression AST instead.`);
567
+ }
347
568
  return escapeIdentifier(expr.identifier);
569
+ case "qualifiedIdentifierExpression":
570
+ return escapeQualifiedName(expr.name);
571
+ case "typeReferenceExpression":
572
+ return printType(expr.type);
348
573
  case "parenthesizedExpression":
349
- return `(${printExpression(expr.expression)})`;
574
+ return `(${printExpression(expr.expression, indent)})`;
350
575
  case "memberAccessExpression":
351
- return `${printPrimaryExpression(expr.expression)}.${escapeIdentifier(expr.memberName)}`;
576
+ return `${printPrimaryExpression(expr.expression, indent)}.${escapeIdentifier(expr.memberName)}`;
352
577
  case "conditionalMemberAccessExpression":
353
- return `${printPrimaryExpression(expr.expression)}?.${escapeIdentifier(expr.memberName)}`;
578
+ return `${printPrimaryExpression(expr.expression, indent)}?.${escapeIdentifier(expr.memberName)}`;
354
579
  case "elementAccessExpression": {
355
- const args = expr.arguments.map(printExpression).join(", ");
356
- return `${printPrimaryExpression(expr.expression)}[${args}]`;
580
+ const args = expr.arguments
581
+ .map((arg) => printExpression(arg, indent))
582
+ .join(", ");
583
+ return `${printPrimaryExpression(expr.expression, indent)}[${args}]`;
357
584
  }
358
585
  case "conditionalElementAccessExpression": {
359
- const args = expr.arguments.map(printExpression).join(", ");
360
- return `${printPrimaryExpression(expr.expression)}?[${args}]`;
586
+ const args = expr.arguments
587
+ .map((arg) => printExpression(arg, indent))
588
+ .join(", ");
589
+ return `${printPrimaryExpression(expr.expression, indent)}?[${args}]`;
590
+ }
591
+ case "implicitElementAccessExpression": {
592
+ const args = expr.arguments
593
+ .map((arg) => printExpression(arg, indent))
594
+ .join(", ");
595
+ return `[${args}]`;
361
596
  }
362
597
  case "invocationExpression": {
363
- const callee = printPrimaryExpression(expr.expression);
598
+ const callee = printPrimaryExpression(expr.expression, indent);
364
599
  const typeArgs = expr.typeArguments && expr.typeArguments.length > 0
365
600
  ? `<${expr.typeArguments.map(printType).join(", ")}>`
366
601
  : "";
367
- const args = expr.arguments.map(printExpression).join(", ");
602
+ const args = expr.arguments
603
+ .map((arg) => printExpression(arg, indent))
604
+ .join(", ");
368
605
  return `${callee}${typeArgs}(${args})`;
369
606
  }
370
607
  case "objectCreationExpression": {
371
608
  const typeName = printType(expr.type);
372
- const args = expr.arguments.map(printExpression).join(", ");
609
+ const args = expr.arguments
610
+ .map((arg) => printExpression(arg, indent))
611
+ .join(", ");
373
612
  const init = expr.initializer && expr.initializer.length > 0
374
- ? ` { ${expr.initializer.map(printExpression).join(", ")} }`
613
+ ? ` { ${expr.initializer.map((item) => printExpression(item, indent)).join(", ")} }`
375
614
  : "";
376
615
  // Omit () when using collection/object initializer with no constructor args
377
616
  // (C# allows `new List<T> { ... }` without parentheses)
@@ -385,58 +624,58 @@ export const printExpression = (expr) => {
385
624
  const isImplicit = expr.elementType.kind === "varType";
386
625
  const elemType = isImplicit ? "" : ` ${printType(expr.elementType)}`;
387
626
  if (expr.initializer && expr.initializer.length > 0) {
388
- const elems = expr.initializer.map(printExpression).join(", ");
627
+ const elems = expr.initializer
628
+ .map((item) => printExpression(item, indent))
629
+ .join(", ");
389
630
  if (expr.sizeExpression) {
390
- return `new${elemType}[${printExpression(expr.sizeExpression)}] { ${elems} }`;
631
+ return `new${elemType}[${printExpression(expr.sizeExpression, indent)}] { ${elems} }`;
391
632
  }
392
633
  return `new${elemType}[] { ${elems} }`;
393
634
  }
394
635
  if (expr.sizeExpression) {
395
- return `new${elemType}[${printExpression(expr.sizeExpression)}]`;
636
+ return `new${elemType}[${printExpression(expr.sizeExpression, indent)}]`;
396
637
  }
397
638
  return `new${elemType}[0]`;
398
639
  }
399
640
  case "stackAllocArrayCreationExpression":
400
- return `stackalloc ${printType(expr.elementType)}[${printExpression(expr.sizeExpression)}]`;
641
+ return `stackalloc ${printType(expr.elementType)}[${printExpression(expr.sizeExpression, indent)}]`;
401
642
  case "assignmentExpression": {
402
- const left = printExpression(expr.left);
403
- const right = printExpression(expr.right);
643
+ const left = printExpression(expr.left, indent);
644
+ const right = printExpression(expr.right, indent);
404
645
  return `${left} ${expr.operatorToken} ${right}`;
405
646
  }
406
647
  case "binaryExpression": {
407
648
  const prec = getOperatorPrecedence(expr.operatorToken);
408
- const left = parenthesizeIfNeeded(expr.left, prec, false);
409
- const right = parenthesizeIfNeeded(expr.right, prec, true);
649
+ const left = parenthesizeIfNeeded(expr.left, prec, false, indent);
650
+ const right = parenthesizeIfNeeded(expr.right, prec, true, indent);
410
651
  return `${left} ${expr.operatorToken} ${right}`;
411
652
  }
412
653
  case "prefixUnaryExpression": {
413
- const operand = printUnaryOperand(expr.operand, true);
414
- // Operators like ++ and -- need no space, but ! and - do if operand starts with same char
415
- if ((expr.operatorToken === "-" && operand.startsWith("-")) ||
416
- (expr.operatorToken === "+" && operand.startsWith("+"))) {
654
+ const operand = printUnaryOperand(expr.operand, true, indent);
655
+ if (needsPrefixUnarySeparator(expr.operatorToken, expr.operand)) {
417
656
  return `${expr.operatorToken} ${operand}`;
418
657
  }
419
658
  return `${expr.operatorToken}${operand}`;
420
659
  }
421
660
  case "postfixUnaryExpression":
422
- return `${printUnaryOperand(expr.operand, false)}${expr.operatorToken}`;
661
+ return `${printUnaryOperand(expr.operand, false, indent)}${expr.operatorToken}`;
423
662
  case "conditionalExpression": {
424
- const cond = printExpression(expr.condition);
425
- const whenTrue = printExpression(expr.whenTrue);
426
- const whenFalse = printExpression(expr.whenFalse);
663
+ const cond = printExpression(expr.condition, indent);
664
+ const whenTrue = printExpression(expr.whenTrue, indent);
665
+ const whenFalse = printExpression(expr.whenFalse, indent);
427
666
  return `${cond} ? ${whenTrue} : ${whenFalse}`;
428
667
  }
429
668
  case "castExpression": {
430
669
  const typeName = printType(expr.type);
431
- const operand = printCastOperand(expr.expression);
670
+ const operand = printCastOperand(expr.expression, indent);
432
671
  return `(${typeName})${operand}`;
433
672
  }
434
673
  case "asExpression": {
435
- const inner = printExpression(expr.expression);
674
+ const inner = printExpression(expr.expression, indent);
436
675
  return `${inner} as ${printType(expr.type)}`;
437
676
  }
438
677
  case "isExpression": {
439
- const inner = printExpression(expr.expression);
678
+ const inner = printExpression(expr.expression, indent);
440
679
  const pattern = printPattern(expr.pattern);
441
680
  return `${inner} is ${pattern}`;
442
681
  }
@@ -445,23 +684,25 @@ export const printExpression = (expr) => {
445
684
  case "sizeOfExpression":
446
685
  return `sizeof(${printType(expr.type)})`;
447
686
  case "awaitExpression":
448
- return `await ${printUnaryOperand(expr.expression, true)}`;
687
+ return `await ${printUnaryOperand(expr.expression, true, indent)}`;
449
688
  case "lambdaExpression":
450
- return printLambdaExpression(expr);
689
+ return printLambdaExpression(expr, indent);
451
690
  case "interpolatedStringExpression":
452
- return printInterpolatedString(expr.parts);
691
+ return printInterpolatedString(expr.parts, indent);
453
692
  case "throwExpression":
454
- return `throw ${printExpression(expr.expression)}`;
693
+ return `throw ${printExpression(expr.expression, indent)}`;
455
694
  case "suppressNullableWarningExpression":
456
- return `${printPrimaryExpression(expr.expression)}!`;
695
+ return `${printPrimaryExpression(expr.expression, indent)}!`;
457
696
  case "typeofExpression":
458
697
  return `typeof(${printType(expr.type)})`;
459
698
  case "switchExpression":
460
- return printSwitchExpression(expr);
699
+ return printSwitchExpression(expr, indent);
461
700
  case "argumentModifierExpression":
462
- return `${expr.modifier} ${printExpression(expr.expression)}`;
701
+ return `${expr.modifier} ${printExpression(expr.expression, indent)}`;
463
702
  case "tupleExpression": {
464
- const elems = expr.elements.map(printExpression).join(", ");
703
+ const elems = expr.elements
704
+ .map((element) => printExpression(element, indent))
705
+ .join(", ");
465
706
  return `(${elems})`;
466
707
  }
467
708
  default: {
@@ -475,16 +716,21 @@ export const printExpression = (expr) => {
475
716
  * (before `.member`, `[index]`, `(args)`, etc.).
476
717
  * Wraps in parens if needed.
477
718
  */
478
- const printPrimaryExpression = (expr) => {
479
- const text = printExpression(expr);
719
+ const printPrimaryExpression = (expr, indent) => {
720
+ const text = printExpression(expr, indent);
480
721
  const prec = getExpressionPrecedence(expr);
481
722
  // Primary position requires precedence >= 15 (postfix and primary)
482
723
  // or the expression is already a parenthesized/literal/identifier
483
724
  if (prec >= 15)
484
725
  return text;
485
726
  if (expr.kind === "parenthesizedExpression" ||
486
- expr.kind === "literalExpression" ||
727
+ expr.kind === "nullLiteralExpression" ||
728
+ expr.kind === "booleanLiteralExpression" ||
729
+ expr.kind === "stringLiteralExpression" ||
730
+ expr.kind === "charLiteralExpression" ||
731
+ expr.kind === "numericLiteralExpression" ||
487
732
  expr.kind === "identifierExpression" ||
733
+ expr.kind === "qualifiedIdentifierExpression" ||
488
734
  expr.kind === "defaultExpression" ||
489
735
  expr.kind === "sizeOfExpression" ||
490
736
  expr.kind === "typeofExpression" ||
@@ -498,8 +744,8 @@ const printPrimaryExpression = (expr) => {
498
744
  /**
499
745
  * Print an expression that appears as a unary operand.
500
746
  */
501
- const printUnaryOperand = (expr, isPrefix) => {
502
- const text = printExpression(expr);
747
+ const printUnaryOperand = (expr, isPrefix, indent) => {
748
+ const text = printExpression(expr, indent);
503
749
  const prec = getExpressionPrecedence(expr);
504
750
  if (isPrefix) {
505
751
  // Prefix unary needs operand to be at least unary precedence
@@ -512,8 +758,8 @@ const printUnaryOperand = (expr, isPrefix) => {
512
758
  * Print an expression that appears as a cast operand.
513
759
  * Special rules: unary minus after cast needs parens to avoid ambiguity.
514
760
  */
515
- const printCastOperand = (expr) => {
516
- const text = printExpression(expr);
761
+ const printCastOperand = (expr, indent) => {
762
+ const text = printExpression(expr, indent);
517
763
  // Cast operand needs at least unary precedence
518
764
  if (getExpressionPrecedence(expr) < 14) {
519
765
  return `(${text})`;
@@ -523,26 +769,16 @@ const printCastOperand = (expr) => {
523
769
  if (expr.kind === "prefixUnaryExpression" && expr.operatorToken === "-") {
524
770
  return `(${text})`;
525
771
  }
526
- if (expr.kind === "literalExpression" && text.startsWith("-")) {
527
- return `(${text})`;
528
- }
529
772
  return text;
530
773
  };
531
- const printLambdaExpression = (expr) => {
774
+ const printLambdaExpression = (expr, indent) => {
532
775
  const asyncPrefix = expr.isAsync ? "async " : "";
533
776
  const params = printLambdaParameters(expr.parameters);
534
777
  if (expr.body.kind === "blockStatement") {
535
- if (expr.bodyIndent != null) {
536
- // Multi-line block body with flat-block convention (braces + body at same indent)
537
- return `${asyncPrefix}${params} =>\n${printStatementFlatBlock(expr.body, expr.bodyIndent)}`;
538
- }
539
- // Inline single-line block body: () => { stmt1; stmt2; }
540
- const stmts = expr.body.statements
541
- .map((s) => printStatement(s, ""))
542
- .join(" ");
543
- return `${asyncPrefix}${params} => { ${stmts} }`;
778
+ const bodyIndent = `${indent} `;
779
+ return `${asyncPrefix}${params} =>\n${printStatementFlatBlock(expr.body, bodyIndent)}`;
544
780
  }
545
- return `${asyncPrefix}${params} => ${printExpression(expr.body)}`;
781
+ return `${asyncPrefix}${params} => ${printExpression(expr.body, indent)}`;
546
782
  };
547
783
  const printLambdaParameters = (params) => {
548
784
  const sole = params.length === 1 ? params[0] : undefined;
@@ -557,16 +793,15 @@ const printLambdaParameters = (params) => {
557
793
  });
558
794
  return `(${parts.join(", ")})`;
559
795
  };
560
- const printInterpolatedString = (parts) => {
796
+ const printInterpolatedString = (parts, indent) => {
561
797
  const inner = parts
562
798
  .map((part) => {
563
799
  if (part.kind === "text")
564
800
  return part.text;
565
- const exprText = printExpression(part.expression);
566
- // Wrap in parens if the expression text contains ':' to prevent
567
- // C# from interpreting it as a format specifier delimiter.
568
- // Common case: global::Namespace.Type, ternary a ? b : c
569
- const safeText = exprText.includes(":") ? `(${exprText})` : exprText;
801
+ const exprText = printExpression(part.expression, indent);
802
+ const safeText = expressionMayPrintColon(part.expression)
803
+ ? `(${exprText})`
804
+ : exprText;
570
805
  return part.formatClause
571
806
  ? `{${safeText}:${part.formatClause}}`
572
807
  : `{${safeText}}`;
@@ -574,17 +809,19 @@ const printInterpolatedString = (parts) => {
574
809
  .join("");
575
810
  return `$"${inner}"`;
576
811
  };
577
- const printSwitchExpression = (expr) => {
578
- const gov = printExpression(expr.governingExpression);
579
- const arms = expr.arms.map(printSwitchExpressionArm).join(", ");
812
+ const printSwitchExpression = (expr, indent) => {
813
+ const gov = printExpression(expr.governingExpression, indent);
814
+ const arms = expr.arms
815
+ .map((arm) => printSwitchExpressionArm(arm, indent))
816
+ .join(", ");
580
817
  return `${gov} switch { ${arms} }`;
581
818
  };
582
- const printSwitchExpressionArm = (arm) => {
819
+ const printSwitchExpressionArm = (arm, indent) => {
583
820
  const pattern = printPattern(arm.pattern);
584
821
  const whenClause = arm.whenClause
585
- ? ` when ${printExpression(arm.whenClause)}`
822
+ ? ` when ${printExpression(arm.whenClause, indent)}`
586
823
  : "";
587
- const result = printExpression(arm.expression);
824
+ const result = printExpression(arm.expression, indent);
588
825
  return `${pattern}${whenClause} => ${result}`;
589
826
  };
590
827
  // ============================================================
@@ -622,7 +859,7 @@ export const printStatement = (stmt, indent) => {
622
859
  const typeStr = printType(stmt.type);
623
860
  const decls = stmt.declarators
624
861
  .map((d) => d.initializer
625
- ? `${escapeIdentifier(d.name)} = ${printExpression(d.initializer)}`
862
+ ? `${escapeIdentifier(d.name)} = ${printExpression(d.initializer, indent)}`
626
863
  : escapeIdentifier(d.name))
627
864
  .join(", ");
628
865
  return `${indent}${mods}${typeStr} ${decls};`;
@@ -638,11 +875,11 @@ export const printStatement = (stmt, indent) => {
638
875
  return `${indent}${mods}${ret} ${escapeIdentifier(stmt.name)}${typeParams}(${params})\n${body}`;
639
876
  }
640
877
  case "expressionStatement":
641
- return `${indent}${printExpression(stmt.expression)};`;
878
+ return `${indent}${printExpression(stmt.expression, indent)};`;
642
879
  case "ifStatement":
643
880
  return printIfStatement(stmt, indent);
644
881
  case "whileStatement": {
645
- const cond = printExpression(stmt.condition);
882
+ const cond = printExpression(stmt.condition, indent);
646
883
  const body = printStatement(stmt.body, indent);
647
884
  return `${indent}while (${cond})\n${body}`;
648
885
  }
@@ -652,7 +889,7 @@ export const printStatement = (stmt, indent) => {
652
889
  const awaitStr = stmt.isAwait ? "await " : "";
653
890
  const typeStr = printType(stmt.type);
654
891
  const ident = escapeIdentifier(stmt.identifier);
655
- const collection = printExpression(stmt.expression);
892
+ const collection = printExpression(stmt.expression, indent);
656
893
  const body = printStatement(stmt.body, indent);
657
894
  return `${indent}${awaitStr}foreach (${typeStr} ${ident} in ${collection})\n${body}`;
658
895
  }
@@ -662,11 +899,11 @@ export const printStatement = (stmt, indent) => {
662
899
  return printTryStatement(stmt, indent);
663
900
  case "throwStatement":
664
901
  return stmt.expression
665
- ? `${indent}throw ${printExpression(stmt.expression)};`
902
+ ? `${indent}throw ${printExpression(stmt.expression, indent)};`
666
903
  : `${indent}throw;`;
667
904
  case "returnStatement":
668
905
  return stmt.expression
669
- ? `${indent}return ${printExpression(stmt.expression)};`
906
+ ? `${indent}return ${printExpression(stmt.expression, indent)};`
670
907
  : `${indent}return;`;
671
908
  case "breakStatement":
672
909
  return `${indent}break;`;
@@ -679,7 +916,7 @@ export const printStatement = (stmt, indent) => {
679
916
  return `${indent}yield break;`;
680
917
  }
681
918
  return stmt.expression
682
- ? `${indent}yield return ${printExpression(stmt.expression)};`
919
+ ? `${indent}yield return ${printExpression(stmt.expression, indent)};`
683
920
  : `${indent}yield return;`;
684
921
  default: {
685
922
  const exhaustiveCheck = stmt;
@@ -695,7 +932,7 @@ const printBlockStatement = (block, indent) => {
695
932
  return `${indent}{\n${stmts}\n${indent}}`;
696
933
  };
697
934
  const printIfStatement = (stmt, indent) => {
698
- const cond = printExpression(stmt.condition);
935
+ const cond = printExpression(stmt.condition, indent);
699
936
  const thenBody = printStatement(stmt.thenStatement, indent);
700
937
  if (!stmt.elseStatement) {
701
938
  return `${indent}if (${cond})\n${thenBody}`;
@@ -717,27 +954,27 @@ const printForStatement = (stmt, indent) => {
717
954
  const typeStr = printType(stmt.declaration.type);
718
955
  const decls = stmt.declaration.declarators
719
956
  .map((d) => d.initializer
720
- ? `${escapeIdentifier(d.name)} = ${printExpression(d.initializer)}`
957
+ ? `${escapeIdentifier(d.name)} = ${printExpression(d.initializer, indent)}`
721
958
  : escapeIdentifier(d.name))
722
959
  .join(", ");
723
960
  parts.push(`${typeStr} ${decls}`);
724
961
  }
725
962
  else if (stmt.initializers && stmt.initializers.length > 0) {
726
- parts.push(stmt.initializers.map(printExpression).join(", "));
963
+ parts.push(stmt.initializers.map((expr) => printExpression(expr, indent)).join(", "));
727
964
  }
728
965
  else {
729
966
  parts.push("");
730
967
  }
731
968
  // Condition
732
- parts.push(stmt.condition ? printExpression(stmt.condition) : "");
969
+ parts.push(stmt.condition ? printExpression(stmt.condition, indent) : "");
733
970
  // Incrementors
734
- parts.push(stmt.incrementors.map(printExpression).join(", "));
971
+ parts.push(stmt.incrementors.map((expr) => printExpression(expr, indent)).join(", "));
735
972
  const header = parts.join("; ");
736
973
  const body = printStatement(stmt.body, indent);
737
974
  return `${indent}for (${header})\n${body}`;
738
975
  };
739
976
  const printSwitchStatement = (stmt, indent) => {
740
- const expr = printExpression(stmt.expression);
977
+ const expr = printExpression(stmt.expression, indent);
741
978
  const innerIndent = indent + " ";
742
979
  const sections = stmt.sections
743
980
  .map((s) => printSwitchSection(s, innerIndent))
@@ -757,11 +994,11 @@ const printSwitchSection = (section, indent) => {
757
994
  const printSwitchLabel = (label, indent) => {
758
995
  switch (label.kind) {
759
996
  case "caseSwitchLabel":
760
- return `${indent}case ${printExpression(label.value)}:`;
997
+ return `${indent}case ${printExpression(label.value, indent)}:`;
761
998
  case "casePatternSwitchLabel": {
762
999
  const pattern = printPattern(label.pattern);
763
1000
  const when = label.whenClause
764
- ? ` when ${printExpression(label.whenClause)}`
1001
+ ? ` when ${printExpression(label.whenClause, indent)}`
765
1002
  : "";
766
1003
  return `${indent}case ${pattern}${when}:`;
767
1004
  }
@@ -789,7 +1026,7 @@ const printCatchClause = (clause, indent) => {
789
1026
  ? ` ${escapeIdentifier(clause.identifier)}`
790
1027
  : "";
791
1028
  const filter = clause.filter
792
- ? ` when (${printExpression(clause.filter)})`
1029
+ ? ` when (${printExpression(clause.filter, indent)})`
793
1030
  : "";
794
1031
  return `${indent}catch (${typeName}${ident})${filter}\n${body}`;
795
1032
  };
@@ -799,7 +1036,7 @@ export const printParameter = (param) => {
799
1036
  .map((a) => {
800
1037
  const targetPrefix = a.target ? `${a.target}: ` : "";
801
1038
  const args = a.arguments && a.arguments.length > 0
802
- ? `(${a.arguments.map(printExpression).join(", ")})`
1039
+ ? `(${a.arguments.map((arg) => printExpression(arg)).join(", ")})`
803
1040
  : "";
804
1041
  return `[${targetPrefix}${printType(a.type)}${args}]`;
805
1042
  })
@@ -826,7 +1063,7 @@ export const printMember = (member, indent) => {
826
1063
  const typeName = printType(member.type);
827
1064
  const name = escapeIdentifier(member.name);
828
1065
  const init = member.initializer
829
- ? ` = ${printExpression(member.initializer)}`
1066
+ ? ` = ${printExpression(member.initializer, indent)}`
830
1067
  : "";
831
1068
  return `${attrs}${indent}${mods}${typeName} ${name}${init};`;
832
1069
  }
@@ -844,7 +1081,7 @@ export const printMember = (member, indent) => {
844
1081
  : "";
845
1082
  const accessors = ` { ${getStr}${setStr}}`;
846
1083
  const init = member.initializer
847
- ? ` = ${printExpression(member.initializer)};`
1084
+ ? ` = ${printExpression(member.initializer, indent)};`
848
1085
  : "";
849
1086
  return `${attrs}${indent}${mods}${typeName} ${name}${accessors}${init}`;
850
1087
  }
@@ -873,7 +1110,7 @@ export const printMember = (member, indent) => {
873
1110
  const params = member.parameters.map(printParameter).join(", ");
874
1111
  const constraints = printConstraints(member.constraints, indent);
875
1112
  if (member.expressionBody) {
876
- return `${attrs}${indent}${mods}${ret} ${escapeIdentifier(member.name)}${typeParams}(${params})${constraints} => ${printExpression(member.expressionBody)};`;
1113
+ return `${attrs}${indent}${mods}${ret} ${escapeIdentifier(member.name)}${typeParams}(${params})${constraints} => ${printExpression(member.expressionBody, indent)};`;
877
1114
  }
878
1115
  if (member.body) {
879
1116
  return `${attrs}${indent}${mods}${ret} ${escapeIdentifier(member.name)}${typeParams}(${params})${constraints}\n${printBlockStatement(member.body, indent)}`;
@@ -886,7 +1123,7 @@ export const printMember = (member, indent) => {
886
1123
  const mods = member.modifiers.length > 0 ? `${member.modifiers.join(" ")} ` : "";
887
1124
  const params = member.parameters.map(printParameter).join(", ");
888
1125
  const baseCall = member.baseArguments !== undefined
889
- ? ` : base(${member.baseArguments.map(printExpression).join(", ")})`
1126
+ ? ` : base(${member.baseArguments.map((arg) => printExpression(arg, indent)).join(", ")})`
890
1127
  : "";
891
1128
  return `${attrs}${indent}${mods}${escapeIdentifier(member.name)}(${params})${baseCall}\n${printBlockStatement(member.body, indent)}`;
892
1129
  }
@@ -944,7 +1181,7 @@ export const printTypeDeclaration = (decl, indent) => {
944
1181
  }
945
1182
  };
946
1183
  const printEnumMember = (member, indent) => member.value
947
- ? `${indent}${escapeIdentifier(member.name)} = ${printExpression(member.value)}`
1184
+ ? `${indent}${escapeIdentifier(member.name)} = ${printExpression(member.value, indent)}`
948
1185
  : `${indent}${escapeIdentifier(member.name)}`;
949
1186
  const printTypeParameters = (typeParams) => {
950
1187
  if (!typeParams || typeParams.length === 0)
@@ -983,7 +1220,7 @@ export const printAttributes = (attrs, indent) => {
983
1220
  .map((a) => {
984
1221
  const targetPrefix = a.target ? `${a.target}: ` : "";
985
1222
  const args = a.arguments && a.arguments.length > 0
986
- ? `(${a.arguments.map(printExpression).join(", ")})`
1223
+ ? `(${a.arguments.map((arg) => printExpression(arg, indent)).join(", ")})`
987
1224
  : "";
988
1225
  return `${indent}[${targetPrefix}${printType(a.type)}${args}]\n`;
989
1226
  })
@@ -994,8 +1231,8 @@ export const printAttributes = (attrs, indent) => {
994
1231
  // ============================================================
995
1232
  export const printCompilationUnit = (unit) => {
996
1233
  const parts = [];
997
- if (unit.header) {
998
- parts.push(unit.header);
1234
+ if (unit.leadingTrivia && unit.leadingTrivia.length > 0) {
1235
+ parts.push(unit.leadingTrivia.map(printTrivia).join("\n"));
999
1236
  }
1000
1237
  const usings = unit.usings
1001
1238
  .map((u) => `using ${escapeQualifiedName(u.namespace, false)};`)
@@ -1049,7 +1286,7 @@ export const printStatementFlatBlock = (stmt, indent) => {
1049
1286
  return `${indent}{\n${inner}\n${indent}}`;
1050
1287
  }
1051
1288
  case "ifStatement": {
1052
- const cond = printExpression(stmt.condition);
1289
+ const cond = printExpression(stmt.condition, indent);
1053
1290
  const thenBody = printStatementFlatBlock(stmt.thenStatement, bodyIndent);
1054
1291
  if (!stmt.elseStatement) {
1055
1292
  return `${indent}if (${cond})\n${thenBody}`;
@@ -1064,7 +1301,7 @@ export const printStatementFlatBlock = (stmt, indent) => {
1064
1301
  return `${indent}if (${cond})\n${thenBody}\n${indent}else\n${elseBody}`;
1065
1302
  }
1066
1303
  case "whileStatement": {
1067
- const cond = printExpression(stmt.condition);
1304
+ const cond = printExpression(stmt.condition, indent);
1068
1305
  const body = printStatementFlatBlock(stmt.body, bodyIndent);
1069
1306
  return `${indent}while (${cond})\n${body}`;
1070
1307
  }
@@ -1074,19 +1311,23 @@ export const printStatementFlatBlock = (stmt, indent) => {
1074
1311
  const typeStr = printType(stmt.declaration.type);
1075
1312
  const decls = stmt.declaration.declarators
1076
1313
  .map((d) => d.initializer
1077
- ? `${escapeIdentifier(d.name)} = ${printExpression(d.initializer)}`
1314
+ ? `${escapeIdentifier(d.name)} = ${printExpression(d.initializer, indent)}`
1078
1315
  : escapeIdentifier(d.name))
1079
1316
  .join(", ");
1080
1317
  parts.push(`${typeStr} ${decls}`);
1081
1318
  }
1082
1319
  else if (stmt.initializers && stmt.initializers.length > 0) {
1083
- parts.push(stmt.initializers.map(printExpression).join(", "));
1320
+ parts.push(stmt.initializers
1321
+ .map((expr) => printExpression(expr, indent))
1322
+ .join(", "));
1084
1323
  }
1085
1324
  else {
1086
1325
  parts.push("");
1087
1326
  }
1088
- parts.push(stmt.condition ? printExpression(stmt.condition) : "");
1089
- parts.push(stmt.incrementors.map(printExpression).join(", "));
1327
+ parts.push(stmt.condition ? printExpression(stmt.condition, indent) : "");
1328
+ parts.push(stmt.incrementors
1329
+ .map((expr) => printExpression(expr, indent))
1330
+ .join(", "));
1090
1331
  const header = parts.join("; ");
1091
1332
  const body = printStatementFlatBlock(stmt.body, bodyIndent);
1092
1333
  return `${indent}for (${header})\n${body}`;
@@ -1095,12 +1336,12 @@ export const printStatementFlatBlock = (stmt, indent) => {
1095
1336
  const awaitStr = stmt.isAwait ? "await " : "";
1096
1337
  const typeStr = printType(stmt.type);
1097
1338
  const ident = escapeIdentifier(stmt.identifier);
1098
- const collection = printExpression(stmt.expression);
1339
+ const collection = printExpression(stmt.expression, indent);
1099
1340
  const body = printStatementFlatBlock(stmt.body, bodyIndent);
1100
1341
  return `${indent}${awaitStr}foreach (${typeStr} ${ident} in ${collection})\n${body}`;
1101
1342
  }
1102
1343
  case "switchStatement": {
1103
- const expr = printExpression(stmt.expression);
1344
+ const expr = printExpression(stmt.expression, indent);
1104
1345
  const sections = stmt.sections
1105
1346
  .map((s) => {
1106
1347
  const labels = s.labels
@@ -1129,7 +1370,9 @@ export const printStatementFlatBlock = (stmt, indent) => {
1129
1370
  const ident = c.identifier
1130
1371
  ? ` ${escapeIdentifier(c.identifier)}`
1131
1372
  : "";
1132
- const filter = c.filter ? ` when (${printExpression(c.filter)})` : "";
1373
+ const filter = c.filter
1374
+ ? ` when (${printExpression(c.filter, indent)})`
1375
+ : "";
1133
1376
  return `${indent}catch (${typeName}${ident})${filter}\n${catchBody}`;
1134
1377
  })
1135
1378
  .join("\n");