@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,324 @@
1
+ import { emitCommentLines } from "../utils/index.js";
2
+ import { appendSourceLine, appendRenderedStatement } from "./line-appender.js";
3
+ import { createChildEmissionScope } from "../snprintf-helpers.js";
4
+ import { escapeCppKeyword } from "../../utils/strings.js";
5
+ import { isStringEnum } from "../../api/shared/index.js";
6
+ import { resolveEnumValues, narrowestEnumUnderlying } from "../utils/cpp-helpers.js";
7
+ export function emitNamespaces(ctx) {
8
+ const { program, strategy, reservedNames, mappedFunctions, topLevelScope, exprRenderer, statementRenderer } = ctx;
9
+ const normalizeCppTypeForTarget = (cppType) => strategy.normalizeCppType(cppType);
10
+ const renderExpression = (expr, calleeTransformer) => exprRenderer.render(expr, calleeTransformer);
11
+ const renderParameters = (params, forHeader = false) => statementRenderer.renderParameters(params, forHeader);
12
+ const renderTypedName = (cppType, name) => statementRenderer.renderTypedName(cppType, name);
13
+ for (const ns of program.namespaces) {
14
+ emitCommentLines(ns.leadingComments, "", (line) => appendSourceLine(ctx, line));
15
+ appendSourceLine(ctx, `namespace ${ns.name} {`);
16
+ appendSourceLine(ctx, "");
17
+ // Namespace enums
18
+ for (const enumDef of ns.enums) {
19
+ emitCommentLines(enumDef.leadingComments, " ", (line) => appendSourceLine(ctx, line));
20
+ // String enum → inner namespace of constexpr const char* constants
21
+ // (see type-decl-emitter.ts / isStringEnum for rationale).
22
+ if (isStringEnum(enumDef)) {
23
+ appendSourceLine(ctx, ` namespace ${enumDef.name} {`);
24
+ for (const member of enumDef.members) {
25
+ const memberName = ctx.reservedNames.has(member.name)
26
+ ? `_${member.name}`
27
+ : member.name;
28
+ const renamed = strategy.renameEnumMember(enumDef.name, memberName);
29
+ const escaped = String(member.value).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
30
+ appendSourceLine(ctx, ` constexpr const char* ${renamed} = "${escaped}";`);
31
+ }
32
+ appendSourceLine(ctx, " }");
33
+ emitCommentLines(enumDef.trailingComments, " ", (line) => appendSourceLine(ctx, line));
34
+ appendSourceLine(ctx, "");
35
+ continue;
36
+ }
37
+ const enumKeyword = "enum class";
38
+ const underlyingType = narrowestEnumUnderlying(resolveEnumValues(enumDef.members), strategy.needsLargeEnumUnderlying());
39
+ appendSourceLine(ctx, ` ${enumKeyword} ${enumDef.name}${underlyingType} {`);
40
+ let autoValue = 0;
41
+ for (let i = 0; i < enumDef.members.length; i++) {
42
+ const member = enumDef.members[i];
43
+ let valueSuffix;
44
+ if (typeof member.value === "number") {
45
+ valueSuffix = ` = ${member.value}`;
46
+ autoValue = member.value + 1;
47
+ }
48
+ else if (typeof member.value === "string") {
49
+ valueSuffix = ` = ${autoValue}`;
50
+ autoValue++;
51
+ }
52
+ else {
53
+ valueSuffix = "";
54
+ autoValue++;
55
+ }
56
+ const commaSuffix = i < enumDef.members.length - 1 ? "," : "";
57
+ appendSourceLine(ctx, ` ${member.name}${valueSuffix}${commaSuffix}`);
58
+ }
59
+ appendSourceLine(ctx, " };");
60
+ emitCommentLines(enumDef.trailingComments, " ", (line) => appendSourceLine(ctx, line));
61
+ appendSourceLine(ctx, "");
62
+ }
63
+ // Namespace type aliases
64
+ for (const typeAlias of ns.typeAliases) {
65
+ emitCommentLines(typeAlias.leadingComments, " ", (line) => appendSourceLine(ctx, line));
66
+ const cppType = normalizeCppTypeForTarget(typeAlias.cppType);
67
+ if (cppType !== "auto" && !strategy.shouldSkipTypeAlias(cppType)) {
68
+ appendSourceLine(ctx, ` using ${typeAlias.name} = ${cppType};`);
69
+ emitCommentLines(typeAlias.trailingComments, " ", (line) => appendSourceLine(ctx, line));
70
+ appendSourceLine(ctx, "");
71
+ }
72
+ }
73
+ // Namespace constants
74
+ for (const constant of ns.constants) {
75
+ const constType = normalizeCppTypeForTarget(constant.cppType);
76
+ const isConst = constant.storage === "const" || constant.storage === undefined;
77
+ if (constType !== "auto") {
78
+ if (isConst) {
79
+ appendSourceLine(ctx, ` const ${constType} ${constant.name} = ${renderExpression(constant.value, undefined)};`);
80
+ }
81
+ else {
82
+ appendSourceLine(ctx, ` ${constType} ${constant.name} = ${renderExpression(constant.value, undefined)};`);
83
+ }
84
+ }
85
+ else {
86
+ if (isConst) {
87
+ appendSourceLine(ctx, ` const auto ${constant.name} = ${renderExpression(constant.value, undefined)};`);
88
+ }
89
+ else {
90
+ appendSourceLine(ctx, ` auto ${constant.name} = ${renderExpression(constant.value, undefined)};`);
91
+ }
92
+ }
93
+ }
94
+ if (ns.assignments) {
95
+ for (const assign of ns.assignments) {
96
+ appendSourceLine(ctx, ` ${assign.target} = ${renderExpression(assign.value, undefined)};`);
97
+ }
98
+ }
99
+ if (ns.constants.length > 0) {
100
+ appendSourceLine(ctx, "");
101
+ }
102
+ // Namespace classes
103
+ for (const classDef of ns.classes) {
104
+ emitCommentLines(classDef.leadingComments, " ", (line) => appendSourceLine(ctx, line));
105
+ if (classDef.isAbstract) {
106
+ appendSourceLine(ctx, ` // Abstract class - contains pure virtual methods`);
107
+ }
108
+ appendSourceLine(ctx, ` class ${classDef.name} {`);
109
+ const publicFields = classDef.fields.filter(f => f.visibility === "public");
110
+ const privateFields = classDef.fields.filter(f => f.visibility === "private");
111
+ const protectedFields = classDef.fields.filter(f => f.visibility === "protected");
112
+ const publicMethods = classDef.methods.filter(m => m.visibility === "public");
113
+ const privateMethods = classDef.methods.filter(m => m.visibility === "private");
114
+ const protectedMethods = classDef.methods.filter(m => m.visibility === "protected");
115
+ const needsPublicSection = publicFields.length > 0 || publicMethods.length > 0 || classDef.constructor || ctx.callbackFunctions.length > 0;
116
+ if (needsPublicSection) {
117
+ appendSourceLine(ctx, " public:");
118
+ if (ctx.callbackFunctions.length > 0) {
119
+ for (const callback of ctx.callbackFunctions) {
120
+ // Friend declaration must match the synthesized callback's actual
121
+ // signature (void name() for ISRs, or R name(args) for typed
122
+ // std::function-callback lambdas). See renderCallbackSignature in
123
+ // function-emitter-impl.ts.
124
+ const fret = callback.returnType && callback.returnType !== "void" ? callback.returnType : "void";
125
+ const fparams = (callback.typedParams ?? []).map((p) => `${p.cppType} ${p.name}`).join(", ");
126
+ appendSourceLine(ctx, ` friend ${fret} ${callback.name}(${fparams});`);
127
+ }
128
+ appendSourceLine(ctx, "");
129
+ }
130
+ if (classDef.constructor) {
131
+ const ctorParams = renderParameters(classDef.constructor.parameters);
132
+ appendSourceLine(ctx, ` ${classDef.name}(${ctorParams}) {`);
133
+ const ctorScope = createChildEmissionScope(topLevelScope, classDef.constructor.parameters);
134
+ for (const stmt of classDef.constructor.statements) {
135
+ appendRenderedStatement(ctx, stmt, " ", ctorScope);
136
+ }
137
+ appendSourceLine(ctx, " }");
138
+ appendSourceLine(ctx, "");
139
+ }
140
+ for (const field of publicFields) {
141
+ const initSuffix = field.initializer ? ` = ${renderExpression(field.initializer, undefined)}` : "";
142
+ const fieldType = strategy.overrideClassFieldType(field.name, normalizeCppTypeForTarget(field.cppType));
143
+ // Mirror the method-render prefix (line ~159) and the top-level
144
+ // class-emitter: a static field renders as `static inline` so a
145
+ // static method's `Cls::field` access resolves. Without this, a
146
+ // static field on a namespace-nested class silently dropped to an
147
+ // instance field (namespace stress test Finding 2).
148
+ const staticPrefix = field.isStatic ? "static inline " : "";
149
+ appendSourceLine(ctx, ` ${staticPrefix}${renderTypedName(fieldType, field.name)}${initSuffix};`);
150
+ }
151
+ if (publicFields.length > 0)
152
+ appendSourceLine(ctx, "");
153
+ for (const method of publicMethods) {
154
+ const methodParams = renderParameters(method.parameters);
155
+ const staticPrefix = method.isStatic ? "static " : "";
156
+ const returnType = normalizeCppTypeForTarget(method.returnType);
157
+ if (method.isAbstract) {
158
+ appendSourceLine(ctx, ` virtual ${returnType} ${escapeCppKeyword(method.name, reservedNames)}(${methodParams}) = 0;`);
159
+ appendSourceLine(ctx, "");
160
+ continue;
161
+ }
162
+ appendSourceLine(ctx, ` ${staticPrefix}${returnType} ${escapeCppKeyword(method.name, reservedNames)}(${methodParams}) {`);
163
+ const methodScope = createChildEmissionScope(topLevelScope, method.parameters);
164
+ for (const stmt of method.statements) {
165
+ appendRenderedStatement(ctx, stmt, " ", methodScope);
166
+ }
167
+ appendSourceLine(ctx, " }");
168
+ appendSourceLine(ctx, "");
169
+ }
170
+ }
171
+ if (privateFields.length > 0 || privateMethods.length > 0) {
172
+ appendSourceLine(ctx, " private:");
173
+ for (const field of privateFields) {
174
+ const initSuffix = field.initializer ? ` = ${renderExpression(field.initializer, undefined)}` : "";
175
+ const fieldType = strategy.overrideClassFieldType(field.name, normalizeCppTypeForTarget(field.cppType));
176
+ // Mirror the method-render prefix (line ~159) and the top-level
177
+ // class-emitter: a static field renders as `static inline` so a
178
+ // static method's `Cls::field` access resolves. Without this, a
179
+ // static field on a namespace-nested class silently dropped to an
180
+ // instance field (namespace stress test Finding 2).
181
+ const staticPrefix = field.isStatic ? "static inline " : "";
182
+ appendSourceLine(ctx, ` ${staticPrefix}${renderTypedName(fieldType, field.name)}${initSuffix};`);
183
+ }
184
+ for (const method of privateMethods) {
185
+ const methodParams = renderParameters(method.parameters);
186
+ appendSourceLine(ctx, ` ${normalizeCppTypeForTarget(method.returnType)} ${escapeCppKeyword(method.name, reservedNames)}(${methodParams}) {`);
187
+ const methodScope = createChildEmissionScope(topLevelScope, method.parameters);
188
+ for (const stmt of method.statements) {
189
+ appendRenderedStatement(ctx, stmt, " ", methodScope);
190
+ }
191
+ appendSourceLine(ctx, " }");
192
+ }
193
+ }
194
+ if (protectedFields.length > 0 || protectedMethods.length > 0) {
195
+ appendSourceLine(ctx, " protected:");
196
+ for (const field of protectedFields) {
197
+ const initSuffix = field.initializer ? ` = ${renderExpression(field.initializer, undefined)}` : "";
198
+ const fieldType = strategy.overrideClassFieldType(field.name, normalizeCppTypeForTarget(field.cppType));
199
+ // Mirror the method-render prefix (line ~159) and the top-level
200
+ // class-emitter: a static field renders as `static inline` so a
201
+ // static method's `Cls::field` access resolves. Without this, a
202
+ // static field on a namespace-nested class silently dropped to an
203
+ // instance field (namespace stress test Finding 2).
204
+ const staticPrefix = field.isStatic ? "static inline " : "";
205
+ appendSourceLine(ctx, ` ${staticPrefix}${renderTypedName(fieldType, field.name)}${initSuffix};`);
206
+ }
207
+ for (const method of protectedMethods) {
208
+ const methodParams = renderParameters(method.parameters);
209
+ appendSourceLine(ctx, ` ${normalizeCppTypeForTarget(method.returnType)} ${escapeCppKeyword(method.name, reservedNames)}(${methodParams}) {`);
210
+ const methodScope = createChildEmissionScope(topLevelScope, method.parameters);
211
+ for (const stmt of method.statements) {
212
+ appendRenderedStatement(ctx, stmt, " ", methodScope);
213
+ }
214
+ appendSourceLine(ctx, " }");
215
+ }
216
+ }
217
+ appendSourceLine(ctx, " };");
218
+ emitCommentLines(classDef.trailingComments, " ", (line) => appendSourceLine(ctx, line));
219
+ appendSourceLine(ctx, "");
220
+ }
221
+ // Namespace functions
222
+ for (const fn of ns.functions) {
223
+ const parameterList = renderParameters(fn.parameters);
224
+ emitCommentLines(fn.leadingComments, " ", (line) => appendSourceLine(ctx, line));
225
+ if (fn.typeParameters && fn.typeParameters.length > 0) {
226
+ appendSourceLine(ctx, ` template<typename ${fn.typeParameters.join(", typename ")}>`);
227
+ }
228
+ appendSourceLine(ctx, ` ${normalizeCppTypeForTarget(fn.returnType)} ${fn.originalName}(${parameterList}) {`);
229
+ const namespaceFunctionScope = createChildEmissionScope(topLevelScope, fn.parameters);
230
+ for (const statement of fn.statements) {
231
+ appendRenderedStatement(ctx, statement, " ", namespaceFunctionScope);
232
+ }
233
+ appendSourceLine(ctx, " }");
234
+ emitCommentLines(fn.trailingComments, " ", (line) => appendSourceLine(ctx, line));
235
+ appendSourceLine(ctx, "");
236
+ }
237
+ if (ns.children && ns.children.length > 0) {
238
+ emitNestedNamespaces(ctx, ns.children, " ");
239
+ }
240
+ appendSourceLine(ctx, `} // namespace ${ns.name}`);
241
+ emitCommentLines(ns.trailingComments, "", (line) => appendSourceLine(ctx, line));
242
+ appendSourceLine(ctx, "");
243
+ }
244
+ }
245
+ function emitNestedNamespaces(ctx, namespaces, indent) {
246
+ const { strategy, reservedNames, topLevelScope, exprRenderer, statementRenderer } = ctx;
247
+ const normalizeCppTypeForTarget = (cppType) => strategy.normalizeCppType(cppType);
248
+ const renderExpression = (expr, calleeTransformer) => exprRenderer.render(expr, calleeTransformer);
249
+ const renderParameters = (params, forHeader = false) => statementRenderer.renderParameters(params, forHeader);
250
+ const renderTypedName = (cppType, name) => statementRenderer.renderTypedName(cppType, name);
251
+ for (const ns of namespaces) {
252
+ emitCommentLines(ns.leadingComments, indent, (line) => appendSourceLine(ctx, line));
253
+ appendSourceLine(ctx, `${indent}namespace ${ns.name} {`);
254
+ appendSourceLine(ctx, "");
255
+ for (const enumDef of ns.enums) {
256
+ emitCommentLines(enumDef.leadingComments, `${indent} `, (line) => appendSourceLine(ctx, line));
257
+ const enumKeyword = "enum class";
258
+ const underlyingType = narrowestEnumUnderlying(resolveEnumValues(enumDef.members), strategy.needsLargeEnumUnderlying());
259
+ appendSourceLine(ctx, `${indent} ${enumKeyword} ${enumDef.name}${underlyingType} {`);
260
+ let autoValue = 0;
261
+ for (let i = 0; i < enumDef.members.length; i++) {
262
+ const member = enumDef.members[i];
263
+ let valueSuffix;
264
+ if (typeof member.value === "number") {
265
+ valueSuffix = ` = ${member.value}`;
266
+ autoValue = member.value + 1;
267
+ }
268
+ else if (typeof member.value === "string") {
269
+ valueSuffix = ` = ${autoValue}`;
270
+ autoValue++;
271
+ }
272
+ else {
273
+ valueSuffix = "";
274
+ autoValue++;
275
+ }
276
+ const commaSuffix = i < enumDef.members.length - 1 ? "," : "";
277
+ appendSourceLine(ctx, `${indent} ${member.name}${valueSuffix}${commaSuffix}`);
278
+ }
279
+ appendSourceLine(ctx, `${indent} };`);
280
+ appendSourceLine(ctx, "");
281
+ }
282
+ for (const constant of ns.constants) {
283
+ const constType = normalizeCppTypeForTarget(constant.cppType);
284
+ const isConst = constant.storage === "const" || constant.storage === undefined;
285
+ if (constType !== "auto") {
286
+ if (isConst) {
287
+ appendSourceLine(ctx, `${indent} const ${constType} ${constant.name} = ${renderExpression(constant.value, undefined)};`);
288
+ }
289
+ else {
290
+ appendSourceLine(ctx, `${indent} ${constType} ${constant.name} = ${renderExpression(constant.value, undefined)};`);
291
+ }
292
+ }
293
+ else {
294
+ if (isConst) {
295
+ appendSourceLine(ctx, `${indent} const auto ${constant.name} = ${renderExpression(constant.value, undefined)};`);
296
+ }
297
+ else {
298
+ appendSourceLine(ctx, `${indent} auto ${constant.name} = ${renderExpression(constant.value, undefined)};`);
299
+ }
300
+ }
301
+ }
302
+ if (ns.assignments) {
303
+ for (const assign of ns.assignments) {
304
+ appendSourceLine(ctx, `${indent} ${assign.target} = ${renderExpression(assign.value, undefined)};`);
305
+ }
306
+ }
307
+ for (const fn of ns.functions) {
308
+ const parameterList = renderParameters(fn.parameters);
309
+ appendSourceLine(ctx, `${indent} ${normalizeCppTypeForTarget(fn.returnType)} ${fn.originalName}(${parameterList}) {`);
310
+ const fnScope = createChildEmissionScope(topLevelScope, fn.parameters);
311
+ for (const statement of fn.statements) {
312
+ appendRenderedStatement(ctx, statement, `${indent} `, fnScope);
313
+ }
314
+ appendSourceLine(ctx, `${indent} }`);
315
+ appendSourceLine(ctx, "");
316
+ }
317
+ if (ns.children && ns.children.length > 0) {
318
+ emitNestedNamespaces(ctx, ns.children, `${indent} `);
319
+ }
320
+ appendSourceLine(ctx, `${indent}} // namespace ${ns.name}`);
321
+ emitCommentLines(ns.trailingComments, indent, (line) => appendSourceLine(ctx, line));
322
+ appendSourceLine(ctx, "");
323
+ }
324
+ }
@@ -0,0 +1,4 @@
1
+ import type { GeneratedOutputs } from "../../types.js";
2
+ import type { EmitterContext } from "./emitter-context.js";
3
+ export declare function emitPreamble(ctx: EmitterContext): void;
4
+ export declare function finalizeOutput(ctx: EmitterContext): GeneratedOutputs;
@@ -0,0 +1,267 @@
1
+ import path from "node:path";
2
+ import { writeText } from "../../utils/fs.js";
3
+ import { makeGeneratedMap, writeSourceMap } from "../../mapping/source-map.js";
4
+ import { dedupe, hasConsoleCalls, resolveTranspiledModuleInclude } from "../utils/index.js";
5
+ import { appendHeaderLine } from "./line-appender.js";
6
+ /** Derives a unique C preprocessor guard name from a source file path. */
7
+ function sanitizeGuardName(filePath) {
8
+ // Use the basename minus extension, uppercased, with non-alphanumeric
9
+ // characters replaced by underscores.
10
+ const base = filePath.replace(/^.*[\\/]/, "").replace(/\.[^.]+$/, "");
11
+ return base.replace(/[^a-zA-Z0-9]/g, "_").toUpperCase();
12
+ }
13
+ /** Extracts a C preprocessor guard from a polyfill definition string. */
14
+ function polyfillDefinitionGuard(definition) {
15
+ // Match function names after 'inline', 'template<...>', or at start of line.
16
+ // Handles: "inline double __tc_random() { ... }"
17
+ // "template<typename T> std::string __tc_join(...) { ... }"
18
+ // "int __tc_setTimeout(...) { ... }"
19
+ // "struct __tc_task_state { ... };"
20
+ const funcMatch = definition.match(/\b(__tc_\w+)\s*\(/);
21
+ if (funcMatch)
22
+ return `__TC_POLYFILL_${funcMatch[1].toUpperCase()}`;
23
+ const structMatch = definition.match(/\b(struct|class)\s+(\w+)/);
24
+ if (structMatch)
25
+ return `__TC_POLYFILL_${structMatch[2].toUpperCase()}`;
26
+ return null;
27
+ }
28
+ export function emitPreamble(ctx) {
29
+ const { strategy, effectiveEmitMode, program, shimLines, emittedPolyfills, asyncTaskClasses, includes, programAnalysis } = ctx;
30
+ for (const include of dedupe(includes)) {
31
+ appendSourceLineLocal(ctx, `#include ${include}`);
32
+ }
33
+ appendSourceLineLocal(ctx, "");
34
+ if (emittedPolyfills) {
35
+ if (emittedPolyfills.declarations.length > 0) {
36
+ for (const declaration of emittedPolyfills.declarations) {
37
+ appendSourceLineLocal(ctx, declaration);
38
+ }
39
+ appendSourceLineLocal(ctx, "");
40
+ }
41
+ if (emittedPolyfills.definitions.length > 0) {
42
+ if (effectiveEmitMode === "split") {
43
+ // Use per-definition guards based on function/struct names so that
44
+ // the same inline helper (e.g. __tc_random) is only defined once
45
+ // even when multiple headers are included by the same TU.
46
+ for (const definition of emittedPolyfills.definitions) {
47
+ const guard = polyfillDefinitionGuard(definition);
48
+ if (guard) {
49
+ appendHeaderLine(ctx, `#ifndef ${guard}`);
50
+ appendHeaderLine(ctx, `#define ${guard}`);
51
+ }
52
+ appendHeaderLine(ctx, definition.trimEnd());
53
+ if (guard) {
54
+ appendHeaderLine(ctx, `#endif // ${guard}`);
55
+ }
56
+ }
57
+ appendHeaderLine(ctx, "");
58
+ }
59
+ else {
60
+ for (const definition of emittedPolyfills.definitions) {
61
+ appendSourceLineLocal(ctx, definition.trimEnd());
62
+ appendSourceLineLocal(ctx, "");
63
+ }
64
+ }
65
+ }
66
+ }
67
+ // Shim lines (CUTTLEFISH_UNDEFINED, nullish helpers) must come BEFORE
68
+ // async task classes — the async state machine references CUTTLEFISH_UNDEFINED
69
+ // for default timeout values (e.g. waitForRising with no timeout arg).
70
+ if (shimLines.length > 0) {
71
+ for (const line of shimLines) {
72
+ appendSourceLineLocal(ctx, line);
73
+ }
74
+ appendSourceLineLocal(ctx, "");
75
+ }
76
+ if (asyncTaskClasses.length > 0) {
77
+ for (const { classDef, instanceDecl } of asyncTaskClasses) {
78
+ for (const line of classDef.split("\n")) {
79
+ appendSourceLineLocal(ctx, line);
80
+ }
81
+ appendSourceLineLocal(ctx, "");
82
+ appendSourceLineLocal(ctx, instanceDecl);
83
+ appendSourceLineLocal(ctx, "");
84
+ }
85
+ }
86
+ if (strategy.needsVectorOverload() && hasConsoleCalls(program, strategy) && (programAnalysis.usesVectorTypes || programAnalysis.hasArrayInObjectLiteral)) {
87
+ appendSourceLineLocal(ctx, "template <typename T>");
88
+ appendSourceLineLocal(ctx, "std::ostream& operator<<(std::ostream& os, const std::vector<T>& values)");
89
+ appendSourceLineLocal(ctx, "{");
90
+ appendSourceLineLocal(ctx, ' os << "[";');
91
+ appendSourceLineLocal(ctx, " for (size_t i = 0; i < values.size(); ++i)");
92
+ appendSourceLineLocal(ctx, " {");
93
+ appendSourceLineLocal(ctx, " if (i > 0)");
94
+ appendSourceLineLocal(ctx, " {");
95
+ appendSourceLineLocal(ctx, ' os << ", ";');
96
+ appendSourceLineLocal(ctx, " }");
97
+ appendSourceLineLocal(ctx, " os << values[i];");
98
+ appendSourceLineLocal(ctx, " }");
99
+ appendSourceLineLocal(ctx, ' os << "]";');
100
+ appendSourceLineLocal(ctx, " return os;");
101
+ appendSourceLineLocal(ctx, "}");
102
+ appendSourceLineLocal(ctx, "");
103
+ }
104
+ if (programAnalysis.hasGenerators) {
105
+ appendSourceLineLocal(ctx, "#include <coroutine>");
106
+ appendSourceLineLocal(ctx, "#include <optional>");
107
+ appendSourceLineLocal(ctx, "");
108
+ appendSourceLineLocal(ctx, "template<typename T>");
109
+ appendSourceLineLocal(ctx, "struct __tc_Generator {");
110
+ appendSourceLineLocal(ctx, " struct promise_type {");
111
+ appendSourceLineLocal(ctx, " T current_value;");
112
+ appendSourceLineLocal(ctx, " auto get_return_object() { return __tc_Generator{std::coroutine_handle<promise_type>::from_promise(*this)}; }");
113
+ appendSourceLineLocal(ctx, " auto initial_suspend() { return std::suspend_always{}; }");
114
+ appendSourceLineLocal(ctx, " auto final_suspend() noexcept { return std::suspend_always{}; }");
115
+ appendSourceLineLocal(ctx, " auto yield_value(T value) { current_value = value; return std::suspend_always{}; }");
116
+ appendSourceLineLocal(ctx, " void return_void() {}");
117
+ appendSourceLineLocal(ctx, " void unhandled_exception() { throw; }");
118
+ appendSourceLineLocal(ctx, " };");
119
+ appendSourceLineLocal(ctx, " std::coroutine_handle<promise_type> handle;");
120
+ appendSourceLineLocal(ctx, " __tc_Generator(std::coroutine_handle<promise_type> h) : handle(h) {}");
121
+ appendSourceLineLocal(ctx, " ~__tc_Generator() { if (handle) handle.destroy(); }");
122
+ appendSourceLineLocal(ctx, " __tc_Generator(const __tc_Generator&) = delete;");
123
+ appendSourceLineLocal(ctx, " __tc_Generator(__tc_Generator&& other) noexcept : handle(other.handle) { other.handle = nullptr; }");
124
+ appendSourceLineLocal(ctx, " bool next() { handle.resume(); return !handle.done(); }");
125
+ appendSourceLineLocal(ctx, " T value() { return handle.promise().current_value; }");
126
+ appendSourceLineLocal(ctx, " struct iterator {");
127
+ appendSourceLineLocal(ctx, " std::coroutine_handle<promise_type> handle;");
128
+ appendSourceLineLocal(ctx, " bool done;");
129
+ appendSourceLineLocal(ctx, " iterator& operator++() { handle.resume(); done = handle.done(); return *this; }");
130
+ appendSourceLineLocal(ctx, " T operator*() { return handle.promise().current_value; }");
131
+ appendSourceLineLocal(ctx, " bool operator!=(const iterator& other) const { return done != other.done; }");
132
+ appendSourceLineLocal(ctx, " };");
133
+ appendSourceLineLocal(ctx, " iterator begin() { handle.resume(); return {handle, handle.done()}; }");
134
+ appendSourceLineLocal(ctx, " iterator end() { return {handle, true}; }");
135
+ appendSourceLineLocal(ctx, "};");
136
+ appendSourceLineLocal(ctx, "");
137
+ }
138
+ }
139
+ export function finalizeOutput(ctx) {
140
+ const { program, strategy, options, effectiveEmitMode, isNpmPackage, baseName, includes, shimLines, emittedPolyfills } = ctx;
141
+ const outDir = options.outDir;
142
+ const sourceExtension = strategy.sourceExtension(ctx.isEntryFile, isNpmPackage);
143
+ const headerPath = path.join(outDir, `${baseName}.h`);
144
+ const sourcePath = path.join(outDir, `${baseName}.${sourceExtension}`);
145
+ let outputHeaderPath;
146
+ let outputHeaderMapPath;
147
+ if (effectiveEmitMode === "split") {
148
+ // Re-export includes to the header
149
+ const headerIncludes = [];
150
+ for (const reExport of program.reExports) {
151
+ const transpiledInclude = resolveTranspiledModuleInclude(reExport.moduleSpecifier, options.npmPackages, program.fileName);
152
+ if (transpiledInclude.isTranspiled) {
153
+ headerIncludes.push(transpiledInclude.include);
154
+ continue;
155
+ }
156
+ if (reExport.moduleSpecifier.startsWith(".")) {
157
+ let modulePath = reExport.moduleSpecifier;
158
+ modulePath = modulePath.replace(/\.js$/, "").replace(/\.mjs$/, "");
159
+ const segments = modulePath.split("/");
160
+ const baseName = segments[segments.length - 1] || segments[segments.length - 2];
161
+ const headerName = `${baseName}.h`;
162
+ headerIncludes.push(`"${headerName}"`);
163
+ }
164
+ }
165
+ const finalHeaderLines = [...ctx.headerLines];
166
+ const headerIncludeLines = dedupe([
167
+ ...includes,
168
+ ...headerIncludes,
169
+ ]);
170
+ if (headerIncludeLines.length > 0) {
171
+ const includeLines = headerIncludeLines.map((inc) => `#include ${inc}`);
172
+ finalHeaderLines.splice(1, 0, ...includeLines, "");
173
+ }
174
+ // Cross-module class forward declarations
175
+ if (options.crossModuleClasses && options.crossModuleClasses.size > 0) {
176
+ const localClasses = new Set(program.classes.map(cls => cls.name));
177
+ const importedSymbols = new Set();
178
+ for (const imp of program.imports) {
179
+ for (const sym of imp.namedImports) {
180
+ importedSymbols.add(sym);
181
+ }
182
+ }
183
+ const forwardDecls = [];
184
+ for (const className of options.crossModuleClasses) {
185
+ if (!localClasses.has(className) && importedSymbols.has(className)) {
186
+ forwardDecls.push(`class ${className};`);
187
+ }
188
+ }
189
+ if (forwardDecls.length > 0) {
190
+ let insertIdx = 1;
191
+ while (insertIdx < finalHeaderLines.length &&
192
+ (finalHeaderLines[insertIdx].startsWith("#include") ||
193
+ finalHeaderLines[insertIdx] === "")) {
194
+ insertIdx++;
195
+ }
196
+ finalHeaderLines.splice(insertIdx, 0, ...forwardDecls, "");
197
+ }
198
+ }
199
+ // Non-entry split-file headers may contain inline class method bodies
200
+ // that emit cuttlefish_nullish(...) calls (from `??` lowering). The
201
+ // helper shim is appended to the .cpp source via appendHelpers above,
202
+ // but the .h header — which is #included by the entry .cpp and by other
203
+ // headers — also needs the shim, because the inline method bodies live
204
+ // in the header. The shim is wrapped in a single #ifndef guard so
205
+ // emitting it into every non-entry header is safe.
206
+ //
207
+ // To decide whether THIS header needs the shim, scan its already-emitted
208
+ // lines for an actual cuttlefish_nullish( call. The programAnalysis flag
209
+ // is unreliable here (it's computed per-file before emit, and class
210
+ // method bodies on abstract bases can produce cuttlefish_nullish calls
211
+ // the analysis didn't attribute). A post-emit text scan is exact.
212
+ if (!ctx.isEntryFile && shimLines.length > 0) {
213
+ const headerNeedsNullish = finalHeaderLines.some(l => l.includes('cuttlefish_nullish('));
214
+ if (headerNeedsNullish) {
215
+ let insertIdx = 1;
216
+ while (insertIdx < finalHeaderLines.length) {
217
+ const l = finalHeaderLines[insertIdx].trim();
218
+ // Skip blank lines, includes, comments, and forward declarations
219
+ // (e.g. `class Foo;`) — these are all preamble.
220
+ if (l === "" || l.startsWith("#include") || l.startsWith("//") || /^class\s+\w+\s*;$/.test(l)) {
221
+ insertIdx++;
222
+ continue;
223
+ }
224
+ break;
225
+ }
226
+ finalHeaderLines.splice(insertIdx, 0, ...shimLines, "");
227
+ }
228
+ }
229
+ writeText(headerPath, finalHeaderLines.join("\n").trimEnd() + "\n");
230
+ outputHeaderPath = headerPath;
231
+ if (options.emitMaps) {
232
+ outputHeaderMapPath = writeSourceMap(makeGeneratedMap(headerPath, program.fileName, ctx.headerMapEntries));
233
+ }
234
+ }
235
+ // Non-entry Arduino files: header-only
236
+ const sourceExtension2 = strategy.sourceExtension(ctx.isEntryFile, isNpmPackage);
237
+ if (sourceExtension2 === "h" && !isNpmPackage) {
238
+ ctx.sourceLines.unshift("#pragma once", "");
239
+ }
240
+ // NOTE: The file-wide `\b${varName}\.` → `${varName}->` text sweep that lived
241
+ // here has been REMOVED. The `->`/`.` decision for global pointer variables
242
+ // (including ISR-captured ones like `const btn = new Button()` accessed inside
243
+ // a hoisted callback) is now made structurally by ExpressionRenderer, which
244
+ // consults `globalPointerVarTypes` (threaded in from this context) in
245
+ // inferExpressionCppType. That decision runs per-IR-node with the resolved
246
+ // symbol/type, replacing the name-keyed regex that operated on joined output
247
+ // text and could not distinguish a global pointer variable from a same-named
248
+ // value field/member (the demo #15–#23 failure class).
249
+ writeText(sourcePath, ctx.sourceLines.join("\n").trimEnd() + "\n");
250
+ const outputSourceMapPath = options.emitMaps
251
+ ? writeSourceMap(makeGeneratedMap(sourcePath, program.fileName, ctx.sourceMapEntries))
252
+ : undefined;
253
+ const diagnostics = [...program.diagnostics, ...ctx.profileDiagnostics, ...ctx.emitDiagnostics];
254
+ diagnostics.push(...strategy.emitDiagnostics(options.emitMode));
255
+ return {
256
+ headerPath: outputHeaderPath,
257
+ sourcePath,
258
+ headerMapPath: outputHeaderMapPath,
259
+ sourceMapPath: outputSourceMapPath,
260
+ diagnostics,
261
+ asyncTaskNames: ctx.asyncTaskClasses.map(t => t.taskVarName),
262
+ usesTimers: ctx.usesTimers,
263
+ };
264
+ }
265
+ function appendSourceLineLocal(ctx, line) {
266
+ ctx.sourceLines.push(line);
267
+ }
@@ -0,0 +1,3 @@
1
+ import type { ProgramIR } from "../../api/index.js";
2
+ import type { EmitterContext, EmitterOptions } from "./emitter-context.js";
3
+ export declare function buildEmitterContext(program: ProgramIR, options: EmitterOptions): EmitterContext;