@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
@@ -4,6 +4,7 @@
4
4
  // Checks that pins configured with inputPullDown() actually support
5
5
  // hardware pulldown on the target board. Emits a compile-time error if not.
6
6
  // ---------------------------------------------------------------------------
7
+ import { pinEntryIndexForNumber } from './pin-capability-validation.js';
7
8
  /**
8
9
  * Validate that pins used with inputPullDown() support pulldown on this board.
9
10
  */
@@ -13,9 +14,14 @@ export function validatePulldownSupport(usage, boardConstants, filePath) {
13
14
  return diagnostics;
14
15
  }
15
16
  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`);
17
+ // Check the pin's own pullDown capability from board definition.
18
+ // undefined or false both mean pulldown is not supported on this pin.
19
+ // The entry is resolved by pin NUMBER — the pins.all array index diverges
20
+ // from the number on MCUs with unbonded pads (see pinEntryIndexForNumber).
21
+ const entryIdx = pinEntryIndexForNumber(pinNumber, boardConstants);
22
+ if (entryIdx < 0)
23
+ continue; // Unknown pin — the emitter's own resolution reports it.
24
+ const supportsPullDown = boardConstants?.get(`pins.all.${entryIdx}.capabilities.pullDown`);
19
25
  if (supportsPullDown !== true) {
20
26
  const pinName = getPinName(pinNumber, boardConstants);
21
27
  const arch = boardConstants?.get('architecture');
@@ -39,7 +45,8 @@ function getPinName(pinNumber, boardConstants) {
39
45
  return `A${pinNumber - 14}`;
40
46
  return `D${pinNumber}`;
41
47
  }
42
- const name = boardConstants.get(`pins.all.${pinNumber}.name`);
48
+ const entryIdx = pinEntryIndexForNumber(pinNumber, boardConstants);
49
+ const name = entryIdx >= 0 ? boardConstants.get(`pins.all.${entryIdx}.name`) : undefined;
43
50
  if (typeof name === 'string')
44
51
  return name;
45
52
  // Fallback naming
@@ -125,10 +125,22 @@ function isPinUsedAsGpio(pinName, pinNumber, usage) {
125
125
  return false;
126
126
  }
127
127
  function isPeripheralActive(type, instance, usage) {
128
+ // When the program's ops identify WHICH controller instances are used, only
129
+ // those instances claim pins. The old `usage.i2c || ...` disjunct claimed
130
+ // every instance's pins whenever the bus type appeared at all — on boards
131
+ // whose alternate-bus pin sets overlap another bus's (the blackpill's
132
+ // i2c-alt on PB3/PB4 shares pins with spi2), that manufactured phantom
133
+ // peripheral-peripheral conflicts. The bare-type fallback only applies when
134
+ // NO instance information was recorded (degenerate programs whose ops carry
135
+ // no instance), preserving the conservative claim where it's the only
136
+ // signal available.
128
137
  switch (type) {
129
- case 'i2c': return usage.i2c || usage.i2cInstancesUsed.has(instance);
130
- case 'spi': return usage.spi || usage.spiInstancesUsed.has(instance);
131
- case 'uart': return usage.uart || usage.uartInstancesUsed.has(instance);
138
+ case 'i2c':
139
+ return usage.i2cInstancesUsed.size > 0 ? usage.i2cInstancesUsed.has(instance) : usage.i2c;
140
+ case 'spi':
141
+ return usage.spiInstancesUsed.size > 0 ? usage.spiInstancesUsed.has(instance) : usage.spi;
142
+ case 'uart':
143
+ return usage.uartInstancesUsed.size > 0 ? usage.uartInstancesUsed.has(instance) : usage.uart;
132
144
  default: return false;
133
145
  }
134
146
  }
@@ -3,7 +3,6 @@ import { isStringEnum } from "../api/shared/index.js";
3
3
  import { extractNodeComments, makeDiagnostic, makeSourceSpan } from "./ast-node-utils.js";
4
4
  import { isCompileTimeOnlyCallName, isCompileTimeOnlyClassName } from "./compile-time-only.js";
5
5
  import { TYPED_ARRAY_ELEMENT_MAP, hoistedNestedEnums, hoistedNestedInterfaces, hoistedNestedTypeAliases, nestedFunctionAliases, nestedClassAliases, mutableArrayVars, arrayLiteralSizes, activeEnumNames, activeStringEnumNames, resetFunctionScopeState } from "./build-ir-state.js";
6
- import { isPinFoldingEnabled, setPinFoldingEnabled, invalidatePinLevels } from "./pin-state-tracking.js";
7
6
  import { getCurrentIrTypeScope, bindIrTypeScopeLocals } from "./symbol-types.js";
8
7
  import { renderExprAsText } from "./render-expr.js";
9
8
  import { expressionToIR } from "./expression-to-ir.js";
@@ -184,9 +183,6 @@ export function lowerStatementList(statements, fileName, sourceText, diagnostics
184
183
  // top-level levels afterwards. "" and "<top-level>" are the top-level
185
184
  // markers; everything else names a function/method/lambda body.
186
185
  const isFunctionBodyCtx = functionNameForDiagnostics !== "" && functionNameForDiagnostics !== "<top-level>";
187
- const prevPinFolding = isPinFoldingEnabled();
188
- if (isFunctionBodyCtx)
189
- setPinFoldingEnabled(false);
190
186
  // Phase 1: Pre-scan for nested function declarations — register aliases only.
191
187
  // This ensures sibling functions can reference each other.
192
188
  for (const statement of statements) {
@@ -356,8 +352,6 @@ export function lowerStatementList(statements, fileName, sourceText, diagnostics
356
352
  nestedClassAliases.delete(name);
357
353
  }
358
354
  if (isFunctionBodyCtx) {
359
- setPinFoldingEnabled(prevPinFolding);
360
- invalidatePinLevels();
361
355
  }
362
356
  return lowered;
363
357
  }
@@ -87,7 +87,7 @@ export function validateBlockingDelayInLoop(program, strategy) {
87
87
  ? `Blocking delayMicroseconds() inside loop() is a busy-wait that wastes CPU cycles. ` +
88
88
  `On RTOS targets (ESP-IDF), prefer timing.delay() (vTaskDelay) which yields the CPU to other tasks.`
89
89
  : `Blocking delay() inside loop() freezes the async microtask queue and UI rendering ` +
90
- `for the delay duration. This causes display tearing and makes the sketch unresponsive.`;
90
+ `for the delay duration. This causes display tearing and makes the program unresponsive.`;
91
91
  const hint = isRtos
92
92
  ? `Replace delayMicroseconds with delay() if the timing permits, or accept the brief busy-wait if sub-millisecond precision is required.`
93
93
  : `Use the cooperative pattern instead: track elapsed time with millis() comparisons, ` +
@@ -229,9 +229,16 @@ export function tryLowerArrayAndStringMethods(expr, sourceText, diagnostics, poi
229
229
  //
230
230
  // Target gate: the __tc_* helpers are native/hosted-only (Arduino/embedded
231
231
  // lower arrays to StaticArray, caught by the mutableArrayVars branch above,
232
- // and have no __tc_* polyfills). requiresLoopFunction() is false exactly on
233
- // hosted targets the same set that ran the old native normalizeRawExpression.
234
- const isHostedTarget = !getContext().activeStrategy?.requiresLoopFunction();
232
+ // and have no __tc_* polyfills). Two signals compose: the target has no
233
+ // repeatedly-called loop() (requiresLoopFunction() false the historical
234
+ // proxy for "hosted"), AND it actually carries std::vector (getStdLibSupport
235
+ // ().hasVector). The second signal matters because a main()-entry RTOS
236
+ // target (Zephyr) also reports requiresLoopFunction()=false but lowers
237
+ // arrays to __tc_StaticArray — without the hasVector conjunct it would
238
+ // wrongly take the std::vector/.push_back path.
239
+ const strat = getContext().activeStrategy;
240
+ const isHostedTarget = !strat?.requiresLoopFunction()
241
+ && (strat?.getStdLibSupport?.().hasVector ?? true);
235
242
  if (isHostedTarget && ts.isPropertyAccessExpression(expr.expression)) {
236
243
  const methodName = expr.expression.name.text;
237
244
  // `push` lowers to native push_back (matches the old
@@ -403,8 +410,7 @@ function resolveReceiverCppType(receiverNode) {
403
410
  *
404
411
  * When the element type is integral and the arg is a numeric-enum value, wrap
405
412
  * the rendered arg in `static_cast<int>(...)`. Demo #32 Finding A. Mirrors the
406
- * SUPPORT_MATRIX §1.7 enum↔integral family fixed at the assign/var_decl sites
407
- * in the emit layer.
413
+ * enum↔integral family fixed at the assign/var_decl sites in the emit layer.
408
414
  */
409
415
  function renderPushArgForElement(argNode, receiverNode, sourceText, diagnostics, pointerVars) {
410
416
  const rendered = renderExprAsText(expressionToIR(argNode, sourceText, diagnostics, pointerVars));
@@ -1,7 +1,7 @@
1
1
  import ts from "typescript";
2
- import { requiredIncludes, mutableArrayVars, nestedClassAliases, hoistedNestedClasses, topLevelClassNames, topLevelClasses, activeEnumNames, hoistedNestedFunctions, getContext } from "../build-ir-state.js";
2
+ import { requiredIncludes, mutableArrayVars, nestedClassAliases, hoistedNestedClasses, topLevelClassNames, topLevelClasses, activeEnumNames } from "../build-ir-state.js";
3
3
  import { getCurrentIrTypeScope } from "../symbol-types.js";
4
- import { extractNodeComments, makeSourceSpan } from "../ast-node-utils.js";
4
+ import { extractNodeComments, makeSourceSpan, makeDiagnostic } from "../ast-node-utils.js";
5
5
  import { tryResolveHALMethod } from "./hal-call-resolver.js";
6
6
  import { tryResolveUICall, isSignalName, resolveUIModuleImport, recordPressBinding, uiPressBindings, resolveNodeIndex, resolveNodeTag, watchPinSpecs, recordWatchPin, recordClickHandler, clickHandlers, pushUnknownElementDiagnostic } from "./ui-call-resolver.js";
7
7
  import { hasSafetyHook, requireSafetyHook } from "../../safety-hook.js";
@@ -10,7 +10,6 @@ import { rewriteCanvasCall } from "./canvas-lowering.js";
10
10
  import { callbackContextLabel, unsupportedStatementHint } from "./callback-context-registry.js";
11
11
  import { tryLowerArrayAndStringMethods } from "./array-methods.js";
12
12
  import { expressionToIR } from "../expression-to-ir.js";
13
- import { lowerStatementList } from "../statement-to-ir.js";
14
13
  import { escapeCppKeyword } from "../../utils/strings.js";
15
14
  import { renderExprAsText, calleeToText } from "../render-expr.js";
16
15
  import { parseCppType, renderCppType, parsedIsPointer, parsedIsMap, parsedIsSet } from "../../api/shared/cpp-type-ir.js";
@@ -163,14 +162,7 @@ function tryResolveSafetyCallStatement(call, fileName, sourceText) {
163
162
  if (a.kind === ts.SyntaxKind.FalseKeyword)
164
163
  return false;
165
164
  if (ts.isIdentifier(a)) {
166
- const name = a.text;
167
- if (name === "INPUT")
168
- return 0;
169
- if (name === "OUTPUT")
170
- return 1;
171
- if (name === "INPUT_PULLUP")
172
- return 2;
173
- return name;
165
+ return a.text;
174
166
  }
175
167
  // Property access (e.g. r.value), arithmetic, or other expression:
176
168
  // render to the C++ expression text so the op can emit it inline.
@@ -188,16 +180,23 @@ function tryResolveSafetyCallStatement(call, fileName, sourceText) {
188
180
  }
189
181
  export function callToStatement(statementNode, call, fileName, sourceText, diagnostics, pointerVars = new Map()) {
190
182
  const comments = extractNodeComments(statementNode, sourceText);
191
- // ── setInterval/setTimeout arrow-callback hoisting (BEFORE HAL) ────────
192
- // The timer helpers are runtime utilities, never HAL methods, but the HAL
193
- // resolver treats bare-identifier globals as pseudo-HAL calls and claims
194
- // them baking the arrow arg into a lambda placeholder before our hoist
195
- // can run. Intercept timer calls with arrow callbacks FIRST, hoist the
196
- // arrow to a named function, and short-circuit before HAL sees it.
197
- if (ts.isIdentifier(call.expression) && TIMER_CALLEES.has(call.expression.text)) {
198
- const hoisted = hoistTimerArrowArg(call, fileName, sourceText, diagnostics, pointerVars, comments);
199
- if (hoisted)
200
- return hoisted;
183
+ // ── console.* is not a supported API ────────────────────────────────────
184
+ // The TypeScript console carry-over (lowering to a platform print plus a
185
+ // config section routing it) is gone. Programs write to a serial console
186
+ // explicitly: USB0.writeLine(...) or UART0.writeLine(...). Sourced at IR
187
+ // build time so the diagnostic points at the user's statement and the
188
+ // real pipeline aborts before emit.
189
+ if (ts.isPropertyAccessExpression(call.expression) &&
190
+ ts.isIdentifier(call.expression.expression) &&
191
+ call.expression.expression.text === "console") {
192
+ diagnostics.push(makeDiagnostic(sourceText, call.getStart(), `console.${call.expression.name.text}() is not supported — write to a serial console instead: \`USB0.writeLine(...)\` (USB CDC) or \`UART0.writeLine(...)\` from the board module.`, "error", "console-unsupported"));
193
+ return {
194
+ kind: "block",
195
+ sourceSpan: makeSourceSpan(call, fileName, sourceText),
196
+ leadingComments: comments.leadingComments,
197
+ trailingComments: comments.trailingComments,
198
+ body: [],
199
+ };
201
200
  }
202
201
  // ── Ambient canvas ctx: rewrite ctx.method(...) while drawCanvas lowers ──
203
202
  {
@@ -783,8 +782,6 @@ export function callToStatement(statementNode, call, fileName, sourceText, diagn
783
782
  else {
784
783
  calleeText = calleeToText(call.expression);
785
784
  }
786
- // Timer calls with arrow callbacks are intercepted before HAL (above);
787
- // named-function callbacks fall through here unchanged.
788
785
  return {
789
786
  kind: "call",
790
787
  sourceSpan: makeSourceSpan(call, fileName, sourceText),
@@ -794,70 +791,6 @@ export function callToStatement(statementNode, call, fileName, sourceText, diagn
794
791
  args: call.arguments.map((arg) => expressionToIR(arg, sourceText, diagnostics, pointerVars)),
795
792
  };
796
793
  }
797
- // ── setInterval/setTimeout arrow-callback hoisting ──────────────────────────
798
- const TIMER_CALLEES = new Set(["setInterval", "setTimeout", "__tc_setInterval", "__tc_setTimeout"]);
799
- let timerCallbackCounter = 0;
800
- /**
801
- * Hoist an inline arrow/function-expression callback argument of a
802
- * setInterval/setTimeout call to a named free function, and return the
803
- * rewritten call with the function name replacing the arrow.
804
- *
805
- * Returns null if arg[0] isn't an inline arrow/function (named-function
806
- * callbacks pass through to the generic path unchanged).
807
- *
808
- * Called from the generic fallthrough at the end of callToStatement — NOT
809
- * as an early return — because top-level timer calls reach the fallthrough
810
- * path, not the early-interception points.
811
- */
812
- function hoistTimerArrowArg(call, fileName, sourceText, diagnostics, pointerVars, comments) {
813
- const callbackArg = call.arguments[0];
814
- if (!callbackArg || !(ts.isArrowFunction(callbackArg) || ts.isFunctionExpression(callbackArg))) {
815
- return null;
816
- }
817
- const fnName = `__tc_timer_cb_${timerCallbackCounter++}`;
818
- const scope = getCurrentIrTypeScope();
819
- const localVariableTypes = new Map();
820
- if (scope) {
821
- for (const [k, v] of scope.globals)
822
- localVariableTypes.set(k, v);
823
- }
824
- const functionReturnTypes = new Map([...(getContext().activeFunctionReturnTypes ?? new Map())]);
825
- const bodyStatements = lowerStatementList(ts.isBlock(callbackArg.body) ? callbackArg.body.statements : [], fileName, sourceText, diagnostics, functionReturnTypes, localVariableTypes, fnName, undefined, pointerVars);
826
- if (!ts.isBlock(callbackArg.body)) {
827
- const exprText = renderExprAsText(expressionToIR(callbackArg.body, sourceText, diagnostics));
828
- bodyStatements.push({
829
- kind: "call",
830
- sourceSpan: makeSourceSpan(callbackArg.body, fileName, sourceText),
831
- callee: "__EMIT__",
832
- args: [{ kind: "string", value: exprText }],
833
- });
834
- }
835
- hoistedNestedFunctions.push({
836
- originalName: fnName,
837
- isAsync: false,
838
- returnType: "void",
839
- sourceSpan: makeSourceSpan(callbackArg, fileName, sourceText),
840
- leadingComments: [],
841
- trailingComments: [],
842
- parameters: [],
843
- statements: bodyStatements,
844
- });
845
- // Apply the polyfill helper rename (setInterval → __tc_setInterval) so the
846
- // emitted call matches the runtime helper the framework provides.
847
- const rawCallee = ts.isIdentifier(call.expression) ? call.expression.text : calleeToText(call.expression);
848
- const calleeText = rawCallee === "setInterval" ? "__tc_setInterval"
849
- : rawCallee === "setTimeout" ? "__tc_setTimeout"
850
- : rawCallee;
851
- const remainingArgs = call.arguments.slice(1).map((arg) => expressionToIR(arg, sourceText, diagnostics, pointerVars));
852
- return {
853
- kind: "call",
854
- sourceSpan: makeSourceSpan(call, fileName, sourceText),
855
- leadingComments: comments.leadingComments,
856
- trailingComments: comments.trailingComments,
857
- callee: calleeText,
858
- args: [{ kind: "identifier", value: fnName }, ...remainingArgs],
859
- };
860
- }
861
794
  // ── Helper: lower a callback expression to C++ text ─────────────────────────
862
795
  // (Moved to ui-callback-lowering.ts so onToggle and watchPin share one path,
863
796
  // including console.* → platform transform which lived in neither copy.)
@@ -1,4 +1,4 @@
1
- export type CallbackContextId = "setInterval" | "ui-event-callback" | "ui-draw-canvas";
1
+ export type CallbackContextId = "ui-event-callback" | "ui-draw-canvas";
2
2
  export interface CallbackContextCapabilities {
3
3
  id: CallbackContextId;
4
4
  /** Human label used in diagnostic messages, e.g. "UI event callback". */
@@ -1,22 +1,14 @@
1
1
  // ---------------------------------------------------------------------------
2
2
  // Declarative capability registry for UI callback contexts.
3
3
  //
4
- // UI callback bodies (setInterval, ui.bind/onClick/onToggle/watchPin,
5
- // ui.drawCanvas) each lower through lowerCallbackStatements →
6
- // lowerStatementList (the same pipeline setInterval uses). This registry is
7
- // the single declarative source of truth for diagnostics: each context lists
8
- // what it lowers, and unsupportedStatementHint() renders that list into the
9
- // hint text shown next to fatal "ui-callback-unsupported-statement"
10
- // diagnostics.
4
+ // UI callback bodies (ui.bind/onClick/onToggle/watchPin, ui.drawCanvas)
5
+ // each lower through lowerCallbackStatements → lowerStatementList. This
6
+ // registry is the single declarative source of truth for diagnostics: each
7
+ // context lists what it lowers, and unsupportedStatementHint() renders that
8
+ // list into the hint text shown next to fatal "ui-callback-unsupported-
9
+ // statement" diagnostics.
11
10
  // ---------------------------------------------------------------------------
12
11
  export const CALLBACK_CONTEXTS = {
13
- setInterval: {
14
- id: "setInterval",
15
- label: "setInterval callback",
16
- statements: ["const/let", "if/else", "for", "while", "do/while", "break/continue", "nested blocks"],
17
- expressions: ["the full statement-to-IR expression pipeline — the same one top-level code uses"],
18
- escapeHatch: "setInterval callbacks already route through the main statement-to-IR pipeline, so a failure here reflects a general transpiler limitation rather than a callback-context restriction",
19
- },
20
12
  "ui-event-callback": {
21
13
  id: "ui-event-callback",
22
14
  label: "UI event callback",
@@ -27,7 +19,7 @@ export const CALLBACK_CONTEXTS = {
27
19
  "console.* calls",
28
20
  "any other expression via the standard expression pipeline (arithmetic, comparisons, ternaries, color literals, ...)",
29
21
  ],
30
- escapeHatch: "move the logic to setInterval or a plain function",
22
+ escapeHatch: "move the logic to a Thread or a plain function",
31
23
  },
32
24
  "ui-draw-canvas": {
33
25
  id: "ui-draw-canvas",
@@ -36,7 +28,7 @@ export const CALLBACK_CONTEXTS = {
36
28
  expressions: [
37
29
  "ctx.*() draw calls (drawPixel, fillRect, rect, fillRoundRect, roundRect, line, hline, vline, fillCircle, circle, rgbBitmap, text, fillScreen)",
38
30
  ],
39
- escapeHatch: "move non-drawing side effects (calls not on ctx, e.g. signal writes or console output) to setInterval",
31
+ escapeHatch: "move non-drawing side effects (calls not on ctx, e.g. signal writes or console output) to a Thread",
40
32
  },
41
33
  };
42
34
  /** Human-readable name for a context, used in diagnostic messages. */
@@ -6,7 +6,6 @@ import { parseCppType, renderCppType, isPointer, parsedIsVector, parsedElementSt
6
6
  import { expressionToIR } from "../expression-to-ir.js";
7
7
  import { lowerStatementList, expressionStatementToIR } from "../statement-to-ir.js";
8
8
  import { assignmentOperatorToString, updateLocalTypeFromAssignment, extractForInKeys } from "./variables.js";
9
- import { snapshotPinLevels, restorePinLevels, mergePinLevels, invalidatePinLevels } from "../pin-state-tracking.js";
10
9
  // Monotonic counter for synthetic for...of destructure loop variables.
11
10
  let forOfDestructureCounter = 0;
12
11
  /**
@@ -187,7 +186,6 @@ export function lowerControlFlowStatement(statement, fileName, sourceText, diagn
187
186
  if (ts.isWhileStatement(statement)) {
188
187
  // Loop conditions/bodies may evaluate any number of times, so tracked
189
188
  // pin levels from before the loop are not valid inside it.
190
- invalidatePinLevels();
191
189
  const comments = extractNodeComments(statement, sourceText);
192
190
  const bodyStatements = lowerStatementList(ts.isBlock(statement.statement) ? statement.statement.statements : [statement.statement], fileName, sourceText, diagnostics, functionReturnTypes, localVariableTypes, functionNameForDiagnostics, typeAliases, pointerVars);
193
191
  return [{
@@ -205,19 +203,15 @@ export function lowerControlFlowStatement(statement, fileName, sourceText, diagn
205
203
  // after the branches in this function but runs before them at runtime,
206
204
  // so the pre-branch state is restored before the condition is evaluated
207
205
  // and the merge is applied last.
208
- const preBranchPinState = snapshotPinLevels();
209
206
  const comments = extractNodeComments(statement, sourceText);
210
207
  const thenStatements = lowerStatementList(ts.isBlock(statement.thenStatement) ? statement.thenStatement.statements : [statement.thenStatement], fileName, sourceText, diagnostics, functionReturnTypes, localVariableTypes, functionNameForDiagnostics, typeAliases, pointerVars);
211
- const thenBranchPinState = snapshotPinLevels();
212
208
  // Restore the pre-branch state before lowering the else branch and the
213
209
  // condition — both run before the branches at runtime... the condition
214
210
  // before them, the else on the path where the then branch never ran.
215
- restorePinLevels(preBranchPinState);
216
211
  let elseBranch;
217
212
  if (statement.elseStatement) {
218
213
  elseBranch = lowerStatementList(ts.isBlock(statement.elseStatement) ? statement.elseStatement.statements : [statement.elseStatement], fileName, sourceText, diagnostics, functionReturnTypes, localVariableTypes, functionNameForDiagnostics, typeAliases, pointerVars);
219
214
  }
220
- const elseBranchPinState = snapshotPinLevels();
221
215
  // Evaluate the condition. If it's a bare identifier that resolves to a
222
216
  // HAL alias (e.g. `if (bus2)` where bus2 = I2C0.take()), the alias is a
223
217
  // compile-time non-null reference — constant-fold to `true` so the emit
@@ -229,10 +223,6 @@ export function lowerControlFlowStatement(statement, fileName, sourceText, diagn
229
223
  else {
230
224
  condition = expressionToIR(statement.expression, sourceText, diagnostics, pointerVars);
231
225
  }
232
- // Join the branch-end states into the live state. With no else branch,
233
- // elseBranchPinState equals the pre-branch state, so pins written by the
234
- // then branch invalidate unless the write agrees with the prior level.
235
- mergePinLevels(thenBranchPinState, elseBranchPinState);
236
226
  return [{
237
227
  kind: "if",
238
228
  sourceSpan: makeSourceSpan(statement, fileName, sourceText),
@@ -257,7 +247,6 @@ export function lowerControlFlowStatement(statement, fileName, sourceText, diagn
257
247
  }
258
248
  // Loop conditions/bodies may evaluate any number of times, so tracked
259
249
  // pin levels from before the loop are not valid inside it.
260
- invalidatePinLevels();
261
250
  const condition = statement.condition
262
251
  ? expressionToIR(statement.condition, sourceText, diagnostics, pointerVars)
263
252
  : undefined;
@@ -387,7 +376,6 @@ export function lowerControlFlowStatement(statement, fileName, sourceText, diagn
387
376
  if (ts.isDoStatement(statement)) {
388
377
  // Loop bodies may run more than once; pre-loop pin levels are not valid
389
378
  // inside them.
390
- invalidatePinLevels();
391
379
  const comments = extractNodeComments(statement, sourceText);
392
380
  const bodyStatements = lowerStatementList(ts.isBlock(statement.statement) ? statement.statement.statements : [statement.statement], fileName, sourceText, diagnostics, functionReturnTypes, localVariableTypes, functionNameForDiagnostics, typeAliases, pointerVars);
393
381
  return [{
@@ -403,7 +391,6 @@ export function lowerControlFlowStatement(statement, fileName, sourceText, diagn
403
391
  if (ts.isSwitchStatement(statement)) {
404
392
  // Exactly one case runs at runtime, but all are lowered here; pin levels
405
393
  // from case bodies must not leak past the switch.
406
- invalidatePinLevels();
407
394
  const comments = extractNodeComments(statement, sourceText);
408
395
  const cases = [];
409
396
  for (const clause of statement.caseBlock.clauses) {
@@ -11,6 +11,14 @@ export function expressionStatementToIR(statement, fileName, sourceText, diagnos
11
11
  if (ts.isCallExpression(expr)) {
12
12
  return callToStatement(statement, expr, fileName, sourceText, diagnostics, pointerVars);
13
13
  }
14
+ // `void expr();` — the fire-and-forget idiom. Lower the inner call like a
15
+ // bare call statement (the raw (void)(...) form drops it entirely, which
16
+ // silently skipped the async-method kickoff: `void b.run();`). Free async
17
+ // function calls reaching here are still filtered at top level (their
18
+ // tasks auto-start), so the idiom keeps its meaning there.
19
+ if (ts.isVoidExpression(expr) && ts.isCallExpression(expr.expression)) {
20
+ return callToStatement(statement, expr.expression, fileName, sourceText, diagnostics, pointerVars);
21
+ }
14
22
  if (ts.isAwaitExpression(expr) && ts.isCallExpression(expr.expression)) {
15
23
  const callStmt = callToStatement(statement, expr.expression, fileName, sourceText, diagnostics, pointerVars);
16
24
  if (callStmt && callStmt.kind === "call") {
@@ -420,17 +428,10 @@ export function expressionStatementToIR(statement, fileName, sourceText, diagnos
420
428
  * timing.delay is included because `delay()` from @typecad/hal resolves to a
421
429
  * hal-op, dropping the isAwaited flag the state machine keys on. */
422
430
  const AWAITABLE_HAL_OPS = new Set([
423
- "timing.delay",
424
- "wifi.connect",
425
- "wifi.wait_connected",
426
- "wifi.wait_disconnected",
431
+ "timing.sleep",
432
+ "wifi.join",
427
433
  "wifi.scan",
428
434
  "http.send",
429
- "ble.until_connected",
430
- // Worker offload: `await worker.submit(...)` rewrites to submit + poll
431
- // worker.done — mirrors `await http.send(...)`. The start op is worker.submit
432
- // (emitted by the previous state segment); the poll predicate is worker.done.
433
- "worker.submit",
434
435
  ]);
435
436
  /**
436
437
  * Rewrite an awaited hal-op statement (or a block whose LAST statement is
@@ -4,8 +4,8 @@ import { PointerTracker } from "../build-ir-state.js";
4
4
  import { StatementIR, ExpressionIR, HALOpIR } from "../../api/index.js";
5
5
  /**
6
6
  * Resolve a HAL method call using the HAL resolver.
7
- * Handles all HAL classes: Pin, I2CBus, SPIBus, SerialPort, EEPROMClass, WDTClass,
8
- * plus device accessor patterns (I2CDevice, SPIDevice) and namespace methods (Pulse, Shift, Random).
7
+ * Handles all HAL classes: Pin, I2CBus, SPIBus, UART, WDTClass,
8
+ * plus device accessor patterns (I2CTarget, SPITarget) and namespace methods (Pulse, Shift, Random).
9
9
  */
10
10
  export declare function tryResolveHALMethod(call: ts.CallExpression, fileName: string, sourceText: string, diagnostics: Diagnostic[], pointerVars: PointerTracker): StatementIR | null;
11
11
  /**
@@ -7,8 +7,8 @@ import { resolveNamespaceMethodCall } from "./namespace-methods.js";
7
7
  import { makeSourceSpan } from "../ast-node-utils.js";
8
8
  /**
9
9
  * Resolve a HAL method call using the HAL resolver.
10
- * Handles all HAL classes: Pin, I2CBus, SPIBus, SerialPort, EEPROMClass, WDTClass,
11
- * plus device accessor patterns (I2CDevice, SPIDevice) and namespace methods (Pulse, Shift, Random).
10
+ * Handles all HAL classes: Pin, I2CBus, SPIBus, UART, WDTClass,
11
+ * plus device accessor patterns (I2CTarget, SPITarget) and namespace methods (Pulse, Shift, Random).
12
12
  */
13
13
  export function tryResolveHALMethod(call, fileName, sourceText, diagnostics, pointerVars) {
14
14
  let method;
@@ -31,8 +31,8 @@ export function tryResolveHALMethod(call, fileName, sourceText, diagnostics, poi
31
31
  if (instance) {
32
32
  const result = processHALMethodBody(instance, method, argIRs);
33
33
  if (result) {
34
- // Collect emit lines and halOps from chained inner calls: led.tone(440).for(400)
35
- // The receiver of this call is itself a chained HAL call (led.tone(440)).
34
+ // Collect emit lines and halOps from chained inner calls: rgb.brightness(50).show()
35
+ // The receiver of this call is itself a chained HAL call (rgb.brightness(50)).
36
36
  // We need to process that inner call to collect its emit lines too.
37
37
  const chainedEmits = [];
38
38
  const chainedHalOps = [];
@@ -101,7 +101,7 @@ export function tryResolveHALMethod(call, fileName, sourceText, diagnostics, poi
101
101
  }
102
102
  const receiver = ts.isPropertyAccessExpression(call.expression) ? call.expression.expression : null;
103
103
  // Try device accessor pattern: <bus>.device(addr).method(args)
104
- // This resolves I2CDevice and SPIDevice calls
104
+ // This resolves I2CTarget and SPITarget device()-factory calls
105
105
  if (receiver && ts.isCallExpression(receiver)) {
106
106
  const deviceCall = receiver;
107
107
  if (ts.isPropertyAccessExpression(deviceCall.expression) && deviceCall.expression.name.text === "device") {
@@ -112,12 +112,16 @@ export function tryResolveHALMethod(call, fileName, sourceText, diagnostics, poi
112
112
  const deviceArgs = deviceCall.arguments;
113
113
  if (deviceArgs && deviceArgs.length > 0) {
114
114
  // Determine the device class based on bus class
115
- const deviceClassName = busInstance.className === "SPIBus" ? "SPIDevice" : "I2CDevice";
115
+ const isSpiDevice = busInstance.className === "SPIBus";
116
+ const deviceClassName = isSpiDevice ? "SPITarget" : "I2CTarget";
116
117
  // Build field values for the device: _bus from bus instance, _address/_cs from device() arg
117
118
  const deviceFieldValues = new Map();
118
119
  const busField = busInstance.fieldValues.get("_bus");
119
120
  if (busField)
120
121
  deviceFieldValues.set("_bus", busField);
122
+ deviceFieldValues.set("_hz", isSpiDevice ? "1000000" : "0");
123
+ if (isSpiDevice)
124
+ deviceFieldValues.set("_mode", "0");
121
125
  const deviceArg = deviceArgs[0];
122
126
  if (ts.isNumericLiteral(deviceArg)) {
123
127
  const fieldName = busInstance.className === "SPIBus" ? "_cs" : "_address";
@@ -191,11 +195,15 @@ export function resolveHALCallForVarInit(call, sourceText, diagnostics, pointerV
191
195
  if (busInstance) {
192
196
  const deviceArgs = deviceCall.arguments;
193
197
  if (deviceArgs && deviceArgs.length > 0) {
194
- const deviceClassName = busInstance.className === "SPIBus" ? "SPIDevice" : "I2CDevice";
198
+ const isSpiDevice = busInstance.className === "SPIBus";
199
+ const deviceClassName = isSpiDevice ? "SPITarget" : "I2CTarget";
195
200
  const deviceFieldValues = new Map();
196
201
  const busField = busInstance.fieldValues.get("_bus");
197
202
  if (busField)
198
203
  deviceFieldValues.set("_bus", busField);
204
+ deviceFieldValues.set("_hz", isSpiDevice ? "1000000" : "0");
205
+ if (isSpiDevice)
206
+ deviceFieldValues.set("_mode", "0");
199
207
  const deviceArg = deviceArgs[0];
200
208
  if (ts.isNumericLiteral(deviceArg)) {
201
209
  const fieldName = busInstance.className === "SPIBus" ? "_cs" : "_address";
@@ -239,10 +247,15 @@ export function tryResolveHALExpression(call, sourceText, diagnostics, pointerVa
239
247
  if (result) {
240
248
  // Prefer hal-expr for semantic HAL operations
241
249
  if (result.halOps.length > 0) {
242
- // Use the last halOp as the expression; preceding ones are side effects
250
+ // Use the last halOp as the expression; PRECEDING ones are its
251
+ // prefixOps — a method body's leading side effects (bus transaction
252
+ // begin/write/end, a pin configure) that must still run. The renderer
253
+ // wraps them with the value in a statement-expression. (They were
254
+ // historically dropped here — the "dead keypress" bug class.)
243
255
  const lastOp = result.halOps[result.halOps.length - 1];
256
+ const prefixOps = result.halOps.slice(0, -1);
244
257
  return {
245
- ir: { kind: "hal-expr", operation: lastOp },
258
+ ir: { kind: "hal-expr", operation: lastOp, ...(prefixOps.length > 0 ? { prefixOps } : {}) },
246
259
  sideEffects: result.emitLines,
247
260
  };
248
261
  }
@@ -281,8 +294,9 @@ export function tryResolveHALExpression(call, sourceText, diagnostics, pointerVa
281
294
  if (nsResult) {
282
295
  if (nsResult.halOps.length > 0) {
283
296
  const lastOp = nsResult.halOps[nsResult.halOps.length - 1];
297
+ const prefixOps = nsResult.halOps.slice(0, -1);
284
298
  return {
285
- ir: { kind: "hal-expr", operation: lastOp },
299
+ ir: { kind: "hal-expr", operation: lastOp, ...(prefixOps.length > 0 ? { prefixOps } : {}) },
286
300
  sideEffects: nsResult.emitLines,
287
301
  };
288
302
  }
@@ -4,8 +4,8 @@ import { HALOpIR, StatementIR } from "../../api/index.js";
4
4
  import { PointerTracker } from "../build-ir-state.js";
5
5
  /**
6
6
  * Recursively collect emit lines from chained HAL method calls.
7
- * For an expression like led.tone(440).for(400), this collects
8
- * the emit lines from the inner led.tone(440) call.
7
+ * For an expression like rgb.brightness(50).show(), this collects
8
+ * the emit lines from the inner rgb.brightness(50) call.
9
9
  */
10
10
  export declare function collectChainedHALEmits(expr: ts.Expression, sourceText: string, diagnostics: Diagnostic[], pointerVars: PointerTracker, emitLines: string[], halOps?: HALOpIR[]): void;
11
11
  /** Convert emit lines to a StatementIR (single emit or block of emits). */
@@ -4,8 +4,8 @@ import { expressionToIR } from "../expression-to-ir.js";
4
4
  import { resolveHALReceiver, processHALMethodBody } from "../hal-resolver.js";
5
5
  /**
6
6
  * Recursively collect emit lines from chained HAL method calls.
7
- * For an expression like led.tone(440).for(400), this collects
8
- * the emit lines from the inner led.tone(440) call.
7
+ * For an expression like rgb.brightness(50).show(), this collects
8
+ * the emit lines from the inner rgb.brightness(50) call.
9
9
  */
10
10
  export function collectChainedHALEmits(expr, sourceText, diagnostics, pointerVars, emitLines, halOps = []) {
11
11
  // Chained call: led.tone(440).for(400) — the receiver is the inner call led.tone(440)
@@ -82,7 +82,7 @@ export function resolveNamespaceMethodCall(ns, method, argIRs) {
82
82
  }
83
83
  if (ns === "Random") {
84
84
  // Random.* lowers to the random.* HAL op family, which frameworks lower to
85
- // their platform PRNG (Arduino random()/randomSeed(), ESP-IDF esp_random()).
85
+ // their platform PRNG (e.g. Zephyr's sys_rand).
86
86
  // Previously these emitted bare `random()`/`randomSeed()` calls, which only
87
87
  // resolve to symbols on Arduino-core frameworks — on ESP-IDF they were
88
88
  // undefined and failed at C++ link time.
@@ -15,8 +15,6 @@ export declare function resolveColorsInStatements(statements: StatementIR[]): St
15
15
  /** Recursively rename identifiers in a StatementIR tree (e.g. bindInput
16
16
  * param → `text`, list tap param → `idx`). */
17
17
  export declare function renameIdentifiersInStatements(statements: StatementIR[], from: string, to: string): StatementIR[];
18
- export declare function noteConsoleInCallback(): void;
19
- export declare function loweredConsoleInCallback(): boolean;
20
18
  export declare function resetCallbackLoweringState(): void;
21
19
  export declare function beginCanvasAmbient(ctxName: string, diagnostics: Diagnostic[], sourceText: string): void;
22
20
  export declare function endCanvasAmbient(): void;