@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
@@ -0,0 +1,664 @@
1
+ // ---------------------------------------------------------------------------
2
+ // NativeStrategy — standard C++ target for portable Windows/Linux executables
3
+ //
4
+ // Outputs standard C++ with main(), std::string, and std::thread-
5
+ // based async. No hardware or Arduino dependencies.
6
+ //
7
+ // EMIT BOUNDARY: This file is a canonical entry point of the framework strategy
8
+ // surface (B) — its main()/stdout scaffold bytes land in user executables.
9
+ // The emitted bytes are covered by the TypeCAD Runtime Exception (see
10
+ // RUNTIME_EXCEPTION.md at the repository root) and are not subject to the
11
+ // license of this tool source.
12
+ // ---------------------------------------------------------------------------
13
+ import { DEFAULT_STDLIB_SUPPORT, generateStaticAsyncRuntime } from '../../api/shared/index.js';
14
+ import { programUsesSafety } from '../../api/index.js';
15
+ import { resolveTerminalPreviewOp } from './graphics/terminal-preview.js';
16
+ export class NativeStrategy {
17
+ constructor() {
18
+ this.id = 'native';
19
+ this._largeEnumNames = new Set();
20
+ }
21
+ // ── Profile ─────────────────────────────────────────────────────────────
22
+ forcedIncludes(program, ctx) {
23
+ // <cstdint>, <cctype>, and <chrono> are universal: type-resolution passes
24
+ // int32_t/uint8_t/etc. through verbatim, char classification is broadly
25
+ // used, and the shim unconditionally emits Date.now()/millis() definitions
26
+ // that reference std::chrono (see shimLines). The remaining headers are
27
+ // gated on usage analysis so a native program that doesn't touch
28
+ // std::vector / etc. doesn't pull them in. When ctx.analysis is absent
29
+ // (capability queries, manifest validation), the gates default open to
30
+ // preserve existing behavior in those paths.
31
+ const inc = ['<cctype>', '<cstdint>', '<chrono>'];
32
+ const a = ctx?.analysis;
33
+ const uses = (f) => a ? !!a[f] : true;
34
+ if (uses('usesVectorTypes'))
35
+ inc.push('<vector>');
36
+ if (uses('usesStdMap'))
37
+ inc.push('<map>');
38
+ if (uses('usesSet'))
39
+ inc.push('<set>');
40
+ if (uses('usesAlgorithm'))
41
+ inc.push('<algorithm>');
42
+ if (uses('usesCstdio'))
43
+ inc.push('<cstdio>');
44
+ return inc;
45
+ }
46
+ symbolAliases() {
47
+ return {};
48
+ }
49
+ shimLines(program, ctx) {
50
+ const a = ctx?.analysis;
51
+ const uses = (f) => a ? !!a[f] : true;
52
+ const baseLines = [
53
+ '// cuttlefish runtime shim. Wrapped in a single include guard so the',
54
+ '// block is safe to emit into multiple headers and .cpp files within',
55
+ '// one translation unit (a .cpp may #include several headers that each',
56
+ '// carry the shim, e.g. when a class method body uses `??` which lowers',
57
+ '// to cuttlefish_nullish(...)). The guard ensures the definitions are',
58
+ '// seen exactly once per TU.',
59
+ '#ifndef CUTTLEFISH_SHIM_DEFINED',
60
+ '#define CUTTLEFISH_SHIM_DEFINED',
61
+ '#ifndef CUTTLEFISH_UNDEFINED',
62
+ '#define CUTTLEFISH_UNDEFINED 0',
63
+ '#endif',
64
+ 'template<typename T> inline bool cuttlefish_is_nullish(const T& v) { return false; }',
65
+ 'inline bool cuttlefish_is_nullish(long long v) { return v == CUTTLEFISH_UNDEFINED; }',
66
+ 'inline bool cuttlefish_is_nullish(int v) { return v == CUTTLEFISH_UNDEFINED; }',
67
+ 'inline bool cuttlefish_is_nullish(double v) { return v == static_cast<double>(CUTTLEFISH_UNDEFINED); }',
68
+ 'inline bool cuttlefish_is_nullish(bool v) { return v == false; }',
69
+ 'template<typename T> inline bool cuttlefish_is_nullish(T* v) { return v == nullptr; }',
70
+ 'template<typename T> inline bool cuttlefish_exists(const T& v) { return !cuttlefish_is_nullish(v); }',
71
+ 'template<typename T, typename U> inline T cuttlefish_nullish(const T& a, U b) { return !cuttlefish_is_nullish(a) ? a : (T)b; }',
72
+ 'namespace Date { inline long now() { auto t = std::chrono::system_clock::now(); return static_cast<long>(std::chrono::duration_cast<std::chrono::milliseconds>(t.time_since_epoch()).count()); } }',
73
+ 'inline uint32_t __tc_now_ms(void) { return static_cast<uint32_t>(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count()); }',
74
+ ];
75
+ // Arduino-compat polyfills (pin reads, constrain, map) — emit only when the
76
+ // program (or a mounted UI) actually references them. The UI runtime references
77
+ // digitalRead/HIGH/LOW, so emit them when GPIO is in use too. Default open
78
+ // when ctx.analysis is absent (capability queries).
79
+ if (uses('usesDigitalRead') || uses('usesGPIO')) {
80
+ baseLines.push('#ifndef HIGH', '#define HIGH 1', '#endif', '#ifndef LOW', '#define LOW 0', '#endif', '#ifndef PROGMEM', '#define PROGMEM', '#endif', 'inline int digitalRead(int) { return LOW; }');
81
+ }
82
+ if (uses('usesMap')) {
83
+ baseLines.push('inline long map(long x, long in_min, long in_max, long out_min, long out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; }');
84
+ }
85
+ if (uses('usesConstrain')) {
86
+ baseLines.push('inline long constrain(long x, long a, long b) { return x < a ? a : (x > b ? b : x); }');
87
+ }
88
+ baseLines.push('#endif // CUTTLEFISH_SHIM_DEFINED');
89
+ // Safety: emit the __tc_gpio_read / __tc_delay_us shims when the program
90
+ // uses @typecad/safety. Native target stubs GPIO read (the SDL simulator
91
+ // doesn't model real digital input levels) and the microsecond delay
92
+ // (no real timing source); returns 0 (LOW) / no-op. Real native demos
93
+ // that exercise safe.read would need their own input source wired in here.
94
+ if (program && programUsesSafety(program)) {
95
+ baseLines.push('inline int __tc_gpio_read(uint32_t pin) { return 0; }', 'inline void __tc_gpio_write(uint32_t pin, uint32_t value) { (void)pin; (void)value; }', '#ifndef __TC_DELAY_US_DEFINED', '#define __TC_DELAY_US_DEFINED', 'inline void __tc_delay_us(uint32_t us) { (void)us; }', '#endif');
96
+ }
97
+ return baseLines;
98
+ }
99
+ profileDiagnostics() {
100
+ return [];
101
+ }
102
+ // ── File shape ──────────────────────────────────────────────────────────
103
+ sourceExtension() {
104
+ return 'cpp';
105
+ }
106
+ entrypointFunctionName() {
107
+ return 'main';
108
+ }
109
+ requiresLoopFunction() {
110
+ return false;
111
+ }
112
+ overrideBaseName(originalBaseName) {
113
+ return originalBaseName;
114
+ }
115
+ effectiveEmitMode(requestedMode) {
116
+ return requestedMode;
117
+ }
118
+ // ── Type normalisation ──────────────────────────────────────────────────
119
+ normalizeCppType(typeName) {
120
+ // Preserve auto — C++ compiler deduces the correct type (critical for template returns)
121
+ if (typeName === 'auto')
122
+ return 'auto';
123
+ // JavaScript number is 64-bit — map to long long to avoid overflow
124
+ if (typeName === 'int')
125
+ return 'long long';
126
+ // JavaScript number fractional precision needs double, not float
127
+ if (typeName === 'float')
128
+ return 'double';
129
+ // Map StaticArray back to its alias name (handled by pipeline typedef)
130
+ if (typeName.startsWith("__tc_StaticArray")) {
131
+ const match = typeName.match(/^__tc_StaticArray<(.+),\s*\d+>$/);
132
+ if (match)
133
+ return `std::vector<${match[1]}>`;
134
+ return typeName.replace("__tc_StaticArray", "StaticArray");
135
+ }
136
+ return typeName;
137
+ }
138
+ defaultNumericType(compliance) {
139
+ return compliance?.isBanned("A3-9-1") ? 'int64_t' : 'long long';
140
+ }
141
+ mapReturnType(functionName, returnType) {
142
+ if (functionName === 'main')
143
+ return 'int';
144
+ return this.normalizeCppType(returnType);
145
+ }
146
+ isStringLikeType(cppType) {
147
+ return cppType === "std::string" || cppType === "const char*" || cppType === "char*";
148
+ }
149
+ isPointerType(cppType) {
150
+ return cppType.endsWith("*");
151
+ }
152
+ mapFunctionName(originalName) {
153
+ if (originalName === '__cuttlefish_entrypoint__')
154
+ return 'main';
155
+ return originalName;
156
+ }
157
+ // ── Expression rendering ────────────────────────────────────────────────
158
+ normalizeRawExpression(value) {
159
+ let prev = '';
160
+ let v = value;
161
+ // NOTE: array/collection method lowering (`.push`/`.pop`/`.map`/`.filter`/
162
+ // `.splice`/... → `__tc_*` helpers) and `.length` → `.size()` previously
163
+ // lived here as RECV-regex rewrites over rendered C++ text. They have been
164
+ // MOVED to structural IR-build-time lowering: array mutators in
165
+ // `ir/transformers/array-methods.ts` `tryLowerArrayAndStringMethods`
166
+ // (gated to hosted targets via `requiresLoopFunction()`), and `.length` in
167
+ // `ir/expression-to-ir.ts` `resolveLengthProperty`. Both render the
168
+ // receiver via `expressionToIR` so pointer/value access is already correct,
169
+ // eliminating the RECV receiver-capture class of bug (demo #22 Finding A,
170
+ // where `(\w+)` stopped at `>` and emitted `this->__tc_pop(ops)`).
171
+ //
172
+ // What remains here is genuinely text-level: literal→sentinel and
173
+ // well-known free-function rewrites that don't depend on symbol resolution.
174
+ while (prev !== v) {
175
+ prev = v;
176
+ v = v.replace(/\bundefined\b/g, 'CUTTLEFISH_UNDEFINED');
177
+ v = v.replace(/\bnull\b/g, 'CUTTLEFISH_UNDEFINED');
178
+ v = v.replace(/Date\.now\(\)/g, 'Date::now()');
179
+ // String-method lowering now happens at IR-build time
180
+ // (tryLowerArrayAndStringMethods in array-methods.ts, demo #27 Findings
181
+ // D/E), so it handles every receiver shape (bare id / this.field /
182
+ // obj.field / X[i]) structurally. The old text-level
183
+ // `applyStringMethodRewrites` call is removed; its RECEIVER_PATTERN only
184
+ // matched bare identifiers and `.member` chains, which left
185
+ // `ALPHABET[i].toLowerCase()` verbatim and failed to register the
186
+ // `__tc_toLowerCase` helper. The native `startsWith` → `rfind` special
187
+ // case is preserved inside the structural lowering (lowerStringMethod).
188
+ v = v.replace(/JSON\.stringify\(([^)]+)\)/g, '__tc_jsonStringify($1)');
189
+ v = v.replace(/JSON\.parse\(([^)]+)\)/g, '__tc_jsonParse($1)');
190
+ }
191
+ return v;
192
+ }
193
+ nullValue() {
194
+ return 'CUTTLEFISH_UNDEFINED';
195
+ }
196
+ wrapStringConcat() {
197
+ return undefined;
198
+ }
199
+ wrapStringObject(value) {
200
+ // With useSnprintfForStrings() = true, concat flows through the snprintf
201
+ // path and this fallback is rarely used. Keep std::to_string for safety,
202
+ // but it must never receive an enum/class instance in practice.
203
+ return `std::to_string(${value})`;
204
+ }
205
+ useSnprintfForStrings() {
206
+ // Unify native with the Arduino/AVR snprintf path so string concatenation
207
+ // handles enums/floats/objects correctly and never emits std::to_string
208
+ // on non-arithmetic types. See inferFormatSpecifier for type handling.
209
+ return true;
210
+ }
211
+ promoteDivisionToDouble() {
212
+ return true;
213
+ }
214
+ renameEnumMember(_enumName, memberName) {
215
+ return memberName;
216
+ }
217
+ setLargeEnumNames(names) {
218
+ this._largeEnumNames = new Set(names);
219
+ }
220
+ enumCastType(enumName) {
221
+ return undefined;
222
+ }
223
+ renderBoardDefinitionAccess() {
224
+ return undefined;
225
+ }
226
+ // ── Statement rendering ─────────────────────────────────────────────────
227
+ /**
228
+ * Native lowers array literals to std::vector (not __tc_StaticArray), so the
229
+ * structural array-method lowering must use the std::vector/__tc_* helper form
230
+ * (.push_back, __tc_pop) rather than the StaticArray wrapper's .push/.pop.
231
+ * Embedded/generic targets promote literals to StaticArray and default to true.
232
+ */
233
+ promotesArrayLiteralsToStaticArray() {
234
+ return false;
235
+ }
236
+ renderThrow(valueExpr) {
237
+ return `throw ${valueExpr};`;
238
+ }
239
+ objectFieldInitializer() {
240
+ return undefined;
241
+ }
242
+ overrideClassFieldType(_fieldName, normalizedType) {
243
+ return normalizedType;
244
+ }
245
+ // ── Name guards ─────────────────────────────────────────────────────────
246
+ reservedNames() {
247
+ return new Set();
248
+ }
249
+ passthroughMacroNames() {
250
+ return new Set();
251
+ }
252
+ apiReservedEnumNames() {
253
+ return new Set();
254
+ }
255
+ apiReservedEnumGuard() {
256
+ return '';
257
+ }
258
+ ambientTypeDeclarations() {
259
+ return [
260
+ "",
261
+ " // Host timers — real OS threads back these on the native (host) target",
262
+ " // only. Embedded targets have no JS-named timers: periodic work is a",
263
+ " // Thread.",
264
+ " declare function setInterval(handler: () => void, timeout?: number): number;",
265
+ " declare function setTimeout(handler: () => void, timeout?: number): number;",
266
+ " declare function clearInterval(id: number): void;",
267
+ " declare function clearTimeout(id: number): void;",
268
+ ];
269
+ }
270
+ // ── Includes ────────────────────────────────────────────────────────────
271
+ needsIostream() { return true; }
272
+ needsStdString() { return true; }
273
+ needsStdVector() { return true; }
274
+ needsStdExcept() { return true; }
275
+ needsStdFunction() { return true; }
276
+ mathHeader() { return '<cmath>'; }
277
+ cstringHeader() { return '<cstring>'; }
278
+ needsLargeEnumUnderlying() { return false; }
279
+ // ── Struct field handling ───────────────────────────────────────────────
280
+ renameStructField(fieldName) {
281
+ return fieldName;
282
+ }
283
+ structFieldInitializer() {
284
+ return undefined;
285
+ }
286
+ // ── Async — std::async background pump ──────────────────────────────────
287
+ getAsyncRuntimeConfig() {
288
+ return {
289
+ queueCapacity: 256,
290
+ scheduler: "thread",
291
+ waitForPinEdge: "stub",
292
+ hasPromiseRuntime: true,
293
+ hasTimers: true,
294
+ requiredIncludes: ["<functional>", "<vector>", "<utility>", "<string>", "<thread>", "<chrono>", "<future>"],
295
+ };
296
+ }
297
+ asyncLoopInjection(taskVarNames, configOrBool, hasTimers) {
298
+ let hasPromiseRuntime;
299
+ let hasTimersVal;
300
+ if (typeof configOrBool === 'boolean') {
301
+ hasPromiseRuntime = configOrBool;
302
+ hasTimersVal = hasTimers ?? false;
303
+ }
304
+ else {
305
+ hasPromiseRuntime = configOrBool.hasPromiseRuntime;
306
+ hasTimersVal = configOrBool.hasTimers;
307
+ }
308
+ const lines = [];
309
+ if (taskVarNames.length > 0 || hasPromiseRuntime) {
310
+ lines.push('std::async(std::launch::async, [&]() {');
311
+ lines.push(' while (true) {');
312
+ for (const n of taskVarNames) {
313
+ lines.push(` ${n}.run();`);
314
+ }
315
+ if (hasPromiseRuntime) {
316
+ lines.push(' cuttlefish_pump_microtasks();');
317
+ }
318
+ lines.push(' std::this_thread::sleep_for(std::chrono::milliseconds(1));');
319
+ lines.push(' }');
320
+ lines.push('});');
321
+ }
322
+ return lines;
323
+ }
324
+ asyncDriverFunctionName() {
325
+ return 'main';
326
+ }
327
+ // ── Type aliases ────────────────────────────────────────────────────────
328
+ shouldSkipTypeAlias() {
329
+ return false;
330
+ }
331
+ // ── Diagnostics ─────────────────────────────────────────────────────────
332
+ emitDiagnostics() {
333
+ return [];
334
+ }
335
+ currentTimeMillis() {
336
+ return '__tc_now_ms()';
337
+ }
338
+ // ── Build configuration ──────────────────────────────────────────────────
339
+ asyncQueueCapacity() { return 256; }
340
+ outputSubdirectory(_baseName) { return ".build"; }
341
+ generateHeaderFile() { return true; }
342
+ enumApiGuard(_enumName) { return undefined; }
343
+ getStdLibSupport(_architecture) { return DEFAULT_STDLIB_SUPPORT; }
344
+ // ── Native polyfills ────────────────────────────────────────────────────
345
+ nativePolyfills() {
346
+ return new Set(['console', 'string_methods', 'timer_methods', 'array_methods', 'math_methods']);
347
+ }
348
+ generateNativePolyfills(program) {
349
+ const polyfills = [
350
+ {
351
+ kind: 'polyfill',
352
+ id: 'string_methods',
353
+ domain: 'standard',
354
+ requiredIncludes: ['<sstream>'],
355
+ forwardDeclarations: [],
356
+ helperStructs: [],
357
+ helperFunctions: [
358
+ // ── Core string methods (existing) ─────────────────────────────
359
+ 'inline std::string __tc_toUpperCase(const std::string& s) { std::string r = s; for (auto& c : r) c = static_cast<char>(toupper(static_cast<unsigned char>(c))); return r; }',
360
+ 'inline std::string __tc_toLowerCase(const std::string& s) { std::string r = s; for (auto& c : r) c = static_cast<char>(tolower(static_cast<unsigned char>(c))); return r; }',
361
+ 'inline std::string __tc_trim(const std::string& s) { size_t start = s.find_first_not_of(" \\t\\n\\r"); if (start == std::string::npos) return ""; size_t end = s.find_last_not_of(" \\t\\n\\r"); return s.substr(start, end - start + 1); }',
362
+ 'inline std::string __tc_substring2(const std::string& s, int start, int end) { return s.substr(start, end - start); }',
363
+ 'inline std::string __tc_substring1(const std::string& s, int start) { return s.substr(start); }',
364
+ 'inline std::string __tc_replace(const std::string& s, const std::string& old, const std::string& repl) { std::string r = s; size_t pos = 0; while ((pos = r.find(old, pos)) != std::string::npos) { r.replace(pos, old.length(), repl); pos += repl.length(); } return r; }',
365
+ 'inline std::string __tc_charAt(const std::string& s, int idx) { return std::string(1, s[idx]); }',
366
+ 'inline int __tc_charCodeAt(const std::string& s, int idx) { return static_cast<int>(static_cast<unsigned char>(s[idx])); }',
367
+ 'inline std::vector<std::string> __tc_split(const std::string& s, const std::string& delim) { std::vector<std::string> parts; if (delim.empty()) { for (char c : s) parts.push_back(std::string(1, c)); return parts; } size_t start = 0, end; while ((end = s.find(delim, start)) != std::string::npos) { parts.push_back(s.substr(start, end - start)); start = end + delim.length(); } parts.push_back(s.substr(start)); return parts; }',
368
+ // ── Extended string methods (Phase 1) ──────────────────────────
369
+ 'inline bool __tc_endsWith(const std::string& s, const std::string& suffix) { if (suffix.size() > s.size()) return false; return s.compare(s.size() - suffix.size(), suffix.size(), suffix) == 0; }',
370
+ 'inline int __tc_lastIndexOf(const std::string& s, const std::string& search) { size_t pos = s.rfind(search); return pos != std::string::npos ? static_cast<int>(pos) : -1; }',
371
+ 'inline std::string __tc_padStart(const std::string& s, int len, const std::string& fill) { if (static_cast<int>(s.size()) >= len) return s; std::string result; int padLen = len - static_cast<int>(s.size()); for (int i = 0; i < padLen; i++) result += fill[i % static_cast<int>(fill.size())]; return result + s; }',
372
+ 'inline std::string __tc_padStart_default(const std::string& s, int len) { return __tc_padStart(s, len, " "); }',
373
+ 'inline std::string __tc_padEnd(const std::string& s, int len, const std::string& fill) { if (static_cast<int>(s.size()) >= len) return s; std::string result = s; int padLen = len - static_cast<int>(s.size()); for (int i = 0; i < padLen; i++) result += fill[i % static_cast<int>(fill.size())]; return result; }',
374
+ 'inline std::string __tc_padEnd_default(const std::string& s, int len) { return __tc_padEnd(s, len, " "); }',
375
+ 'inline std::string __tc_repeat(const std::string& s, int count) { std::string result; for (int i = 0; i < count; i++) result += s; return result; }',
376
+ // ── Overloaded includes/indexOf for std::string ────────────────
377
+ 'inline bool __tc_includes(const std::string& s, const std::string& search) { return s.find(search) != std::string::npos; }',
378
+ 'inline int __tc_indexOf(const std::string& s, const std::string& search) { size_t pos = s.find(search); return pos != std::string::npos ? static_cast<int>(pos) : -1; }',
379
+ // ── String slice overloads ──────────────────────────────────────
380
+ 'inline std::string __tc_slice2(const std::string& s, int start, int end) { return s.substr(start, end - start); }',
381
+ 'inline std::string __tc_slice1(const std::string& s, int start) { return s.substr(start); }',
382
+ ],
383
+ shimMacros: [],
384
+ dependencies: [],
385
+ },
386
+ {
387
+ kind: 'polyfill',
388
+ id: 'timer_methods',
389
+ domain: 'standard',
390
+ // <atomic> for the cancel flag, <map>+<memory> for the handle store.
391
+ // <future> kept for any caller that still threads a detached policy.
392
+ requiredIncludes: ['<thread>', '<chrono>', '<future>', '<atomic>', '<map>', '<memory>'],
393
+ forwardDeclarations: [],
394
+ helperStructs: [],
395
+ helperFunctions: [
396
+ // Cancellable timer handles. The old shims launched a detached
397
+ // std::async (`(void)f;`) whose `while(true)` ignored clear* —
398
+ // cancelled timers kept firing and the futures leaked. Timers are a
399
+ // language feature on native (not hardware), so they must actually
400
+ // cancel: each handle owns an atomic cancel flag its worker thread
401
+ // checks each iteration; clear* sets the flag. Leaked handles at
402
+ // process exit are fine (the OS reclaims threads); the fix is about
403
+ // correctness (a cleared timer stops firing) and bounded growth.
404
+ 'struct __tc_timer_handle { std::atomic<bool> cancelled{false}; std::thread worker; };',
405
+ 'static std::map<int, std::shared_ptr<__tc_timer_handle>>& __tc_timers() { static std::map<int, std::shared_ptr<__tc_timer_handle>> m; return m; }',
406
+ 'static int __tc_next_timer_id = 1;',
407
+ 'static int __tc_start_timer(std::function<void()> cb, long long ms, bool repeat) { int id = __tc_next_timer_id++; auto h = std::make_shared<__tc_timer_handle>(); h->worker = std::thread([h, cb, ms, repeat]() { if (repeat) { while (!h->cancelled.load()) { std::this_thread::sleep_for(std::chrono::milliseconds(ms)); if (h->cancelled.load()) break; cb(); } } else { std::this_thread::sleep_for(std::chrono::milliseconds(ms)); if (!h->cancelled.load()) cb(); } }); h->worker.detach(); __tc_timers()[id] = h; return id; }',
408
+ 'int __tc_setTimeout(std::function<void()> cb, long long ms) { return __tc_start_timer(cb, ms, false); }',
409
+ 'int __tc_setInterval(std::function<void()> cb, long long ms) { return __tc_start_timer(cb, ms, true); }',
410
+ 'void __tc_clearInterval(int id) { auto it = __tc_timers().find(id); if (it != __tc_timers().end()) { it->second->cancelled.store(true); __tc_timers().erase(it); } }',
411
+ 'void __tc_clearTimeout(int id) { __tc_clearInterval(id); }',
412
+ ],
413
+ shimMacros: [],
414
+ dependencies: [],
415
+ },
416
+ {
417
+ kind: 'polyfill',
418
+ id: 'math_methods',
419
+ domain: 'standard',
420
+ requiredIncludes: ['<cstdlib>', '<random>', '<iomanip>', '<sstream>'],
421
+ forwardDeclarations: [],
422
+ helperStructs: [],
423
+ helperFunctions: [
424
+ 'inline double __tc_random() { static std::mt19937 gen(std::random_device{}()); static std::uniform_real_distribution<double> dist(0.0, 1.0); return dist(gen); }',
425
+ 'inline std::string __tc_toFixed(double val, int digits) { std::ostringstream oss; oss << std::fixed << std::setprecision(digits) << val; return oss.str(); }',
426
+ ],
427
+ shimMacros: [],
428
+ dependencies: [],
429
+ },
430
+ {
431
+ kind: 'polyfill',
432
+ id: 'array_methods',
433
+ domain: 'standard',
434
+ // `<sstream>` is required by `__tc_join` below (it builds the joined
435
+ // string through a `std::ostringstream`). A project that uses `.join`
436
+ // WITHOUT also pulling in `__tc_toFixed`/`__tc_random` (whose
437
+ // `math_methods` block is what previously transitively included
438
+ // `<sstream>`) emitted the `__tc_join` template with no `<sstream>`
439
+ // → g++ "std::ostringstream has incomplete type". Declaring the include
440
+ // on THIS block makes `.join` self-contained. Demo #32 Finding B.
441
+ requiredIncludes: ['<algorithm>', '<map>', '<sstream>'],
442
+ forwardDeclarations: [],
443
+ helperStructs: [],
444
+ helperFunctions: [
445
+ // ── Core array methods (existing) ───────────────────────────────
446
+ 'template<typename T> std::string __tc_join(const std::vector<T>& v, const std::string& delim) { std::ostringstream oss; for (size_t i = 0; i < v.size(); i++) { if (i > 0) oss << delim; oss << v[i]; } return oss.str(); }',
447
+ 'template<typename T> std::vector<T> __tc_slice2(const std::vector<T>& v, int start, int end) { if (end > static_cast<int>(v.size())) end = static_cast<int>(v.size()); return std::vector<T>(v.begin() + start, v.begin() + end); }',
448
+ 'template<typename T> std::vector<T> __tc_slice1(const std::vector<T>& v, int start) { return std::vector<T>(v.begin() + start, v.end()); }',
449
+ 'template<typename T> std::vector<T> __tc_reverse(std::vector<T> v) { std::reverse(v.begin(), v.end()); return v; }',
450
+ // ── Overloaded includes/indexOf for std::vector ─────────────────
451
+ 'template<typename T> bool __tc_includes(const std::vector<T>& v, const T& val) { return std::find(v.begin(), v.end(), val) != v.end(); }',
452
+ 'template<typename T> int __tc_indexOf(const std::vector<T>& v, const T& val) { auto it = std::find(v.begin(), v.end(), val); return it != v.end() ? static_cast<int>(it - v.begin()) : -1; }',
453
+ // ── Array mutation methods (Phase 1) ────────────────────────────
454
+ 'template<typename T> T __tc_shift(std::vector<T>& v) { T val = v.front(); v.erase(v.begin()); return val; }',
455
+ 'template<typename T> T __tc_pop(std::vector<T>& v) { T val = v.back(); v.pop_back(); return val; }',
456
+ 'template<typename T> void __tc_unshift(std::vector<T>& v, const T& val) { v.insert(v.begin(), val); }',
457
+ 'template<typename T> void __tc_sort(std::vector<T>& v) { std::sort(v.begin(), v.end()); }',
458
+ 'template<typename T, typename F> void __tc_sort_fn(std::vector<T>& v, F comp) { std::sort(v.begin(), v.end(), [&v, comp](const typename std::vector<T>::value_type& a, const typename std::vector<T>::value_type& b) { return comp(a, b) < 0; }); }',
459
+ 'template<typename T> void __tc_fill(std::vector<T>& v, const T& val) { std::fill(v.begin(), v.end(), val); }',
460
+ 'template<typename T> void __tc_fill3(std::vector<T>& v, const T& val, int start, int end) { if (end > static_cast<int>(v.size())) end = static_cast<int>(v.size()); std::fill(v.begin() + start, v.begin() + end, val); }',
461
+ 'template<typename T> std::vector<T> __tc_concat(const std::vector<T>& a, const std::vector<T>& b) { std::vector<T> result = a; result.insert(result.end(), b.begin(), b.end()); return result; }',
462
+ 'template<typename T> std::vector<T> __tc_splice1(std::vector<T>& v, int start) { std::vector<T> removed(v.begin() + start, v.end()); v.erase(v.begin() + start, v.end()); return removed; }',
463
+ 'template<typename T> std::vector<T> __tc_splice2(std::vector<T>& v, int start, int deleteCount) { int end = start + deleteCount; if (end > static_cast<int>(v.size())) end = static_cast<int>(v.size()); std::vector<T> removed(v.begin() + start, v.begin() + end); v.erase(v.begin() + start, v.begin() + end); return removed; }',
464
+ // ── Array functional methods (Phase 1) ──────────────────────────
465
+ 'template<typename T, typename F> std::vector<T> __tc_filter(const std::vector<T>& v, F pred) { std::vector<T> result; for (const auto& x : v) if (pred(x)) result.push_back(x); return result; }',
466
+ 'template<typename T, typename F> auto __tc_map(const std::vector<T>& v, F fn) -> std::vector<decltype(fn(v[0]))> { using R = decltype(fn(v[0])); std::vector<R> result; result.reserve(v.size()); for (const auto& x : v) result.push_back(fn(x)); return result; }',
467
+ 'template<typename T, typename U, typename F> auto __tc_reduce(const std::vector<T>& v, F fn, U init) -> U { U acc = init; for (const auto& x : v) acc = fn(acc, x); return acc; }',
468
+ 'template<typename T, typename F> T __tc_reduce_no_init(std::vector<T>& v, F fn) { T acc = v[0]; for (size_t i = 1; i < v.size(); i++) acc = fn(acc, v[i]); return acc; }',
469
+ 'template<typename T, typename F> T __tc_find(const std::vector<T>& v, F pred) { for (const auto& x : v) if (pred(x)) return x; return T(); }',
470
+ 'template<typename T, typename F> int __tc_findIndex(const std::vector<T>& v, F pred) { for (int i = 0; i < static_cast<int>(v.size()); i++) if (pred(v[i])) return i; return -1; }',
471
+ 'template<typename T, typename F> bool __tc_every(const std::vector<T>& v, F pred) { for (const auto& x : v) if (!pred(x)) return false; return true; }',
472
+ 'template<typename T, typename F> bool __tc_some(const std::vector<T>& v, F pred) { for (const auto& x : v) if (pred(x)) return true; return false; }',
473
+ // ── Map helper methods (Object.keys/values/entries) ──────────────
474
+ 'template<typename K, typename V> std::vector<K> __tc_mapKeys(const std::map<K, V>& m) { std::vector<K> keys; for (const auto& p : m) keys.push_back(p.first); return keys; }',
475
+ 'template<typename K, typename V> std::vector<V> __tc_mapValues(const std::map<K, V>& m) { std::vector<V> vals; for (const auto& p : m) vals.push_back(p.second); return vals; }',
476
+ 'template<typename K, typename V> std::vector<std::pair<K, V>> __tc_mapEntries(const std::map<K, V>& m) { std::vector<std::pair<K, V>> entries; for (const auto& p : m) entries.push_back(p); return entries; }',
477
+ // ── Set helper methods (Set.values()/keys()/entries()) ───────────
478
+ // Set.values()/keys() both yield the elements; entries() yields
479
+ // pair<elem,elem>. (demo #15 fix A)
480
+ 'template<typename T> std::vector<T> __tc_setValues(const std::set<T>& s) { std::vector<T> vals; for (const auto& x : s) vals.push_back(x); return vals; }',
481
+ 'template<typename T> std::vector<std::pair<T, T>> __tc_setEntries(const std::set<T>& s) { std::vector<std::pair<T, T>> entries; for (const auto& x : s) entries.push_back({x, x}); return entries; }',
482
+ // ── Object.fromEntries helper ───────────────────────────────
483
+ 'template<typename K, typename V> std::map<K, V> __tc_fromEntries(const std::vector<std::pair<K, V>>& entries) { std::map<K, V> result; for (const auto& p : entries) result[p.first] = p.second; return result; }',
484
+ // ── JSON helpers ─────────────────────────────────────────────
485
+ 'inline std::string __tc_jsonStringify(const std::string& s) { return s; }',
486
+ 'template<typename T> std::string __tc_jsonStringify(const T& v) { return std::to_string(v); }',
487
+ 'inline std::string __tc_jsonParse(const std::string& s) { return s; }',
488
+ ],
489
+ shimMacros: [],
490
+ dependencies: [],
491
+ },
492
+ ];
493
+ // Heap-free async runtime, mirroring the Zephyr strategy: the static
494
+ // runtime needs no STL headers and polls the millis() shim the native
495
+ // base shim defines unconditionally. Polyfill definitions emit before
496
+ // shimLines, so forward-declare millis() for the runtime's timer bodies.
497
+ if (program && program.functions.some((fn) => fn && fn.isAsync)) {
498
+ polyfills.push({
499
+ kind: 'polyfill',
500
+ id: 'async_runtime',
501
+ domain: 'embedded',
502
+ requiredIncludes: [],
503
+ forwardDeclarations: ['uint32_t __tc_now_ms(void);'],
504
+ helperStructs: [generateStaticAsyncRuntime(8, this.getAsyncRuntimeConfig().waitForPinEdge)],
505
+ helperFunctions: [],
506
+ shimMacros: [],
507
+ dependencies: [],
508
+ hasPromiseRuntime: true,
509
+ });
510
+ }
511
+ return polyfills;
512
+ }
513
+ // ── Graphics ───────────────────────────────────────────────────────────
514
+ resolveDisplayOp(op) {
515
+ // The sdl driver has a real display adapter (SdlGfxTarget) that defines
516
+ // display_init() etc., so route its display.init op to a real call instead
517
+ // of the terminal-preview comment. Other ops (fill_rect/draw_text/flush)
518
+ // are drawn by the reactive runtime through the HAL, not via DisplayHALOp,
519
+ // so they stay as comments (harmless — the runtime drives the real draws).
520
+ if (op.operation === "display.init" && op.driver === "sdl") {
521
+ return { code: "display_init();" };
522
+ }
523
+ return resolveTerminalPreviewOp(op);
524
+ }
525
+ // SDL event loop: pump SDL events, tick the UI, present the framebuffer each
526
+ // frame. Only active when a UI is mounted (the emitter's entryHasUI() gate),
527
+ // so non-UI native programs stay single-shot. The preIteration body is emitted
528
+ // into the same .cpp as the runtime header, so it can call ui_kb_* /
529
+ // ui_apply_scroll_delta / ui_hit_test / __ui_kb_visible directly.
530
+ hostEventLoop() {
531
+ return {
532
+ flagName: "sdl_running",
533
+ continueCondition: "sdl_running",
534
+ preIteration: [
535
+ // Feature 3 — event-driven mouse: SDL_MOUSEBUTTONDOWN/MOTION/BUTTONUP
536
+ // write to file-scope __sdl_mouse_* state that the SDL touch shim reads
537
+ // (instead of polling SDL_GetMouseState every frame). The flags are
538
+ // declared alongside the other __sdl_* globals in the SDL adapter.
539
+ `SDL_Event __e; while (SDL_PollEvent(&__e)) {`,
540
+ ` if (__e.type == SDL_QUIT) { sdl_running = false; }`,
541
+ ` else if (__e.type == SDL_MOUSEBUTTONDOWN || __e.type == SDL_MOUSEBUTTONUP) {`,
542
+ ` __sdl_mouse_down = (__e.type == SDL_MOUSEBUTTONDOWN && __e.button.button == SDL_BUTTON_LEFT) ? 1 : 0;`,
543
+ ` __sdl_mouse_x = static_cast<int16_t>(__e.button.x);`,
544
+ ` __sdl_mouse_y = static_cast<int16_t>(__e.button.y);`,
545
+ ` } else if (__e.type == SDL_MOUSEMOTION) {`,
546
+ ` __sdl_mouse_x = static_cast<int16_t>(__e.motion.x);`,
547
+ ` __sdl_mouse_y = static_cast<int16_t>(__e.motion.y);`,
548
+ ` }`,
549
+ // Feature 1 — real keyboard text input: route keystrokes into the
550
+ // on-screen keyboard buffer while it's visible, so a desktop user types
551
+ // on their real keyboard instead of clicking the 6×4 grid. Start/stop
552
+ // SDL text input to track visibility (also enables IME composition).
553
+ ` else if (__e.type == SDL_TEXTINPUT) {`,
554
+ ` if (__ui_kb_visible) { for (int __i = 0; __e.text.text[__i] != 0 && __i < 4; __i++) ui_kb_insert(__e.text.text[__i]); }`,
555
+ ` } else if (__e.type == SDL_KEYDOWN && __ui_kb_visible) {`,
556
+ ` if (__e.key.keysym.sym == SDLK_BACKSPACE) ui_kb_delete();`,
557
+ ` else if (__e.key.keysym.sym == SDLK_RETURN || __e.key.keysym.sym == SDLK_KP_ENTER || __e.key.keysym.sym == SDLK_ESCAPE) ui_kb_close();`,
558
+ ` }`,
559
+ // Feature 2 — mouse-wheel scrolling: SDL_MOUSEWHEEL scrolls the
560
+ // scrollable container under the cursor. Query the live mouse position
561
+ // here (NOT __sdl_mouse_x/y — those only update on MOTION, so they go
562
+ // stale when the user stops moving the mouse and just spins the wheel).
563
+ // Use ui_scroll_node_at (the same scan the touch path uses) — the
564
+ // hit-test + ancestor-walk approach misses when the cursor is over a
565
+ // non-child node (text/sibling/padding), giving "works on some screens,
566
+ // needs two attempts" behavior. Pass event.wheel.y through UNNEGATED:
567
+ // ui_apply_scroll_delta does nextY = sy - dy, so wheel-down (-1) yields
568
+ // dy=-40 → scrollY increases → scrolls toward bottom (the desktop
569
+ // expectation). SDL already delivers the OS's natural-scroll direction,
570
+ // so this respects the system preference with no extra setting needed.
571
+ ` else if (__e.type == SDL_MOUSEWHEEL && !__ui_kb_visible) {`,
572
+ ` int __wx, __wy; SDL_GetMouseState(&__wx, &__wy);`,
573
+ // Scale window/logical coords to framebuffer coords (same as
574
+ // touch_readRaw) so the hit-test lands on the right node in fullscreen,
575
+ // where the window is larger than the fixed w_×h_ framebuffer.
576
+ ` int __ww = 0, __wh = 0; SDL_GetWindowSize(__tc_display.win, &__ww, &__wh);`,
577
+ ` if (__ww <= 0) __ww = display_width();`,
578
+ ` if (__wh <= 0) __wh = display_height();`,
579
+ ` int16_t __fx = static_cast<int16_t>(static_cast<int32_t>(__wx) * display_width() / __ww);`,
580
+ ` int16_t __fy = static_cast<int16_t>(static_cast<int32_t>(__wy) * display_height() / __wh);`,
581
+ ` int16_t __owner = ui_scroll_node_at(__fx, __fy);`,
582
+ ` if (__owner >= 0) ui_apply_scroll_delta(__owner, static_cast<int16_t>(__e.wheel.y * 40));`,
583
+ ` }`,
584
+ `}`,
585
+ // Track keyboard visibility with SDL text input so IME composition works
586
+ // and the OS shows an on-screen cursor while typing. Self-corrects each
587
+ // frame rather than hooking ui_kb_open/close (no cross-layer wiring).
588
+ `if (__ui_kb_visible && !SDL_IsTextInputActive()) SDL_StartTextInput();`,
589
+ `else if (!__ui_kb_visible && SDL_IsTextInputActive()) SDL_StopTextInput();`,
590
+ ].join(" "),
591
+ postIteration: "display_present();",
592
+ };
593
+ }
594
+ supportedDisplayDrivers() {
595
+ // Only `sdl` has a registered display adapter (display-adapter.ts registers
596
+ // st7796/ssd1680/ssd1309/sdl/ili9341). `native-preview` was a terminal-stub
597
+ // concept that was never wired up as a real adapter — advertising it here
598
+ // let mount validation pass and then crashed the transpile with
599
+ // "No display adapter registered for driver native-preview". Drop it so the
600
+ // standard "Unsupported display driver" error fires up front instead.
601
+ return new Set(["sdl"]);
602
+ }
603
+ modelsGpio() {
604
+ // The SDL desktop target has no GPIO pins. ui.watchPin / ui.press({pin})
605
+ // are GPIO-hardware APIs with no native equivalent — the shim's digitalRead
606
+ // returns constant LOW (so watchers never fire) and pinMode/attachInterrupt
607
+ // are undefined (link failure). Returning false makes the entrypoint
608
+ // synthesizer emit a clear transpile-time diagnostic instead of those.
609
+ return false;
610
+ }
611
+ // ── Atomic HAL primitives (no GPIO on the native target) ──────────────────
612
+ // These return documented no-op stubs so cuttlefish never emits a Wiring
613
+ // token by name. The native target has no GPIO/timing hardware.
614
+ readDigitalPin(_pin) {
615
+ return "/* gpio unavailable on native target */ 0";
616
+ }
617
+ readAnalogPin(_pin) {
618
+ return "/* adc unavailable on native target */ 0";
619
+ }
620
+ writeDigitalPin(_pin, _val) {
621
+ return "/* gpio unavailable on native target */";
622
+ }
623
+ setPinMode(_pin, _mode) {
624
+ return "/* gpio unavailable on native target */";
625
+ }
626
+ delayMs(_ms) {
627
+ return "/* delay unavailable on native target */";
628
+ }
629
+ delayMicroseconds(_us) {
630
+ return "/* delay unavailable on native target */";
631
+ }
632
+ halCallNames() {
633
+ return new Set();
634
+ }
635
+ isHalCall(_name) {
636
+ return false;
637
+ }
638
+ analogReadCallNames() {
639
+ return new Set();
640
+ }
641
+ colorFormat() {
642
+ // Honor the resolved display profile's colorFormat so an rgb888 SDL target
643
+ // lowers colors at full 888 precision (and emits UI_COLOR_DEPTH 888).
644
+ // Defaults to rgb565 for non-display native programs (byte-identical).
645
+ try {
646
+ const { getDisplayProfile } = require('../../api/shared/index.js');
647
+ const profile = getDisplayProfile?.();
648
+ if (profile?.colorFormat)
649
+ return profile.colorFormat;
650
+ }
651
+ catch {
652
+ // getDisplayProfile not available (e.g. capability query before a build) → default.
653
+ }
654
+ return "rgb565";
655
+ }
656
+ graphicsCapacity() {
657
+ return {
658
+ maxNodes: Number.MAX_SAFE_INTEGER,
659
+ maxBindings: Number.MAX_SAFE_INTEGER,
660
+ maxActiveTransitions: Number.MAX_SAFE_INTEGER,
661
+ nodeStorage: "flash",
662
+ };
663
+ }
664
+ }