@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
@@ -5,11 +5,10 @@ import { parseSource } from "../ast/parse.js";
5
5
  import { isStringEnum } from "../api/shared/index.js";
6
6
  import { makeDiagnostic } from "./ast-node-utils.js";
7
7
  import { buildFunctionReturnTypeMap } from "./type-resolution.js";
8
- import { resolveBoardConstants, tryResolveBoardDefFile } from "./board-resolver.js";
8
+ import { tryResolveBoardDefFile, findGeneratedBoard, readGeneratedBoardConstants } from "./board-resolver.js";
9
9
  import { analyzePeripheralUsage, createEmptyPeripheralUsage } from "./peripheral-usage.js";
10
10
  import { runProgramValidations } from "./validation-orchestrator.js";
11
- import { registerFieldMap, hoistedNestedFunctions, hoistedNestedClasses, hoistedNestedEnums, hoistedNestedInterfaces, hoistedNestedTypeAliases, activeNamespaceNames, activeEnumNames, activeStringEnumNames, peripheralAliasMap, pinAliasMap, mcuPinReverseMap, topLevelClassNames, topLevelInterfaceNames, classTypeNames, topLevelClasses, requiredIncludes, resetBuildState, getCurrentBoardConstants, setCurrentBoardConstants, contextStorage, CompilationContext, registeredCallbacks, getContext, discriminatedUnionVariantNames, restParamFunctions, topLevelAliasReceivers } from "./build-ir-state.js";
12
- import { pinShadowVarName, takeShadowDeclarations, resetPinStateTracking, markShadowUpdatingOps } from "./pin-state-tracking.js";
11
+ import { registerFieldMap, hoistedNestedFunctions, hoistedNestedClasses, hoistedNestedEnums, hoistedNestedInterfaces, hoistedNestedTypeAliases, activeNamespaceNames, activeEnumNames, activeStringEnumNames, peripheralAliasMap, pinAliasMap, mcuPinForwardMap, mcuPinReverseMap, topLevelClassNames, topLevelInterfaceNames, classTypeNames, topLevelClasses, requiredIncludes, resetBuildState, getCurrentBoardConstants, setCurrentBoardConstants, contextStorage, CompilationContext, registeredCallbacks, getContext, discriminatedUnionVariantNames, restParamFunctions, topLevelAliasReceivers } from "./build-ir-state.js";
13
12
  import { collectPointerVars, expressionStatementToIR, lowerStatement, variableStatementToIR, prescanArrayUsage, lowerStatementList } from "./statement-to-ir.js";
14
13
  import { registerUIModuleImport, registerElementValue } from "./transformers/ui-call-resolver.js";
15
14
  import { requireUIHook } from "../ui-hook.js";
@@ -141,7 +140,7 @@ function resolveUIImportPath(fromFile, moduleSpecifier) {
141
140
  catch { /* skip */ }
142
141
  return undefined;
143
142
  }
144
- export function buildProgramIR(fileName, sourceText, boardPackage, prebuiltClassMap) {
143
+ export function buildProgramIR(fileName, sourceText, boardTarget, prebuiltClassMap) {
145
144
  const parentStrategy = getContext().activeStrategy;
146
145
  return contextStorage.run(new CompilationContext(), () => {
147
146
  getContext().activeStrategy = parentStrategy;
@@ -182,7 +181,6 @@ export function buildProgramIR(fileName, sourceText, boardPackage, prebuiltClass
182
181
  // Reset module-level state for this file
183
182
  resetBuildState();
184
183
  resetHALResolver();
185
- resetPinStateTracking();
186
184
  registerFieldMap.clear();
187
185
  // Phase 0: Pre-scan for top-level classes and register them so type inference can resolve them.
188
186
  // Also register classes from other files in the transpile graph so that property accesses
@@ -299,7 +297,7 @@ export function buildProgramIR(fileName, sourceText, boardPackage, prebuiltClass
299
297
  // lowered to IR, but `ui` itself must NOT be emitted as a C++ value
300
298
  // (it would synthesize a bogus _ui_t struct). Drop it from the imports
301
299
  // IR so the emit path never sees it as an imported value.
302
- const isUiPackage = moduleSpecifier === '@typecad/ui' || moduleSpecifier === '@typecad/ui';
300
+ const isUiPackage = moduleSpecifier === '@typecad/ui';
303
301
  const filteredImports = isUiPackage
304
302
  ? namedImports.filter((n) => n !== 'ui')
305
303
  : namedImports;
@@ -307,10 +305,10 @@ export function buildProgramIR(fileName, sourceText, boardPackage, prebuiltClass
307
305
  }
308
306
  }
309
307
  for (const imp of earlyImports) {
310
- const boardFile = tryResolveBoardDefFile(fileName, imp.moduleSpecifier, boardPackage);
308
+ const boardFile = tryResolveBoardDefFile(fileName, imp.moduleSpecifier, boardTarget);
311
309
  if (boardFile) {
312
310
  try {
313
- setCurrentBoardConstants(resolveBoardConstants(boardFile));
311
+ setCurrentBoardConstants(readGeneratedBoardConstants(boardFile));
314
312
  }
315
313
  catch {
316
314
  // Non-fatal
@@ -319,20 +317,21 @@ export function buildProgramIR(fileName, sourceText, boardPackage, prebuiltClass
319
317
  }
320
318
  }
321
319
  // If only the default board constants are loaded (4 keys from getDefaultBoardConstants),
322
- // try the config's boardPackage directly. This covers the case where board()/boardResolve()
323
- // is imported from @typecad/hal but no @typecad/board-* import is present in the user's code.
320
+ // load the generated board manifest directly covers the case where board()/boardResolve()
321
+ // is imported from @typecad/hal but no @typecad/board import is present in the user's code.
324
322
  const currentBC = getCurrentBoardConstants();
325
- if (currentBC && currentBC.size <= 4 && boardPackage) {
326
- const boardFile = tryResolveBoardDefFile(fileName, boardPackage, boardPackage);
327
- if (boardFile) {
323
+ if (currentBC && currentBC.size <= 4) {
324
+ const generated = findGeneratedBoard(fileName);
325
+ if (generated) {
328
326
  try {
329
- setCurrentBoardConstants(resolveBoardConstants(boardFile));
327
+ setCurrentBoardConstants(readGeneratedBoardConstants(generated.boardJson));
330
328
  }
331
329
  catch {
332
330
  // Non-fatal
333
331
  }
334
332
  }
335
333
  }
334
+ void boardTarget;
336
335
  // Phase 0c-bis: register UI module imports (name → .ui.html path) so
337
336
  // ui.mount(screen, ...) can resolve `screen` back to its source tree.
338
337
  // Only .ui.html specifiers are registered; their named imports are the UI
@@ -387,8 +386,7 @@ export function buildProgramIR(fileName, sourceText, boardPackage, prebuiltClass
387
386
  "asOutput", "asInput", "asInputPullUp", "asInputPullDown",
388
387
  "output", "inputPullUp", "inputPullDown",
389
388
  "device", // I2CBus.device(addr) / SPIBus.device(cs) → device instance
390
- "tone", // OutputPin.tone(freq) → ToneChain
391
- "begin", // I2CBus.begin() / SPIBus.begin() / SerialPort.begin() → same instance
389
+ "begin", // I2CBus.begin() / SPIBus.begin() same instance
392
390
  "take", // Bus.take() → same instance (ownership is compile-time only)
393
391
  ]);
394
392
  for (const node of source.statements) {
@@ -402,7 +400,7 @@ export function buildProgramIR(fileName, sourceText, boardPackage, prebuiltClass
402
400
  && HAL_ALIASING_METHODS.has(init.expression.name.text)
403
401
  && ts.isIdentifier(init.expression.expression)) {
404
402
  // Capture call arguments for factory methods like device(0x76) that
405
- // need the arg to construct the derived instance (I2CDevice._address).
403
+ // need the arg to construct the derived instance (I2CTarget._address).
406
404
  const argTexts = init.arguments.map(a => {
407
405
  if (ts.isNumericLiteral(a))
408
406
  return a.text;
@@ -445,20 +443,20 @@ export function buildProgramIR(fileName, sourceText, boardPackage, prebuiltClass
445
443
  }
446
444
  }
447
445
  }
448
- // Track HAL instances imported from board packages and framework HAL
449
- // subpaths so the HAL resolver can resolve them to framework C++ names.
450
- // The `@typecad/board` virtual import resolves to the board package, so it
451
- // also registers pin aliases (LED, etc.). Case-insensitive on the scope.
446
+ // Track HAL instances imported from the board module (virtual
447
+ // `@typecad/board`, or a legacy `@typecad/board-*` package import from
448
+ // pre-boardgen projects, which resolves against the project's generated
449
+ // board constants) so the HAL resolver can resolve them to framework
450
+ // C++ names. Case-insensitive.
452
451
  const lowerSpecifier = moduleSpecifier.toLowerCase();
453
452
  const isHALSource = lowerSpecifier.startsWith('@typecad/board-')
454
- || lowerSpecifier === '@typecad/board'
455
- || /^@typecad\/framework-[a-z0-9-]+\/(arduino|hal|gpio)$/.test(lowerSpecifier);
453
+ || lowerSpecifier === '@typecad/board';
456
454
  // UI authoring namespace: `import { ui } from "@typecad/ui"`. The `ui`
457
455
  // value is a compile-time construct (its calls are intercepted by
458
456
  // tryResolveUICall); it must NOT be emitted as a C++ struct/value.
459
457
  // Treat it like the HAL namespace imports (Pulse/Shift/Random): register
460
458
  // as a namespace name and skip, so no struct is synthesized.
461
- if (moduleSpecifier === '@typecad/ui' || moduleSpecifier === '@typecad/ui') {
459
+ if (moduleSpecifier === '@typecad/ui') {
462
460
  for (const name of namedImports) {
463
461
  if (name === 'ui') {
464
462
  activeNamespaceNames.add(name);
@@ -497,10 +495,31 @@ export function buildProgramIR(fileName, sourceText, boardPackage, prebuiltClass
497
495
  halInstances.set(name, { className: "Pin", fieldValues: fields });
498
496
  continue;
499
497
  }
500
- // A-pins: A0-A19Pin instance with board-specific offset and MCU port name (fallback)
498
+ // A-pins: A0, A1, … resolve through the board manifest's analog
499
+ // pin list first (A-ordered on every board package: A<n> →
500
+ // pins.analog[n] → the MCU port name → pin number). Only when the
501
+ // list is absent (bare Arduino-style boards) fall back to the
502
+ // analogOffset convention (A0 = 14) — on port-named boards that
503
+ // fallback resolves A1 to a random GPIO (Black Pill PA15, a
504
+ // non-analog pin, was the first to surface it via a capability
505
+ // error).
501
506
  const aMatch = name.match(/^A(\d+)$/);
502
507
  if (aMatch) {
503
- const pinNum = String(analogOffset + parseInt(aMatch[1]));
508
+ let pinNum;
509
+ // The flattener stores the manifest's analog pin list as a
510
+ // comma-joined string under `pins.analog`.
511
+ const analogList = boardConstants.get("pins.analog");
512
+ if (typeof analogList === "string") {
513
+ const analogName = analogList.split(",")[parseInt(aMatch[1], 10)];
514
+ if (analogName) {
515
+ const byName = mcuPinForwardMap.get(analogName);
516
+ if (byName !== undefined)
517
+ pinNum = String(byName);
518
+ }
519
+ }
520
+ if (pinNum === undefined) {
521
+ pinNum = String(analogOffset + parseInt(aMatch[1]));
522
+ }
504
523
  const fields = new Map([["_pin", pinNum]]);
505
524
  const portName = mcuPinReverseMap.get(pinNum);
506
525
  if (portName)
@@ -511,22 +530,36 @@ export function buildProgramIR(fileName, sourceText, boardPackage, prebuiltClass
511
530
  // I2C buses: I2C0, I2C1, ...
512
531
  const i2cMatch = name.match(/^I2C(\d+)$/);
513
532
  if (i2cMatch) {
514
- const alias = peripheralAliasMap.get(name) ?? (i2cMatch[1] === '0' ? 'Wire' : `Wire${i2cMatch[1]}`);
533
+ const alias = peripheralAliasMap.get(name) ?? `I2C${i2cMatch[1]}`;
515
534
  halInstances.set(name, { className: "I2CBus", fieldValues: new Map([["_bus", alias]]) });
516
535
  continue;
517
536
  }
518
537
  // SPI buses: SPI0, SPI1, ...
519
538
  const spiMatch = name.match(/^SPI(\d+)$/);
520
539
  if (spiMatch) {
521
- const alias = peripheralAliasMap.get(name) ?? (spiMatch[1] === '0' ? 'SPI' : `SPI${spiMatch[1]}`);
540
+ const alias = peripheralAliasMap.get(name) ?? `SPI${spiMatch[1]}`;
522
541
  halInstances.set(name, { className: "SPIBus", fieldValues: new Map([["_bus", alias]]) });
523
542
  continue;
524
543
  }
525
- // UART: UART0, UART1, ...
544
+ // UART: UART0, UART1, ... — the FUNCTIONAL thin UART instance, so
545
+ // the board singleton is directly usable (UART0.println(...)) with
546
+ // the same fields a `new UART('UART0')` construction captures
547
+ // (port + the class's baud/ring defaults; variables.ts merges those
548
+ // only at construction, so the registration carries them).
526
549
  const uartMatch = name.match(/^UART(\d+)$/);
527
550
  if (uartMatch) {
528
- const alias = peripheralAliasMap.get(name) ?? (uartMatch[1] === '0' ? 'Serial' : `Serial${uartMatch[1]}`);
529
- halInstances.set(name, { className: "SerialPort", fieldValues: new Map([["_port", alias]]) });
551
+ const alias = peripheralAliasMap.get(name) ?? `UART${uartMatch[1]}`;
552
+ halInstances.set(name, {
553
+ className: "UART",
554
+ fieldValues: new Map([["_port", alias], ["_bus", alias], ["_baud", "115200"], ["_rxBufferBytes", "64"]]),
555
+ });
556
+ continue;
557
+ }
558
+ // USB CDC serial ports: USB0, USB1, ...
559
+ const usbMatch = name.match(/^USB(\d+)$/);
560
+ if (usbMatch) {
561
+ const alias = peripheralAliasMap.get(name) ?? `USB${usbMatch[1]}`;
562
+ halInstances.set(name, { className: "USBConsole", fieldValues: new Map([["_port", alias]]) });
530
563
  continue;
531
564
  }
532
565
  // HAL namespace imports: Pulse, Shift, Random
@@ -814,20 +847,6 @@ export function buildProgramIR(fileName, sourceText, boardPackage, prebuiltClass
814
847
  // write/toggle ops, while this file's tracker state is still live (the
815
848
  // next file's build resets it, and emit runs after every file is built —
816
849
  // multi-file programs would lose the updates otherwise). Then consume the
817
- // shadow declarations — pins whose reads lowered to the shadow variable
818
- // form need a file-scope declaration.
819
- markShadowUpdatingOps(program);
820
- const shadowDecls = takeShadowDeclarations();
821
- for (const { pin, initial } of shadowDecls) {
822
- program.topLevelStatements.unshift({
823
- kind: "var_decl",
824
- sourceSpan: { filePath: fileName, startOffset: 0, endOffset: 0, startLine: 0, startColumn: 0, endLine: 0, endColumn: 0 },
825
- name: pinShadowVarName(pin),
826
- storage: "var",
827
- cppType: "bool",
828
- initializer: { kind: "boolean", value: initial },
829
- });
830
- }
831
850
  return program;
832
851
  });
833
852
  }
@@ -256,6 +256,7 @@ export function classDeclarationToIR(node, fileName, sourceText, diagnostics, fu
256
256
  visibility: methodVisibility,
257
257
  isStatic,
258
258
  isAbstract: isMethodAbstract,
259
+ isAsync: member.modifiers?.some(m => m.kind === ts.SyntaxKind.AsyncKeyword) ?? false,
259
260
  isOverride,
260
261
  ...(member.typeParameters && member.typeParameters.length > 0
261
262
  ? { typeParameters: member.typeParameters.map(tp => tp.name.text) }
@@ -1,7 +1,6 @@
1
1
  import ts from "typescript";
2
2
  import { makeDiagnostic, makeSourceSpan } from "./ast-node-utils.js";
3
3
  import { PIN_FACTORY_FUNCTIONS, CONSTANT_FOLD_FUNCTIONS, TYPED_ARRAY_ELEMENT_MAP, activeCArrayVars, activeArrayLiteralVars, activeStringVars, nestedFunctionAliases, nestedClassAliases, hoistedNestedClasses, mutableArrayVars, arrayLiteralSizes, filteredArrayLengthVars, activeNamespaceNames, activeEnumNames, activeStringEnumNames, topLevelClassNames, topLevelInterfaceNames, classTypeNames, topLevelClasses, getActiveExtendsClass, restParamFunctions, getContext, getCurrentBoardConstants } from "./build-ir-state.js";
4
- import { isPinFoldingEnabled, setPinFoldingEnabled } from "./pin-state-tracking.js";
5
4
  import { getCurrentIrTypeScope } from "./symbol-types.js";
6
5
  import { renderExprAsText } from "./render-expr.js";
7
6
  import { lowerStatement, tryResolveHALExpression } from "./statement-to-ir.js";
@@ -414,8 +413,8 @@ export function expressionToIR(expr, sourceText, diagnostics, pointerVars = new
414
413
  return `(sizeof(${safeText}) / sizeof(${safeText}[0]))`;
415
414
  }
416
415
  if (ts.isCallExpression(receiverNode)) {
417
- // Case B: a HAL buffer-returning method (I2CDevice.readBytes /
418
- // SPIDevice.readRegister) used INLINE as a sub-expression — e.g.
416
+ // Case B: a HAL buffer-returning method (a device target's read
417
+ // verbs) used INLINE as a sub-expression — e.g.
419
418
  // `dev.readBytes(0,6).length`. These methods lower to STATEMENTS (a fill
420
419
  // loop), not a single C++ expression, so by the time we get here the
421
420
  // receiver text is already a leaked `for (...) __buf[__i] = Wire.read()`
@@ -685,9 +684,9 @@ export function expressionToIR(expr, sourceText, diagnostics, pointerVars = new
685
684
  // When the cast involves an `enum class` on one side and an integral type
686
685
  // on the other, emit a `static_cast<T>(...)` instead of erasing. C++ enum
687
686
  // class has NO implicit conversion, so the erased cast produces invalid
688
- // C++. The SUPPORT_MATRIX handles this for specific sites (relational,
689
- // index, Map key, storage boundary) but NOT for the general `as` cast —
690
- // the user's explicit escape hatch (enum stress test Finding C).
687
+ // C++. This is handled for specific sites (relational, index, Map key,
688
+ // storage boundary) but NOT for the general `as` cast — the user's
689
+ // explicit escape hatch (enum stress test Finding C).
691
690
  const targetTypeName = expr.type && ts.isTypeReferenceNode(expr.type) && ts.isIdentifier(expr.type.typeName)
692
691
  ? expr.type.typeName.text : "";
693
692
  const isTargetEnum = targetTypeName && activeEnumNames.has(targetTypeName) && !activeStringEnumNames.has(targetTypeName);
@@ -1103,6 +1102,17 @@ export function expressionToIR(expr, sourceText, diagnostics, pointerVars = new
1103
1102
  };
1104
1103
  }
1105
1104
  if (ts.isCallExpression(expr)) {
1105
+ // ---- console.* is not a supported API (value position) ----
1106
+ // Statement-position console calls are rejected in callToStatement; this
1107
+ // covers value-position uses (e.g. `const line = console.readLine()`).
1108
+ // Same rationale: the TypeScript console carry-over is gone — programs
1109
+ // write to a serial console explicitly via the board module.
1110
+ if (ts.isPropertyAccessExpression(expr.expression) &&
1111
+ ts.isIdentifier(expr.expression.expression) &&
1112
+ expr.expression.expression.text === "console") {
1113
+ diagnostics.push(makeDiagnostic(sourceText, expr.pos, `console.${expr.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"));
1114
+ return { kind: "raw", value: "0 /* console.* is not supported */" };
1115
+ }
1106
1116
  // ---- safe.read/safe.write chained with .ok/.fail/.fault/.always ----
1107
1117
  // Method chains like `safe.read(pin).ok(r => {...}).fail(r => {...})` cannot
1108
1118
  // use the generic method-call builder because it flattens the receiver into
@@ -1657,7 +1667,7 @@ export function expressionToIR(expr, sourceText, diagnostics, pointerVars = new
1657
1667
  // with '*' (a class-pointer struct field, e.g. FloorState.monster), the
1658
1668
  // method call must use ->. Without this, `dungeon.monster.bounty()`
1659
1669
  // emits `.` and fails g++ ("request for member 'bounty' ... pointer
1660
- // type"). See SUPPORT_MATRIX §4.5 (demo #4 fix).
1670
+ // type"). (demo #4 fix.)
1661
1671
  isPointer: calleeText.includes("->")
1662
1672
  || (ts.isCallExpression(expr)
1663
1673
  && ts.isPropertyAccessExpression(expr.expression)
@@ -2199,8 +2209,6 @@ export function expressionToIR(expr, sourceText, diagnostics, pointerVars = new
2199
2209
  const isBlock = ts.isBlock(body);
2200
2210
  // Lambda bodies run at an unmodeled time (callbacks), so pin-state
2201
2211
  // constant folding must be off inside them.
2202
- const prevPinFolding = isPinFoldingEnabled();
2203
- setPinFoldingEnabled(false);
2204
2212
  const bodyStmts = isBlock
2205
2213
  ? body.statements.map(stmt => {
2206
2214
  const lowered = lowerStatement(stmt, "", sourceText, diagnostics, new Map(), new Map(), "<lambda>", new Map(), pointerVars);
@@ -2212,7 +2220,6 @@ export function expressionToIR(expr, sourceText, diagnostics, pointerVars = new
2212
2220
  sourceSpan: makeSourceSpan(body, "", sourceText),
2213
2221
  value: expressionToIR(body, sourceText, diagnostics, pointerVars),
2214
2222
  }];
2215
- setPinFoldingEnabled(prevPinFolding);
2216
2223
  // Infer return type: use explicit annotation, or infer from body. Thread
2217
2224
  // the lambda's own param types into the inference so a body like
2218
2225
  // `(n) => n.capacity` can resolve `n` and deduce the return type.
@@ -55,8 +55,6 @@ export declare function resolveHALExprToText(expr: Extract<import("../../api/sha
55
55
  kind: "hal-expr";
56
56
  }>): string | null;
57
57
  export declare function registerFloatVariable(name: string): void;
58
- /** Build snprintf prelude lines from a string_concat expression.
59
- * Returns { lines, bufferName } or null if the expression can't be formatted. */
60
58
  export declare function buildSnprintfFromConcat(expr: Extract<ExpressionIR, {
61
59
  kind: "string_concat";
62
60
  }>): {
@@ -1,11 +1,10 @@
1
1
  import ts from "typescript";
2
- import { requiredIncludes, registeredCallbacks, activeStringVars, TYPED_ARRAY_ELEMENT_MAP, getContext, floatVariables, halInstances, getCurrentBoardConstants } from "../build-ir-state.js";
2
+ import { requiredIncludes, registeredCallbacks, activeStringVars, TYPED_ARRAY_ELEMENT_MAP, getContext, floatVariables, halInstances, getCurrentBoardConstants, markHalOpResolved } from "../build-ir-state.js";
3
3
  import { getCurrentIrTypeScope } from "../symbol-types.js";
4
4
  import { renderExprAsText } from "../render-expr.js";
5
- import { escapeCppKeyword } from "../../utils/strings.js";
5
+ import { escapeCppKeyword, escapeCppStringLiteral } from "../../utils/strings.js";
6
6
  import { halClassRegistry, halGlobalFunctions } from "./hal-parser.js";
7
7
  import { tryResolveSemanticCall, tryResolveBoardResolveArg, tryResolveCompoundSemanticReturn, resolveConcatPath } from "./hal-plugins.js";
8
- import { resolveTrackedRead, pinShadowVarName } from "../pin-state-tracking.js";
9
8
  import { cppTypeForHalOp } from "../../emit/utils/hal-op-cpp-type.js";
10
9
  /** Escape C++ keywords in resolved text, but only when the text looks like a
11
10
  * variable reference (not a literal like "false", "true", "42", or a string). */
@@ -65,16 +64,6 @@ function inlineThisGetterCall(methodName, pin, strategy) {
65
64
  // lower to the tracked level (constant when statically known, shadow
66
65
  // variable otherwise) instead of a hardware read. Reading back a
67
66
  // direction-only output is not portable (e.g. Zephyr).
68
- const pinNum = Number.parseInt(pin, 10);
69
- if (Number.isFinite(pinNum)) {
70
- const tracked = resolveTrackedRead(pinNum);
71
- if (tracked !== null) {
72
- const levelText = tracked === "shadow"
73
- ? pinShadowVarName(pinNum)
74
- : (tracked === "high" ? "true" : "false");
75
- return methodName === "isLow" ? `(!${levelText})` : levelText;
76
- }
77
- }
78
67
  if (methodName === "read")
79
68
  return strategy?.readDigitalPin?.(pin) ?? `digitalRead(${pin})`;
80
69
  if (methodName === "isHigh")
@@ -150,8 +139,12 @@ export function resolveExpressionText(expr, instance, paramNames, callArgTexts,
150
139
  }
151
140
  if (ts.isNumericLiteral(expr))
152
141
  return expr.text;
142
+ // Escape the DECODED text back to a valid C++ literal — expr.text holds
143
+ // real control chars (a "\n" argument decodes to a newline), and a raw
144
+ // newline inside a C string literal is an unterminated literal that
145
+ // corrupts the rest of the file. Same helper every other renderer uses.
153
146
  if (ts.isStringLiteral(expr))
154
- return expr.text;
147
+ return `"${escapeCppStringLiteral(expr.text)}"`;
155
148
  // Call expression (e.g., digitalRead(this._pin), board("path"))
156
149
  if (ts.isCallExpression(expr)) {
157
150
  // callback(param) → return the patched placeholder text
@@ -300,7 +293,7 @@ export function resolveExpressionText(expr, instance, paramNames, callArgTexts,
300
293
  * ESP-IDF, trips -Werror=attributes when IRAM_ATTR's __COUNTER__ disagrees
301
294
  * between forward declaration and definition. */
302
295
  const ISR_CALLBACK_SEMANTIC_FNS = new Set([
303
- "interruptAttach",
296
+ "interruptAttachFlags",
304
297
  ]);
305
298
  /** True when a HAL semantic call name wraps a GPIO/hardware ISR callback. */
306
299
  export function semanticCallUsesIsrCallback(fnName) {
@@ -665,10 +658,16 @@ export function resolveHALExprToText(expr) {
665
658
  if (!strategy?.resolveHALOperation)
666
659
  return null;
667
660
  const resolved = strategy.resolveHALOperation(expr.operation);
668
- if (resolved?.expression)
669
- return resolved.expression;
670
- if (resolved?.code)
671
- return resolved.code.replace(/;\s*$/, "");
661
+ if (resolved) {
662
+ // The op may never exist as an IR node (its text is baked into the
663
+ // calling method's emit lines), so record it for program-analysis's
664
+ // peripheral usage flags.
665
+ markHalOpResolved(expr.operation.operation);
666
+ if (resolved.expression)
667
+ return resolved.expression;
668
+ if (resolved.code)
669
+ return resolved.code.replace(/;\s*$/, "");
670
+ }
672
671
  return null;
673
672
  }
674
673
  export function registerFloatVariable(name) {
@@ -676,6 +675,20 @@ export function registerFloatVariable(name) {
676
675
  }
677
676
  /** Build snprintf prelude lines from a string_concat expression.
678
677
  * Returns { lines, bufferName } or null if the expression can't be formatted. */
678
+ /** True when a binary IR expression touches a known float variable on either
679
+ * side (recursively) — its rendered C++ is double-valued. */
680
+ function binaryTouchesFloatVar(expr) {
681
+ for (const side of [expr.left, expr.right]) {
682
+ if (!side || typeof side !== "object")
683
+ continue;
684
+ const s = side;
685
+ if (s.kind === "identifier" && typeof s.value === "string" && floatVariables.has(s.value))
686
+ return true;
687
+ if (s.kind === "binary" && binaryTouchesFloatVar(s))
688
+ return true;
689
+ }
690
+ return false;
691
+ }
679
692
  export function buildSnprintfFromConcat(expr) {
680
693
  let formatString = "";
681
694
  const args = [];
@@ -685,18 +698,21 @@ export function buildSnprintfFromConcat(expr) {
685
698
  for (const part of expr.parts) {
686
699
  const text = renderExprAsText(part);
687
700
  if (part.kind === "string") {
688
- formatString += text.slice(1, -1).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
701
+ // Escape % %% first (a bare % in the format string starts a
702
+ // conversion — a literal '%RH' becomes the unknown-conversion 'R'),
703
+ // then the C-literal escapes.
704
+ formatString += text.slice(1, -1).replace(/%/g, "%%").replace(/\\/g, "\\\\").replace(/"/g, '\\"');
689
705
  estimatedLength += part.value.length;
690
706
  }
691
707
  else if (part.kind === "number") {
692
708
  const isFloat = part.cppType === "float" || part.cppType === "double" || !Number.isInteger(part.value);
693
709
  if (isFloat) {
694
- requiredIncludes.add("<stdlib.h>");
695
- const floatBuf = `__cuttlefish_float_${getContext().snprintfCounter++}`;
696
- prelude.push(`char ${floatBuf}[16];`);
697
- prelude.push(`dtostrf(${text}, 0, 1, ${floatBuf});`);
698
- formatString += "%s";
699
- args.push(floatBuf);
710
+ // %g formats the double literal directly — portable (Zephyr's
711
+ // cbprintf turns on FP support when it sees a float specifier);
712
+ // dtostrf is AVR-only and fails to compile elsewhere (same reasoning
713
+ // as the float-VARIABLE branch below).
714
+ formatString += "%g";
715
+ args.push(text);
700
716
  estimatedLength += 16;
701
717
  }
702
718
  else {
@@ -710,15 +726,32 @@ export function buildSnprintfFromConcat(expr) {
710
726
  const isStringVar = part.kind === "template_string"
711
727
  && part.expression.kind === "identifier"
712
728
  && (activeStringVars.has(part.expression.value) || getCurrentIrTypeScope()?.locals.get(part.expression.value) === "std::string" || getCurrentIrTypeScope()?.globals.get(part.expression.value) === "std::string");
713
- // Check for float variable reference: template_string wrapping an identifier
729
+ // Check for float variable reference: template_string wrapping an identifier.
730
+ // A var initialized from a double-returning HAL op (sensor.get) records
731
+ // as a float var; one declared `: number` from such an initializer also
732
+ // lands in the IR scope's float types.
714
733
  const isFloatVar = part.kind === "template_string"
715
734
  && part.expression.kind === "identifier"
716
735
  && floatVariables.has(part.expression.value);
736
+ // Inline double-returning HAL call (template_string wrapping a call):
737
+ // the lowerings' deterministic shape for a double return is
738
+ // `static_cast<double>(...)` — Time.now()/sensor.get()/millivolt reads.
739
+ // Formatting that with the %d default is a -Wformat warning at best and
740
+ // wrong output at worst; %g matches the float-variable branch.
741
+ const isDoubleCall = part.kind === "template_string"
742
+ && /^static_cast<double>\(/.test(text);
717
743
  if (isStringVar) {
718
744
  formatString += "%s";
719
745
  const varName = part.expression.value;
720
746
  const varType = getCurrentIrTypeScope()?.locals.get(varName) || getCurrentIrTypeScope()?.globals.get(varName) || "";
721
- const cleanType = varType.replace(/\bconst\b\s*/g, "").trim();
747
+ // Normalize through the ACTIVE strategy before the char* check — the
748
+ // IR scope carries the pre-normalization type ("std::string") while
749
+ // the declaration renderer emitted the strategy's mapping of it
750
+ // (Zephyr: std::string → const char*). Without this, a string-literal
751
+ // variable declares as const char* but its snprintf arg gains a
752
+ // .c_str() that const char* does not have.
753
+ const normalizedType = getContext().activeStrategy?.normalizeCppType(varType) ?? varType;
754
+ const cleanType = normalizedType.replace(/\bconst\b\s*/g, "").trim();
722
755
  if (cleanType && cleanType !== "char*" && cleanType !== "const char*") {
723
756
  args.push(`${text}.c_str()`);
724
757
  }
@@ -728,12 +761,18 @@ export function buildSnprintfFromConcat(expr) {
728
761
  estimatedLength += 32;
729
762
  }
730
763
  else if (isFloatVar) {
731
- requiredIncludes.add("<stdlib.h>");
732
- const floatBuf = `__cuttlefish_float_${getContext().snprintfCounter++}`;
733
- prelude.push(`char ${floatBuf}[16];`);
734
- prelude.push(`dtostrf(${text}, 0, 1, ${floatBuf});`);
735
- formatString += "%s";
736
- args.push(floatBuf);
764
+ // %g formats the double expression directly — portable (Zephyr's
765
+ // cbprintf turns on FP support when it sees a float specifier);
766
+ // dtostrf is AVR-only and fails to compile elsewhere.
767
+ formatString += "%g";
768
+ args.push(text);
769
+ estimatedLength += 16;
770
+ }
771
+ else if (isDoubleCall) {
772
+ // Inline double-returning HAL call (`${Time.now()}`) — the rendered
773
+ // text IS the double expression; %g, never the %d default.
774
+ formatString += "%g";
775
+ args.push(text);
737
776
  estimatedLength += 16;
738
777
  }
739
778
  else if (part.kind === "template_string" && part.expression.kind === "hal-expr") {
@@ -751,6 +790,12 @@ export function buildSnprintfFromConcat(expr) {
751
790
  args.push(`(${argText} ? "true" : "false")`);
752
791
  estimatedLength += 5;
753
792
  }
793
+ else if (cppType === "float" || cppType === "double") {
794
+ // %g formats the double expression directly — no AVR-only dtostrf.
795
+ formatString += "%g";
796
+ args.push(argText);
797
+ estimatedLength += 12;
798
+ }
754
799
  else {
755
800
  formatString += "%d";
756
801
  args.push(argText);
@@ -760,15 +805,21 @@ export function buildSnprintfFromConcat(expr) {
760
805
  else {
761
806
  const numVal = Number(text);
762
807
  if (!isNaN(numVal) && !Number.isInteger(numVal)) {
763
- requiredIncludes.add("<stdlib.h>");
764
- const floatBuf = `__cuttlefish_float_${getContext().snprintfCounter++}`;
765
- const precision = text.includes(".") ? text.split(".")[1].length : 1;
766
- prelude.push(`char ${floatBuf}[16];`);
767
- prelude.push(`dtostrf(${text}, 0, ${precision}, ${floatBuf});`);
768
- formatString += "%s";
769
- args.push(floatBuf);
808
+ // A float literal (or float-valued expression) — %g directly; the
809
+ // AVR dtostrf detour fails to compile on every other framework.
810
+ formatString += "%g";
811
+ args.push(text);
770
812
  estimatedLength += 16;
771
813
  }
814
+ else if (part.kind === "template_string"
815
+ && part.expression.kind === "binary"
816
+ && binaryTouchesFloatVar(part.expression)) {
817
+ // Arithmetic on a double var (`tenths / 10`) is double-valued: %g,
818
+ // not %d — the rendered text is already the C++ expression.
819
+ formatString += "%g";
820
+ args.push(text);
821
+ estimatedLength += 12;
822
+ }
772
823
  else {
773
824
  formatString += "%d";
774
825
  args.push(text);
@@ -16,6 +16,10 @@ export interface HALMethodEntry {
16
16
  export interface HALClassEntry {
17
17
  ctorFieldMap: Map<string, string>;
18
18
  ctorDefaults: Map<string, string>;
19
+ /** Class-field initializer literals ("_spiHz" → "1000000") — the defaults
20
+ * a method body reads when construction didn't set the field. Seeded into
21
+ * instance fieldValues so `this._spiHz` in an inlined method resolves. */
22
+ fieldDefaults: Map<string, string>;
19
23
  methods: Map<string, HALMethodEntry>;
20
24
  }
21
25
  export declare const halClassRegistry: Map<string, HALClassEntry>;
@@ -50,11 +54,7 @@ export declare function extractMethods(cls: ts.ClassDeclaration): Map<string, HA
50
54
  export declare function loadHALModules(force?: boolean): void;
51
55
  /** Get constructor includes for a HAL class. */
52
56
  export declare function getCtorIncludes(className: string): string[];
53
- /** Map an HttpClass factory method name to its HTTP verb, or null. */
54
- export declare function httpFactoryVerb(methodName: string): string | null;
55
- /** Render an Http factory URL argument as C++ expression text (string
56
- * literals quoted, identifiers/member accesses verbatim), or null when the
57
- * argument shape can't be resolved at compile time. */
57
+ export declare function requestCtorFields(ctorArgs: readonly ts.Expression[] | undefined, sourceFile?: ts.SourceFile): Map<string, string> | null;
58
58
  export declare function httpUrlArgText(arg: ts.Expression): string | null;
59
59
  /** Resolve a call receiver to a tracked HAL instance. */
60
60
  export declare function resolveHALReceiver(receiver: ts.Expression): HALInstance | null;