@typecad/cuttlefish 1.0.0-alpha.13 → 1.0.0-alpha.15

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 (343) hide show
  1. package/README.md +82 -79
  2. package/assets/editor-extensions/typecad-debug/README.md +141 -0
  3. package/assets/editor-extensions/typecad-debug/out/extension.js +347 -0
  4. package/assets/editor-extensions/typecad-debug/out/extension.js.map +1 -0
  5. package/assets/editor-extensions/typecad-debug/package.json +76 -0
  6. package/assets/editor-extensions/typecad-ui/LICENSE +27 -0
  7. package/assets/editor-extensions/typecad-ui/README.md +52 -0
  8. package/assets/editor-extensions/typecad-ui/file-icon-dark.png +0 -0
  9. package/assets/editor-extensions/typecad-ui/file-icon-light.png +0 -0
  10. package/assets/editor-extensions/typecad-ui/icon.png +0 -0
  11. package/assets/editor-extensions/typecad-ui/language-configuration.json +43 -0
  12. package/assets/editor-extensions/typecad-ui/package.json +54 -0
  13. package/assets/editor-extensions/typecad-ui/snippets/typecad-ui.json +80 -0
  14. package/assets/editor-extensions/typecad-ui/syntaxes/markdown-ui.json +45 -0
  15. package/assets/editor-extensions/typecad-ui/syntaxes/typecad-ui.tmLanguage.json +1269 -0
  16. package/dist/api/config.d.ts +30 -27
  17. package/dist/api/schema/types.d.ts +20 -3
  18. package/dist/api/shared/async-runtime-static.d.ts +1 -1
  19. package/dist/api/shared/async-runtime-static.js +5 -5
  20. package/dist/api/shared/async-types.d.ts +3 -2
  21. package/dist/api/shared/board-catalog.d.ts +2 -0
  22. package/dist/api/shared/board-catalog.js +6 -0
  23. package/dist/api/shared/board-resolver.d.ts +4 -7
  24. package/dist/api/shared/board-resolver.js +2 -1
  25. package/dist/api/shared/coop-scheduler.d.ts +1 -1
  26. package/dist/api/shared/coop-scheduler.js +1 -1
  27. package/dist/api/shared/cpp-type-ir.d.ts +1 -1
  28. package/dist/api/shared/cpp-type-ir.js +1 -1
  29. package/dist/api/shared/display-profile.d.ts +1 -1
  30. package/dist/api/shared/display-profile.js +3 -5
  31. package/dist/api/shared/framework-manifest-registry.d.ts +1 -1
  32. package/dist/api/shared/framework-manifest-registry.js +0 -1
  33. package/dist/api/shared/framework-manifest.d.ts +65 -507
  34. package/dist/api/shared/framework-manifest.js +6 -11
  35. package/dist/api/shared/hal-op-ir.d.ts +294 -685
  36. package/dist/api/shared/hal-op-ir.js +31 -65
  37. package/dist/api/shared/index.d.ts +0 -4
  38. package/dist/api/shared/index.js +1 -7
  39. package/dist/api/shared/ir-core.d.ts +6 -0
  40. package/dist/api/shared/ir-declarations.d.ts +4 -0
  41. package/dist/api/shared/ir.d.ts +1 -3
  42. package/dist/api/shared/platform-strategy.d.ts +14 -37
  43. package/dist/api/shared/polyfill-helper-registry.js +0 -5
  44. package/dist/api/shared/polyfill-types.js +0 -27
  45. package/dist/api/shared/promise-runtime.js +3 -3
  46. package/dist/api/shared/spdx-licenses.d.ts +12 -10
  47. package/dist/api/shared/spdx-licenses.js +1 -1
  48. package/dist/api/shared/toolchain-types.d.ts +1 -1
  49. package/dist/api/shared/toolchain-types.js +3 -3
  50. package/dist/api/shared/types.d.ts +0 -3
  51. package/dist/api/shared/validate-framework-manifest.js +13 -33
  52. package/dist/board-catalog/dts-reader.d.ts +220 -0
  53. package/dist/board-catalog/dts-reader.js +1052 -0
  54. package/dist/board-catalog/index.d.ts +11 -0
  55. package/dist/board-catalog/index.js +12 -0
  56. package/dist/board-catalog/pinconfig.d.ts +48 -0
  57. package/dist/board-catalog/pinconfig.js +263 -0
  58. package/dist/board-catalog/sdk.d.ts +82 -0
  59. package/dist/board-catalog/sdk.js +180 -0
  60. package/dist/board-catalog/store.d.ts +196 -0
  61. package/dist/board-catalog/store.js +363 -0
  62. package/dist/board-catalog/types.d.ts +233 -0
  63. package/dist/board-catalog/types.js +7 -0
  64. package/dist/board-catalog/walker.d.ts +112 -0
  65. package/dist/board-catalog/walker.js +1101 -0
  66. package/dist/cli-utils.d.ts +2 -2
  67. package/dist/cli-utils.js +5 -5
  68. package/dist/cli.js +227 -244
  69. package/dist/config-loader.d.ts +14 -19
  70. package/dist/config-loader.js +242 -78
  71. package/dist/config-schema.d.ts +19 -227
  72. package/dist/config-schema.js +9 -8
  73. package/dist/contract/board-generator.d.ts +4 -4
  74. package/dist/contract/board-generator.js +16 -5
  75. package/dist/contract/contract-parser.d.ts +36 -127
  76. package/dist/contract/contract-parser.js +76 -0
  77. package/dist/contract/index.d.ts +1 -1
  78. package/dist/contract/index.js +70 -21
  79. package/dist/create/active-board-catalog.d.ts +9 -0
  80. package/dist/create/active-board-catalog.js +94 -0
  81. package/dist/create/board-catalog.generated.d.ts +96 -0
  82. package/dist/create/board-catalog.generated.js +128737 -0
  83. package/dist/create/board-search.d.ts +23 -0
  84. package/dist/create/board-search.js +88 -0
  85. package/dist/create/editor-integration.d.ts +32 -0
  86. package/dist/create/editor-integration.js +257 -0
  87. package/dist/create/eslint-rules-template.d.ts +2 -2
  88. package/dist/create/framework-catalog.d.ts +48 -8
  89. package/dist/create/framework-catalog.js +58 -44
  90. package/dist/create/index.d.ts +8 -13
  91. package/dist/create/index.js +5 -9
  92. package/dist/create/mcu-target.d.ts +39 -0
  93. package/dist/create/mcu-target.js +80 -0
  94. package/dist/create/pack-targets.d.ts +19 -0
  95. package/dist/create/pack-targets.js +56 -0
  96. package/dist/create/{init-scaffold.d.ts → scaffold.d.ts} +8 -11
  97. package/dist/create/{init-scaffold.js → scaffold.js} +28 -87
  98. package/dist/create/templates.d.ts +51 -0
  99. package/dist/create/{init-templates.js → templates.js} +135 -116
  100. package/dist/create/wizard.d.ts +19 -0
  101. package/dist/create/wizard.js +314 -0
  102. package/dist/debug/preprocessor.d.ts +5 -0
  103. package/dist/debug/preprocessor.js +31 -7
  104. package/dist/diagnostics/diagnostics-report.d.ts +1 -1
  105. package/dist/diagnostics/diagnostics-report.js +3 -11
  106. package/dist/diagnostics/json-schema.d.ts +1 -1
  107. package/dist/diagnostics/md-writer.js +2 -2
  108. package/dist/diagnostics/mermaid-builder.d.ts +1 -1
  109. package/dist/diagnostics/mermaid-builder.js +1 -1
  110. package/dist/emit/cpp-emitter.js +4 -1
  111. package/dist/emit/emitters/class-emitter.js +32 -4
  112. package/dist/emit/emitters/emitter-context.d.ts +11 -0
  113. package/dist/emit/emitters/entrypoint-synthesizer.js +1 -1
  114. package/dist/emit/emitters/function-emitter-impl.js +33 -17
  115. package/dist/emit/emitters/output-finalizer.d.ts +7 -0
  116. package/dist/emit/emitters/output-finalizer.js +31 -23
  117. package/dist/emit/emitters/setup.js +147 -63
  118. package/dist/emit/emitters/top-level-prep.js +1 -1
  119. package/dist/emit/emitters/type-decl-emitter.js +13 -8
  120. package/dist/emit/emitters/ui-emitter.js +1 -1
  121. package/dist/emit/expression-renderer.d.ts +3 -3
  122. package/dist/emit/expression-renderer.js +17 -7
  123. package/dist/emit/route-hal-op.js +17 -48
  124. package/dist/emit/snprintf-helpers.d.ts +1 -3
  125. package/dist/emit/snprintf-helpers.js +1 -39
  126. package/dist/emit/statement-renderer.d.ts +0 -4
  127. package/dist/emit/statement-renderer.js +54 -45
  128. package/dist/emit/utils/async-state-machine.d.ts +16 -9
  129. package/dist/emit/utils/async-state-machine.js +56 -54
  130. package/dist/emit/utils/comment-helpers.d.ts +0 -8
  131. package/dist/emit/utils/comment-helpers.js +1 -1
  132. package/dist/emit/utils/cpp-helpers.d.ts +2 -2
  133. package/dist/emit/utils/cpp-helpers.js +2 -2
  134. package/dist/emit/utils/hal-op-cpp-type.js +4 -6
  135. package/dist/emit/utils/index.d.ts +3 -3
  136. package/dist/emit/utils/index.js +3 -3
  137. package/dist/emit/utils/type-inference.d.ts +1 -29
  138. package/dist/emit/utils/type-inference.js +0 -75
  139. package/dist/framework-package.d.ts +3 -0
  140. package/dist/framework-package.js +23 -6
  141. package/dist/framework-registry.d.ts +5 -5
  142. package/dist/frameworks/native/graphics/terminal-preview.d.ts +5 -0
  143. package/dist/frameworks/native/graphics/terminal-preview.js +33 -0
  144. package/dist/frameworks/native/index.d.ts +3 -0
  145. package/dist/frameworks/native/index.js +15 -0
  146. package/dist/frameworks/native/native-compile.d.ts +17 -0
  147. package/dist/frameworks/native/native-compile.js +170 -0
  148. package/dist/frameworks/native/native-config.d.ts +41 -0
  149. package/dist/frameworks/native/native-config.js +7 -0
  150. package/dist/frameworks/native/strategy.d.ts +97 -0
  151. package/dist/frameworks/native/strategy.js +664 -0
  152. package/dist/ir/board-resolver.d.ts +18 -23
  153. package/dist/ir/board-resolver.js +43 -401
  154. package/dist/ir/build-ir-state.d.ts +3 -0
  155. package/dist/ir/build-ir-state.js +42 -0
  156. package/dist/ir/build-ir.d.ts +1 -1
  157. package/dist/ir/build-ir.js +64 -45
  158. package/dist/ir/declaration-builders.js +1 -0
  159. package/dist/ir/expression-to-ir.js +17 -10
  160. package/dist/ir/hal/hal-emitter.d.ts +0 -2
  161. package/dist/ir/hal/hal-emitter.js +92 -41
  162. package/dist/ir/hal/hal-parser.d.ts +5 -5
  163. package/dist/ir/hal/hal-parser.js +128 -36
  164. package/dist/ir/hal/hal-plugins.d.ts +0 -1
  165. package/dist/ir/hal/hal-plugins.js +425 -716
  166. package/dist/ir/heap-analysis.js +2 -41
  167. package/dist/ir/identifier-collector.js +32 -20
  168. package/dist/ir/network-validation.js +7 -11
  169. package/dist/ir/ownership-analysis.js +75 -13
  170. package/dist/ir/peripheral-usage.d.ts +8 -2
  171. package/dist/ir/peripheral-usage.js +78 -149
  172. package/dist/ir/peripheral-validation.js +23 -3
  173. package/dist/ir/pin-capability-validation.d.ts +12 -0
  174. package/dist/ir/pin-capability-validation.js +61 -97
  175. package/dist/ir/pin-mode-validation.js +5 -5
  176. package/dist/ir/program-analysis.d.ts +8 -15
  177. package/dist/ir/program-analysis.js +140 -323
  178. package/dist/ir/pulldown-validation.js +11 -4
  179. package/dist/ir/resource-analysis.js +15 -3
  180. package/dist/ir/statement-to-ir.js +0 -6
  181. package/dist/ir/timing-validation.js +1 -1
  182. package/dist/ir/transformers/array-methods.js +11 -5
  183. package/dist/ir/transformers/call-statement.js +20 -87
  184. package/dist/ir/transformers/callback-context-registry.d.ts +1 -1
  185. package/dist/ir/transformers/callback-context-registry.js +8 -16
  186. package/dist/ir/transformers/control-flow.js +0 -13
  187. package/dist/ir/transformers/expressions.js +10 -9
  188. package/dist/ir/transformers/hal-call-resolver.d.ts +2 -2
  189. package/dist/ir/transformers/hal-call-resolver.js +24 -10
  190. package/dist/ir/transformers/hal-emit-helpers.d.ts +2 -2
  191. package/dist/ir/transformers/hal-emit-helpers.js +2 -2
  192. package/dist/ir/transformers/namespace-methods.js +1 -1
  193. package/dist/ir/transformers/ui-callback-lowering.d.ts +0 -2
  194. package/dist/ir/transformers/ui-callback-lowering.js +0 -24
  195. package/dist/ir/transformers/variables.js +338 -42
  196. package/dist/ir/try-catch-validation.js +4 -3
  197. package/dist/ir/type-resolution.js +15 -4
  198. package/dist/ir/validation-orchestrator.js +0 -9
  199. package/dist/libdef/cpp-to-decl.d.ts +0 -9
  200. package/dist/libdef/cpp-to-decl.js +0 -72
  201. package/dist/libdef/registry.d.ts +0 -1
  202. package/dist/libdef/registry.js +1 -24
  203. package/dist/library/catalog.d.ts +35 -0
  204. package/dist/library/catalog.js +67 -0
  205. package/dist/library/cli.d.ts +2 -0
  206. package/dist/library/cli.js +168 -0
  207. package/dist/library/init.d.ts +25 -0
  208. package/dist/library/init.js +397 -0
  209. package/dist/library/install.d.ts +9 -0
  210. package/dist/library/install.js +80 -0
  211. package/dist/library/registry-search.d.ts +34 -0
  212. package/dist/library/registry-search.js +50 -0
  213. package/dist/library/validate.d.ts +17 -0
  214. package/dist/library/validate.js +175 -0
  215. package/dist/library-packages.d.ts +95 -0
  216. package/dist/library-packages.js +275 -0
  217. package/dist/mapping/peripheral-names.js +9 -4
  218. package/dist/mapping/source-map.d.ts +3 -4
  219. package/dist/mapping/source-map.js +12 -18
  220. package/dist/orchestrator/graph-builder.d.ts +3 -3
  221. package/dist/orchestrator/graph-builder.js +29 -12
  222. package/dist/orchestrator/type-checker.d.ts +3 -3
  223. package/dist/orchestrator/type-checker.js +3 -3
  224. package/dist/platform/async-runtime.js +1 -1
  225. package/dist/platform/coop-scheduler-runtime.js +2 -2
  226. package/dist/platform/generic-debug-codegen.d.ts +36 -0
  227. package/dist/platform/generic-debug-codegen.js +185 -0
  228. package/dist/platform/generic-strategy.d.ts +3 -4
  229. package/dist/platform/generic-strategy.js +5 -80
  230. package/dist/platform/index.js +1 -1
  231. package/dist/platform/registry.d.ts +2 -2
  232. package/dist/platform/registry.js +2 -2
  233. package/dist/preview/client.js +17 -3
  234. package/dist/safety/asil-decorators.d.ts +32 -0
  235. package/dist/safety/asil-decorators.js +32 -0
  236. package/dist/safety/authoring.d.ts +85 -0
  237. package/dist/safety/authoring.js +61 -0
  238. package/dist/safety/engine.d.ts +3 -0
  239. package/dist/safety/engine.js +83 -0
  240. package/dist/safety/hal/ops.d.ts +48 -0
  241. package/dist/safety/hal/ops.js +46 -0
  242. package/dist/safety/iso26262/analyze.d.ts +13 -0
  243. package/dist/safety/iso26262/analyze.js +29 -0
  244. package/dist/safety/iso26262/asil.d.ts +10 -0
  245. package/dist/safety/iso26262/asil.js +22 -0
  246. package/dist/safety/iso26262/collect.d.ts +14 -0
  247. package/dist/safety/iso26262/collect.js +137 -0
  248. package/dist/safety/iso26262/goto-checker.d.ts +10 -0
  249. package/dist/safety/iso26262/goto-checker.js +72 -0
  250. package/dist/safety/iso26262/heap-checker.d.ts +7 -0
  251. package/dist/safety/iso26262/heap-checker.js +57 -0
  252. package/dist/safety/iso26262/init-checker.d.ts +13 -0
  253. package/dist/safety/iso26262/init-checker.js +127 -0
  254. package/dist/safety/iso26262/loop-checker.d.ts +7 -0
  255. package/dist/safety/iso26262/loop-checker.js +86 -0
  256. package/dist/safety/iso26262/recursion-checker.d.ts +9 -0
  257. package/dist/safety/iso26262/recursion-checker.js +134 -0
  258. package/dist/safety/iso26262/sidecar-writer.d.ts +25 -0
  259. package/dist/safety/iso26262/sidecar-writer.js +13 -0
  260. package/dist/safety/passes/pinMode-intercept.d.ts +3 -0
  261. package/dist/safety/passes/pinMode-intercept.js +60 -0
  262. package/dist/safety/runtime/mode-table.d.ts +5 -0
  263. package/dist/safety/runtime/mode-table.js +55 -0
  264. package/dist/safety/runtime/polyfills.d.ts +6 -0
  265. package/dist/safety/runtime/polyfills.js +12 -0
  266. package/dist/safety/runtime/result-struct.d.ts +11 -0
  267. package/dist/safety/runtime/result-struct.js +98 -0
  268. package/dist/safety/runtime/safe-int.d.ts +33 -0
  269. package/dist/safety/runtime/safe-int.js +170 -0
  270. package/dist/safety/runtime/safe-traits.d.ts +4 -0
  271. package/dist/safety/runtime/safe-traits.js +95 -0
  272. package/dist/safety/runtime/safe-variable.d.ts +39 -0
  273. package/dist/safety/runtime/safe-variable.js +226 -0
  274. package/dist/safety/runtime/vote.d.ts +8 -0
  275. package/dist/safety/runtime/vote.js +92 -0
  276. package/dist/safety/runtime/write-verify.d.ts +8 -0
  277. package/dist/safety/runtime/write-verify.js +71 -0
  278. package/dist/safety/safe-int-types.d.ts +45 -0
  279. package/dist/safety/safe-int-types.js +25 -0
  280. package/dist/safety/safe-variable-types.d.ts +29 -0
  281. package/dist/safety/safe-variable-types.js +19 -0
  282. package/dist/safety/safety-bridge.d.ts +5 -6
  283. package/dist/safety/safety-bridge.js +15 -28
  284. package/dist/safety/sidecar-bridge.d.ts +1 -3
  285. package/dist/safety/sidecar-bridge.js +3 -20
  286. package/dist/safety/specifiers.d.ts +6 -0
  287. package/dist/safety/specifiers.js +14 -0
  288. package/dist/safety-hook.d.ts +8 -7
  289. package/dist/safety-hook.js +12 -13
  290. package/dist/testing.d.ts +5 -6
  291. package/dist/testing.js +5 -5
  292. package/dist/transpile/resolution.d.ts +1 -1
  293. package/dist/transpile/resolution.js +18 -9
  294. package/dist/transpile/test-pins.d.ts +18 -0
  295. package/dist/transpile/test-pins.js +142 -0
  296. package/dist/transpile.d.ts +1 -2
  297. package/dist/transpile.js +90 -29
  298. package/dist/types.d.ts +45 -26
  299. package/dist/ui-hook.d.ts +1 -1
  300. package/dist/utils/cli.d.ts +2 -2
  301. package/dist/utils/cli.js +160 -157
  302. package/dist/utils/fs.d.ts +3 -4
  303. package/dist/utils/fs.js +4 -5
  304. package/dist/utils/strings.d.ts +0 -1
  305. package/dist/utils/strings.js +0 -8
  306. package/dist/utils/ui.d.ts +5 -2
  307. package/dist/utils/ui.js +13 -3
  308. package/package.json +158 -149
  309. package/dist/add-preset.d.ts +0 -4
  310. package/dist/add-preset.js +0 -74
  311. package/dist/api/shared/async-symbol-detector.d.ts +0 -11
  312. package/dist/api/shared/async-symbol-detector.js +0 -140
  313. package/dist/api/shared/native-display-op-resolver.d.ts +0 -10
  314. package/dist/api/shared/native-display-op-resolver.js +0 -64
  315. package/dist/create/board-checklist.d.ts +0 -2
  316. package/dist/create/board-checklist.js +0 -52
  317. package/dist/create/board-codegen.d.ts +0 -9
  318. package/dist/create/board-codegen.js +0 -238
  319. package/dist/create/board-generators.d.ts +0 -12
  320. package/dist/create/board-generators.js +0 -651
  321. package/dist/create/board-spec.d.ts +0 -637
  322. package/dist/create/board-spec.js +0 -214
  323. package/dist/create/init-templates.d.ts +0 -28
  324. package/dist/create/init-wizard.d.ts +0 -8
  325. package/dist/create/init-wizard.js +0 -182
  326. package/dist/install/framework-catalog.d.ts +0 -53
  327. package/dist/install/framework-catalog.js +0 -107
  328. package/dist/install/handle-install.d.ts +0 -35
  329. package/dist/install/handle-install.js +0 -177
  330. package/dist/install/index.d.ts +0 -4
  331. package/dist/install/index.js +0 -3
  332. package/dist/ir/pin-state-tracking.d.ts +0 -58
  333. package/dist/ir/pin-state-tracking.js +0 -182
  334. package/dist/ir/pwm-timer-sharing.d.ts +0 -4
  335. package/dist/ir/pwm-timer-sharing.js +0 -94
  336. package/dist/ir/timer0-pwm-timing-conflict.d.ts +0 -4
  337. package/dist/ir/timer0-pwm-timing-conflict.js +0 -72
  338. package/dist/libdef/component-decls.d.ts +0 -2
  339. package/dist/libdef/component-decls.js +0 -6
  340. package/dist/libdef/component-discovery.d.ts +0 -43
  341. package/dist/libdef/component-discovery.js +0 -83
  342. package/dist/theme-tokens.d.ts +0 -22
  343. package/dist/theme-tokens.js +0 -172
@@ -2,17 +2,116 @@
2
2
  * Combined program analysis - single-pass detection of multiple features.
3
3
  *
4
4
  * Instead of traversing the IR multiple times for different checks
5
- * (hasConsoleCalls, hasArrayInObjectLiteral, hasThrowStatements, etc.),
5
+ * (hasArrayInObjectLiteral, hasThrowStatements, etc.),
6
6
  * this module performs all checks in a single traversal.
7
7
  */
8
8
  import { POLYFILL_HELPER_MAP } from "../api/shared/index.js";
9
9
  import { parseCppType } from "../api/shared/cpp-type-ir.js";
10
- import { loweredConsoleInCallback } from "./transformers/ui-callback-lowering.js";
11
10
  import { watchPinSpecs, clickHandlers } from "./transformers/ui-call-resolver.js";
12
11
  import { canvasBindings } from "./transformers/canvas-lowering.js";
13
12
  import { getInputBindings, getListBindings } from "./transformers/ui-reactive.js";
13
+ import { getTranspileResolvedHalOps } from "./build-ir-state.js";
14
+ /**
15
+ * Map one HAL op name onto the peripheral usage flags its lowering requires.
16
+ * Called from three places: the hal-expr expression case, the hal-op statement
17
+ * case, and analyzeProgram's merge of transpile-resolved ops (ops baked into
18
+ * another HAL method's emit lines never appear as IR nodes, so without the
19
+ * merge their peripheral's init block + include were dropped — e.g.
20
+ * `sense.readMillivolts()` inside `USB0.writeLine(...)` compiled against a
21
+ * missing adc.h). Keep in sync with the per-strategy gating in the frameworks.
22
+ */
23
+ function applyHalOpUsageFlags(opName, result) {
24
+ if (opName.startsWith("display.")) {
25
+ result.usesGPIO = true;
26
+ result.usesDisplay = true;
27
+ }
28
+ if (opName.startsWith("gpio."))
29
+ result.usesGPIO = true;
30
+ if (opName === "gpio.read")
31
+ result.usesDigitalRead = true;
32
+ if (opName.startsWith("pwm."))
33
+ result.usesPWM = true;
34
+ if (opName.startsWith("rmt."))
35
+ result.usesRmt = true;
36
+ if (opName.startsWith("adc."))
37
+ result.usesADC = true;
38
+ if (opName.startsWith("dac."))
39
+ result.usesDAC = true;
40
+ if (opName.startsWith("wdt."))
41
+ result.usesWdt = true;
42
+ if (opName.startsWith("spi."))
43
+ result.usesSPI = true;
44
+ if (opName.startsWith("i2c."))
45
+ result.usesI2C = true;
46
+ if (opName.startsWith("uart."))
47
+ result.usesUart = true;
48
+ if (opName.startsWith("usb."))
49
+ result.usesUsb = true;
50
+ // Safety HAL ops (@typecad/safety) — map each op to the __tc_safety_*
51
+ // polyfill helper it triggers, so the mode-table and voter polyfills
52
+ // survive tree-shaking when actually used. Matches the resolveSafetyOp
53
+ // output naming. Cast through string because the HALOpIR operation union is
54
+ // closed and doesn't include safety.* ops (those are owned by the optional
55
+ // @typecad/safety package).
56
+ const safetyOpName = opName;
57
+ if (safetyOpName === "safety.record_pin_mode") {
58
+ result.usedPolyfillHelpers.add("__tc_safety_record_pin_mode");
59
+ }
60
+ if (safetyOpName === "safety.read_safe") {
61
+ result.usedPolyfillHelpers.add("__tc_safety_read_safe");
62
+ }
63
+ if (safetyOpName === "safety.write_verify") {
64
+ result.usedPolyfillHelpers.add("__tc_safety_write_verify");
65
+ }
66
+ if (opName.startsWith("interrupt."))
67
+ result.usesInterrupts = true;
68
+ if (opName.startsWith("pulse."))
69
+ result.usesPulse = true;
70
+ if (opName.startsWith("shift."))
71
+ result.usesShift = true;
72
+ if (opName.startsWith("wifi.")) {
73
+ result.usesWifi = true;
74
+ if (opName === "wifi.join" || opName === "wifi.connect_start" || opName === "wifi.disconnect") {
75
+ result.usesWifiConnect = true;
76
+ if (opName === "wifi.join")
77
+ result.usesWifiConnectBlocking = true;
78
+ }
79
+ else if (opName.startsWith("wifi.scan"))
80
+ result.usesWifiScan = true;
81
+ else if (opName === "wifi.is_connected" || opName === "wifi.local_ip" || opName === "wifi.rssi" || opName === "wifi.mac")
82
+ result.usesWifiQuery = true;
83
+ else if (opName === "wifi.on_event")
84
+ result.usesWifiConfig = true;
85
+ }
86
+ if (opName.startsWith("http."))
87
+ result.usesHttp = true;
88
+ if (opName.startsWith("ble."))
89
+ result.usesBle = true;
90
+ if (opName.startsWith("preferences."))
91
+ result.usesPreferences = true;
92
+ if (opName.startsWith("random."))
93
+ result.usesRandom = true;
94
+ if (opName.startsWith("fs."))
95
+ result.usesFS = true;
96
+ if (opName.startsWith("mdns."))
97
+ result.usesMdns = true;
98
+ if (opName.startsWith("mqtt."))
99
+ result.usesMqtt = true;
100
+ if (opName.startsWith("ota."))
101
+ result.usesOta = true;
102
+ if (opName.startsWith("temp."))
103
+ result.usesTemp = true;
104
+ if (opName.startsWith("sensor."))
105
+ result.usesSensor = true;
106
+ if (opName.startsWith("hwtimer.") || opName.startsWith("counter."))
107
+ result.usesHwtimer = true;
108
+ if (opName.startsWith("capacitive."))
109
+ result.usesCapacitive = true;
110
+ }
14
111
  // 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/;
112
+ // Both the lowered form (std::<fn>) and the source form (Math.<fn>) — the
113
+ // analysis can see either depending on when expressions render.
114
+ const MATH_PATTERN = /\b(?:std::|Math\.)(floor|ceil|round|trunc|sqrt|pow|sin|cos|tan|asin|acos|atan|abs|max|min)\b/;
16
115
  /**
17
116
  * Analyze an expression for all features in a single pass.
18
117
  */
@@ -38,20 +137,6 @@ function analyzeExpression(expr, result, strategy) {
38
137
  }
39
138
  }
40
139
  }
41
- // Timer polyfill sizing — Timing.setInterval/Timing.setTimeout in
42
- // expression position (e.g. `const id = Timing.setInterval(...)`) lower to
43
- // a raw expression whose value contains `__tc_setInterval(...)`. The
44
- // callee-based counter in the "call" case only fires for bare timer
45
- // calls; without this the timer_methods polyfill is gated off and the
46
- // link fails: "'__tc_setInterval' was not declared in this scope".
47
- {
48
- const intervals = expr.value.match(/__tc_setInterval\s*\(/g);
49
- if (intervals)
50
- result.timerCallCount += intervals.length;
51
- const timeouts = expr.value.match(/__tc_setTimeout\s*\(/g);
52
- if (timeouts)
53
- result.timerCallCount += timeouts.length;
54
- }
55
140
  if (/\bString\s*\(/.test(expr.value)) {
56
141
  result.usesStringConversion = true;
57
142
  }
@@ -106,9 +191,6 @@ function analyzeExpression(expr, result, strategy) {
106
191
  }
107
192
  break;
108
193
  case "method-call":
109
- if (strategy.isConsoleCall(expr.callee)) {
110
- result.hasConsoleCalls = true;
111
- }
112
194
  if (/\bmillis\b/.test(expr.callee) || /\bdelay\b/.test(expr.callee) || /\bmicros\b/.test(expr.callee)) {
113
195
  result.usesMillis = true;
114
196
  }
@@ -150,7 +232,7 @@ function analyzeExpression(expr, result, strategy) {
150
232
  result.usesWDT = true;
151
233
  }
152
234
  // Native AVR peripheral usage from namespace-prefixed method calls
153
- // (Serial.* / SPI.* / Wire.* / EEPROM.*). The HAL resolver lowers these
235
+ // (Serial.* / SPI.* / Wire.*). The HAL resolver lowers these
154
236
  // to structured hal-ops (detected in analyzeStatement) OR to bare
155
237
  // lowered calls; these checks cover the pre-lowering and direct forms.
156
238
  if (expr.callee.startsWith("Serial.") || expr.callee === "Serial") {
@@ -162,9 +244,6 @@ function analyzeExpression(expr, result, strategy) {
162
244
  if (expr.callee.startsWith("Wire.") || expr.callee === "Wire") {
163
245
  result.usesI2C = true;
164
246
  }
165
- if (expr.callee.startsWith("EEPROM.") || expr.callee === "EEPROM") {
166
- result.usesEEPROM = true;
167
- }
168
247
  // map()/constrain() Arduino-API calls appear as method-call exprs
169
248
  // (callee "map"/"constrain"). framework-avr lowers these to _native_map/
170
249
  // _native_constrain via symbol aliases, so the helpers are dead code
@@ -173,12 +252,6 @@ function analyzeExpression(expr, result, strategy) {
173
252
  result.usesMap = true;
174
253
  if (expr.callee === "constrain")
175
254
  result.usesConstrain = true;
176
- // Count setInterval/setTimeout call sites (post-rename callee names) so
177
- // __tc_TimerRuntime::MAX_TIMERS can be sized to the observed count.
178
- if (expr.callee === "__tc_setInterval" || expr.callee === "__tc_setTimeout"
179
- || expr.callee === "setInterval" || expr.callee === "setTimeout") {
180
- result.timerCallCount++;
181
- }
182
255
  for (const arg of expr.args) {
183
256
  analyzeExpression(arg, result, strategy);
184
257
  }
@@ -271,98 +344,11 @@ function analyzeExpression(expr, result, strategy) {
271
344
  // a value-returning HAL op used in a var-init or expression context fails
272
345
  // to set its analysis flag — the framework then drops the matching init
273
346
  // block + forced includes (e.g. __tc_adc_read was emitted but the
274
- // CUTTLEFISH_ADC init block and adc_oneshot.h include were not). Keep this
275
- // list in sync with the hal-op statement case at the bottom of this file.
347
+ // CUTTLEFISH_ADC init block and adc_oneshot.h include were not). Both
348
+ // this case and the hal-op statement case delegate to
349
+ // applyHalOpUsageFlags, which also covers transpile-resolved ops.
276
350
  if (expr.operation && typeof expr.operation.operation === "string") {
277
- const opName = expr.operation.operation;
278
- if (opName.startsWith("display.")) {
279
- result.usesGPIO = true;
280
- result.usesDisplay = true;
281
- }
282
- if (opName.startsWith("gpio."))
283
- result.usesGPIO = true;
284
- if (opName === "gpio.read")
285
- result.usesDigitalRead = true;
286
- if (opName.startsWith("pwm."))
287
- result.usesPWM = true;
288
- if (opName.startsWith("rmt."))
289
- result.usesRmt = true;
290
- if (opName.startsWith("adc."))
291
- result.usesADC = true;
292
- if (opName.startsWith("dac."))
293
- result.usesDAC = true;
294
- if (opName.startsWith("power."))
295
- result.usesPower = true;
296
- if (opName.startsWith("wdt."))
297
- result.usesWdt = true;
298
- // Safety HAL ops (@typecad/safety) — map each op to the
299
- // __tc_safety_* polyfill helper it triggers, so the mode-table and
300
- // voter polyfills survive tree-shaking when actually used. Matches
301
- // the resolveSafetyOp output naming. Cast through string because the
302
- // HALOpIR operation union is closed and doesn't include safety.* ops
303
- // (those are owned by the optional @typecad/safety package).
304
- const safetyOpName = opName;
305
- if (safetyOpName === "safety.record_pin_mode") {
306
- result.usedPolyfillHelpers.add("__tc_safety_record_pin_mode");
307
- }
308
- if (safetyOpName === "safety.read_safe") {
309
- result.usedPolyfillHelpers.add("__tc_safety_read_safe");
310
- }
311
- if (safetyOpName === "safety.write_verify") {
312
- result.usedPolyfillHelpers.add("__tc_safety_write_verify");
313
- }
314
- if (opName.startsWith("interrupt."))
315
- result.usesInterrupts = true;
316
- if (opName.startsWith("pulse."))
317
- result.usesPulse = true;
318
- if (opName.startsWith("shift."))
319
- result.usesShift = true;
320
- if (opName.startsWith("tone."))
321
- result.usesTone = true;
322
- if (opName.startsWith("i2c."))
323
- result.usesI2C = true;
324
- if (opName.startsWith("spi."))
325
- result.usesSPI = true;
326
- if (opName.startsWith("uart."))
327
- result.usesUart = true;
328
- if (opName.startsWith("wifi.")) {
329
- result.usesWifi = true;
330
- if (opName === "wifi.connect" || opName === "wifi.connect_start" || opName === "wifi.disconnect") {
331
- result.usesWifiConnect = true;
332
- if (opName === "wifi.connect")
333
- result.usesWifiConnectBlocking = true;
334
- }
335
- else if (opName.startsWith("wifi.scan"))
336
- result.usesWifiScan = true;
337
- else if (opName === "wifi.status" || opName === "wifi.local_ip" || opName === "wifi.rssi" || opName === "wifi.mac")
338
- result.usesWifiQuery = true;
339
- else if (opName === "wifi.set_hostname")
340
- result.usesWifiConfig = true;
341
- }
342
- if (opName.startsWith("http."))
343
- result.usesHttp = true;
344
- if (opName.startsWith("ble."))
345
- result.usesBle = true;
346
- if (opName.startsWith("preferences."))
347
- result.usesPreferences = true;
348
- if (opName.startsWith("random."))
349
- result.usesRandom = true;
350
- if (opName.startsWith("fs."))
351
- result.usesFS = true;
352
- if (opName.startsWith("mdns."))
353
- result.usesMdns = true;
354
- if (opName.startsWith("mqtt."))
355
- result.usesMqtt = true;
356
- if (opName.startsWith("ota."))
357
- result.usesOta = true;
358
- if (opName.startsWith("temp."))
359
- result.usesTemp = true;
360
- if (opName.startsWith("hwtimer."))
361
- result.usesHwtimer = true;
362
- if (opName.startsWith("capacitive."))
363
- result.usesCapacitive = true;
364
- if (opName.startsWith("worker."))
365
- result.usesWorker = true;
351
+ applyHalOpUsageFlags(expr.operation.operation, result);
366
352
  }
367
353
  break;
368
354
  }
@@ -376,9 +362,6 @@ function analyzeStatement(statement, result, strategy) {
376
362
  }
377
363
  switch (statement.kind) {
378
364
  case "call":
379
- if (strategy.isConsoleCall(statement.callee)) {
380
- result.hasConsoleCalls = true;
381
- }
382
365
  if (statement.callee === "Serial.begin" || statement.callee.endsWith(".begin")) {
383
366
  result.hasSerialBegin = true;
384
367
  }
@@ -403,6 +386,17 @@ function analyzeStatement(statement, result, strategy) {
403
386
  if (statement.callee === "__tc_print" || statement.callee === "__tc_println") {
404
387
  result.usedPolyfillHelpers.add(statement.callee);
405
388
  }
389
+ // emit()/rawCpp() statements (__EMIT__) carry verbatim C++ in string
390
+ // args — the raw-text regex below never sees them (the arg is a string
391
+ // IR node, not raw text). Scan them for the printf family so a debug
392
+ // build (or any rawCpp'd stdio call) pulls in <cstdio>.
393
+ if (statement.callee === "__EMIT__") {
394
+ for (const arg of statement.args) {
395
+ if (arg.kind === "string" && /\b(printf|fprintf|sprintf|snprintf|getchar|putchar|puts)\s*\(/.test(arg.value)) {
396
+ result.usesCstdio = true;
397
+ }
398
+ }
399
+ }
406
400
  // Namespace-qualified polyfill entry points used as bare call statements
407
401
  // (e.g. `Timing.delay(5);`). The expression-level analyzer (case
408
402
  // "method-call") already checks these prefixes, but a statement-form call
@@ -419,15 +413,10 @@ function analyzeStatement(statement, result, strategy) {
419
413
  if (statement.callee.startsWith("WDT.") || statement.callee === "WDT") {
420
414
  result.usesWDT = true;
421
415
  }
422
- // Native AVR peripheral usage from statement-form calls. tone()/noTone()
423
- // are bare Arduino-API calls; console.* / Serial.* drive UART; the
424
- // namespace prefixes mirror the method-call checks above.
425
- if (statement.callee === "tone" || statement.callee === "noTone") {
426
- result.usesTone = true;
427
- }
428
- // console.* is NOT UART: on ESP-IDF it lowers to printf, on Arduino to
429
- // Serial via hasConsoleCalls. Only real UART HAL / Serial peripheral
430
- // usage should gate the uart shim (avoids unused __tc_uart*_init).
416
+ // Native AVR peripheral usage from statement-form calls. Serial.* drives
417
+ // UART; the namespace prefixes mirror the method-call checks above.
418
+ // Only real UART HAL / Serial peripheral usage should gate the uart shim
419
+ // (avoids unused __tc_uart*_init).
431
420
  if (statement.callee.startsWith("_uart_")) {
432
421
  result.usesUart = true;
433
422
  }
@@ -440,26 +429,11 @@ function analyzeStatement(statement, result, strategy) {
440
429
  if (statement.callee.startsWith("Wire.") || statement.callee === "Wire") {
441
430
  result.usesI2C = true;
442
431
  }
443
- if (statement.callee.startsWith("EEPROM.") || statement.callee === "EEPROM") {
444
- result.usesEEPROM = true;
445
- }
446
432
  // Statement-form map()/constrain() mirror the method-call checks above.
447
433
  if (statement.callee === "map")
448
434
  result.usesMap = true;
449
435
  if (statement.callee === "constrain")
450
436
  result.usesConstrain = true;
451
- // Statement-form setInterval/setTimeout mirror the expression-level
452
- // timer-count (analyzeExpression). A top-level `setInterval(...)` call
453
- // stays a `call` statement (never becomes a method-call expression — see
454
- // the comment above re: Timing./Num./WDT.), so without this mirror the
455
- // timer polyfill gate (timerCallCount) stays 0 and __tc_setInterval is
456
- // emitted as a call but never defined (demo: "'__tc_setInterval' was not
457
- // declared in this scope"). The arrow-callback hoister renames the callee
458
- // to __tc_setInterval/__tc_setTimeout, so check both pre- and post-rename.
459
- if (statement.callee === "setInterval" || statement.callee === "setTimeout"
460
- || statement.callee === "__tc_setInterval" || statement.callee === "__tc_setTimeout") {
461
- result.timerCallCount++;
462
- }
463
437
  // The HAL resolver lowers WDT.*/Timing.* namespace calls to bare AVR
464
438
  // library functions (WDT.reset() → wdt_reset(), Timing.delay() → delay(),
465
439
  // Timing.millis() → millis()). When that happens the `WDT.`/`Timing.`
@@ -487,27 +461,6 @@ function analyzeStatement(statement, result, strategy) {
487
461
  }
488
462
  }
489
463
  }
490
- // Timer polyfill sizing for __EMIT__ statements (callee "__EMIT__"):
491
- // Timing.setInterval/Timing.setTimeout can lower to an __EMIT__ call whose
492
- // single string arg is the raw C++ payload, e.g.
493
- // `return __tc_setInterval(<cb>, 500)`. The callee-based timer counter
494
- // above only fires for bare setInterval/__tc_setInterval calls, so without
495
- // this the timer_methods polyfill is gated off and the link fails:
496
- // "'__tc_setInterval' was not declared in this scope". Count call sites
497
- // embedded in the raw payload. (The hal-op raw-code path has a parallel
498
- // counter below.)
499
- if (statement.callee === "__EMIT__") {
500
- for (const arg of statement.args) {
501
- if (arg && arg.kind === "string" && typeof arg.value === "string") {
502
- const matches = arg.value.match(/__tc_setInterval\s*\(/g);
503
- if (matches)
504
- result.timerCallCount += matches.length;
505
- const timeouts = arg.value.match(/__tc_setTimeout\s*\(/g);
506
- if (timeouts)
507
- result.timerCallCount += timeouts.length;
508
- }
509
- }
510
- }
511
464
  for (const arg of statement.args) {
512
465
  analyzeExpression(arg, result, strategy);
513
466
  }
@@ -612,116 +565,7 @@ function analyzeStatement(statement, result, strategy) {
612
565
  // always be emitted. Same blind spot the wdt.* fix below the raw-code
613
566
  // block addresses for the watchdog.
614
567
  if (statement.operation && typeof statement.operation.operation === "string") {
615
- const opName = statement.operation.operation;
616
- if (opName.startsWith("spi."))
617
- result.usesSPI = true;
618
- if (opName.startsWith("i2c."))
619
- result.usesI2C = true;
620
- if (opName.startsWith("tone."))
621
- result.usesTone = true;
622
- if (opName.startsWith("uart."))
623
- result.usesUart = true;
624
- // Display HAL ops (display.init from ui.mount, display.flush per frame)
625
- // always imply GPIO usage (CS/DC/RST pins). Native SPI/I2C display
626
- // adapters emit their own transport #includes (driver/spi_master.h,
627
- // driver/i2c_master.h) — we don't force usesSPI/usesI2C here because
628
- // that would pull headers even for non-display SPI/I2C code, and the
629
- // display's transport type can't be determined from the op alone.
630
- if (opName.startsWith("display.")) {
631
- result.usesGPIO = true;
632
- result.usesDisplay = true;
633
- }
634
- // ESP32 peripheral usage — framework-esp32 gates IDF driver blocks
635
- // and forced includes on these. No-op for other frameworks (their
636
- // shimLines emit no CUTTLEFISH_* blocks with these marker names).
637
- if (opName.startsWith("gpio."))
638
- result.usesGPIO = true;
639
- if (opName === "gpio.read")
640
- result.usesDigitalRead = true;
641
- if (opName.startsWith("pwm."))
642
- result.usesPWM = true;
643
- if (opName.startsWith("rmt."))
644
- result.usesRmt = true;
645
- if (opName.startsWith("adc."))
646
- result.usesADC = true;
647
- if (opName.startsWith("dac."))
648
- result.usesDAC = true;
649
- if (opName.startsWith("power."))
650
- result.usesPower = true;
651
- if (opName.startsWith("wdt."))
652
- result.usesWdt = true;
653
- // Safety HAL ops (@typecad/safety) — map each op to the
654
- // __tc_safety_* polyfill helper it triggers, so the mode-table and
655
- // voter polyfills survive tree-shaking when actually used. Matches
656
- // the resolveSafetyOp output naming. Cast through string because the
657
- // HALOpIR operation union is closed and doesn't include safety.* ops
658
- // (those are owned by the optional @typecad/safety package).
659
- const safetyOpName = opName;
660
- if (safetyOpName === "safety.record_pin_mode") {
661
- result.usedPolyfillHelpers.add("__tc_safety_record_pin_mode");
662
- }
663
- if (safetyOpName === "safety.read_safe") {
664
- result.usedPolyfillHelpers.add("__tc_safety_read_safe");
665
- }
666
- if (safetyOpName === "safety.write_verify") {
667
- result.usedPolyfillHelpers.add("__tc_safety_write_verify");
668
- }
669
- if (opName.startsWith("interrupt."))
670
- result.usesInterrupts = true;
671
- if (opName.startsWith("pulse."))
672
- result.usesPulse = true;
673
- if (opName.startsWith("shift."))
674
- result.usesShift = true;
675
- if (opName.startsWith("wifi.")) {
676
- result.usesWifi = true;
677
- if (opName === "wifi.connect" || opName === "wifi.connect_start" || opName === "wifi.disconnect") {
678
- result.usesWifiConnect = true;
679
- if (opName === "wifi.connect")
680
- result.usesWifiConnectBlocking = true;
681
- }
682
- else if (opName.startsWith("wifi.scan"))
683
- result.usesWifiScan = true;
684
- else if (opName === "wifi.status" || opName === "wifi.local_ip" || opName === "wifi.rssi" || opName === "wifi.mac")
685
- result.usesWifiQuery = true;
686
- else if (opName === "wifi.set_hostname")
687
- result.usesWifiConfig = true;
688
- }
689
- if (opName.startsWith("http."))
690
- result.usesHttp = true;
691
- if (opName.startsWith("ble."))
692
- result.usesBle = true;
693
- if (opName.startsWith("preferences."))
694
- result.usesPreferences = true;
695
- if (opName.startsWith("random."))
696
- result.usesRandom = true;
697
- if (opName.startsWith("fs."))
698
- result.usesFS = true;
699
- if (opName.startsWith("mdns."))
700
- result.usesMdns = true;
701
- if (opName.startsWith("mqtt."))
702
- result.usesMqtt = true;
703
- if (opName.startsWith("ota."))
704
- result.usesOta = true;
705
- if (opName.startsWith("temp."))
706
- result.usesTemp = true;
707
- if (opName.startsWith("hwtimer."))
708
- result.usesHwtimer = true;
709
- if (opName.startsWith("capacitive."))
710
- result.usesCapacitive = true;
711
- if (opName.startsWith("worker."))
712
- result.usesWorker = true;
713
- // Timing HAL ops (timing.delay/millis/micros) carry a typed operation
714
- // name, not raw code, so the regex scans below miss them. Mirror the
715
- // raw-code timing detection here so usesMillis/usesTiming (and thus
716
- // usesNativeTiming) fire for `delay()`/`millis()` on AVR.
717
- if (opName === "timing.delay" || opName === "timing.delay_microseconds"
718
- || opName === "timing.millis" || opName === "timing.micros") {
719
- result.usesTiming = true;
720
- result.usesMillis = true;
721
- }
722
- if (opName === "timing.millis" || opName === "timing.micros") {
723
- result.usesWallClock = true;
724
- }
568
+ applyHalOpUsageFlags(statement.operation.operation, result);
725
569
  }
726
570
  // Scan raw C++ code in HAL ops for polyfill helper usage
727
571
  if (statement.operation && statement.operation.operation === "raw" && typeof statement.operation.code === "string") {
@@ -759,29 +603,8 @@ function analyzeStatement(statement, result, strategy) {
759
603
  if (code.includes("__tc_print(")) {
760
604
  result.usedPolyfillHelpers.add("__tc_print");
761
605
  }
762
- // Timer polyfill sizing `Timing.setInterval(...)` / `Timing.setTimeout(...)`
763
- // are resolved by the HAL method resolver, which reads TimingClass's
764
- // rawCpp body and emits a raw hal-op whose code is e.g.
765
- // `return __tc_setInterval(<cb>, 500)`. The callee-based counter below
766
- // (statement.callee === "__tc_setInterval") never fires for these — the
767
- // statement is a hal-op, not a bare timer call — so without counting
768
- // here the timer_methods polyfill is gated off (timerCallCount == 0)
769
- // and the link fails: "'__tc_setInterval' was not declared in this
770
- // scope". Count each __tc_setInterval/__tc_setTimeout call site in the
771
- // raw code. The optional `return ` prefix is emitted by value-returning
772
- // HAL methods (statement context), so match with or without it.
773
- const intervalSites = code.match(/__tc_setInterval\s*\(/g);
774
- if (intervalSites)
775
- result.timerCallCount += intervalSites.length;
776
- const timeoutSites = code.match(/__tc_setTimeout\s*\(/g);
777
- if (timeoutSites)
778
- result.timerCallCount += timeoutSites.length;
779
- // Native AVR peripheral usage inside raw hal-op code (e.g. the
780
- // EEPROM namespace lowers to `EEPROM.write(...)` in a raw hal-op;
781
- // Serial/SPI/Wire may appear as lowered library calls too).
782
- if (/\bEEPROM\b/.test(code) || /\beeprom_(read|write|update)_byte\b/.test(code)) {
783
- result.usesEEPROM = true;
784
- }
606
+ // Native AVR peripheral usage inside raw hal-op code (Serial/SPI/Wire
607
+ // may appear as lowered library calls).
785
608
  if (/\bSerial\b/.test(code)) {
786
609
  result.usesUart = true;
787
610
  }
@@ -820,7 +643,6 @@ function analyzeStatement(statement, result, strategy) {
820
643
  */
821
644
  export function analyzeProgram(program, strategy) {
822
645
  const result = {
823
- hasConsoleCalls: false,
824
646
  hasArrayInObjectLiteral: false,
825
647
  hasThrowStatements: false,
826
648
  hasStdMathCalls: false,
@@ -840,23 +662,20 @@ export function analyzeProgram(program, strategy) {
840
662
  usesWDT: false,
841
663
  usesStrPtr: false,
842
664
  usesUart: false,
665
+ usesUsb: false,
843
666
  usesSPI: false,
844
667
  usesI2C: false,
845
- usesEEPROM: false,
846
- usesTone: false,
847
668
  usesMap: false,
848
669
  usesConstrain: false,
849
670
  usesNativeTiming: false,
850
671
  hasSerialBegin: false,
851
672
  hasGenerators: false,
852
673
  usesStdMap: false,
853
- timerCallCount: 0,
854
674
  usesGPIO: false,
855
675
  usesPWM: false,
856
676
  usesRmt: false,
857
677
  usesADC: false,
858
678
  usesDAC: false,
859
- usesPower: false,
860
679
  usesWdt: false,
861
680
  usesInterrupts: false,
862
681
  usesPulse: false,
@@ -876,9 +695,9 @@ export function analyzeProgram(program, strategy) {
876
695
  usesMqtt: false,
877
696
  usesOta: false,
878
697
  usesTemp: false,
698
+ usesSensor: false,
879
699
  usesHwtimer: false,
880
700
  usesCapacitive: false,
881
- usesWorker: false,
882
701
  hasAsync: false,
883
702
  usesSet: false,
884
703
  usesAlgorithm: false,
@@ -1003,7 +822,7 @@ export function analyzeProgram(program, strategy) {
1003
822
  // Analyze UI callback bodies that live outside program.functions
1004
823
  // (onClick / watchPin / drawCanvas / bindInput / bindList). They now carry
1005
824
  // StatementIR[] from the main lowerStatementList pipeline, so console /
1006
- // helper usage is visible here the same way setInterval bodies are.
825
+ // helper usage is visible here the same way nested-function bodies are.
1007
826
  for (const wp of watchPinSpecs()) {
1008
827
  for (const stmt of wp.bodyStatements ?? [])
1009
828
  analyzeStatement(stmt, result, strategy);
@@ -1028,27 +847,25 @@ export function analyzeProgram(program, strategy) {
1028
847
  for (const stmt of spec.tapStatements ?? [])
1029
848
  analyzeStatement(stmt, result, strategy);
1030
849
  }
1031
- // Console calls lowered inside leftover string-baked UI callbacks are baked
1032
- // into callbackBody strings, not IR nodes, so the statement walk above can't
1033
- // see them. Consult the flag recorded during lowering so hasConsoleCalls
1034
- // reflects them this is what gates auto-injected Serial.begin(baud) and
1035
- // <iostream>.
1036
- if (loweredConsoleInCallback()) {
1037
- result.hasConsoleCalls = true;
850
+ // HAL ops the transpiler resolved to C++ text while inlining one HAL method
851
+ // inside another (e.g. `sense.readMillivolts()` in a USB0.writeLine template)
852
+ // never appear as hal-op/hal-expr IR nodes, so the walks above can't see
853
+ // them. The lowering seams record every op they resolve; merge their
854
+ // peripheral flags here.
855
+ for (const opName of getTranspileResolvedHalOps()) {
856
+ applyHalOpUsageFlags(opName, result);
1038
857
  }
1039
858
  // Derive the comprehensive native-timing gate for the AVR millis() Timer0
1040
859
  // ISR. The ISR is needed whenever the program touches the soft clock
1041
- // directly (millis/delay/micros) OR has a hidden consumer: setInterval/
1042
- // setTimeout (the scheduler polls millis), or async functions (the runtime
1043
- // polls millis). The per-frame UI tick is injected by the emitter, not
1044
- // present in user source the setup emitter ORs entryHasUI() in at the
1045
- // consume site. Without this gate, every AVR program pulled in the Timer0
1046
- // ISR even when it never uses timing.
860
+ // directly (millis/delay/micros) OR has a hidden consumer: async functions
861
+ // (the runtime polls millis). The per-frame UI tick is injected by the
862
+ // emitter, not present in user source the setup emitter ORs entryHasUI()
863
+ // in at the consume site. Without this gate, every AVR program pulled in
864
+ // the Timer0 ISR even when it never uses timing.
1047
865
  const hasAsync = program.functions.some(fn => fn.isAsync);
1048
866
  result.hasAsync = hasAsync;
1049
867
  result.usesNativeTiming = result.usesMillis
1050
868
  || result.usesTiming
1051
- || result.timerCallCount > 0
1052
869
  || hasAsync;
1053
870
  return result;
1054
871
  }