@typecad/cuttlefish 0.1.0-alpha.1

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 (377) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +79 -0
  3. package/dist/api/board-types.d.ts +1 -0
  4. package/dist/api/board-types.js +4 -0
  5. package/dist/api/capabilities.d.ts +12 -0
  6. package/dist/api/capabilities.js +1 -0
  7. package/dist/api/config.d.ts +120 -0
  8. package/dist/api/config.js +7 -0
  9. package/dist/api/index.d.ts +5 -0
  10. package/dist/api/index.js +2 -0
  11. package/dist/api/schema/builder.d.ts +14 -0
  12. package/dist/api/schema/builder.js +15 -0
  13. package/dist/api/schema/index.d.ts +2 -0
  14. package/dist/api/schema/index.js +1 -0
  15. package/dist/api/schema/types.d.ts +257 -0
  16. package/dist/api/schema/types.js +4 -0
  17. package/dist/api/shared/async-runtime-static.d.ts +8 -0
  18. package/dist/api/shared/async-runtime-static.js +201 -0
  19. package/dist/api/shared/async-types.d.ts +42 -0
  20. package/dist/api/shared/async-types.js +8 -0
  21. package/dist/api/shared/board-resolver.d.ts +12 -0
  22. package/dist/api/shared/board-resolver.js +7 -0
  23. package/dist/api/shared/cpp-type-ir.d.ts +229 -0
  24. package/dist/api/shared/cpp-type-ir.js +672 -0
  25. package/dist/api/shared/display-adapter.d.ts +12 -0
  26. package/dist/api/shared/display-adapter.js +145 -0
  27. package/dist/api/shared/display-adapters/eink-mono.d.ts +2 -0
  28. package/dist/api/shared/display-adapters/eink-mono.js +53 -0
  29. package/dist/api/shared/display-adapters/sdl.d.ts +2 -0
  30. package/dist/api/shared/display-adapters/sdl.js +452 -0
  31. package/dist/api/shared/display-adapters/ssd1309.d.ts +2 -0
  32. package/dist/api/shared/display-adapters/ssd1309.js +136 -0
  33. package/dist/api/shared/display-adapters/st7796.d.ts +2 -0
  34. package/dist/api/shared/display-adapters/st7796.js +132 -0
  35. package/dist/api/shared/display-capabilities.d.ts +45 -0
  36. package/dist/api/shared/display-capabilities.js +54 -0
  37. package/dist/api/shared/display-op-ir.d.ts +62 -0
  38. package/dist/api/shared/display-op-ir.js +19 -0
  39. package/dist/api/shared/display-profile.d.ts +265 -0
  40. package/dist/api/shared/display-profile.js +338 -0
  41. package/dist/api/shared/graphics-strategy.d.ts +29 -0
  42. package/dist/api/shared/graphics-strategy.js +11 -0
  43. package/dist/api/shared/hal-op-ir.d.ts +393 -0
  44. package/dist/api/shared/hal-op-ir.js +18 -0
  45. package/dist/api/shared/index.d.ts +26 -0
  46. package/dist/api/shared/index.js +21 -0
  47. package/dist/api/shared/ir-core.d.ts +363 -0
  48. package/dist/api/shared/ir-core.js +8 -0
  49. package/dist/api/shared/ir-declarations.d.ts +201 -0
  50. package/dist/api/shared/ir-declarations.js +26 -0
  51. package/dist/api/shared/ir.d.ts +85 -0
  52. package/dist/api/shared/ir.js +13 -0
  53. package/dist/api/shared/platform-strategy.d.ts +402 -0
  54. package/dist/api/shared/platform-strategy.js +14 -0
  55. package/dist/api/shared/polyfill-helper-registry.d.ts +11 -0
  56. package/dist/api/shared/polyfill-helper-registry.js +86 -0
  57. package/dist/api/shared/polyfill-types.d.ts +33 -0
  58. package/dist/api/shared/polyfill-types.js +76 -0
  59. package/dist/api/shared/promise-runtime.d.ts +10 -0
  60. package/dist/api/shared/promise-runtime.js +244 -0
  61. package/dist/api/shared/snprintf-types.d.ts +29 -0
  62. package/dist/api/shared/snprintf-types.js +8 -0
  63. package/dist/api/shared/string-method-registry.d.ts +53 -0
  64. package/dist/api/shared/string-method-registry.js +168 -0
  65. package/dist/api/shared/toolchain-types.d.ts +63 -0
  66. package/dist/api/shared/toolchain-types.js +71 -0
  67. package/dist/api/shared/types.d.ts +50 -0
  68. package/dist/api/shared/types.js +6 -0
  69. package/dist/ast/parse.d.ts +2 -0
  70. package/dist/ast/parse.js +4 -0
  71. package/dist/cache.d.ts +26 -0
  72. package/dist/cache.js +95 -0
  73. package/dist/cli-utils.d.ts +37 -0
  74. package/dist/cli-utils.js +250 -0
  75. package/dist/cli.d.ts +2 -0
  76. package/dist/cli.js +635 -0
  77. package/dist/config-loader.d.ts +78 -0
  78. package/dist/config-loader.js +508 -0
  79. package/dist/config-schema.d.ts +233 -0
  80. package/dist/config-schema.js +83 -0
  81. package/dist/create/board-checklist.d.ts +2 -0
  82. package/dist/create/board-checklist.js +52 -0
  83. package/dist/create/board-codegen.d.ts +9 -0
  84. package/dist/create/board-codegen.js +238 -0
  85. package/dist/create/board-generators.d.ts +12 -0
  86. package/dist/create/board-generators.js +652 -0
  87. package/dist/create/board-spec.d.ts +640 -0
  88. package/dist/create/board-spec.js +215 -0
  89. package/dist/create/eslint-rules-template.d.ts +2 -0
  90. package/dist/create/eslint-rules-template.js +672 -0
  91. package/dist/create/index.d.ts +11 -0
  92. package/dist/create/index.js +8 -0
  93. package/dist/create/init-scaffold.d.ts +27 -0
  94. package/dist/create/init-scaffold.js +150 -0
  95. package/dist/create/init-templates.d.ts +24 -0
  96. package/dist/create/init-templates.js +379 -0
  97. package/dist/create/init-wizard.d.ts +8 -0
  98. package/dist/create/init-wizard.js +168 -0
  99. package/dist/debug/breakpoint-loader.d.ts +24 -0
  100. package/dist/debug/breakpoint-loader.js +137 -0
  101. package/dist/debug/index.d.ts +3 -0
  102. package/dist/debug/index.js +7 -0
  103. package/dist/debug/preprocessor.d.ts +9 -0
  104. package/dist/debug/preprocessor.js +214 -0
  105. package/dist/debug/types.d.ts +32 -0
  106. package/dist/debug/types.js +6 -0
  107. package/dist/diagnostics/diagnostics-report.d.ts +51 -0
  108. package/dist/diagnostics/diagnostics-report.js +333 -0
  109. package/dist/diagnostics/json-schema.d.ts +138 -0
  110. package/dist/diagnostics/json-schema.js +27 -0
  111. package/dist/diagnostics/md-writer.d.ts +10 -0
  112. package/dist/diagnostics/md-writer.js +336 -0
  113. package/dist/diagnostics/mermaid-builder.d.ts +65 -0
  114. package/dist/diagnostics/mermaid-builder.js +681 -0
  115. package/dist/emit/cpp-emitter.d.ts +6 -0
  116. package/dist/emit/cpp-emitter.js +48 -0
  117. package/dist/emit/emitters/class-emitter.d.ts +2 -0
  118. package/dist/emit/emitters/class-emitter.js +523 -0
  119. package/dist/emit/emitters/emitter-context.d.ts +174 -0
  120. package/dist/emit/emitters/emitter-context.js +1 -0
  121. package/dist/emit/emitters/entrypoint-synthesizer.d.ts +2 -0
  122. package/dist/emit/emitters/entrypoint-synthesizer.js +175 -0
  123. package/dist/emit/emitters/function-emitter-impl.d.ts +19 -0
  124. package/dist/emit/emitters/function-emitter-impl.js +428 -0
  125. package/dist/emit/emitters/line-appender.d.ts +15 -0
  126. package/dist/emit/emitters/line-appender.js +344 -0
  127. package/dist/emit/emitters/namespace-emitter.d.ts +2 -0
  128. package/dist/emit/emitters/namespace-emitter.js +324 -0
  129. package/dist/emit/emitters/output-finalizer.d.ts +4 -0
  130. package/dist/emit/emitters/output-finalizer.js +267 -0
  131. package/dist/emit/emitters/setup.d.ts +3 -0
  132. package/dist/emit/emitters/setup.js +851 -0
  133. package/dist/emit/emitters/top-level-prep.d.ts +2 -0
  134. package/dist/emit/emitters/top-level-prep.js +706 -0
  135. package/dist/emit/emitters/type-decl-emitter.d.ts +2 -0
  136. package/dist/emit/emitters/type-decl-emitter.js +251 -0
  137. package/dist/emit/emitters/ui-emitter.d.ts +21 -0
  138. package/dist/emit/emitters/ui-emitter.js +564 -0
  139. package/dist/emit/enum-emitter.d.ts +1 -0
  140. package/dist/emit/enum-emitter.js +1 -0
  141. package/dist/emit/expression-renderer.d.ts +283 -0
  142. package/dist/emit/expression-renderer.js +1477 -0
  143. package/dist/emit/native-helpers-emitter.d.ts +11 -0
  144. package/dist/emit/native-helpers-emitter.js +34 -0
  145. package/dist/emit/route-hal-op.d.ts +5 -0
  146. package/dist/emit/route-hal-op.js +13 -0
  147. package/dist/emit/snprintf-helpers.d.ts +17 -0
  148. package/dist/emit/snprintf-helpers.js +462 -0
  149. package/dist/emit/statement-renderer.d.ts +189 -0
  150. package/dist/emit/statement-renderer.js +948 -0
  151. package/dist/emit/utils/async-state-machine.d.ts +42 -0
  152. package/dist/emit/utils/async-state-machine.js +343 -0
  153. package/dist/emit/utils/comment-helpers.d.ts +20 -0
  154. package/dist/emit/utils/comment-helpers.js +31 -0
  155. package/dist/emit/utils/cpp-helpers.d.ts +47 -0
  156. package/dist/emit/utils/cpp-helpers.js +85 -0
  157. package/dist/emit/utils/include-resolver.d.ts +58 -0
  158. package/dist/emit/utils/include-resolver.js +155 -0
  159. package/dist/emit/utils/index.d.ts +8 -0
  160. package/dist/emit/utils/index.js +12 -0
  161. package/dist/emit/utils/type-inference.d.ts +159 -0
  162. package/dist/emit/utils/type-inference.js +559 -0
  163. package/dist/eslint-check.d.ts +10 -0
  164. package/dist/eslint-check.js +102 -0
  165. package/dist/framework-package.d.ts +10 -0
  166. package/dist/framework-package.js +58 -0
  167. package/dist/framework-registry.d.ts +39 -0
  168. package/dist/framework-registry.js +30 -0
  169. package/dist/incremental-cache.d.ts +116 -0
  170. package/dist/incremental-cache.js +335 -0
  171. package/dist/ir/adc-range-validation.d.ts +11 -0
  172. package/dist/ir/adc-range-validation.js +250 -0
  173. package/dist/ir/ast-node-utils.d.ts +8 -0
  174. package/dist/ir/ast-node-utils.js +32 -0
  175. package/dist/ir/board-pin-utils.d.ts +13 -0
  176. package/dist/ir/board-pin-utils.js +65 -0
  177. package/dist/ir/board-resolver.d.ts +36 -0
  178. package/dist/ir/board-resolver.js +437 -0
  179. package/dist/ir/build-ir-state.d.ts +167 -0
  180. package/dist/ir/build-ir-state.js +306 -0
  181. package/dist/ir/build-ir.d.ts +2 -0
  182. package/dist/ir/build-ir.js +808 -0
  183. package/dist/ir/call-graph.d.ts +35 -0
  184. package/dist/ir/call-graph.js +194 -0
  185. package/dist/ir/compile-time-only.d.ts +2 -0
  186. package/dist/ir/compile-time-only.js +16 -0
  187. package/dist/ir/declaration-builders.d.ts +9 -0
  188. package/dist/ir/declaration-builders.js +608 -0
  189. package/dist/ir/entry-points.d.ts +30 -0
  190. package/dist/ir/entry-points.js +191 -0
  191. package/dist/ir/expression-to-ir.d.ts +5 -0
  192. package/dist/ir/expression-to-ir.js +2249 -0
  193. package/dist/ir/extract-property-chain.d.ts +10 -0
  194. package/dist/ir/extract-property-chain.js +30 -0
  195. package/dist/ir/feature-prescan.d.ts +3 -0
  196. package/dist/ir/feature-prescan.js +43 -0
  197. package/dist/ir/feature-registry.d.ts +30 -0
  198. package/dist/ir/feature-registry.js +816 -0
  199. package/dist/ir/filter.d.ts +7 -0
  200. package/dist/ir/filter.js +85 -0
  201. package/dist/ir/function-builder.d.ts +19 -0
  202. package/dist/ir/function-builder.js +670 -0
  203. package/dist/ir/hal/hal-emitter.d.ts +62 -0
  204. package/dist/ir/hal/hal-emitter.js +735 -0
  205. package/dist/ir/hal/hal-parser.d.ts +61 -0
  206. package/dist/ir/hal/hal-parser.js +473 -0
  207. package/dist/ir/hal/hal-plugins.d.ts +34 -0
  208. package/dist/ir/hal/hal-plugins.js +706 -0
  209. package/dist/ir/hal-resolver.d.ts +5 -0
  210. package/dist/ir/hal-resolver.js +5 -0
  211. package/dist/ir/heap-analysis.d.ts +8 -0
  212. package/dist/ir/heap-analysis.js +350 -0
  213. package/dist/ir/heap-array-validation.d.ts +24 -0
  214. package/dist/ir/heap-array-validation.js +29 -0
  215. package/dist/ir/identifier-collector.d.ts +18 -0
  216. package/dist/ir/identifier-collector.js +439 -0
  217. package/dist/ir/interrupt-analysis.d.ts +39 -0
  218. package/dist/ir/interrupt-analysis.js +467 -0
  219. package/dist/ir/memory-budget-validation.d.ts +10 -0
  220. package/dist/ir/memory-budget-validation.js +86 -0
  221. package/dist/ir/namespace-builder.d.ts +7 -0
  222. package/dist/ir/namespace-builder.js +152 -0
  223. package/dist/ir/ownership-analysis.d.ts +9 -0
  224. package/dist/ir/ownership-analysis.js +1207 -0
  225. package/dist/ir/peripheral-ownership.d.ts +3 -0
  226. package/dist/ir/peripheral-ownership.js +152 -0
  227. package/dist/ir/peripheral-symbols.d.ts +7 -0
  228. package/dist/ir/peripheral-symbols.js +57 -0
  229. package/dist/ir/peripheral-usage.d.ts +54 -0
  230. package/dist/ir/peripheral-usage.js +691 -0
  231. package/dist/ir/peripheral-validation.d.ts +8 -0
  232. package/dist/ir/peripheral-validation.js +77 -0
  233. package/dist/ir/pin-alias-conflict.d.ts +4 -0
  234. package/dist/ir/pin-alias-conflict.js +34 -0
  235. package/dist/ir/pin-capability-validation.d.ts +6 -0
  236. package/dist/ir/pin-capability-validation.js +413 -0
  237. package/dist/ir/pin-mode-validation.d.ts +10 -0
  238. package/dist/ir/pin-mode-validation.js +301 -0
  239. package/dist/ir/pin-safety.d.ts +11 -0
  240. package/dist/ir/pin-safety.js +58 -0
  241. package/dist/ir/program-analysis.d.ts +44 -0
  242. package/dist/ir/program-analysis.js +589 -0
  243. package/dist/ir/pulldown-validation.d.ts +7 -0
  244. package/dist/ir/pulldown-validation.js +49 -0
  245. package/dist/ir/pwm-timer-sharing.d.ts +4 -0
  246. package/dist/ir/pwm-timer-sharing.js +93 -0
  247. package/dist/ir/reachability.d.ts +68 -0
  248. package/dist/ir/reachability.js +224 -0
  249. package/dist/ir/register-decorators.d.ts +6 -0
  250. package/dist/ir/register-decorators.js +49 -0
  251. package/dist/ir/render-expr.d.ts +4 -0
  252. package/dist/ir/render-expr.js +127 -0
  253. package/dist/ir/resource-analysis.d.ts +19 -0
  254. package/dist/ir/resource-analysis.js +153 -0
  255. package/dist/ir/statement-to-ir.d.ts +23 -0
  256. package/dist/ir/statement-to-ir.js +349 -0
  257. package/dist/ir/symbol-table.d.ts +68 -0
  258. package/dist/ir/symbol-table.js +179 -0
  259. package/dist/ir/symbol-types.d.ts +56 -0
  260. package/dist/ir/symbol-types.js +107 -0
  261. package/dist/ir/timer0-pwm-timing-conflict.d.ts +4 -0
  262. package/dist/ir/timer0-pwm-timing-conflict.js +71 -0
  263. package/dist/ir/timing-validation.d.ts +7 -0
  264. package/dist/ir/timing-validation.js +95 -0
  265. package/dist/ir/transformers/array-methods.d.ts +8 -0
  266. package/dist/ir/transformers/array-methods.js +493 -0
  267. package/dist/ir/transformers/call-statement.d.ts +5 -0
  268. package/dist/ir/transformers/call-statement.js +758 -0
  269. package/dist/ir/transformers/callback-context-registry.d.ts +20 -0
  270. package/dist/ir/transformers/callback-context-registry.js +55 -0
  271. package/dist/ir/transformers/canvas-lowering.d.ts +42 -0
  272. package/dist/ir/transformers/canvas-lowering.js +249 -0
  273. package/dist/ir/transformers/control-flow.d.ts +8 -0
  274. package/dist/ir/transformers/control-flow.js +508 -0
  275. package/dist/ir/transformers/expressions.d.ts +7 -0
  276. package/dist/ir/transformers/expressions.js +406 -0
  277. package/dist/ir/transformers/hal-call-resolver.d.ts +29 -0
  278. package/dist/ir/transformers/hal-call-resolver.js +274 -0
  279. package/dist/ir/transformers/hal-emit-helpers.d.ts +14 -0
  280. package/dist/ir/transformers/hal-emit-helpers.js +63 -0
  281. package/dist/ir/transformers/namespace-methods.d.ts +20 -0
  282. package/dist/ir/transformers/namespace-methods.js +110 -0
  283. package/dist/ir/transformers/register-assignment.d.ts +5 -0
  284. package/dist/ir/transformers/register-assignment.js +56 -0
  285. package/dist/ir/transformers/ui-call-resolver.d.ts +149 -0
  286. package/dist/ir/transformers/ui-call-resolver.js +1136 -0
  287. package/dist/ir/transformers/ui-callback-lowering.d.ts +62 -0
  288. package/dist/ir/transformers/ui-callback-lowering.js +623 -0
  289. package/dist/ir/transformers/ui-mount.d.ts +20 -0
  290. package/dist/ir/transformers/ui-mount.js +35 -0
  291. package/dist/ir/transformers/ui-reactive.d.ts +68 -0
  292. package/dist/ir/transformers/ui-reactive.js +129 -0
  293. package/dist/ir/transformers/variables.d.ts +14 -0
  294. package/dist/ir/transformers/variables.js +1045 -0
  295. package/dist/ir/try-catch-validation.d.ts +26 -0
  296. package/dist/ir/try-catch-validation.js +128 -0
  297. package/dist/ir/type-resolution.d.ts +31 -0
  298. package/dist/ir/type-resolution.js +977 -0
  299. package/dist/ir/ui-element-auto-wire.d.ts +50 -0
  300. package/dist/ir/ui-element-auto-wire.js +218 -0
  301. package/dist/ir/unit-suspicion-validation.d.ts +12 -0
  302. package/dist/ir/unit-suspicion-validation.js +296 -0
  303. package/dist/ir/utils/walk-ir.d.ts +6 -0
  304. package/dist/ir/utils/walk-ir.js +162 -0
  305. package/dist/ir/validation-orchestrator.d.ts +4 -0
  306. package/dist/ir/validation-orchestrator.js +45 -0
  307. package/dist/libdef/base-class-resolver.d.ts +23 -0
  308. package/dist/libdef/base-class-resolver.js +50 -0
  309. package/dist/libdef/cpp-to-decl.d.ts +34 -0
  310. package/dist/libdef/cpp-to-decl.js +584 -0
  311. package/dist/libdef/header-parser.d.ts +53 -0
  312. package/dist/libdef/header-parser.js +269 -0
  313. package/dist/libdef/registry.d.ts +10 -0
  314. package/dist/libdef/registry.js +142 -0
  315. package/dist/mapping/peripheral-names.d.ts +23 -0
  316. package/dist/mapping/peripheral-names.js +63 -0
  317. package/dist/mapping/source-map.d.ts +46 -0
  318. package/dist/mapping/source-map.js +207 -0
  319. package/dist/orchestrator/dts-generator.d.ts +17 -0
  320. package/dist/orchestrator/dts-generator.js +83 -0
  321. package/dist/orchestrator/graph-builder.d.ts +18 -0
  322. package/dist/orchestrator/graph-builder.js +218 -0
  323. package/dist/orchestrator/semantic-facts-verifier.d.ts +38 -0
  324. package/dist/orchestrator/semantic-facts-verifier.js +121 -0
  325. package/dist/orchestrator/semantic-facts.d.ts +141 -0
  326. package/dist/orchestrator/semantic-facts.js +652 -0
  327. package/dist/orchestrator/type-checker.d.ts +39 -0
  328. package/dist/orchestrator/type-checker.js +760 -0
  329. package/dist/platform/async-runtime.d.ts +8 -0
  330. package/dist/platform/async-runtime.js +26 -0
  331. package/dist/platform/generic-strategy.d.ts +101 -0
  332. package/dist/platform/generic-strategy.js +289 -0
  333. package/dist/platform/index.d.ts +4 -0
  334. package/dist/platform/index.js +9 -0
  335. package/dist/platform/registry.d.ts +21 -0
  336. package/dist/platform/registry.js +42 -0
  337. package/dist/platform/toolchain.d.ts +4 -0
  338. package/dist/platform/toolchain.js +43 -0
  339. package/dist/preview/client.d.ts +1 -0
  340. package/dist/preview/client.js +137 -0
  341. package/dist/preview/server.d.ts +5 -0
  342. package/dist/preview/server.js +199 -0
  343. package/dist/profiler/index.d.ts +28 -0
  344. package/dist/profiler/index.js +28 -0
  345. package/dist/profiler/profiler.d.ts +95 -0
  346. package/dist/profiler/profiler.js +338 -0
  347. package/dist/profiler/types.d.ts +87 -0
  348. package/dist/profiler/types.js +12 -0
  349. package/dist/stores/display-profile-store.d.ts +16 -0
  350. package/dist/stores/display-profile-store.js +48 -0
  351. package/dist/stores/theme-store.d.ts +13 -0
  352. package/dist/stores/theme-store.js +30 -0
  353. package/dist/testing.d.ts +45 -0
  354. package/dist/testing.js +47 -0
  355. package/dist/transpile/resolution.d.ts +29 -0
  356. package/dist/transpile/resolution.js +282 -0
  357. package/dist/transpile.d.ts +3 -0
  358. package/dist/transpile.js +722 -0
  359. package/dist/types.d.ts +217 -0
  360. package/dist/types.js +1 -0
  361. package/dist/ui/ui-bridge.d.ts +4 -0
  362. package/dist/ui/ui-bridge.js +34 -0
  363. package/dist/ui-hook.d.ts +84 -0
  364. package/dist/ui-hook.js +45 -0
  365. package/dist/utils/cli.d.ts +3 -0
  366. package/dist/utils/cli.js +463 -0
  367. package/dist/utils/fs.d.ts +4 -0
  368. package/dist/utils/fs.js +23 -0
  369. package/dist/utils/logger.d.ts +2 -0
  370. package/dist/utils/logger.js +8 -0
  371. package/dist/utils/strings.d.ts +35 -0
  372. package/dist/utils/strings.js +142 -0
  373. package/dist/utils/ui.d.ts +66 -0
  374. package/dist/utils/ui.js +149 -0
  375. package/dist/watch.d.ts +35 -0
  376. package/dist/watch.js +111 -0
  377. package/package.json +127 -0
@@ -0,0 +1,670 @@
1
+ import ts from "typescript";
2
+ import { extractNodeComments, makeDiagnostic, makeSourceSpan } from "./ast-node-utils.js";
3
+ import { collectReturns, inferExprCppType, typeNodeToCppType, extractOwnershipKindFromTypeNode, resolveFunctionReturnType, resolveFunctionTypeSignature, resolveAliasedTypeNode, } from "./type-resolution.js";
4
+ import { parsedIsPointer } from "../api/shared/cpp-type-ir.js";
5
+ import { expressionToIR } from "./expression-to-ir.js";
6
+ import { hoistedNestedFunctions, hoistedNestedClasses, nestedClassAliases, restParamFunctions, } from "./build-ir-state.js";
7
+ import { getCurrentIrTypeScope } from "./symbol-types.js";
8
+ import { renderExprAsText } from "./render-expr.js";
9
+ function processDestructuredParameter(parameter, typeAliasNodes, sourceText, diagnostics, paramIndex) {
10
+ const paramType = typeNodeToCppType(parameter.type, typeAliasNodes) || "auto";
11
+ const syntheticName = `__param_${paramIndex}`;
12
+ const ownershipKind = extractOwnershipKindFromTypeNode(parameter.type, typeAliasNodes);
13
+ const syntheticParam = {
14
+ name: syntheticName,
15
+ cppType: (paramType === "void" ? "auto" : paramType),
16
+ isRest: !!parameter.dotDotDotToken,
17
+ ...(ownershipKind ? { ownershipKind } : {}),
18
+ };
19
+ const localVariableTypes = new Map();
20
+ const extractionStatements = [];
21
+ const isPointer = parsedIsPointer(paramType);
22
+ const accessor = isPointer ? "->" : ".";
23
+ const processBindingElement = (element, prefix) => {
24
+ if (ts.isIdentifier(element.name)) {
25
+ const varName = element.name.text;
26
+ const propName = element.propertyName && ts.isIdentifier(element.propertyName)
27
+ ? element.propertyName.text
28
+ : varName;
29
+ const accessExpr = { kind: "raw", value: `${prefix}${accessor}${propName}` };
30
+ const initializer = element.initializer
31
+ ? { kind: "raw", value: `cuttlefish_nullish(${prefix}${accessor}${propName}, ${renderExprAsText(expressionToIR(element.initializer, sourceText, diagnostics))})` }
32
+ : accessExpr;
33
+ extractionStatements.push({
34
+ kind: "var_decl",
35
+ sourceSpan: makeSourceSpan(element, sourceText, sourceText),
36
+ leadingComments: [],
37
+ trailingComments: [],
38
+ name: varName,
39
+ storage: "const",
40
+ cppType: "auto",
41
+ initializer,
42
+ });
43
+ localVariableTypes.set(varName, "auto");
44
+ }
45
+ else if (ts.isObjectBindingPattern(element.name)) {
46
+ const propName = element.propertyName && ts.isIdentifier(element.propertyName)
47
+ ? element.propertyName.text
48
+ : null;
49
+ const newPrefix = propName ? `${prefix}${accessor}${propName}` : prefix;
50
+ for (const nested of element.name.elements) {
51
+ if (ts.isBindingElement(nested) && ts.isIdentifier(nested.name)) {
52
+ const nestedVarName = nested.name.text;
53
+ const nestedPropName = nested.propertyName && ts.isIdentifier(nested.propertyName)
54
+ ? nested.propertyName.text
55
+ : nestedVarName;
56
+ const nestedAccess = `${newPrefix}${accessor}${nestedPropName}`;
57
+ const nestedInitializer = nested.initializer
58
+ ? { kind: "raw", value: `cuttlefish_nullish(${nestedAccess}, ${renderExprAsText(expressionToIR(nested.initializer, sourceText, diagnostics))})` }
59
+ : { kind: "raw", value: nestedAccess };
60
+ extractionStatements.push({
61
+ kind: "var_decl",
62
+ sourceSpan: makeSourceSpan(nested, sourceText, sourceText),
63
+ leadingComments: [],
64
+ trailingComments: [],
65
+ name: nestedVarName,
66
+ storage: "const",
67
+ cppType: "auto",
68
+ initializer: nestedInitializer,
69
+ });
70
+ localVariableTypes.set(nestedVarName, "auto");
71
+ }
72
+ }
73
+ }
74
+ };
75
+ const bindingPattern = parameter.name;
76
+ if (ts.isObjectBindingPattern(bindingPattern)) {
77
+ for (const element of bindingPattern.elements) {
78
+ if (ts.isBindingElement(element)) {
79
+ processBindingElement(element, syntheticName);
80
+ }
81
+ }
82
+ }
83
+ else if (ts.isArrayBindingPattern(bindingPattern)) {
84
+ for (let i = 0; i < bindingPattern.elements.length; i++) {
85
+ const element = bindingPattern.elements[i];
86
+ if (ts.isBindingElement(element) && ts.isIdentifier(element.name)) {
87
+ const varName = element.name.text;
88
+ const accessExpr = { kind: "raw", value: `${syntheticName}[${i}]` };
89
+ const initializer = element.initializer
90
+ ? { kind: "raw", value: `cuttlefish_nullish(${syntheticName}[${i}], ${renderExprAsText(expressionToIR(element.initializer, sourceText, diagnostics))})` }
91
+ : accessExpr;
92
+ extractionStatements.push({
93
+ kind: "var_decl",
94
+ sourceSpan: makeSourceSpan(element, sourceText, sourceText),
95
+ leadingComments: [],
96
+ trailingComments: [],
97
+ name: varName,
98
+ storage: "const",
99
+ cppType: "auto",
100
+ initializer,
101
+ });
102
+ localVariableTypes.set(varName, "auto");
103
+ }
104
+ }
105
+ }
106
+ return {
107
+ syntheticParam,
108
+ extractionStatements,
109
+ localVariableTypes,
110
+ };
111
+ }
112
+ export function functionDeclarationToIR(node, fileName, sourceText, diagnostics, functionReturnTypes, typeAliasNodes, boilerplates, pointerVars = new Map(), lowerStatementList) {
113
+ // Skip overload signatures (declarations without a body).
114
+ if (!node.body)
115
+ return undefined;
116
+ if (!node.name) {
117
+ diagnostics.push(makeDiagnostic(sourceText, node.pos, "Anonymous function declaration is unsupported.", "warning"));
118
+ return undefined;
119
+ }
120
+ const isAsync = node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) ?? false;
121
+ const isGenerator = !!node.asteriskToken;
122
+ const isExported = node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) ?? false;
123
+ if (isAsync) {
124
+ boilerplates.add("async_stub");
125
+ }
126
+ const localVariableTypes = new Map();
127
+ const parameters = [];
128
+ const destructuredParamStatements = [];
129
+ for (let paramIndex = 0; paramIndex < node.parameters.length; paramIndex++) {
130
+ const parameter = node.parameters[paramIndex];
131
+ if (ts.isIdentifier(parameter.name)) {
132
+ const parameterType = typeNodeToCppType(parameter.type, typeAliasNodes);
133
+ const paramOwnershipKind = extractOwnershipKindFromTypeNode(parameter.type, typeAliasNodes);
134
+ localVariableTypes.set(parameter.name.text, parameterType);
135
+ parameters.push({
136
+ name: parameter.name.text,
137
+ cppType: (parameterType === "void" ? "auto" : parameterType),
138
+ defaultValue: parameter.initializer
139
+ ? expressionToIR(parameter.initializer, sourceText, diagnostics, pointerVars)
140
+ : undefined,
141
+ isRest: !!parameter.dotDotDotToken,
142
+ ...(paramOwnershipKind ? { ownershipKind: paramOwnershipKind } : {}),
143
+ });
144
+ }
145
+ else if (ts.isObjectBindingPattern(parameter.name) || ts.isArrayBindingPattern(parameter.name)) {
146
+ const result = processDestructuredParameter(parameter, typeAliasNodes, sourceText, diagnostics, paramIndex);
147
+ if (result) {
148
+ parameters.push(result.syntheticParam);
149
+ destructuredParamStatements.push(...result.extractionStatements);
150
+ result.localVariableTypes.forEach((v, k) => localVariableTypes.set(k, v));
151
+ }
152
+ }
153
+ }
154
+ const bodyStatements = lowerStatementList(node.body?.statements ?? [], fileName, sourceText, diagnostics, functionReturnTypes, localVariableTypes, node.name.text, typeAliasNodes, pointerVars);
155
+ const statements = destructuredParamStatements.length > 0
156
+ ? [...destructuredParamStatements, ...bodyStatements]
157
+ : bodyStatements;
158
+ const fnTypeParams = node.typeParameters
159
+ ? node.typeParameters.map(tp => tp.name.text)
160
+ : undefined;
161
+ const restParam = parameters.find(p => p.isRest);
162
+ if (restParam && restParam.cppType.includes("std::vector<")) {
163
+ const elementType = restParam.cppType.replace(/^(?:const\s+)?std::vector<(.+)>&?$/, "$1");
164
+ restParamFunctions.set(node.name.text, elementType);
165
+ }
166
+ return {
167
+ originalName: node.name.text,
168
+ isAsync,
169
+ returnType: resolveFunctionReturnType(node.name.text, functionReturnTypes),
170
+ sourceSpan: makeSourceSpan(node, fileName, sourceText),
171
+ ...extractNodeComments(node, sourceText),
172
+ parameters,
173
+ statements,
174
+ ...(fnTypeParams && fnTypeParams.length > 0 ? { typeParameters: fnTypeParams } : {}),
175
+ ...(isGenerator ? { isGenerator: true } : {}),
176
+ ...(isExported ? { isExported: true } : {}),
177
+ };
178
+ }
179
+ export function variableAsFunctionToIR(node, fileName, sourceText, diagnostics, functionReturnTypes, typeAliasNodes, boilerplates, pointerVars = new Map(), lowerStatementList) {
180
+ const functionExpressionDeclarations = node.declarationList.declarations.filter((declaration) => {
181
+ if (!ts.isIdentifier(declaration.name) || !declaration.initializer) {
182
+ return false;
183
+ }
184
+ return ts.isFunctionExpression(declaration.initializer) || ts.isArrowFunction(declaration.initializer);
185
+ });
186
+ if (functionExpressionDeclarations.length === 0 ||
187
+ functionExpressionDeclarations.length !== node.declarationList.declarations.length) {
188
+ return undefined;
189
+ }
190
+ const declarationComments = extractNodeComments(node, sourceText);
191
+ const isExported = node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) ?? false;
192
+ let commentsAssigned = false;
193
+ const results = [];
194
+ for (const declaration of functionExpressionDeclarations) {
195
+ if (!ts.isIdentifier(declaration.name) || !declaration.initializer) {
196
+ continue;
197
+ }
198
+ const fnExpression = declaration.initializer;
199
+ if (!ts.isFunctionExpression(fnExpression) && !ts.isArrowFunction(fnExpression)) {
200
+ continue;
201
+ }
202
+ const signatureFromAlias = resolveFunctionTypeSignature(declaration.type, typeAliasNodes);
203
+ const localVariableTypes = new Map();
204
+ const parameters = [];
205
+ const destructuredParamStatements = [];
206
+ for (let index = 0; index < fnExpression.parameters.length; index++) {
207
+ const parameter = fnExpression.parameters[index];
208
+ if (ts.isIdentifier(parameter.name)) {
209
+ const explicitParameterType = typeNodeToCppType(parameter.type, typeAliasNodes);
210
+ const aliasedParameterType = signatureFromAlias?.parameterTypes[index] ?? "auto";
211
+ const parameterType = explicitParameterType !== "auto" ? explicitParameterType : aliasedParameterType;
212
+ localVariableTypes.set(parameter.name.text, parameterType);
213
+ const paramOwnershipKind = extractOwnershipKindFromTypeNode(parameter.type, typeAliasNodes);
214
+ parameters.push({
215
+ name: parameter.name.text,
216
+ cppType: (parameterType === "void" ? "auto" : parameterType),
217
+ defaultValue: parameter.initializer
218
+ ? expressionToIR(parameter.initializer, sourceText, diagnostics, pointerVars)
219
+ : undefined,
220
+ isRest: !!parameter.dotDotDotToken,
221
+ ...(paramOwnershipKind ? { ownershipKind: paramOwnershipKind } : {}),
222
+ });
223
+ }
224
+ else if (ts.isObjectBindingPattern(parameter.name) || ts.isArrayBindingPattern(parameter.name)) {
225
+ const result = processDestructuredParameter(parameter, typeAliasNodes, sourceText, diagnostics, index);
226
+ if (result) {
227
+ parameters.push(result.syntheticParam);
228
+ destructuredParamStatements.push(...result.extractionStatements);
229
+ result.localVariableTypes.forEach((v, k) => localVariableTypes.set(k, v));
230
+ }
231
+ }
232
+ }
233
+ const bodyStatements = ts.isBlock(fnExpression.body)
234
+ ? lowerStatementList(fnExpression.body.statements, fileName, sourceText, diagnostics, functionReturnTypes, localVariableTypes, declaration.name.text, typeAliasNodes, pointerVars)
235
+ : [
236
+ {
237
+ kind: "return",
238
+ sourceSpan: makeSourceSpan(fnExpression.body, fileName, sourceText),
239
+ value: expressionToIR(fnExpression.body, sourceText, diagnostics, pointerVars),
240
+ },
241
+ ];
242
+ const statements = destructuredParamStatements.length > 0
243
+ ? [...destructuredParamStatements, ...bodyStatements]
244
+ : bodyStatements;
245
+ const explicitReturnType = typeNodeToCppType(fnExpression.type, typeAliasNodes);
246
+ let resolvedReturnType = explicitReturnType;
247
+ if (resolvedReturnType === "auto" && signatureFromAlias && signatureFromAlias.returnType !== "auto") {
248
+ resolvedReturnType = signatureFromAlias.returnType;
249
+ }
250
+ // Promote int → double when the function body returns double/float expressions
251
+ if (resolvedReturnType === "int") {
252
+ if (ts.isBlock(fnExpression.body)) {
253
+ const returnTypes = collectReturns(fnExpression.body)
254
+ .filter((item) => item.expression)
255
+ .map((item) => inferExprCppType(item.expression, functionReturnTypes, localVariableTypes, sourceText))
256
+ .filter((item) => item !== "auto");
257
+ if (returnTypes.includes("float") || returnTypes.includes("double")) {
258
+ resolvedReturnType = "double";
259
+ }
260
+ }
261
+ else {
262
+ const inferredBodyType = inferExprCppType(fnExpression.body, functionReturnTypes, localVariableTypes, sourceText);
263
+ if (inferredBodyType === "float" || inferredBodyType === "double") {
264
+ resolvedReturnType = "double";
265
+ }
266
+ }
267
+ }
268
+ if (resolvedReturnType === "auto") {
269
+ if (ts.isBlock(fnExpression.body)) {
270
+ const returnTypes = collectReturns(fnExpression.body)
271
+ .filter((item) => item.expression)
272
+ .map((item) => inferExprCppType(item.expression, functionReturnTypes, localVariableTypes, sourceText))
273
+ .filter((item) => item !== "auto");
274
+ if (returnTypes.includes("float") || returnTypes.includes("double")) {
275
+ resolvedReturnType = "double";
276
+ }
277
+ else if (returnTypes.includes("int")) {
278
+ resolvedReturnType = "int";
279
+ }
280
+ else if (returnTypes.includes("bool")) {
281
+ resolvedReturnType = "bool";
282
+ }
283
+ else if (returnTypes.includes("std::string")) {
284
+ resolvedReturnType = "std::string";
285
+ }
286
+ else if (returnTypes.length > 0) {
287
+ resolvedReturnType = returnTypes[0];
288
+ }
289
+ }
290
+ else {
291
+ resolvedReturnType = inferExprCppType(fnExpression.body, functionReturnTypes, localVariableTypes, sourceText);
292
+ }
293
+ }
294
+ const isAsync = fnExpression.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) ?? false;
295
+ const isGenerator = !!fnExpression.asteriskToken;
296
+ if (isAsync) {
297
+ boilerplates.add("async_stub");
298
+ }
299
+ const sourceSpanTarget = fnExpression.name ?? declaration;
300
+ const fnIR = {
301
+ originalName: declaration.name.text,
302
+ isAsync,
303
+ returnType: resolvedReturnType === "auto" ? "void" : resolvedReturnType,
304
+ sourceSpan: makeSourceSpan(sourceSpanTarget, fileName, sourceText),
305
+ leadingComments: commentsAssigned ? [] : declarationComments.leadingComments,
306
+ trailingComments: commentsAssigned ? [] : declarationComments.trailingComments,
307
+ parameters,
308
+ statements,
309
+ ...(isGenerator ? { isGenerator: true } : {}),
310
+ ...(isExported ? { isExported: true } : {}),
311
+ };
312
+ results.push(fnIR);
313
+ const restParam = parameters.find(p => p.isRest);
314
+ if (restParam && restParam.cppType.includes("std::vector<")) {
315
+ const elementType = restParam.cppType.replace(/^(?:const\s+)?std::vector<(.+)>&?$/, "$1");
316
+ restParamFunctions.set(declaration.name.text, elementType);
317
+ }
318
+ functionReturnTypes.set(declaration.name.text, resolvedReturnType === "auto" ? "void" : resolvedReturnType);
319
+ commentsAssigned = true;
320
+ }
321
+ return results;
322
+ }
323
+ /** Convert a TS type constraint to a C++ static_assert expression. */
324
+ export function typeConstraintToCppAssert(paramName, constraint) {
325
+ // Handle union types: string | number → std::is_same_v<T, std::string> || std::is_arithmetic_v<T>
326
+ if (ts.isUnionTypeNode(constraint)) {
327
+ const parts = constraint.types
328
+ .map(t => singleConstraintToCpp(paramName, t))
329
+ .filter((s) => !!s);
330
+ return parts.length > 0 ? parts.join(" || ") : undefined;
331
+ }
332
+ return singleConstraintToCpp(paramName, constraint);
333
+ }
334
+ function singleConstraintToCpp(paramName, constraint) {
335
+ if (constraint.kind === ts.SyntaxKind.StringKeyword) {
336
+ return `std::is_same_v<${paramName}, std::string>`;
337
+ }
338
+ if (constraint.kind === ts.SyntaxKind.NumberKeyword) {
339
+ return `std::is_arithmetic_v<${paramName}>`;
340
+ }
341
+ if (constraint.kind === ts.SyntaxKind.BooleanKeyword) {
342
+ return `std::is_same_v<${paramName}, bool>`;
343
+ }
344
+ return undefined;
345
+ }
346
+ /** Check if a type node resolves through a mapped type with readonly modifier. */
347
+ export function isReadonlyMappedType(node, typeAliases) {
348
+ if (!typeAliases)
349
+ return false;
350
+ // Resolve through type aliases
351
+ const resolvedNode = resolveAliasedTypeNode(node, typeAliases) ?? node;
352
+ if (ts.isMappedTypeNode(resolvedNode)) {
353
+ // Check if the mapped type has a readonly modifier
354
+ const modifier = resolvedNode.readonlyToken;
355
+ if (modifier)
356
+ return true;
357
+ // Also check the modifier property (TS uses different representations)
358
+ if (resolvedNode.modifier)
359
+ return true;
360
+ }
361
+ // If the original node is a type reference, resolve the alias and check
362
+ if (ts.isTypeReferenceNode(node) && ts.isIdentifier(node.typeName)) {
363
+ const aliasNode = typeAliases.get(node.typeName.text);
364
+ if (aliasNode && ts.isMappedTypeNode(aliasNode)) {
365
+ const modifier = aliasNode.readonlyToken;
366
+ if (modifier)
367
+ return true;
368
+ if (aliasNode.modifier)
369
+ return true;
370
+ }
371
+ }
372
+ return false;
373
+ }
374
+ /**
375
+ * Hoist a nested function declaration to file scope.
376
+ * Creates a mangled name (parent__inner) and registers it in the alias map
377
+ * so that call sites within the parent function get rewritten.
378
+ */
379
+ export function hoistNestedFunction(statement, fileName, sourceText, diagnostics, functionReturnTypes, parentFunctionName, typeAliases, pointerVars, lowerStatementList) {
380
+ const originalName = statement.name.text;
381
+ const safeParentName = parentFunctionName.replace(/\./g, "_");
382
+ const mangledName = `${safeParentName}__${originalName}`;
383
+ // Resolve return type from annotation, or default to auto
384
+ const returnType = statement.type
385
+ ? typeNodeToCppType(statement.type, typeAliases)
386
+ : "auto";
387
+ // Detect if the return type is a readonly mapped type (e.g. ReadonlyGuarded<T>)
388
+ // so the emitter can add `const` to the C++ return type.
389
+ const isReadonlyReturnType = statement.type
390
+ ? isReadonlyMappedType(statement.type, typeAliases)
391
+ : false;
392
+ // Register the nested function's return type so that inferExprCppType
393
+ // can resolve call expressions to this function later in the same scope.
394
+ // For template functions, callers should use auto (concrete type depends
395
+ // on template argument deduction which only the C++ compiler can do).
396
+ const hasTypeParams = !!(statement.typeParameters && statement.typeParameters.length > 0);
397
+ functionReturnTypes.set(originalName, (hasTypeParams ? "auto" : returnType));
398
+ functionReturnTypes.set(mangledName, returnType);
399
+ const localVariableTypes = new Map();
400
+ const parameters = [];
401
+ const destructuredParamStatements = [];
402
+ for (let paramIndex = 0; paramIndex < statement.parameters.length; paramIndex++) {
403
+ const parameter = statement.parameters[paramIndex];
404
+ if (ts.isIdentifier(parameter.name)) {
405
+ const parameterType = typeNodeToCppType(parameter.type, typeAliases);
406
+ localVariableTypes.set(parameter.name.text, parameterType);
407
+ const paramOwnershipKind = extractOwnershipKindFromTypeNode(parameter.type, typeAliases);
408
+ parameters.push({
409
+ name: parameter.name.text,
410
+ cppType: (parameterType === "void" ? "auto" : parameterType),
411
+ defaultValue: parameter.initializer
412
+ ? expressionToIR(parameter.initializer, sourceText, diagnostics)
413
+ : undefined,
414
+ isRest: !!parameter.dotDotDotToken,
415
+ ...(paramOwnershipKind ? { ownershipKind: paramOwnershipKind } : {}),
416
+ });
417
+ }
418
+ else if (ts.isObjectBindingPattern(parameter.name) || ts.isArrayBindingPattern(parameter.name)) {
419
+ const result = processDestructuredParameter(parameter, typeAliases ?? new Map(), sourceText, diagnostics, paramIndex);
420
+ if (result) {
421
+ parameters.push(result.syntheticParam);
422
+ destructuredParamStatements.push(...result.extractionStatements);
423
+ result.localVariableTypes.forEach((v, k) => localVariableTypes.set(k, v));
424
+ }
425
+ }
426
+ }
427
+ // Lower the body — recursive call to lowerStatementListCallback
428
+ const bodyStatements = lowerStatementList(statement.body?.statements ?? [], fileName, sourceText, diagnostics, functionReturnTypes, localVariableTypes, mangledName, typeAliases, pointerVars);
429
+ const statements = destructuredParamStatements.length > 0
430
+ ? [...destructuredParamStatements, ...bodyStatements]
431
+ : bodyStatements;
432
+ const typeParams = statement.typeParameters
433
+ ? statement.typeParameters.map(tp => tp.name.text)
434
+ : undefined;
435
+ // Capture generic type constraints as C++ static_assert expressions
436
+ const constraints = new Map();
437
+ if (statement.typeParameters) {
438
+ for (const tp of statement.typeParameters) {
439
+ if (tp.constraint) {
440
+ const cppConstraint = typeConstraintToCppAssert(tp.name.text, tp.constraint);
441
+ if (cppConstraint) {
442
+ constraints.set(tp.name.text, cppConstraint);
443
+ }
444
+ }
445
+ }
446
+ }
447
+ hoistedNestedFunctions.push({
448
+ originalName: mangledName,
449
+ isAsync: false,
450
+ returnType: returnType,
451
+ sourceSpan: makeSourceSpan(statement, fileName, sourceText),
452
+ ...extractNodeComments(statement, sourceText),
453
+ parameters,
454
+ statements,
455
+ ...(typeParams && typeParams.length > 0 ? { typeParameters: typeParams } : {}),
456
+ ...(constraints.size > 0 ? { typeParameterConstraints: constraints } : {}),
457
+ ...(isReadonlyReturnType ? { isReadonlyReturnType: true } : {}),
458
+ });
459
+ }
460
+ export function hoistNestedClass(node, fileName, sourceText, diagnostics, functionReturnTypes, functionNameForDiagnostics, typeAliases, pointerVars = new Map(), lowerStatementList) {
461
+ if (!node.name)
462
+ return;
463
+ const originalClassName = node.name.text;
464
+ const safeParentName = functionNameForDiagnostics.replace(/\./g, "_");
465
+ const className = safeParentName ? `${safeParentName}__${originalClassName}` : originalClassName;
466
+ const rawExtendsClass = node.heritageClauses
467
+ ?.find((clause) => clause.token === ts.SyntaxKind.ExtendsKeyword)
468
+ ?.types[0]
469
+ ?.expression
470
+ ?.getText();
471
+ // Resolve extends name through nested class aliases (abstract parent may also be hoisted).
472
+ const extendsClass = rawExtendsClass
473
+ ? (nestedClassAliases.get(rawExtendsClass) ?? rawExtendsClass)
474
+ : undefined;
475
+ const isAbstract = node.modifiers?.some(m => m.kind === ts.SyntaxKind.AbstractKeyword) ?? false;
476
+ const classComments = extractNodeComments(node, sourceText);
477
+ const fields = [];
478
+ const methods = [];
479
+ const getters = [];
480
+ const setters = [];
481
+ let ctor;
482
+ for (const member of node.members) {
483
+ if (ts.isPropertyDeclaration(member) && member.name && ts.isIdentifier(member.name)) {
484
+ const fType = typeNodeToCppType(member.type, typeAliases);
485
+ getCurrentIrTypeScope()?.classFields.set(`this->${member.name.text}`, fType);
486
+ }
487
+ }
488
+ for (const member of node.members) {
489
+ if (ts.isConstructorDeclaration(member)) {
490
+ const ctorParams = [];
491
+ const ctorLocalTypes = new Map();
492
+ for (const param of member.parameters) {
493
+ if (ts.isIdentifier(param.name)) {
494
+ const paramType = typeNodeToCppType(param.type, typeAliases);
495
+ ctorLocalTypes.set(param.name.text, paramType);
496
+ const paramOwnershipKind = extractOwnershipKindFromTypeNode(param.type, typeAliases);
497
+ ctorParams.push({
498
+ name: param.name.text,
499
+ cppType: (paramType === "void" ? "auto" : paramType),
500
+ defaultValue: param.initializer
501
+ ? expressionToIR(param.initializer, sourceText, diagnostics)
502
+ : undefined,
503
+ isRest: !!param.dotDotDotToken,
504
+ ...(paramOwnershipKind ? { ownershipKind: paramOwnershipKind } : {}),
505
+ });
506
+ // TypeScript parameter property shorthand: constructor(public x: number)
507
+ const hasVisibility = param.modifiers?.some(m => m.kind === ts.SyntaxKind.PublicKeyword ||
508
+ m.kind === ts.SyntaxKind.PrivateKeyword ||
509
+ m.kind === ts.SyntaxKind.ProtectedKeyword);
510
+ if (hasVisibility) {
511
+ const visibility = param.modifiers.some(m => m.kind === ts.SyntaxKind.PrivateKeyword)
512
+ ? "private"
513
+ : param.modifiers.some(m => m.kind === ts.SyntaxKind.ProtectedKeyword)
514
+ ? "protected"
515
+ : "public";
516
+ fields.push({
517
+ name: param.name.text,
518
+ cppType: (paramType === "void" ? "auto" : paramType),
519
+ visibility,
520
+ initializer: param.initializer
521
+ ? expressionToIR(param.initializer, sourceText, diagnostics)
522
+ : undefined,
523
+ });
524
+ }
525
+ }
526
+ }
527
+ const ctorBody = member.body
528
+ ? lowerStatementList(member.body.statements, fileName, sourceText, diagnostics, functionReturnTypes, ctorLocalTypes, `${className}.constructor`, typeAliases)
529
+ : [];
530
+ ctor = { parameters: ctorParams, statements: ctorBody };
531
+ continue;
532
+ }
533
+ if (ts.isPropertyDeclaration(member) && member.name && ts.isIdentifier(member.name)) {
534
+ const visibility = member.modifiers?.some(m => m.kind === ts.SyntaxKind.PrivateKeyword)
535
+ ? "private"
536
+ : member.modifiers?.some(m => m.kind === ts.SyntaxKind.ProtectedKeyword)
537
+ ? "protected"
538
+ : "public";
539
+ const fieldType = typeNodeToCppType(member.type, typeAliases);
540
+ fields.push({
541
+ name: member.name.text,
542
+ cppType: (fieldType === "void" ? "auto" : fieldType),
543
+ visibility,
544
+ initializer: member.initializer
545
+ ? expressionToIR(member.initializer, sourceText, diagnostics)
546
+ : undefined,
547
+ });
548
+ continue;
549
+ }
550
+ if (ts.isMethodDeclaration(member) && member.name && ts.isIdentifier(member.name)) {
551
+ const visibility = member.modifiers?.some(m => m.kind === ts.SyntaxKind.PrivateKeyword)
552
+ ? "private"
553
+ : member.modifiers?.some(m => m.kind === ts.SyntaxKind.ProtectedKeyword)
554
+ ? "protected"
555
+ : "public";
556
+ const isStatic = member.modifiers?.some(m => m.kind === ts.SyntaxKind.StaticKeyword) ?? false;
557
+ const isMethodAbstract = member.modifiers?.some(m => m.kind === ts.SyntaxKind.AbstractKeyword) ?? false;
558
+ const methodParams = [];
559
+ const methodLocalTypes = new Map();
560
+ for (const param of member.parameters) {
561
+ if (ts.isIdentifier(param.name)) {
562
+ const paramType = typeNodeToCppType(param.type, typeAliases);
563
+ methodLocalTypes.set(param.name.text, paramType);
564
+ const paramOwnershipKind = extractOwnershipKindFromTypeNode(param.type, typeAliases);
565
+ methodParams.push({
566
+ name: param.name.text,
567
+ cppType: (paramType === "void" ? "auto" : paramType),
568
+ defaultValue: param.initializer
569
+ ? expressionToIR(param.initializer, sourceText, diagnostics)
570
+ : undefined,
571
+ isRest: !!param.dotDotDotToken,
572
+ ...(paramOwnershipKind ? { ownershipKind: paramOwnershipKind } : {}),
573
+ });
574
+ }
575
+ }
576
+ const methodBody = member.body
577
+ ? lowerStatementList(member.body.statements, fileName, sourceText, diagnostics, functionReturnTypes, methodLocalTypes, `${className}.${member.name.text}`, typeAliases)
578
+ : [];
579
+ const methodReturnType = typeNodeToCppType(member.type, typeAliases);
580
+ const typeText = member.type ? sourceText.substring(member.type.pos, member.type.end).trim() : "";
581
+ const returnsSelf = member.type?.kind === ts.SyntaxKind.ThisType
582
+ || typeText === originalClassName
583
+ || typeText === className
584
+ || methodReturnType === originalClassName
585
+ || methodReturnType === className;
586
+ // Resolve return type through nested class aliases
587
+ const resolvedReturnType = nestedClassAliases.get(methodReturnType) ?? methodReturnType;
588
+ methods.push({
589
+ name: member.name.text,
590
+ returnType: (returnsSelf
591
+ ? `${className}*`
592
+ : (resolvedReturnType === "void" ? "void" : resolvedReturnType)),
593
+ parameters: methodParams,
594
+ statements: methodBody,
595
+ visibility,
596
+ isStatic,
597
+ isAbstract: isMethodAbstract,
598
+ ...(member.typeParameters && member.typeParameters.length > 0
599
+ ? { typeParameters: member.typeParameters.map(tp => tp.name.text) }
600
+ : {}),
601
+ });
602
+ continue;
603
+ }
604
+ // Handle get accessors in nested classes
605
+ if (ts.isGetAccessorDeclaration(member) && member.name && ts.isIdentifier(member.name)) {
606
+ const visibility = member.modifiers?.some(m => m.kind === ts.SyntaxKind.PrivateKeyword)
607
+ ? "private"
608
+ : member.modifiers?.some(m => m.kind === ts.SyntaxKind.ProtectedKeyword)
609
+ ? "protected"
610
+ : "public";
611
+ const isStatic = member.modifiers?.some(m => m.kind === ts.SyntaxKind.StaticKeyword) ?? false;
612
+ const returnType = typeNodeToCppType(member.type, typeAliases);
613
+ const body = member.body
614
+ ? lowerStatementList(member.body.statements, fileName, sourceText, diagnostics, functionReturnTypes, new Map(), `${className}.${member.name.text}`, typeAliases)
615
+ : [];
616
+ getters.push({
617
+ name: member.name.text,
618
+ returnType: (returnType === "void" ? "auto" : returnType),
619
+ statements: body,
620
+ visibility,
621
+ isStatic,
622
+ });
623
+ continue;
624
+ }
625
+ // Handle set accessors in nested classes
626
+ if (ts.isSetAccessorDeclaration(member) && member.name && ts.isIdentifier(member.name)) {
627
+ const visibility = member.modifiers?.some(m => m.kind === ts.SyntaxKind.PrivateKeyword)
628
+ ? "private"
629
+ : member.modifiers?.some(m => m.kind === ts.SyntaxKind.ProtectedKeyword)
630
+ ? "protected"
631
+ : "public";
632
+ const isStatic = member.modifiers?.some(m => m.kind === ts.SyntaxKind.StaticKeyword) ?? false;
633
+ const param = member.parameters[0];
634
+ const paramType = param && ts.isIdentifier(param.name)
635
+ ? typeNodeToCppType(param.type, typeAliases)
636
+ : "auto";
637
+ const body = member.body
638
+ ? lowerStatementList(member.body.statements, fileName, sourceText, diagnostics, functionReturnTypes, new Map(), `${className}.${member.name.text}`, typeAliases)
639
+ : [];
640
+ setters.push({
641
+ name: member.name.text,
642
+ parameter: {
643
+ name: param && ts.isIdentifier(param.name) ? param.name.text : "value",
644
+ cppType: (paramType === "void" ? "auto" : paramType),
645
+ isRest: false,
646
+ },
647
+ statements: body,
648
+ visibility,
649
+ isStatic,
650
+ });
651
+ continue;
652
+ }
653
+ }
654
+ hoistedNestedClasses.push({
655
+ name: className,
656
+ extendsClass,
657
+ isAbstract,
658
+ sourceSpan: makeSourceSpan(node, fileName, sourceText),
659
+ leadingComments: classComments.leadingComments,
660
+ trailingComments: classComments.trailingComments,
661
+ fields,
662
+ methods,
663
+ constructor: ctor,
664
+ getters,
665
+ setters,
666
+ });
667
+ if (safeParentName) {
668
+ nestedClassAliases.set(originalClassName, className);
669
+ }
670
+ }