@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,589 @@
1
+ /**
2
+ * Combined program analysis - single-pass detection of multiple features.
3
+ *
4
+ * Instead of traversing the IR multiple times for different checks
5
+ * (hasConsoleCalls, hasArrayInObjectLiteral, hasThrowStatements, etc.),
6
+ * this module performs all checks in a single traversal.
7
+ */
8
+ import { POLYFILL_HELPER_MAP } from "../api/shared/index.js";
9
+ import { parseCppType } from "../api/shared/cpp-type-ir.js";
10
+ import { loweredConsoleInCallback } from "./transformers/ui-callback-lowering.js";
11
+ import { watchPinSpecs, clickHandlers } from "./transformers/ui-call-resolver.js";
12
+ import { canvasBindings } from "./transformers/canvas-lowering.js";
13
+ import { getInputBindings, getListBindings } from "./transformers/ui-reactive.js";
14
+ // Regex for std:: math calls
15
+ const MATH_PATTERN = /\bstd::(floor|ceil|round|trunc|sqrt|pow|sin|cos|tan|asin|acos|atan|abs|max|min)\b/;
16
+ /**
17
+ * Analyze an expression for all features in a single pass.
18
+ */
19
+ function analyzeExpression(expr, result, strategy) {
20
+ if (!expr || typeof expr !== 'object' || !expr.kind) {
21
+ return;
22
+ }
23
+ switch (expr.kind) {
24
+ case "raw":
25
+ if (MATH_PATTERN.test(expr.value)) {
26
+ result.hasStdMathCalls = true;
27
+ }
28
+ for (const [pattern, helperNames] of Object.entries(POLYFILL_HELPER_MAP)) {
29
+ if (expr.value.includes(pattern)) {
30
+ for (const name of helperNames) {
31
+ result.usedPolyfillHelpers.add(name);
32
+ }
33
+ }
34
+ // Also check for already-lowered __tc_ names
35
+ for (const name of helperNames) {
36
+ if (expr.value.includes(name)) {
37
+ result.usedPolyfillHelpers.add(name);
38
+ }
39
+ }
40
+ }
41
+ if (/\bString\s*\(/.test(expr.value)) {
42
+ result.usesStringConversion = true;
43
+ }
44
+ if (/Date\.now\s*\(/.test(expr.value) || /Date::now\s*\(/.test(expr.value)) {
45
+ result.usesDateNow = true;
46
+ }
47
+ if (/\bmillis\s*\(/.test(expr.value)) {
48
+ result.usesMillis = true;
49
+ }
50
+ if (expr.value.includes('cuttlefish_nullish(') || expr.value.includes('cuttlefish_exists(') || expr.value.includes('cuttlefish_is_nullish(')) {
51
+ result.usesNullish = true;
52
+ result.usesNullishHelper = true;
53
+ }
54
+ if (/\bNum\b/.test(expr.value)) {
55
+ result.usesNum = true;
56
+ }
57
+ if (/\bTiming\b/.test(expr.value)) {
58
+ result.usesTiming = true;
59
+ }
60
+ if (/\bWDT\b/.test(expr.value)) {
61
+ result.usesWDT = true;
62
+ }
63
+ if (expr.value.includes('__tc_str_ptr')) {
64
+ result.usesStrPtr = true;
65
+ }
66
+ break;
67
+ case "method-call":
68
+ if (strategy.isConsoleCall(expr.callee)) {
69
+ result.hasConsoleCalls = true;
70
+ }
71
+ if (/\bmillis\b/.test(expr.callee) || /\bdelay\b/.test(expr.callee) || /\bmicros\b/.test(expr.callee)) {
72
+ result.usesMillis = true;
73
+ }
74
+ if (expr.callee === "Date.now" || expr.callee === "Date::now") {
75
+ result.usesDateNow = true;
76
+ }
77
+ if (expr.callee === "String") {
78
+ result.usesStringConversion = true;
79
+ }
80
+ if (MATH_PATTERN.test(expr.callee)) {
81
+ result.hasStdMathCalls = true;
82
+ }
83
+ for (const [pattern, helperNames] of Object.entries(POLYFILL_HELPER_MAP)) {
84
+ const methodName = pattern.startsWith('.') ? pattern.slice(1, -1) : pattern.slice(0, -1);
85
+ if (expr.callee.includes(pattern) || expr.callee.endsWith("." + methodName) || expr.callee === methodName) {
86
+ for (const name of helperNames) {
87
+ result.usedPolyfillHelpers.add(name);
88
+ }
89
+ }
90
+ for (const name of helperNames) {
91
+ if (expr.callee.includes(name)) {
92
+ result.usedPolyfillHelpers.add(name);
93
+ }
94
+ }
95
+ }
96
+ if (expr.callee.startsWith("Num.") || expr.callee === "Num") {
97
+ result.usesNum = true;
98
+ }
99
+ if (expr.callee.startsWith("Timing.") || expr.callee === "Timing") {
100
+ result.usesTiming = true;
101
+ }
102
+ if (expr.callee.startsWith("WDT.") || expr.callee === "WDT") {
103
+ result.usesWDT = true;
104
+ }
105
+ // Count setInterval/setTimeout call sites (post-rename callee names) so
106
+ // __tc_TimerRuntime::MAX_TIMERS can be sized to the observed count.
107
+ if (expr.callee === "__tc_setInterval" || expr.callee === "__tc_setTimeout"
108
+ || expr.callee === "setInterval" || expr.callee === "setTimeout") {
109
+ result.timerCallCount++;
110
+ }
111
+ for (const arg of expr.args) {
112
+ analyzeExpression(arg, result, strategy);
113
+ }
114
+ break;
115
+ case "identifier":
116
+ // expression-to-ir lowers the TS `null` literal to the "nullptr" sentinel
117
+ // (routed through nullValue() at render time, which yields CUTTLEFISH_UNDEFINED
118
+ // on native/arduino). Include it so usesNullish triggers the defining shim.
119
+ if (expr.value === "null" || expr.value === "undefined" || expr.value === "nullptr" || expr.value === "CUTTLEFISH_UNDEFINED") {
120
+ result.usesNullish = true;
121
+ }
122
+ break;
123
+ case "string":
124
+ for (const [pattern, helperNames] of Object.entries(POLYFILL_HELPER_MAP)) {
125
+ if (expr.value.includes(pattern)) {
126
+ for (const name of helperNames) {
127
+ result.usedPolyfillHelpers.add(name);
128
+ }
129
+ }
130
+ // Also check for already-lowered __tc_ names (e.g. in __EMIT__ calls from HAL resolver)
131
+ for (const name of helperNames) {
132
+ if (expr.value.includes(name)) {
133
+ result.usedPolyfillHelpers.add(name);
134
+ }
135
+ }
136
+ }
137
+ break;
138
+ case "array":
139
+ result.usesVectorTypes = true;
140
+ for (const element of expr.elements) {
141
+ analyzeExpression(element, result, strategy);
142
+ }
143
+ break;
144
+ case "object":
145
+ for (const field of expr.fields) {
146
+ analyzeExpression(field.value, result, strategy);
147
+ }
148
+ break;
149
+ case "ternary":
150
+ analyzeExpression(expr.condition, result, strategy);
151
+ analyzeExpression(expr.whenTrue, result, strategy);
152
+ analyzeExpression(expr.whenFalse, result, strategy);
153
+ break;
154
+ case "await":
155
+ analyzeExpression(expr.value, result, strategy);
156
+ break;
157
+ case "instanceof":
158
+ analyzeExpression(expr.object, result, strategy);
159
+ break;
160
+ case "spread_array":
161
+ analyzeExpression(expr.spreadExpr, result, strategy);
162
+ for (const element of expr.additionalElements) {
163
+ analyzeExpression(element, result, strategy);
164
+ }
165
+ break;
166
+ case "binary":
167
+ if (expr.operator === "**") {
168
+ result.hasStdMathCalls = true;
169
+ }
170
+ analyzeExpression(expr.left, result, strategy);
171
+ analyzeExpression(expr.right, result, strategy);
172
+ break;
173
+ case "unary":
174
+ analyzeExpression(expr.operand, result, strategy);
175
+ break;
176
+ case "property-access":
177
+ analyzeExpression(expr.object, result, strategy);
178
+ break;
179
+ case "element-access":
180
+ analyzeExpression(expr.object, result, strategy);
181
+ analyzeExpression(expr.index, result, strategy);
182
+ break;
183
+ case "string_concat":
184
+ case "template_string":
185
+ result.usesStringConversion = true;
186
+ if (expr.kind === "string_concat") {
187
+ for (const part of expr.parts) {
188
+ analyzeExpression(part, result, strategy);
189
+ }
190
+ }
191
+ else {
192
+ analyzeExpression(expr.expression, result, strategy);
193
+ }
194
+ break;
195
+ }
196
+ }
197
+ /**
198
+ * Analyze a statement for all features in a single pass.
199
+ */
200
+ function analyzeStatement(statement, result, strategy) {
201
+ if (!statement || typeof statement !== 'object' || !statement.kind) {
202
+ return;
203
+ }
204
+ switch (statement.kind) {
205
+ case "call":
206
+ if (strategy.isConsoleCall(statement.callee)) {
207
+ result.hasConsoleCalls = true;
208
+ }
209
+ if (statement.callee === "Serial.begin" || statement.callee.endsWith(".begin")) {
210
+ result.hasSerialBegin = true;
211
+ }
212
+ if (statement.callee === "String") {
213
+ result.usesStringConversion = true;
214
+ }
215
+ if (statement.callee === "Date.now" || statement.callee === "Date::now") {
216
+ result.usesDateNow = true;
217
+ }
218
+ if (statement.callee === "millis" || statement.callee === "delay") {
219
+ result.usesMillis = true;
220
+ }
221
+ // Namespace-qualified polyfill entry points used as bare call statements
222
+ // (e.g. `Timing.delay(5);`). The expression-level analyzer (case
223
+ // "method-call") already checks these prefixes, but a statement-form call
224
+ // never becomes a method-call expression — it stays a `call` statement —
225
+ // so without these mirrors `usesTiming`/`usesNum`/`usesWDT` stayed false
226
+ // and the defining shim was filtered out (avr-g++: "'Timing' was not
227
+ // declared in this scope"). Demo #30 Finding A.
228
+ if (statement.callee.startsWith("Timing.") || statement.callee === "Timing") {
229
+ result.usesTiming = true;
230
+ }
231
+ if (statement.callee.startsWith("Num.") || statement.callee === "Num") {
232
+ result.usesNum = true;
233
+ }
234
+ if (statement.callee.startsWith("WDT.") || statement.callee === "WDT") {
235
+ result.usesWDT = true;
236
+ }
237
+ // The HAL resolver lowers WDT.*/Timing.* namespace calls to bare AVR
238
+ // library functions (WDT.reset() → wdt_reset(), Timing.delay() → delay(),
239
+ // Timing.millis() → millis()). When that happens the `WDT.`/`Timing.`
240
+ // prefix is gone, so the namespace checks above miss it and the defining
241
+ // shim gets filtered out (avr-g++: "'wdt_reset' was not declared in this
242
+ // scope"). Detect the lowered names directly. Demo #32 Finding A.
243
+ if (statement.callee === "wdt_reset" || statement.callee === "wdt_enable" || statement.callee === "wdt_disable") {
244
+ result.usesWDT = true;
245
+ }
246
+ for (const [pattern, helperNames] of Object.entries(POLYFILL_HELPER_MAP)) {
247
+ const methodName = pattern.startsWith('.') ? pattern.slice(1, -1) : pattern.slice(0, -1);
248
+ if (statement.callee === methodName || statement.callee.endsWith("." + methodName)) {
249
+ for (const name of helperNames) {
250
+ result.usedPolyfillHelpers.add(name);
251
+ }
252
+ }
253
+ // Also detect already-lowered __tc_* helper calls — including raw-statement
254
+ // wrappers (`__RAW_STMT____tc_pop(...)`) produced by the structural
255
+ // vector-method lowering in call-statement.ts. Without this, a statement
256
+ // form like `arr.pop();` (lowered to `__RAW_STMT____tc_pop(arr)`) wouldn't
257
+ // register the polyfill, and the helper definition would be filtered out.
258
+ for (const name of helperNames) {
259
+ if (statement.callee.includes(name)) {
260
+ result.usedPolyfillHelpers.add(name);
261
+ }
262
+ }
263
+ }
264
+ for (const arg of statement.args) {
265
+ analyzeExpression(arg, result, strategy);
266
+ }
267
+ break;
268
+ case "var_decl":
269
+ result.declaredTypes.push(statement.cppType);
270
+ if (parseCppType(statement.cppType).kind === "strPtr") {
271
+ result.usesStrPtr = true;
272
+ }
273
+ if (statement.initializer) {
274
+ analyzeExpression(statement.initializer, result, strategy);
275
+ // Check for array in object literal
276
+ if (statement.initializer.kind === "array") {
277
+ result.hasArrayInObjectLiteral = true;
278
+ }
279
+ }
280
+ break;
281
+ case "assign":
282
+ analyzeExpression(statement.value, result, strategy);
283
+ break;
284
+ case "return":
285
+ if (statement.value) {
286
+ analyzeExpression(statement.value, result, strategy);
287
+ }
288
+ break;
289
+ case "throw":
290
+ result.hasThrowStatements = true;
291
+ analyzeExpression(statement.value, result, strategy);
292
+ break;
293
+ case "while":
294
+ case "do_while":
295
+ analyzeExpression(statement.condition, result, strategy);
296
+ for (const nested of statement.body) {
297
+ analyzeStatement(nested, result, strategy);
298
+ }
299
+ break;
300
+ case "if":
301
+ analyzeExpression(statement.condition, result, strategy);
302
+ for (const nested of statement.thenBranch) {
303
+ analyzeStatement(nested, result, strategy);
304
+ }
305
+ for (const nested of statement.elseBranch ?? []) {
306
+ analyzeStatement(nested, result, strategy);
307
+ }
308
+ break;
309
+ case "for":
310
+ if (statement.initializer) {
311
+ analyzeStatement(statement.initializer, result, strategy);
312
+ }
313
+ if (statement.condition) {
314
+ analyzeExpression(statement.condition, result, strategy);
315
+ }
316
+ if (statement.increment) {
317
+ analyzeStatement(statement.increment, result, strategy);
318
+ }
319
+ for (const nested of statement.body) {
320
+ analyzeStatement(nested, result, strategy);
321
+ }
322
+ break;
323
+ case "for_of":
324
+ analyzeStatement(statement.variable, result, strategy);
325
+ analyzeExpression(statement.iterable, result, strategy);
326
+ for (const nested of statement.body) {
327
+ analyzeStatement(nested, result, strategy);
328
+ }
329
+ break;
330
+ case "for_in":
331
+ analyzeStatement(statement.variable, result, strategy);
332
+ analyzeExpression(statement.object, result, strategy);
333
+ for (const nested of statement.body) {
334
+ analyzeStatement(nested, result, strategy);
335
+ }
336
+ break;
337
+ case "switch":
338
+ analyzeExpression(statement.expression, result, strategy);
339
+ for (const caseClause of statement.cases) {
340
+ if (caseClause.value) {
341
+ analyzeExpression(caseClause.value, result, strategy);
342
+ }
343
+ for (const nested of caseClause.body) {
344
+ analyzeStatement(nested, result, strategy);
345
+ }
346
+ }
347
+ break;
348
+ case "try":
349
+ for (const nested of statement.tryBlock) {
350
+ analyzeStatement(nested, result, strategy);
351
+ }
352
+ for (const nested of statement.catchBlock ?? []) {
353
+ analyzeStatement(nested, result, strategy);
354
+ }
355
+ for (const nested of statement.finallyBlock ?? []) {
356
+ analyzeStatement(nested, result, strategy);
357
+ }
358
+ break;
359
+ case "hal-op":
360
+ // Scan raw C++ code in HAL ops for polyfill helper usage
361
+ if (statement.operation && statement.operation.operation === "raw" && typeof statement.operation.code === "string") {
362
+ const code = statement.operation.code;
363
+ for (const [pattern, helperNames] of Object.entries(POLYFILL_HELPER_MAP)) {
364
+ if (code.includes(pattern)) {
365
+ for (const name of helperNames) {
366
+ result.usedPolyfillHelpers.add(name);
367
+ }
368
+ }
369
+ for (const name of helperNames) {
370
+ if (code.includes(name)) {
371
+ result.usedPolyfillHelpers.add(name);
372
+ }
373
+ }
374
+ }
375
+ // The HAL resolver lowers WDT.*/Timing.* namespace calls to bare AVR
376
+ // library functions inside hal-op raw code (WDT.reset() → wdt_reset(),
377
+ // Timing.delay() → delay()). The namespace prefix is gone, so detect
378
+ // the lowered names to keep the defining shim/include alive.
379
+ // Demo #32 Finding B.
380
+ if (/\bwdt_(reset|enable|disable)\b/.test(code)) {
381
+ result.usesWDT = true;
382
+ }
383
+ if (/\b(millis|micros|delay|delayMicroseconds)\s*\(/.test(code)) {
384
+ result.usesTiming = true;
385
+ result.usesMillis = true;
386
+ }
387
+ }
388
+ break;
389
+ case "update":
390
+ // update statements just increment/decrement a variable
391
+ break;
392
+ case "break":
393
+ case "continue":
394
+ // no expressions to analyze
395
+ break;
396
+ case "super_call":
397
+ for (const arg of statement.args) {
398
+ analyzeExpression(arg, result, strategy);
399
+ }
400
+ break;
401
+ case "labeled":
402
+ case "block":
403
+ const body = statement.kind === "labeled" ? statement.body : statement.body;
404
+ for (const nested of body) {
405
+ analyzeStatement(nested, result, strategy);
406
+ }
407
+ break;
408
+ }
409
+ }
410
+ /**
411
+ * Analyze a program IR in a single pass to detect all features.
412
+ * This replaces multiple separate traversals with one combined traversal.
413
+ */
414
+ export function analyzeProgram(program, strategy) {
415
+ const result = {
416
+ hasConsoleCalls: false,
417
+ hasArrayInObjectLiteral: false,
418
+ hasThrowStatements: false,
419
+ hasStdMathCalls: false,
420
+ usesVectorTypes: false,
421
+ usesStdString: false,
422
+ usesStdFunction: false,
423
+ declaredTypes: [],
424
+ usedPolyfillHelpers: new Set(),
425
+ usesStringConversion: false,
426
+ usesDateNow: false,
427
+ usesMillis: false,
428
+ usesNullish: false,
429
+ usesNullishHelper: false,
430
+ usesNum: false,
431
+ usesTiming: false,
432
+ usesWDT: false,
433
+ usesStrPtr: false,
434
+ hasSerialBegin: false,
435
+ hasGenerators: false,
436
+ usesStdMap: false,
437
+ timerCallCount: 0,
438
+ };
439
+ // Analyze type aliases
440
+ for (const typeAlias of program.typeAliases) {
441
+ result.declaredTypes.push(typeAlias.cppType);
442
+ if (typeAlias.structFields) {
443
+ for (const field of typeAlias.structFields) {
444
+ result.declaredTypes.push(field.cppType);
445
+ }
446
+ }
447
+ if (typeAlias.variantStructs) {
448
+ for (const variant of typeAlias.variantStructs) {
449
+ for (const field of variant.fields) {
450
+ result.declaredTypes.push(field.cppType);
451
+ }
452
+ }
453
+ }
454
+ }
455
+ // Analyze interfaces for field types and index signatures
456
+ for (const iface of program.interfaces) {
457
+ for (const field of iface.fields) {
458
+ result.declaredTypes.push(field.cppType);
459
+ }
460
+ if (iface.indexSignature) {
461
+ result.usesStdMap = true;
462
+ result.declaredTypes.push(iface.indexSignature.keyType);
463
+ result.declaredTypes.push(iface.indexSignature.valueType);
464
+ }
465
+ }
466
+ // Analyze functions
467
+ for (const fn of program.functions) {
468
+ if (fn.isGenerator)
469
+ result.hasGenerators = true;
470
+ result.declaredTypes.push(fn.returnType);
471
+ for (const parameter of fn.parameters) {
472
+ result.declaredTypes.push(parameter.cppType);
473
+ }
474
+ for (const statement of fn.statements) {
475
+ analyzeStatement(statement, result, strategy);
476
+ }
477
+ }
478
+ // Analyze top-level statements
479
+ for (const statement of program.topLevelStatements) {
480
+ analyzeStatement(statement, result, strategy);
481
+ }
482
+ // Analyze classes
483
+ for (const classDef of program.classes) {
484
+ for (const field of classDef.fields) {
485
+ result.declaredTypes.push(field.cppType);
486
+ if (field.initializer) {
487
+ analyzeExpression(field.initializer, result, strategy);
488
+ if (field.initializer.kind === "array") {
489
+ result.hasArrayInObjectLiteral = true;
490
+ }
491
+ }
492
+ }
493
+ for (const method of classDef.methods) {
494
+ result.declaredTypes.push(method.returnType);
495
+ for (const parameter of method.parameters) {
496
+ result.declaredTypes.push(parameter.cppType);
497
+ }
498
+ for (const statement of method.statements) {
499
+ analyzeStatement(statement, result, strategy);
500
+ }
501
+ }
502
+ if (classDef.constructor) {
503
+ for (const parameter of classDef.constructor.parameters) {
504
+ result.declaredTypes.push(parameter.cppType);
505
+ }
506
+ for (const statement of classDef.constructor.statements) {
507
+ analyzeStatement(statement, result, strategy);
508
+ }
509
+ }
510
+ }
511
+ // Post-process declared types to detect std:: usage
512
+ for (const typeName of result.declaredTypes) {
513
+ if (typeName.includes("std::vector<")) {
514
+ result.usesVectorTypes = true;
515
+ }
516
+ if (strategy.needsStdVector() && typeName.includes("__tc_StaticArray<")) {
517
+ result.usesVectorTypes = true;
518
+ }
519
+ // Track __tc_StaticArray type usage on ALL targets so the defining
520
+ // polyfill is retained by filterPolyfillHelpers (the struct's constructor
521
+ // matches the helper-name regex but is never a user call site, so without
522
+ // this the struct would be filtered out and `__tc_StaticArray<int,N>`
523
+ // undeclared — avr-g++: "'__tc_StaticArray' was not declared"). Demo #23.
524
+ if (typeName.includes("__tc_StaticArray<")) {
525
+ result.usedPolyfillHelpers.add("__tc_StaticArray");
526
+ }
527
+ if (typeName.includes("std::string")) {
528
+ result.usesStdString = true;
529
+ // The Arduino/AVR strategy normalizes `std::string` → `__tc_str_ptr` at
530
+ // emit time (Strategy.normalizeCppType). The `usesStrPtr` flag gates
531
+ // emission of the `__tc_str_ptr` shim block, but the per-statement
532
+ // detector at the `var_decl` arm compares the PRE-normalization cppType
533
+ // (still `std::string`) against `parseCppType(...).kind === "strPtr"` —
534
+ // which never matches, so a string-typed LOCAL/field/return that emits
535
+ // as `__tc_str_ptr` silently drops its own shim and fails at g++ time
536
+ // ("'__tc_str_ptr' does not name a type"). Resolving the type through
537
+ // the strategy's normalizer here — the single broadest chokepoint over
538
+ // every declared type (locals, fields, params, returns, aliases) — makes
539
+ // the analysis agree with the emit path on every target. On native the
540
+ // normalizer leaves `std::string` alone, so this is a no-op there.
541
+ if (strategy.normalizeCppType("std::string") === "__tc_str_ptr") {
542
+ result.usesStrPtr = true;
543
+ }
544
+ }
545
+ if (typeName.includes("std::function<")) {
546
+ result.usesStdFunction = true;
547
+ }
548
+ if (typeName.includes("std::map<")) {
549
+ result.usesStdMap = true;
550
+ }
551
+ }
552
+ // Analyze UI callback bodies that live outside program.functions
553
+ // (onClick / watchPin / drawCanvas / bindInput / bindList). They now carry
554
+ // StatementIR[] from the main lowerStatementList pipeline, so console /
555
+ // helper usage is visible here the same way setInterval bodies are.
556
+ for (const wp of watchPinSpecs()) {
557
+ for (const stmt of wp.bodyStatements ?? [])
558
+ analyzeStatement(stmt, result, strategy);
559
+ }
560
+ for (const ch of clickHandlers()) {
561
+ for (const stmt of ch.bodyStatements ?? [])
562
+ analyzeStatement(stmt, result, strategy);
563
+ }
564
+ for (const spec of canvasBindings()) {
565
+ for (const stmt of spec.bodyStatements ?? [])
566
+ analyzeStatement(stmt, result, strategy);
567
+ }
568
+ for (const spec of getInputBindings()) {
569
+ for (const stmt of spec.bodyStatements ?? [])
570
+ analyzeStatement(stmt, result, strategy);
571
+ }
572
+ for (const spec of getListBindings()) {
573
+ for (const stmt of spec.countStatements ?? [])
574
+ analyzeStatement(stmt, result, strategy);
575
+ for (const stmt of spec.itemStatements ?? [])
576
+ analyzeStatement(stmt, result, strategy);
577
+ for (const stmt of spec.tapStatements ?? [])
578
+ analyzeStatement(stmt, result, strategy);
579
+ }
580
+ // Console calls lowered inside leftover string-baked UI callbacks are baked
581
+ // into callbackBody strings, not IR nodes, so the statement walk above can't
582
+ // see them. Consult the flag recorded during lowering so hasConsoleCalls
583
+ // reflects them — this is what gates auto-injected Serial.begin(baud) and
584
+ // <iostream>.
585
+ if (loweredConsoleInCallback()) {
586
+ result.hasConsoleCalls = true;
587
+ }
588
+ return result;
589
+ }
@@ -0,0 +1,7 @@
1
+ import type { Diagnostic } from '../types.js';
2
+ import type { PeripheralUsage } from './peripheral-usage.js';
3
+ import type { BoardConstants } from './board-resolver.js';
4
+ /**
5
+ * Validate that pins used with inputPullDown() support pulldown on this board.
6
+ */
7
+ export declare function validatePulldownSupport(usage: PeripheralUsage, boardConstants: BoardConstants | undefined): Diagnostic[];
@@ -0,0 +1,49 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Pulldown Capability Validation
3
+ //
4
+ // Checks that pins configured with inputPullDown() actually support
5
+ // hardware pulldown on the target board. Emits a compile-time error if not.
6
+ // ---------------------------------------------------------------------------
7
+ /**
8
+ * Validate that pins used with inputPullDown() support pulldown on this board.
9
+ */
10
+ export function validatePulldownSupport(usage, boardConstants) {
11
+ const diagnostics = [];
12
+ if (usage.inputPulldownPins.size === 0) {
13
+ return diagnostics;
14
+ }
15
+ for (const pinNumber of usage.inputPulldownPins) {
16
+ // Check the pin's own pullDown capability from board definition
17
+ // undefined or false both mean pulldown is not supported on this pin
18
+ const supportsPullDown = boardConstants?.get(`pins.all.${pinNumber}.capabilities.pullDown`);
19
+ if (supportsPullDown !== true) {
20
+ const pinName = getPinName(pinNumber, boardConstants);
21
+ const arch = boardConstants?.get('architecture');
22
+ diagnostics.push({
23
+ code: 'pulldown-not-supported',
24
+ message: `${pinName ?? `pin ${pinNumber}`} does not support hardware pulldown${arch ? ` on ${arch.toUpperCase()} boards` : ''}. Use ${pinName ?? 'pin'}.asInput() or ${pinName ?? 'pin'}.inputPullUp() instead.`,
25
+ source: 'pulldown-validation',
26
+ severity: 'error',
27
+ });
28
+ }
29
+ }
30
+ return diagnostics;
31
+ }
32
+ /**
33
+ * Get the human-readable pin name (e.g., "D3", "A0") from pin number.
34
+ */
35
+ function getPinName(pinNumber, boardConstants) {
36
+ if (!boardConstants) {
37
+ if (pinNumber >= 14 && pinNumber <= 19)
38
+ return `A${pinNumber - 14}`;
39
+ return `D${pinNumber}`;
40
+ }
41
+ const name = boardConstants.get(`pins.all.${pinNumber}.name`);
42
+ if (typeof name === 'string')
43
+ return name;
44
+ // Fallback naming
45
+ if (pinNumber >= 14 && pinNumber <= 19) {
46
+ return `A${pinNumber - 14}`;
47
+ }
48
+ return `D${pinNumber}`;
49
+ }
@@ -0,0 +1,4 @@
1
+ import type { Diagnostic } from '../types.js';
2
+ import type { BoardConstants } from './board-resolver.js';
3
+ import type { PeripheralUsage } from './peripheral-usage.js';
4
+ export declare function validatePWMTimerSharing(usage: PeripheralUsage, boardConstants: BoardConstants | undefined): Diagnostic[];