@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,493 @@
1
+ import ts from "typescript";
2
+ import { arrayLiteralSizes, mutableArrayVars, activeCArrayVars, getContext, activeEnumNames, activeStringEnumNames } from "../build-ir-state.js";
3
+ import { getCurrentIrTypeScope } from "../symbol-types.js";
4
+ import { expressionToIR } from "../expression-to-ir.js";
5
+ import { renderExprAsText } from "../render-expr.js";
6
+ import { assignmentOperatorToString } from "./variables.js";
7
+ import { STRING_METHODS, STRING_METHOD_NAMES } from "../../api/shared/string-method-registry.js";
8
+ import { parsedElementString } from "../../api/shared/cpp-type-ir.js";
9
+ import { INTEGRAL_CPP_TYPE_RE } from "../../emit/utils/cpp-helpers.js";
10
+ // Methods that require StaticArray promotion (not all are mutating — indexOf is read-only
11
+ // but needs StaticArray since C arrays don't have an indexOf method).
12
+ export const ARRAY_METHODS_REQUIRING_STATIC_ARRAY = new Set(["push", "pop", "indexOf"]);
13
+ export function prescanArrayUsage(statement) {
14
+ if (ts.isVariableStatement(statement)) {
15
+ for (const decl of statement.declarationList.declarations) {
16
+ if (ts.isIdentifier(decl.name) && decl.initializer) {
17
+ if (ts.isArrayLiteralExpression(decl.initializer)) {
18
+ arrayLiteralSizes.set(decl.name.text, decl.initializer.elements.length);
19
+ }
20
+ prescanExprForArrayMethods(decl.initializer);
21
+ }
22
+ }
23
+ }
24
+ else if (ts.isExpressionStatement(statement)) {
25
+ prescanExprForArrayMethods(statement.expression);
26
+ }
27
+ else if (ts.isReturnStatement(statement) && statement.expression) {
28
+ prescanExprForArrayMethods(statement.expression);
29
+ }
30
+ else if (ts.isIfStatement(statement)) {
31
+ prescanArrayUsageBlock(statement.thenStatement);
32
+ if (statement.elseStatement)
33
+ prescanArrayUsageBlock(statement.elseStatement);
34
+ }
35
+ else if (ts.isForStatement(statement) || ts.isWhileStatement(statement) || ts.isDoStatement(statement)) {
36
+ prescanArrayUsageBlock(statement.statement);
37
+ }
38
+ else if (ts.isForOfStatement(statement) || ts.isForInStatement(statement)) {
39
+ prescanArrayUsageBlock(statement.statement);
40
+ }
41
+ else if (ts.isBlock(statement)) {
42
+ for (const s of statement.statements)
43
+ prescanArrayUsage(s);
44
+ }
45
+ }
46
+ function prescanArrayUsageBlock(stmt) {
47
+ if (ts.isBlock(stmt)) {
48
+ for (const s of stmt.statements)
49
+ prescanArrayUsage(s);
50
+ }
51
+ else {
52
+ prescanArrayUsage(stmt);
53
+ }
54
+ }
55
+ export function prescanExprForArrayMethods(expr) {
56
+ if (ts.isCallExpression(expr) && ts.isPropertyAccessExpression(expr.expression)) {
57
+ const methodName = expr.expression.name.text;
58
+ if (ARRAY_METHODS_REQUIRING_STATIC_ARRAY.has(methodName) && ts.isIdentifier(expr.expression.expression)) {
59
+ const varName = expr.expression.expression.text;
60
+ mutableArrayVars.add(varName);
61
+ }
62
+ }
63
+ // Detect indexed assignment (arr[i] = val and compounds like arr[i] += val).
64
+ // TypeScript const only locks the binding, not the array contents, so
65
+ // assigning to an element forces non-const C++ storage (matching the
66
+ // existing behaviour for .push() / .pop()).
67
+ if (ts.isBinaryExpression(expr)
68
+ && ts.isElementAccessExpression(expr.left)
69
+ && ts.isIdentifier(expr.left.expression)
70
+ && assignmentOperatorToString(expr.operatorToken.kind) !== undefined) {
71
+ mutableArrayVars.add(expr.left.expression.text);
72
+ }
73
+ // Detect element increment / decrement (arr[i]++ / arr[i]-- / ++arr[i] / --arr[i]).
74
+ if ((ts.isPostfixUnaryExpression(expr) || ts.isPrefixUnaryExpression(expr))
75
+ && ts.isElementAccessExpression(expr.operand)
76
+ && ts.isIdentifier(expr.operand.expression)
77
+ && (expr.operator === ts.SyntaxKind.PlusPlusToken || expr.operator === ts.SyntaxKind.MinusMinusToken)) {
78
+ mutableArrayVars.add(expr.operand.expression.text);
79
+ }
80
+ }
81
+ export function buildInlineForLoop(span, srcSize, srcName, paramName, bodyExpr, sourceText, diagnostics, assignTarget, _isFilter) {
82
+ const bodyIR = expressionToIR(bodyExpr, sourceText, diagnostics);
83
+ return {
84
+ kind: "for",
85
+ sourceSpan: span,
86
+ initializer: { kind: "var_decl", sourceSpan: span, name: "__tc_i", storage: "let", cppType: "int", initializer: { kind: "number", value: 0 } },
87
+ condition: { kind: "binary", left: { kind: "identifier", value: "__tc_i" }, operator: "<", right: { kind: "number", value: srcSize } },
88
+ increment: { kind: "update", sourceSpan: span, target: "__tc_i", operator: "++", prefix: false },
89
+ body: [
90
+ { kind: "var_decl", sourceSpan: span, name: paramName, storage: "const", cppType: "auto",
91
+ initializer: { kind: "raw", value: `${srcName}[__tc_i]` } },
92
+ { kind: "assign", sourceSpan: span, target: assignTarget, operator: "=", value: bodyIR },
93
+ ],
94
+ };
95
+ }
96
+ const VECTOR_VALUE_METHOD_LOWERINGS = {
97
+ // Mutators that the native runtime exposes as free-function helpers:
98
+ pop: (r) => `__tc_pop(${r})`,
99
+ shift: (r) => `__tc_shift(${r})`,
100
+ reverse: (r) => `__tc_reverse(${r})`,
101
+ unshift: (r, [a]) => `__tc_unshift(${r}, ${a})`,
102
+ // .fill(v) vs .fill(v, start, end)
103
+ fill: (r, args, n) => n >= 3 ? `__tc_fill3(${r}, ${args[0]}, ${args[1]}, ${args[2]})` : `__tc_fill(${r}, ${args[0] ?? ""})`,
104
+ concat: (r, [a]) => `__tc_concat(${r}, ${a})`,
105
+ // .splice(i) vs .splice(i, n)
106
+ splice: (r, args, n) => n >= 2 ? `__tc_splice2(${r}, ${args[0]}, ${args[1]})` : `__tc_splice1(${r}, ${args[0]})`,
107
+ // .slice() with no args copies the whole vector. (Sliced sub-ranges are not
108
+ // handled here — they didn't have a regex either.)
109
+ slice: (r, _args, n) => n === 0
110
+ ? `std::vector<typename std::decay<decltype(${r})>::type>(${r}.begin(), ${r}.end())`
111
+ : null,
112
+ // .join(delim) — folds a std::vector<T> into a std::string with `delim`
113
+ // between elements (the __tc_join template helper). Demo #31 Finding B —
114
+ // `join` was previously misclassified as a STRING method (it was listed in
115
+ // STRING_METHODS even though it operates on a vector), so on a known
116
+ // `mutableArrayVars` receiver (a `string[]` built via .push) BOTH lowering
117
+ // paths declined it: the string path rejects known arrays, and this vector
118
+ // table had no `join` entry. The call was then emitted verbatim and g++
119
+ // rejected it. `join` is a vector→string transformation; it lives here.
120
+ join: (r, [a]) => `__tc_join(${r}, ${a ?? '""'})`,
121
+ };
122
+ // Callback-arg methods: map method name → helper callee. The receiver and all
123
+ // args (including the callback) become structured method-call args so the
124
+ // callback hoister can find and name them. `.sort()` with NO arg is a value
125
+ // method (`__tc_sort(recv)`), handled separately below.
126
+ const VECTOR_CALLBACK_METHOD_HELPERS = {
127
+ filter: "__tc_filter",
128
+ map: "__tc_map",
129
+ find: "__tc_find",
130
+ findIndex: "__tc_findIndex",
131
+ every: "__tc_every",
132
+ some: "__tc_some",
133
+ reduce: "__tc_reduce", // 2-arg form; 1-arg → __tc_reduce_no_init (below)
134
+ sort: "__tc_sort_fn", // .sort(fn); bare .sort() → __tc_sort (below)
135
+ };
136
+ /**
137
+ * Render an array/string-method RECEIVER for use as a `__tc_*` helper argument.
138
+ *
139
+ * The only difference from a plain `renderExprAsText(expressionToIR(receiver))`
140
+ * is the INLINE ARRAY LITERAL case: `[...].join(sep)`, `[...].concat(x)`, ....
141
+ * The `__tc_*` helpers are templates, and a bare brace-init-list (`{ ... }`)
142
+ * CANNOT drive template argument deduction (g++: "couldn't deduce template
143
+ * parameter 'T'"). A typed `std::vector<ElemType>{ ... }` temporary CAN. So
144
+ * when the receiver is an inline array literal whose element type we can infer
145
+ * (from a literal element), we wrap it in `std::vector<ElemType>{ ... }`. A
146
+ * NAMED receiver (`x.join(...)` where `x: string[]`) already has a concrete
147
+ * `std::vector<...>` type and is rendered verbatim.
148
+ *
149
+ * Demo #29 Finding D. This is intentionally scoped to the method-receiver
150
+ * position: a bare `{ ... }` is correct in direct-initialization
151
+ * (`const T x = {...}`) and HAL argument (`Wire.write({...})`) contexts, so the
152
+ * type-qualification happens ONLY here, not in the generic array renderer.
153
+ */
154
+ function renderArrayMethodReceiver(receiverNode, sourceText, diagnostics, pointerVars) {
155
+ const ir = expressionToIR(receiverNode, sourceText, diagnostics, pointerVars);
156
+ const text = renderExprAsText(ir);
157
+ // Only an inline array literal needs type-qualification for deduction.
158
+ if (ir.kind === "array" && ir.elementType && ir.elementType !== "auto") {
159
+ return `std::vector<${ir.elementType}>${text}`;
160
+ }
161
+ return text;
162
+ }
163
+ export function tryLowerArrayAndStringMethods(expr, sourceText, diagnostics, pointerVars) {
164
+ if (ts.isPropertyAccessExpression(expr.expression) &&
165
+ ts.isIdentifier(expr.expression.expression)) {
166
+ const receiverName = expr.expression.expression.text;
167
+ const methodName = expr.expression.name.text;
168
+ // ---- Array method translation for mutable arrays (StaticArray) -----------
169
+ // Translate push → push_back, pop → pop_back, indexOf → indexOf at the expression level.
170
+ // IMPORTANT: this branch emits the StaticArray wrapper's own methods
171
+ // (`__tc_StaticArray` exposes .push/.pop/.indexOf). It must NOT fire for a
172
+ // plain std::vector — even one in mutableArrayVars — because std::vector has
173
+ // no `.push` member (it's `push_back`). The `mutableArrayVars` set is
174
+ // populated by prescan whenever .push/.pop/.indexOf is *called* on a var,
175
+ // regardless of whether that var lowered to StaticArray or std::vector; so
176
+ // gate on the resolved C++ type actually being a StaticArray. A std::vector
177
+ // falls through to the vector-method lowering below (push_back / __tc_pop).
178
+ if (mutableArrayVars.has(receiverName)) {
179
+ const resolvedType = getCurrentIrTypeScope()?.locals.get(receiverName) ?? getCurrentIrTypeScope()?.globals.get(receiverName);
180
+ // Use the StaticArray wrapper's own methods (.push/.pop/.indexOf) ONLY when
181
+ // the receiver genuinely lowered to a __tc_StaticArray. The resolved C++
182
+ // type is the primary signal, BUT it can be stale: the StaticArray
183
+ // promotion (variables.ts) runs during var_decl processing, AFTER call
184
+ // statements are lowered — so a literal-declared array's type is still
185
+ // "std::vector<...>" (pre-promotion) when its .push statement is lowered.
186
+ // Predict the post-promotion type instead: if the var is a mutable
187
+ // array-literal on a target that promotes literals to StaticArray, it WILL
188
+ // become a __tc_StaticArray, so use the StaticArray form. Native does not
189
+ // promote (promotesArrayLiteralsToStaticArray() = false), so its
190
+ // std::vector type is genuine and the vector lowering below applies.
191
+ const typeIsStaticArray = !!resolvedType && (resolvedType.startsWith("StaticArray<") || resolvedType.startsWith("__tc_StaticArray<"));
192
+ const promotesLiterals = getContext().activeStrategy?.promotesArrayLiteralsToStaticArray?.() ?? true;
193
+ const willPromoteToStaticArray = promotesLiterals && arrayLiteralSizes.has(receiverName);
194
+ const isStaticArrayType = typeIsStaticArray || willPromoteToStaticArray;
195
+ if (isStaticArrayType) {
196
+ if (methodName === "pop") {
197
+ return { kind: "raw", value: `${receiverName}.pop()` };
198
+ }
199
+ if (methodName === "push") {
200
+ const argsText = expr.arguments.map(arg => renderExprAsText(expressionToIR(arg, sourceText, diagnostics, pointerVars))).join(", ");
201
+ return { kind: "raw", value: `${receiverName}.push(${argsText})` };
202
+ }
203
+ if (methodName === "indexOf") {
204
+ const argsText = expr.arguments.map(arg => renderExprAsText(expressionToIR(arg, sourceText, diagnostics, pointerVars))).join(", ");
205
+ return { kind: "raw", value: `(${receiverName}).indexOf(${argsText})` };
206
+ }
207
+ }
208
+ }
209
+ // ---- String indexOf wrapping (const char* needs String() on Arduino) ---
210
+ if (methodName === "indexOf" &&
211
+ !mutableArrayVars.has(receiverName) &&
212
+ !activeCArrayVars.has(receiverName)) {
213
+ return {
214
+ kind: "method-call",
215
+ callee: `${receiverName}.indexOf`,
216
+ args: expr.arguments.map(arg => expressionToIR(arg, sourceText, diagnostics, pointerVars))
217
+ };
218
+ }
219
+ }
220
+ // ---- Structural vector-method lowering (replaces normalizeRawExpression regexes) ----
221
+ // For a std::vector receiver of ANY shape (bare name OR member chain like
222
+ // `this->ops`, `obj.field`), lower the TS array method to its __tc_* helper
223
+ // at IR-build time. The receiver is rendered via expressionToIR so the
224
+ // pointer/value access decision (this->ops vs obj.field) is already correct,
225
+ // and the helper receives it as a normal argument — no RECV regex needed.
226
+ // Gated on method name only, matching the prior regex behavior (TS type
227
+ // semantics guarantee these names on a non-array/vector would be a type
228
+ // error). `push` is special-cased to `push_back` (the native inlining).
229
+ //
230
+ // Target gate: the __tc_* helpers are native/hosted-only (Arduino/embedded
231
+ // lower arrays to StaticArray, caught by the mutableArrayVars branch above,
232
+ // and have no __tc_* polyfills). requiresLoopFunction() is false exactly on
233
+ // hosted targets — the same set that ran the old native normalizeRawExpression.
234
+ const isHostedTarget = !getContext().activeStrategy?.requiresLoopFunction();
235
+ if (isHostedTarget && ts.isPropertyAccessExpression(expr.expression)) {
236
+ const methodName = expr.expression.name.text;
237
+ // `push` lowers to native push_back (matches the old
238
+ // `${RECV}\.push(([^)]+)\)` → `$1.push_back($2)` regex).
239
+ if (methodName === "push") {
240
+ const receiverNode = expr.expression.expression;
241
+ const receiverText = renderExprAsText(expressionToIR(receiverNode, sourceText, diagnostics, pointerVars));
242
+ const argsText = expr.arguments.map(arg => renderPushArgForElement(arg, receiverNode, sourceText, diagnostics, pointerVars)).join(", ");
243
+ return { kind: "raw", value: `${receiverText}.push_back(${argsText})` };
244
+ }
245
+ // `sort()` with no arg and `reduce` with one arg have distinct helpers.
246
+ if (methodName === "sort" && expr.arguments.length === 0) {
247
+ const receiverText = renderArrayMethodReceiver(expr.expression.expression, sourceText, diagnostics, pointerVars);
248
+ return { kind: "raw", value: `__tc_sort(${receiverText})` };
249
+ }
250
+ if (methodName === "reduce" && expr.arguments.length === 1) {
251
+ const receiverText = renderArrayMethodReceiver(expr.expression.expression, sourceText, diagnostics, pointerVars);
252
+ const cbText = renderExprAsText(expressionToIR(expr.arguments[0], sourceText, diagnostics, pointerVars));
253
+ return { kind: "raw", value: `__tc_reduce_no_init(${receiverText}, ${cbText})` };
254
+ }
255
+ // Callback-arg methods: lower to a method-call IR node (NOT raw) so the
256
+ // emit-time callback hoister (top-level-prep.ts collectCallbacks) can find
257
+ // the structured callback arg in `args`, hoist it to a named _isr_N
258
+ // function, and substitute the name. A raw node is opaque to the hoister.
259
+ const cbHelper = VECTOR_CALLBACK_METHOD_HELPERS[methodName];
260
+ if (cbHelper) {
261
+ // An inline array-literal receiver must be type-qualified so the
262
+ // `__tc_*` template helper can deduce its element type (demo #29 Finding D).
263
+ // Wrap an array-literal receiverIR into a typed raw node.
264
+ const receiverIR = (() => {
265
+ const ir = expressionToIR(expr.expression.expression, sourceText, diagnostics, pointerVars);
266
+ if (ir.kind === "array" && ir.elementType && ir.elementType !== "auto") {
267
+ return { kind: "raw", value: `std::vector<${ir.elementType}>${renderExprAsText(ir)}` };
268
+ }
269
+ return ir;
270
+ })();
271
+ const argIRs = expr.arguments.map(arg => expressionToIR(arg, sourceText, diagnostics, pointerVars));
272
+ return { kind: "method-call", callee: cbHelper, args: [receiverIR, ...argIRs] };
273
+ }
274
+ // Value-arg methods: collapse to a raw helper call (no callbacks to hoist).
275
+ const lowering = VECTOR_VALUE_METHOD_LOWERINGS[methodName];
276
+ if (lowering) {
277
+ const receiverText = renderArrayMethodReceiver(expr.expression.expression, sourceText, diagnostics, pointerVars);
278
+ const argsText = expr.arguments.map(arg => renderExprAsText(expressionToIR(arg, sourceText, diagnostics, pointerVars)));
279
+ const lowered = lowering(receiverText, argsText, expr.arguments.length);
280
+ if (lowered !== null) {
281
+ return { kind: "raw", value: lowered };
282
+ }
283
+ }
284
+ // ---- String-method lowering (structural) ------------------------------
285
+ // Demo #27 Findings D/E — string methods (`s.toLowerCase()`,
286
+ // `s.substring(0,2)`, `s.charAt(i)`, ...) were previously lowered by a
287
+ // post-emit text rewrite (`applyStringMethodRewrites`) whose
288
+ // `RECEIVER_PATTERN` only matched bare identifiers and `.member` chains —
289
+ // NOT `X[i]` element access or `X->member` pointer chains. So
290
+ // `ALPHABET[i].toLowerCase()` was left verbatim (g++: "no member
291
+ // 'toLowerCase'"), and even on a bare local the emitted `__tc_toLowerCase`
292
+ // helper was never registered (the text scan missed it). Array mutators
293
+ // were migrated off the same regex family in demo #22 into this
294
+ // structural path; string methods are routed through the identical path
295
+ // here, so the receiver is rendered via `expressionToIR` (handling
296
+ // bare id / `this.field` / `obj.field` / `X[i]` / chains uniformly) and
297
+ // the helper lands in a `raw` IR node that `program-analysis.ts` scans to
298
+ // register the polyfill.
299
+ //
300
+ // Gate: only fire for a KNOWN string method whose receiver is NOT a known
301
+ // array (the array paths above already handled array `indexOf`/`slice`/
302
+ // etc.). For methods that exist on BOTH strings and arrays
303
+ // (`indexOf`/`includes`/`startsWith`/`endsWith`/`slice`/`substring`), gate
304
+ // on the receiver's resolved C++ type being string-like, so an array
305
+ // `indexOf` is never mis-lowered to the string helper.
306
+ const isStringMethod = STRING_METHOD_NAMES.has(methodName);
307
+ if (isStringMethod) {
308
+ const receiverNode = expr.expression.expression;
309
+ // Use renderArrayMethodReceiver so an INLINE array-literal receiver of an
310
+ // ambiguous string/array method (`.join`, `.concat`, `.slice`, ...) is
311
+ // type-qualified into `std::vector<ElemType>{...}` — the `__tc_*` helpers
312
+ // are templates and a bare brace-init-list cannot drive deduction. A
313
+ // genuine string receiver passes through unchanged. Demo #29 Finding D.
314
+ const receiverText = renderArrayMethodReceiver(receiverNode, sourceText, diagnostics, pointerVars);
315
+ if (shouldLowerAsStringMethod(receiverNode, methodName)) {
316
+ const argsText = expr.arguments.map(arg => renderExprAsText(expressionToIR(arg, sourceText, diagnostics, pointerVars)));
317
+ const lowered = lowerStringMethod(methodName, receiverText, argsText, expr.arguments.length);
318
+ if (lowered !== null) {
319
+ return { kind: "raw", value: lowered };
320
+ }
321
+ }
322
+ }
323
+ }
324
+ return null;
325
+ }
326
+ // Methods that exist on BOTH std::string and std::vector (so the receiver
327
+ // type must be consulted to decide). All other STRING_METHOD_NAMES are
328
+ // unambiguously string-only.
329
+ const AMBIGUOUS_STRING_METHODS = new Set(["indexOf", "includes", "startsWith", "endsWith", "slice", "substring"]);
330
+ /**
331
+ * Decide whether `receiver.methodName(...)` should lower as a STRING method
332
+ * (→ `__tc_*` helper) rather than being left for the array path. Returns true
333
+ * for unambiguously-string methods (toLowerCase, charAt, ...), and for the
334
+ * ambiguous overlap methods only when the receiver's resolved C++ type is
335
+ * string-like (`std::string`/`const char*`/`char*`). Known arrays
336
+ * (`mutableArrayVars`/`activeCArrayVars`) are always rejected so an array
337
+ * `indexOf` is never mis-lowered.
338
+ */
339
+ function shouldLowerAsStringMethod(receiverNode, methodName) {
340
+ // Known array receivers are never string-method receivers.
341
+ if (ts.isIdentifier(receiverNode)) {
342
+ if (mutableArrayVars.has(receiverNode.text) || activeCArrayVars.has(receiverNode.text)) {
343
+ return false;
344
+ }
345
+ }
346
+ if (!AMBIGUOUS_STRING_METHODS.has(methodName)) {
347
+ // Unambiguously a string method (toLowerCase/trim/charAt/charCodeAt/...).
348
+ return true;
349
+ }
350
+ // Ambiguous: decide by the receiver's resolved C++ type.
351
+ const resolvedType = resolveReceiverCppType(receiverNode);
352
+ return resolvedType === "std::string" || resolvedType === "const char*" || resolvedType === "char*";
353
+ }
354
+ /**
355
+ * Resolve the C++ type of a receiver expression for the string/array
356
+ * disambiguation. Handles bare identifiers (scope lookup), `this.field`
357
+ * (`this->field` in the scope map), element access (`arr[i]` — derives the
358
+ * container's element type), and `obj.field` chains (best-effort). Returns
359
+ * undefined if unknown.
360
+ *
361
+ * Element access is the case demo #27 Finding D stressed: `words[i].substring`
362
+ * where `words: string[]`. The container resolves to `std::vector<std::string>`
363
+ * and the element type is `std::string`, so the ambiguous `substring`/`slice`
364
+ * methods lower as string methods. Without this, an indexed receiver resolved
365
+ * to `undefined` and the ambiguous-method gate rejected the lowering.
366
+ */
367
+ function resolveReceiverCppType(receiverNode) {
368
+ const scope = getCurrentIrTypeScope();
369
+ if (!scope)
370
+ return undefined;
371
+ if (ts.isIdentifier(receiverNode)) {
372
+ return scope.locals.get(receiverNode.text) ?? scope.globals.get(receiverNode.text);
373
+ }
374
+ if (ts.isPropertyAccessExpression(receiverNode) && receiverNode.expression.kind === ts.SyntaxKind.ThisKeyword) {
375
+ return scope.locals.get(`this->${receiverNode.name.text}`);
376
+ }
377
+ if (ts.isElementAccessExpression(receiverNode)) {
378
+ // Derive the element type of the indexed container.
379
+ const containerType = resolveReceiverCppType(receiverNode.expression);
380
+ if (containerType) {
381
+ const element = parsedElementString(containerType);
382
+ if (element)
383
+ return element;
384
+ }
385
+ return undefined;
386
+ }
387
+ return undefined;
388
+ }
389
+ /**
390
+ * Render a `.push(arg)` argument, casting it across the enum↔integral storage
391
+ * boundary when the receiver is an integral-element vector and the argument is
392
+ * a numeric-enum value. The IR-build-time counterpart to the emit-layer
393
+ * `renderValueForTarget`: `.push` lowers to a raw `recv.push_back(ARG)` callee
394
+ * with the argument baked into the text, so the boundary must be handled HERE
395
+ * (the emit layer never sees the argument as a structured value).
396
+ *
397
+ * Detection (structural, not regex):
398
+ * - Resolve the receiver's C++ type and derive its element type
399
+ * (`std::vector<uint8_t>` → `uint8_t`).
400
+ * - Detect a numeric-enum argument: a property access on a name in
401
+ * `activeEnumNames` (`Cell.Dead`), or a bare identifier whose scope type is
402
+ * an enum. String-enum members lower to `const char*` and are never cast.
403
+ *
404
+ * When the element type is integral and the arg is a numeric-enum value, wrap
405
+ * the rendered arg in `static_cast<int>(...)`. Demo #32 Finding A. Mirrors the
406
+ * SUPPORT_MATRIX §1.7 enum↔integral family fixed at the assign/var_decl sites
407
+ * in the emit layer.
408
+ */
409
+ function renderPushArgForElement(argNode, receiverNode, sourceText, diagnostics, pointerVars) {
410
+ const rendered = renderExprAsText(expressionToIR(argNode, sourceText, diagnostics, pointerVars));
411
+ // Resolve the receiver element type.
412
+ const receiverType = resolveReceiverCppType(receiverNode);
413
+ const elementType = receiverType ? parsedElementString(receiverType) : undefined;
414
+ const targetIsIntegral = !!elementType && INTEGRAL_CPP_TYPE_RE.test(elementType);
415
+ if (!targetIsIntegral)
416
+ return rendered;
417
+ // Detect a numeric-enum argument (excluding string enums).
418
+ const argEnumName = numericEnumNameOfArg(argNode);
419
+ if (!argEnumName)
420
+ return rendered;
421
+ if (/^static_cast<[^>]+>\(/.test(rendered))
422
+ return rendered;
423
+ return `static_cast<int>(${rendered})`;
424
+ }
425
+ /**
426
+ * Returns the enum name when `node` is a numeric-enum value: either
427
+ * `EnumName.Member` (property access on a name in `activeEnumNames`, not a
428
+ * string enum) or a bare identifier whose IR-scope type is a numeric enum.
429
+ * Returns undefined for string enums and non-enum nodes. Demo #32 Finding A.
430
+ */
431
+ function numericEnumNameOfArg(node) {
432
+ if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression)) {
433
+ const name = node.expression.text;
434
+ if (activeEnumNames.has(name) && !activeStringEnumNames.has(name))
435
+ return name;
436
+ }
437
+ if (ts.isIdentifier(node)) {
438
+ const scope = getCurrentIrTypeScope();
439
+ const t = scope?.locals.get(node.text) ?? scope?.globals.get(node.text);
440
+ if (t && activeEnumNames.has(t) && !activeStringEnumNames.has(t))
441
+ return t;
442
+ }
443
+ return undefined;
444
+ }
445
+ /**
446
+ * Lower a string method to its `__tc_*` helper call, picking the helper by
447
+ * method name AND argument count (so `substring(0,2)` → `__tc_substring2` and
448
+ * `substring(2)` → `__tc_substring1`). Returns null if no spec matches the
449
+ * call's arity (e.g. the demo's `slice()` zero-arg copy form belongs to the
450
+ * vector path, not here).
451
+ *
452
+ * Built from `STRING_METHODS`, which encodes arity in the helper name
453
+ * (`__tc_substring2` / `__tc_substring1`) and argForm. The original
454
+ * `STRING_METHOD_BY_NAME` map in `string-method-registry.ts` collapses both
455
+ * arities onto one key (fine for the names-set, wrong for lowering), so this
456
+ * lookup is keyed by `${name}:${argForm}` instead.
457
+ *
458
+ * Native `startsWith` maps to `std::string::rfind` (the prior `special`
459
+ * override) instead of the `__tc_*` helper.
460
+ */
461
+ const STRING_HELPER_BY_NAME_FORM = new Map();
462
+ for (const spec of STRING_METHODS) {
463
+ const name = spec.methodName ?? spec.helper.replace(/^__tc_/, "").replace(/_default$/, "").replace(/\d+$/, "");
464
+ STRING_HELPER_BY_NAME_FORM.set(`${name}:${spec.argForm}`, spec);
465
+ }
466
+ function lowerStringMethod(methodName, receiver, args, argCount) {
467
+ // Native special case: startsWith → rfind prefix test (no helper).
468
+ if (methodName === "startsWith" && argCount >= 1) {
469
+ return `(${receiver}.rfind(${args[0]}, 0) == 0)`;
470
+ }
471
+ // Map the observed arg count to the argForm that handles it. Methods with a
472
+ // default (`padStart`/`padEnd`) have BOTH a binary and a unaryDefault spec;
473
+ // prefer the binary form when 2 args are given, else the default form.
474
+ const formsForCount = argCount === 0 ? ["receiverOnly"]
475
+ : argCount === 1 ? ["unary", "unaryDefault"]
476
+ : argCount === 2 ? ["binary"]
477
+ : [];
478
+ for (const form of formsForCount) {
479
+ const spec = STRING_HELPER_BY_NAME_FORM.get(`${methodName}:${form}`);
480
+ if (!spec)
481
+ continue;
482
+ switch (form) {
483
+ case "receiverOnly":
484
+ return `${spec.helper}(${receiver})`;
485
+ case "unary":
486
+ case "unaryDefault":
487
+ return `${spec.helper}(${receiver}, ${args[0]})`;
488
+ case "binary":
489
+ return `${spec.helper}(${receiver}, ${args[0]}, ${args[1]})`;
490
+ }
491
+ }
492
+ return null;
493
+ }
@@ -0,0 +1,5 @@
1
+ import ts from "typescript";
2
+ import { Diagnostic } from "../../types.js";
3
+ import { StatementIR } from "../../api/index.js";
4
+ import { PointerTracker } from "../build-ir-state.js";
5
+ export declare function callToStatement(statementNode: ts.ExpressionStatement, call: ts.CallExpression, fileName: string, sourceText: string, diagnostics: Diagnostic[], pointerVars?: PointerTracker): StatementIR;