@typecad/cuttlefish 1.0.0-alpha.14 → 1.0.0-alpha.16

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 (315) hide show
  1. package/README.md +82 -79
  2. package/assets/editor-extensions/typecad-debug/README.md +25 -26
  3. package/dist/api/config.d.ts +22 -26
  4. package/dist/api/schema/types.d.ts +20 -3
  5. package/dist/api/shared/async-runtime-static.d.ts +1 -1
  6. package/dist/api/shared/async-runtime-static.js +5 -5
  7. package/dist/api/shared/async-types.d.ts +3 -2
  8. package/dist/api/shared/board-catalog.d.ts +2 -0
  9. package/dist/api/shared/board-catalog.js +6 -0
  10. package/dist/api/shared/board-resolver.d.ts +4 -7
  11. package/dist/api/shared/board-resolver.js +2 -1
  12. package/dist/api/shared/coop-scheduler.d.ts +1 -1
  13. package/dist/api/shared/coop-scheduler.js +1 -1
  14. package/dist/api/shared/cpp-type-ir.d.ts +1 -1
  15. package/dist/api/shared/cpp-type-ir.js +1 -1
  16. package/dist/api/shared/display-profile.d.ts +1 -1
  17. package/dist/api/shared/display-profile.js +3 -5
  18. package/dist/api/shared/framework-manifest-registry.d.ts +1 -1
  19. package/dist/api/shared/framework-manifest-registry.js +0 -1
  20. package/dist/api/shared/framework-manifest.d.ts +7 -6
  21. package/dist/api/shared/framework-manifest.js +6 -11
  22. package/dist/api/shared/hal-op-ir.d.ts +294 -685
  23. package/dist/api/shared/hal-op-ir.js +31 -65
  24. package/dist/api/shared/index.d.ts +0 -4
  25. package/dist/api/shared/index.js +1 -7
  26. package/dist/api/shared/ir-core.d.ts +6 -0
  27. package/dist/api/shared/ir-declarations.d.ts +4 -0
  28. package/dist/api/shared/ir.d.ts +1 -3
  29. package/dist/api/shared/platform-strategy.d.ts +14 -37
  30. package/dist/api/shared/polyfill-helper-registry.js +0 -5
  31. package/dist/api/shared/polyfill-types.js +0 -27
  32. package/dist/api/shared/promise-runtime.js +3 -3
  33. package/dist/api/shared/spdx-licenses.d.ts +12 -10
  34. package/dist/api/shared/spdx-licenses.js +1 -1
  35. package/dist/api/shared/toolchain-types.d.ts +1 -1
  36. package/dist/api/shared/toolchain-types.js +3 -3
  37. package/dist/api/shared/types.d.ts +0 -3
  38. package/dist/api/shared/validate-framework-manifest.js +13 -33
  39. package/dist/board-catalog/dts-reader.d.ts +220 -0
  40. package/dist/board-catalog/dts-reader.js +1052 -0
  41. package/dist/board-catalog/index.d.ts +11 -0
  42. package/dist/board-catalog/index.js +12 -0
  43. package/dist/board-catalog/pinconfig.d.ts +48 -0
  44. package/dist/board-catalog/pinconfig.js +263 -0
  45. package/dist/board-catalog/sdk.d.ts +82 -0
  46. package/dist/board-catalog/sdk.js +180 -0
  47. package/dist/board-catalog/store.d.ts +196 -0
  48. package/dist/board-catalog/store.js +363 -0
  49. package/dist/board-catalog/types.d.ts +233 -0
  50. package/dist/board-catalog/types.js +7 -0
  51. package/dist/board-catalog/walker.d.ts +112 -0
  52. package/dist/board-catalog/walker.js +1101 -0
  53. package/dist/cli-utils.d.ts +2 -2
  54. package/dist/cli-utils.js +5 -5
  55. package/dist/cli.js +219 -242
  56. package/dist/config-loader.d.ts +14 -19
  57. package/dist/config-loader.js +240 -78
  58. package/dist/config-schema.d.ts +3 -5
  59. package/dist/config-schema.js +8 -8
  60. package/dist/contract/board-generator.d.ts +4 -4
  61. package/dist/contract/board-generator.js +16 -5
  62. package/dist/contract/contract-parser.d.ts +27 -0
  63. package/dist/contract/contract-parser.js +76 -0
  64. package/dist/contract/index.d.ts +1 -1
  65. package/dist/contract/index.js +70 -21
  66. package/dist/create/active-board-catalog.d.ts +9 -0
  67. package/dist/create/active-board-catalog.js +94 -0
  68. package/dist/create/board-catalog.generated.d.ts +96 -0
  69. package/dist/create/board-catalog.generated.js +128737 -0
  70. package/dist/create/board-search.d.ts +23 -0
  71. package/dist/create/board-search.js +88 -0
  72. package/dist/create/editor-integration.d.ts +4 -2
  73. package/dist/create/editor-integration.js +41 -2
  74. package/dist/create/framework-catalog.d.ts +57 -9
  75. package/dist/create/framework-catalog.js +76 -57
  76. package/dist/create/index.d.ts +5 -11
  77. package/dist/create/index.js +3 -8
  78. package/dist/create/mcu-target.d.ts +39 -0
  79. package/dist/create/mcu-target.js +80 -0
  80. package/dist/create/pack-targets.d.ts +19 -0
  81. package/dist/create/pack-targets.js +56 -0
  82. package/dist/create/scaffold.d.ts +4 -7
  83. package/dist/create/scaffold.js +19 -109
  84. package/dist/create/templates.d.ts +32 -5
  85. package/dist/create/templates.js +130 -116
  86. package/dist/create/wizard.d.ts +12 -1
  87. package/dist/create/wizard.js +168 -38
  88. package/dist/debug/preprocessor.d.ts +5 -0
  89. package/dist/debug/preprocessor.js +31 -7
  90. package/dist/diagnostics/diagnostics-report.d.ts +1 -1
  91. package/dist/diagnostics/diagnostics-report.js +3 -11
  92. package/dist/diagnostics/json-schema.d.ts +1 -1
  93. package/dist/diagnostics/md-writer.js +2 -2
  94. package/dist/diagnostics/mermaid-builder.d.ts +1 -1
  95. package/dist/diagnostics/mermaid-builder.js +1 -1
  96. package/dist/emit/cpp-emitter.js +4 -1
  97. package/dist/emit/emitters/class-emitter.js +32 -4
  98. package/dist/emit/emitters/emitter-context.d.ts +11 -0
  99. package/dist/emit/emitters/entrypoint-synthesizer.js +1 -1
  100. package/dist/emit/emitters/function-emitter-impl.js +33 -17
  101. package/dist/emit/emitters/output-finalizer.d.ts +7 -0
  102. package/dist/emit/emitters/output-finalizer.js +31 -23
  103. package/dist/emit/emitters/setup.js +125 -63
  104. package/dist/emit/emitters/top-level-prep.js +1 -1
  105. package/dist/emit/emitters/type-decl-emitter.js +13 -8
  106. package/dist/emit/emitters/ui-emitter.js +1 -1
  107. package/dist/emit/expression-renderer.d.ts +3 -3
  108. package/dist/emit/expression-renderer.js +17 -7
  109. package/dist/emit/route-hal-op.js +17 -48
  110. package/dist/emit/snprintf-helpers.d.ts +1 -3
  111. package/dist/emit/snprintf-helpers.js +1 -39
  112. package/dist/emit/statement-renderer.d.ts +0 -4
  113. package/dist/emit/statement-renderer.js +54 -45
  114. package/dist/emit/utils/async-state-machine.d.ts +16 -9
  115. package/dist/emit/utils/async-state-machine.js +56 -54
  116. package/dist/emit/utils/comment-helpers.d.ts +0 -8
  117. package/dist/emit/utils/comment-helpers.js +1 -1
  118. package/dist/emit/utils/cpp-helpers.d.ts +2 -2
  119. package/dist/emit/utils/cpp-helpers.js +2 -2
  120. package/dist/emit/utils/hal-op-cpp-type.js +4 -6
  121. package/dist/emit/utils/index.d.ts +3 -3
  122. package/dist/emit/utils/index.js +3 -3
  123. package/dist/emit/utils/type-inference.d.ts +1 -29
  124. package/dist/emit/utils/type-inference.js +0 -75
  125. package/dist/framework-package.d.ts +3 -0
  126. package/dist/framework-package.js +23 -6
  127. package/dist/framework-registry.d.ts +5 -5
  128. package/dist/frameworks/native/graphics/terminal-preview.d.ts +5 -0
  129. package/dist/frameworks/native/graphics/terminal-preview.js +33 -0
  130. package/dist/frameworks/native/index.d.ts +3 -0
  131. package/dist/frameworks/native/index.js +15 -0
  132. package/dist/frameworks/native/native-compile.d.ts +17 -0
  133. package/dist/frameworks/native/native-compile.js +170 -0
  134. package/dist/frameworks/native/native-config.d.ts +41 -0
  135. package/dist/frameworks/native/native-config.js +7 -0
  136. package/dist/frameworks/native/strategy.d.ts +97 -0
  137. package/dist/frameworks/native/strategy.js +664 -0
  138. package/dist/ir/board-resolver.d.ts +18 -23
  139. package/dist/ir/board-resolver.js +43 -401
  140. package/dist/ir/build-ir-state.d.ts +3 -0
  141. package/dist/ir/build-ir-state.js +42 -0
  142. package/dist/ir/build-ir.d.ts +1 -1
  143. package/dist/ir/build-ir.js +40 -42
  144. package/dist/ir/declaration-builders.js +1 -0
  145. package/dist/ir/expression-to-ir.js +17 -10
  146. package/dist/ir/hal/hal-emitter.d.ts +0 -2
  147. package/dist/ir/hal/hal-emitter.js +92 -41
  148. package/dist/ir/hal/hal-parser.d.ts +5 -5
  149. package/dist/ir/hal/hal-parser.js +128 -36
  150. package/dist/ir/hal/hal-plugins.d.ts +0 -1
  151. package/dist/ir/hal/hal-plugins.js +425 -716
  152. package/dist/ir/heap-analysis.js +2 -41
  153. package/dist/ir/identifier-collector.js +32 -20
  154. package/dist/ir/network-validation.js +7 -11
  155. package/dist/ir/ownership-analysis.js +75 -13
  156. package/dist/ir/peripheral-usage.d.ts +8 -2
  157. package/dist/ir/peripheral-usage.js +78 -149
  158. package/dist/ir/peripheral-validation.js +23 -3
  159. package/dist/ir/pin-capability-validation.d.ts +12 -0
  160. package/dist/ir/pin-capability-validation.js +61 -97
  161. package/dist/ir/pin-mode-validation.js +5 -5
  162. package/dist/ir/program-analysis.d.ts +8 -15
  163. package/dist/ir/program-analysis.js +140 -323
  164. package/dist/ir/pulldown-validation.js +11 -4
  165. package/dist/ir/resource-analysis.js +15 -3
  166. package/dist/ir/statement-to-ir.js +0 -6
  167. package/dist/ir/timing-validation.js +1 -1
  168. package/dist/ir/transformers/array-methods.js +11 -5
  169. package/dist/ir/transformers/call-statement.js +20 -87
  170. package/dist/ir/transformers/callback-context-registry.d.ts +1 -1
  171. package/dist/ir/transformers/callback-context-registry.js +8 -16
  172. package/dist/ir/transformers/control-flow.js +0 -13
  173. package/dist/ir/transformers/expressions.js +10 -9
  174. package/dist/ir/transformers/hal-call-resolver.d.ts +2 -2
  175. package/dist/ir/transformers/hal-call-resolver.js +24 -10
  176. package/dist/ir/transformers/hal-emit-helpers.d.ts +2 -2
  177. package/dist/ir/transformers/hal-emit-helpers.js +2 -2
  178. package/dist/ir/transformers/namespace-methods.js +1 -1
  179. package/dist/ir/transformers/ui-callback-lowering.d.ts +0 -2
  180. package/dist/ir/transformers/ui-callback-lowering.js +0 -24
  181. package/dist/ir/transformers/variables.js +338 -42
  182. package/dist/ir/try-catch-validation.js +4 -3
  183. package/dist/ir/type-resolution.js +15 -4
  184. package/dist/ir/validation-orchestrator.js +0 -9
  185. package/dist/libdef/cpp-to-decl.d.ts +0 -9
  186. package/dist/libdef/cpp-to-decl.js +0 -72
  187. package/dist/libdef/registry.d.ts +0 -1
  188. package/dist/libdef/registry.js +1 -24
  189. package/dist/library/init.d.ts +1 -1
  190. package/dist/library/init.js +137 -137
  191. package/dist/library-packages.d.ts +1 -1
  192. package/dist/library-packages.js +1 -1
  193. package/dist/mapping/peripheral-names.js +9 -4
  194. package/dist/mapping/source-map.d.ts +3 -4
  195. package/dist/mapping/source-map.js +12 -18
  196. package/dist/orchestrator/graph-builder.d.ts +3 -3
  197. package/dist/orchestrator/graph-builder.js +13 -12
  198. package/dist/orchestrator/type-checker.d.ts +3 -3
  199. package/dist/orchestrator/type-checker.js +3 -3
  200. package/dist/platform/async-runtime.js +1 -1
  201. package/dist/platform/coop-scheduler-runtime.js +2 -2
  202. package/dist/platform/generic-debug-codegen.d.ts +36 -0
  203. package/dist/platform/generic-debug-codegen.js +185 -0
  204. package/dist/platform/generic-strategy.d.ts +3 -4
  205. package/dist/platform/generic-strategy.js +5 -80
  206. package/dist/platform/index.js +1 -1
  207. package/dist/platform/registry.d.ts +2 -2
  208. package/dist/platform/registry.js +2 -2
  209. package/dist/safety/asil-decorators.d.ts +32 -0
  210. package/dist/safety/asil-decorators.js +32 -0
  211. package/dist/safety/authoring.d.ts +85 -0
  212. package/dist/safety/authoring.js +61 -0
  213. package/dist/safety/engine.d.ts +3 -0
  214. package/dist/safety/engine.js +83 -0
  215. package/dist/safety/hal/ops.d.ts +48 -0
  216. package/dist/safety/hal/ops.js +46 -0
  217. package/dist/safety/iso26262/analyze.d.ts +13 -0
  218. package/dist/safety/iso26262/analyze.js +29 -0
  219. package/dist/safety/iso26262/asil.d.ts +10 -0
  220. package/dist/safety/iso26262/asil.js +22 -0
  221. package/dist/safety/iso26262/collect.d.ts +14 -0
  222. package/dist/safety/iso26262/collect.js +137 -0
  223. package/dist/safety/iso26262/goto-checker.d.ts +10 -0
  224. package/dist/safety/iso26262/goto-checker.js +72 -0
  225. package/dist/safety/iso26262/heap-checker.d.ts +7 -0
  226. package/dist/safety/iso26262/heap-checker.js +57 -0
  227. package/dist/safety/iso26262/init-checker.d.ts +13 -0
  228. package/dist/safety/iso26262/init-checker.js +127 -0
  229. package/dist/safety/iso26262/loop-checker.d.ts +7 -0
  230. package/dist/safety/iso26262/loop-checker.js +86 -0
  231. package/dist/safety/iso26262/recursion-checker.d.ts +9 -0
  232. package/dist/safety/iso26262/recursion-checker.js +134 -0
  233. package/dist/safety/iso26262/sidecar-writer.d.ts +25 -0
  234. package/dist/safety/iso26262/sidecar-writer.js +13 -0
  235. package/dist/safety/passes/pinMode-intercept.d.ts +3 -0
  236. package/dist/safety/passes/pinMode-intercept.js +60 -0
  237. package/dist/safety/runtime/mode-table.d.ts +5 -0
  238. package/dist/safety/runtime/mode-table.js +55 -0
  239. package/dist/safety/runtime/polyfills.d.ts +6 -0
  240. package/dist/safety/runtime/polyfills.js +12 -0
  241. package/dist/safety/runtime/result-struct.d.ts +11 -0
  242. package/dist/safety/runtime/result-struct.js +98 -0
  243. package/dist/safety/runtime/safe-int.d.ts +33 -0
  244. package/dist/safety/runtime/safe-int.js +170 -0
  245. package/dist/safety/runtime/safe-traits.d.ts +4 -0
  246. package/dist/safety/runtime/safe-traits.js +95 -0
  247. package/dist/safety/runtime/safe-variable.d.ts +39 -0
  248. package/dist/safety/runtime/safe-variable.js +226 -0
  249. package/dist/safety/runtime/vote.d.ts +8 -0
  250. package/dist/safety/runtime/vote.js +92 -0
  251. package/dist/safety/runtime/write-verify.d.ts +8 -0
  252. package/dist/safety/runtime/write-verify.js +71 -0
  253. package/dist/safety/safe-int-types.d.ts +45 -0
  254. package/dist/safety/safe-int-types.js +25 -0
  255. package/dist/safety/safe-variable-types.d.ts +29 -0
  256. package/dist/safety/safe-variable-types.js +19 -0
  257. package/dist/safety/safety-bridge.d.ts +5 -6
  258. package/dist/safety/safety-bridge.js +15 -28
  259. package/dist/safety/sidecar-bridge.d.ts +1 -3
  260. package/dist/safety/sidecar-bridge.js +3 -20
  261. package/dist/safety/specifiers.d.ts +6 -0
  262. package/dist/safety/specifiers.js +14 -0
  263. package/dist/safety-hook.d.ts +8 -7
  264. package/dist/safety-hook.js +12 -13
  265. package/dist/testing.d.ts +4 -5
  266. package/dist/testing.js +5 -5
  267. package/dist/transpile/resolution.d.ts +1 -1
  268. package/dist/transpile/resolution.js +18 -9
  269. package/dist/transpile/test-pins.d.ts +18 -0
  270. package/dist/transpile/test-pins.js +142 -0
  271. package/dist/transpile.d.ts +1 -2
  272. package/dist/transpile.js +36 -30
  273. package/dist/types.d.ts +26 -26
  274. package/dist/ui-hook.d.ts +1 -1
  275. package/dist/utils/cli.d.ts +2 -2
  276. package/dist/utils/cli.js +92 -154
  277. package/dist/utils/fs.d.ts +3 -4
  278. package/dist/utils/fs.js +4 -5
  279. package/dist/utils/strings.d.ts +0 -1
  280. package/dist/utils/strings.js +0 -8
  281. package/dist/utils/ui.d.ts +5 -2
  282. package/dist/utils/ui.js +13 -3
  283. package/package.json +158 -157
  284. package/dist/add-preset.d.ts +0 -4
  285. package/dist/add-preset.js +0 -74
  286. package/dist/api/shared/async-symbol-detector.d.ts +0 -11
  287. package/dist/api/shared/async-symbol-detector.js +0 -140
  288. package/dist/api/shared/native-display-op-resolver.d.ts +0 -10
  289. package/dist/api/shared/native-display-op-resolver.js +0 -64
  290. package/dist/create/board-checklist.d.ts +0 -2
  291. package/dist/create/board-checklist.js +0 -52
  292. package/dist/create/board-codegen.d.ts +0 -9
  293. package/dist/create/board-codegen.js +0 -238
  294. package/dist/create/board-generators.d.ts +0 -12
  295. package/dist/create/board-generators.js +0 -651
  296. package/dist/create/board-spec.d.ts +0 -181
  297. package/dist/create/board-spec.js +0 -214
  298. package/dist/install/framework-catalog.d.ts +0 -53
  299. package/dist/install/framework-catalog.js +0 -107
  300. package/dist/install/handle-install.d.ts +0 -35
  301. package/dist/install/handle-install.js +0 -177
  302. package/dist/install/index.d.ts +0 -4
  303. package/dist/install/index.js +0 -3
  304. package/dist/ir/pin-state-tracking.d.ts +0 -58
  305. package/dist/ir/pin-state-tracking.js +0 -182
  306. package/dist/ir/pwm-timer-sharing.d.ts +0 -4
  307. package/dist/ir/pwm-timer-sharing.js +0 -94
  308. package/dist/ir/timer0-pwm-timing-conflict.d.ts +0 -4
  309. package/dist/ir/timer0-pwm-timing-conflict.js +0 -72
  310. package/dist/libdef/component-decls.d.ts +0 -2
  311. package/dist/libdef/component-decls.js +0 -6
  312. package/dist/libdef/component-discovery.d.ts +0 -43
  313. package/dist/libdef/component-discovery.js +0 -83
  314. package/dist/theme-tokens.d.ts +0 -22
  315. package/dist/theme-tokens.js +0 -172
@@ -0,0 +1,61 @@
1
+ // Public API surface for cuttlefish safety — importable as
2
+ // '@typecad/cuttlefish/safety' (the legacy '@typecad/safety' specifier is
3
+ // still detected by the transpiler; detection is by name, no module
4
+ // resolution happens).
5
+ //
6
+ // `safe` is a COMPILE-TIME CONSTRUCT ONLY. The cuttlefish transpiler
7
+ // intercepts safe.read calls (via tryResolveSemanticCall → the safety hook's
8
+ // resolveSemanticCall) and lowers them to safety.read_safe HAL ops. The
9
+ // runtime stub below throws so importing `safe` from plain Node never
10
+ // silently works — mirrors how @typecad/ui's ui.mount behaves.
11
+ //
12
+ // Part A v2: mode configuration belongs to @typecad/hal (Pin.asInput() etc.).
13
+ // The safety engine owns only the verified read.
14
+ /** Two-tier fault taxonomy. Stable across safety standards (ISO 26262,
15
+ * IEC 61508, DO-178C). The category is the coarse user-space routing axis;
16
+ * the code is standard-specific detail.
17
+ *
18
+ * Declared as TypeScript `enum` (not `const` object + type alias) so the
19
+ * cuttlefish transpiler lowers these to a single C++ `enum class` definition
20
+ * matching the runtime polyfill's enum, rather than emitting a conflicting
21
+ * struct per usage scope. The transpiler's enum lowering and the polyfill's
22
+ * enum class are structurally identical (same tag name, same enumerators,
23
+ * same values). */
24
+ export var SafetyFaultCategory;
25
+ (function (SafetyFaultCategory) {
26
+ SafetyFaultCategory[SafetyFaultCategory["Ok"] = 1010580540] = "Ok";
27
+ SafetyFaultCategory[SafetyFaultCategory["Signal"] = 1515870810] = "Signal";
28
+ SafetyFaultCategory[SafetyFaultCategory["Integrity"] = 2779096485] = "Integrity";
29
+ SafetyFaultCategory[SafetyFaultCategory["Timing"] = 3284386755] = "Timing";
30
+ SafetyFaultCategory[SafetyFaultCategory["System"] = 1437226410] = "System";
31
+ SafetyFaultCategory[SafetyFaultCategory["Configuration"] = 2857740885] = "Configuration";
32
+ })(SafetyFaultCategory || (SafetyFaultCategory = {}));
33
+ export var SafetyFaultCode;
34
+ (function (SafetyFaultCode) {
35
+ SafetyFaultCode[SafetyFaultCode["Ok"] = 1010580540] = "Ok";
36
+ SafetyFaultCode[SafetyFaultCode["VoteDisagreement"] = 1515870810] = "VoteDisagreement";
37
+ SafetyFaultCode[SafetyFaultCode["StuckHigh"] = 2779096485] = "StuckHigh";
38
+ SafetyFaultCode[SafetyFaultCode["StuckLow"] = 3284386755] = "StuckLow";
39
+ SafetyFaultCode[SafetyFaultCode["PinModeMismatch"] = 1437226410] = "PinModeMismatch";
40
+ SafetyFaultCode[SafetyFaultCode["PinModeUnknown"] = 2857740885] = "PinModeUnknown";
41
+ SafetyFaultCode[SafetyFaultCode["WriteMismatch"] = 1012573635] = "WriteMismatch";
42
+ })(SafetyFaultCode || (SafetyFaultCode = {}));
43
+ export var SafetyStatus;
44
+ (function (SafetyStatus) {
45
+ SafetyStatus[SafetyStatus["Ok"] = 1515870810] = "Ok";
46
+ SafetyStatus[SafetyStatus["Fault"] = 2779096485] = "Fault";
47
+ })(SafetyStatus || (SafetyStatus = {}));
48
+ class CompileTimeOnly extends Error {
49
+ constructor() {
50
+ super("cuttlefish safety: `safe` is a compile-time construct. It is lowered by the cuttlefish transpiler and has no runtime implementation.");
51
+ }
52
+ }
53
+ /** Safe GPIO API. Compile-time construct only — the cuttlefish transpiler
54
+ * intercepts safe.read and lowers it to a safety.read_safe HAL op. The
55
+ * type annotation (rather than `as const`) gives `safe` a single object
56
+ * type so member access doesn't lower to std::variant access — same reason
57
+ * @typecad/ui's `ui` uses an explicit type annotation. */
58
+ export const safe = {
59
+ read(_pin) { throw new CompileTimeOnly(); },
60
+ write(_pin, _value) { throw new CompileTimeOnly(); },
61
+ };
@@ -0,0 +1,3 @@
1
+ import type { TranspilerSafetyHook } from "../safety-hook.js";
2
+ export declare function registerSafetyEngine(): TranspilerSafetyHook;
3
+ export type { TranspilerSafetyHook };
@@ -0,0 +1,83 @@
1
+ import { pinModeInterceptPass } from "./passes/pinMode-intercept.js";
2
+ import { buildSafetyPolyfills } from "./runtime/polyfills.js";
3
+ import { halInstances } from "../ir/build-ir-state.js";
4
+ import { analyzeProgram } from "./iso26262/analyze.js";
5
+ import { collectSafetyMetadata } from "./iso26262/collect.js";
6
+ /** Resolve a safety.* HAL op to C++. MCU-agnostic: emits calls only to the
7
+ * safety package's own __tc_safety_* helpers (never to target-specific
8
+ * symbols like digitalRead). The strategy-injected __tc_gpio_read shim is
9
+ * called from inside the voter polyfill, not from here.
10
+ *
11
+ * `op.operation` is a closed union in cuttlefish's HALOpIR that does NOT
12
+ * include safety.* ops (those are owned by this package). The dispatch in
13
+ * routeHALOp() uses string-prefix matching, so by the time we get here the
14
+ * operation is a safety.* string — cast to `string` so the switch is an
15
+ * open comparison. Field access goes through a generic record view because
16
+ * the safety op shapes are not part of the HALOpIR union. */
17
+ function resolveSafetyOp(op) {
18
+ const operation = op.operation;
19
+ const fields = op;
20
+ switch (operation) {
21
+ case "safety.record_pin_mode":
22
+ // mode is a TrackedMode enum value (numeric) — emitted as-is.
23
+ return { code: `__tc_safety_record_pin_mode(${fields.pin}, ${fields.mode});` };
24
+ case "safety.read_safe":
25
+ return { expression: `__tc_safety::read_safe(${fields.pin})` };
26
+ case "safety.write_verify":
27
+ return { expression: `__tc_safety::write_verify(${fields.pin}, ${fields.value})` };
28
+ default:
29
+ return undefined;
30
+ }
31
+ }
32
+ /** Resolve a Pin-instance argument to its pin number at IR time, using the
33
+ * same halInstances registry the HAL layer uses to resolve `this._pin`
34
+ * inside Pin method bodies. Returns undefined for args that aren't tracked
35
+ * Pin instances (the caller emits a diagnostic in that case). Also accepts
36
+ * literal numbers as a fallback (for code that constructs a Pin inline at
37
+ * the call site, e.g. safe.read(Pin.fromPort('PD2')) — though the idiomatic
38
+ * form is to assign the Pin to a local first). */
39
+ function resolvePinArg(arg) {
40
+ if (typeof arg === "number")
41
+ return arg;
42
+ if (typeof arg === "string") {
43
+ // Identifier — look up in halInstances for a Pin instance with _pin.
44
+ const inst = halInstances.get(arg);
45
+ if (inst) {
46
+ const pin = inst.fieldValues.get("_pin") ?? inst.fieldValues.get("pin");
47
+ if (pin !== undefined)
48
+ return Number(pin);
49
+ }
50
+ }
51
+ return undefined;
52
+ }
53
+ /** Lower a safe.* TS call to a HAL op. Called from tryResolveSemanticCall
54
+ * (hal-plugins.ts) when the callee resolves to the @typecad/safety package. */
55
+ function resolveSemanticCall(callee, args) {
56
+ // `safe.read(Pin)` → safety.read_safe (pin resolved at IR time)
57
+ if (callee === "safe.read") {
58
+ const pin = resolvePinArg(args[0]);
59
+ if (pin === undefined)
60
+ return undefined;
61
+ return { operation: "safety.read_safe", pin };
62
+ }
63
+ // `safe.write(OutputPin, value)` → safety.write_verify
64
+ // value may be a number (literal) or string (rendered C++ expression text)
65
+ if (callee === "safe.write") {
66
+ const pin = resolvePinArg(args[0]);
67
+ if (pin === undefined)
68
+ return undefined;
69
+ const value = args[1] ?? 0;
70
+ return { operation: "safety.write_verify", pin, value };
71
+ }
72
+ return undefined;
73
+ }
74
+ export function registerSafetyEngine() {
75
+ return {
76
+ transformIR: pinModeInterceptPass,
77
+ resolveSafetyOp,
78
+ resolveSemanticCall,
79
+ buildPolyfills: buildSafetyPolyfills,
80
+ analyzeIR: analyzeProgram,
81
+ collectSafetyMetadata,
82
+ };
83
+ }
@@ -0,0 +1,48 @@
1
+ /** 5-value pin mode, mapped from gpio.configure's flag tokens at IR time.
2
+ * Numeric so the voter switches on enum values (no strcmp at runtime). The
3
+ * values are 32-bit Hamming-distance constants (0x5A5A5A5A etc.) chosen for
4
+ * SEU resistance — a single-bit flip never lands on another valid mode.
5
+ * This makes the C++ mode table 4 bytes/pin (~1 KB for the 255-entry table
6
+ * on AVR, which has 2 KB SRAM). That is a deliberate trade-off vs 1-byte
7
+ * storage: the SEU resistance is the whole point of the safety package.
8
+ * Matches the C++ enum class TrackedMode in runtime/mode-table.ts. */
9
+ export declare enum TrackedMode {
10
+ Unknown = 0,
11
+ Input = 1515870810,
12
+ Output = 2779096485,
13
+ InputPullup = 1010580540,
14
+ InputPulldown = 3284386755
15
+ }
16
+ /** Map gpio.configure flag-token text ("GPIO.INPUT | GPIO.PULL_UP", the
17
+ * thin GPIO constructor's resolved flags) to the TrackedMode enum. Used by
18
+ * the intercept pass at IR time. Direction wins over pulls; combos with no
19
+ * tracked equivalent (open-drain, runtime expressions) map to Unknown so
20
+ * the table still gets a fresh entry. */
21
+ export declare function mapFlagTokens(flags: string): TrackedMode;
22
+ /** Companion op injected after every gpio.set_mode by the pinMode-intercept
23
+ * pass. Records the mode in the runtime safety mode table. */
24
+ export interface SafetyRecordPinModeOp {
25
+ operation: "safety.record_pin_mode";
26
+ pin: number;
27
+ /** TrackedMode enum value (numeric) — mapped at IR time from the
28
+ * gpio.set_mode op's mode string. */
29
+ mode: TrackedMode;
30
+ }
31
+ /** Op produced by `safe.read(Pin)`. Resolves to a C++ expression returning
32
+ * a SafeReadResult. The pin number is resolved at IR time from the Pin
33
+ * instance via the halInstances registry. */
34
+ export interface SafetyReadSafeOp {
35
+ operation: "safety.read_safe";
36
+ pin: number;
37
+ }
38
+ /** Op produced by `safe.write(OutputPin, value)`. Resolves to a C++ expression
39
+ * returning a SafeWriteResult. The pin number is resolved at IR time from the
40
+ * Pin instance via the halInstances registry. The value may be a numeric
41
+ * literal or a string containing the rendered C++ expression text (e.g.
42
+ * "r.value", "x + 1"). */
43
+ export interface SafetyWriteVerifyOp {
44
+ operation: "safety.write_verify";
45
+ pin: number;
46
+ value: number | string;
47
+ }
48
+ export type SafetyHALOp = SafetyRecordPinModeOp | SafetyReadSafeOp | SafetyWriteVerifyOp;
@@ -0,0 +1,46 @@
1
+ // Safety HAL op definitions. These are dispatched by their `operation` string
2
+ // prefix ("safety.*") via routeHALOp() in cuttlefish core. The strategy layer
3
+ // NEVER resolves them — they are resolved by the safety package's
4
+ // resolveSafetyOp, which is MCU-agnostic (it emits calls only to the safety
5
+ // package's own __tc_safety_* helpers and the strategy-injected
6
+ // __tc_gpio_read shim — never to target-specific symbols like digitalRead).
7
+ /** 5-value pin mode, mapped from gpio.configure's flag tokens at IR time.
8
+ * Numeric so the voter switches on enum values (no strcmp at runtime). The
9
+ * values are 32-bit Hamming-distance constants (0x5A5A5A5A etc.) chosen for
10
+ * SEU resistance — a single-bit flip never lands on another valid mode.
11
+ * This makes the C++ mode table 4 bytes/pin (~1 KB for the 255-entry table
12
+ * on AVR, which has 2 KB SRAM). That is a deliberate trade-off vs 1-byte
13
+ * storage: the SEU resistance is the whole point of the safety package.
14
+ * Matches the C++ enum class TrackedMode in runtime/mode-table.ts. */
15
+ export var TrackedMode;
16
+ (function (TrackedMode) {
17
+ TrackedMode[TrackedMode["Unknown"] = 0] = "Unknown";
18
+ TrackedMode[TrackedMode["Input"] = 1515870810] = "Input";
19
+ TrackedMode[TrackedMode["Output"] = 2779096485] = "Output";
20
+ TrackedMode[TrackedMode["InputPullup"] = 1010580540] = "InputPullup";
21
+ TrackedMode[TrackedMode["InputPulldown"] = 3284386755] = "InputPulldown";
22
+ })(TrackedMode || (TrackedMode = {}));
23
+ /** Map gpio.configure flag-token text ("GPIO.INPUT | GPIO.PULL_UP", the
24
+ * thin GPIO constructor's resolved flags) to the TrackedMode enum. Used by
25
+ * the intercept pass at IR time. Direction wins over pulls; combos with no
26
+ * tracked equivalent (open-drain, runtime expressions) map to Unknown so
27
+ * the table still gets a fresh entry. */
28
+ export function mapFlagTokens(flags) {
29
+ // Only a pure token list ("GPIO.INPUT | GPIO.PULL_UP") is statically
30
+ // classifiable — anything else (runtime expression) is Unknown.
31
+ if (!/^\s*GPIO\.[A-Z0-9_]+(\s*\|\s*GPIO\.[A-Z0-9_]+)*\s*$/.test(flags)) {
32
+ return TrackedMode.Unknown;
33
+ }
34
+ const output = flags.includes("GPIO.OUTPUT");
35
+ const input = flags.includes("GPIO.INPUT");
36
+ if (output && !input)
37
+ return TrackedMode.Output;
38
+ if (input || output) {
39
+ if (flags.includes("GPIO.PULL_UP"))
40
+ return TrackedMode.InputPullup;
41
+ if (flags.includes("GPIO.PULL_DOWN"))
42
+ return TrackedMode.InputPulldown;
43
+ return TrackedMode.Input;
44
+ }
45
+ return TrackedMode.Unknown;
46
+ }
@@ -0,0 +1,13 @@
1
+ import type { ProgramIR, Diagnostic } from "../../api/index.js";
2
+ import type { SafetyTransformContext } from "../../safety-hook.js";
3
+ /** Part B: ISO 26262 Part 6 software-rule checker.
4
+ *
5
+ * Runs all checkers against the final transformed IR and returns aggregated
6
+ * diagnostics. Each checker is independent — a failure in one does not
7
+ * prevent the others from running.
8
+ *
9
+ * Diagnostics with severity "error" abort the build (via
10
+ * throwIfFatalDiagnostics in transpile.ts); "warning"/"info" are logged
11
+ * but the build succeeds.
12
+ */
13
+ export declare function analyzeProgram(program: ProgramIR, ctx: SafetyTransformContext): Diagnostic[];
@@ -0,0 +1,29 @@
1
+ import { checkRecursion } from "./recursion-checker.js";
2
+ import { checkDynamicAllocation } from "./heap-checker.js";
3
+ import { checkUnboundedLoops } from "./loop-checker.js";
4
+ import { checkInitCompleteness } from "./init-checker.js";
5
+ import { checkGoto } from "./goto-checker.js";
6
+ /** Part B: ISO 26262 Part 6 software-rule checker.
7
+ *
8
+ * Runs all checkers against the final transformed IR and returns aggregated
9
+ * diagnostics. Each checker is independent — a failure in one does not
10
+ * prevent the others from running.
11
+ *
12
+ * Diagnostics with severity "error" abort the build (via
13
+ * throwIfFatalDiagnostics in transpile.ts); "warning"/"info" are logged
14
+ * but the build succeeds.
15
+ */
16
+ export function analyzeProgram(program, ctx) {
17
+ const diags = [];
18
+ for (const checker of [checkRecursion, checkDynamicAllocation, checkUnboundedLoops, checkInitCompleteness, checkGoto]) {
19
+ try {
20
+ const results = checker(program, ctx);
21
+ diags.push(...results);
22
+ }
23
+ catch {
24
+ // A checker crash should not prevent other checkers from running.
25
+ // The diagnostic is lost; the build continues.
26
+ }
27
+ }
28
+ return diags;
29
+ }
@@ -0,0 +1,10 @@
1
+ /** Determine the ASIL level of a function from its decorators.
2
+ * Returns a numeric severity: D=4, C=3, B=2, A=1, QM/none=0.
3
+ * Higher = more rules enforced. */
4
+ export declare function asilLevel(decorators?: string[]): number;
5
+ /** Minimum ASIL level at which each rule applies. */
6
+ export declare const ASIL_THRESHOLDS: {
7
+ readonly recursion: 2;
8
+ readonly dynamicAlloc: 4;
9
+ readonly unboundedLoop: 3;
10
+ };
@@ -0,0 +1,22 @@
1
+ /** Determine the ASIL level of a function from its decorators.
2
+ * Returns a numeric severity: D=4, C=3, B=2, A=1, QM/none=0.
3
+ * Higher = more rules enforced. */
4
+ export function asilLevel(decorators) {
5
+ if (!decorators)
6
+ return 0;
7
+ if (decorators.includes("asilD"))
8
+ return 4;
9
+ if (decorators.includes("asilC"))
10
+ return 3;
11
+ if (decorators.includes("asilB"))
12
+ return 2;
13
+ if (decorators.includes("asilA"))
14
+ return 1;
15
+ return 0;
16
+ }
17
+ /** Minimum ASIL level at which each rule applies. */
18
+ export const ASIL_THRESHOLDS = {
19
+ recursion: 2, // B+ — recursion forbidden
20
+ dynamicAlloc: 4, // D only — heap forbidden after init
21
+ unboundedLoop: 3, // C+ — unbounded loops warned
22
+ };
@@ -0,0 +1,14 @@
1
+ import type { ProgramIR } from "../../api/index.js";
2
+ import type { SafetyTransformContext, SafetyMetadata } from "../../safety-hook.js";
3
+ /** Part C: collect safety metadata for sidecar artifact generation.
4
+ *
5
+ * Walks the program IR and collects structured metadata about each
6
+ * safety-critical function (those with ASIL annotations):
7
+ * - ASIL level (from // @asilD / @asilC / @asilB comments)
8
+ * - Source location (TS file + line)
9
+ * - Safety mechanisms used (safe.read, safe.write, SafeVariable, SafeInt)
10
+ * - Rule check results (B1–B6 pass/warning/error)
11
+ *
12
+ * The caller writes the returned metadata as a sidecar JSON file
13
+ * alongside the emitted C++ artifact. */
14
+ export declare function collectSafetyMetadata(program: ProgramIR, ctx: SafetyTransformContext): SafetyMetadata[];
@@ -0,0 +1,137 @@
1
+ import { asilLevel } from "./asil.js";
2
+ import { analyzeProgram } from "./analyze.js";
3
+ /** Part C: collect safety metadata for sidecar artifact generation.
4
+ *
5
+ * Walks the program IR and collects structured metadata about each
6
+ * safety-critical function (those with ASIL annotations):
7
+ * - ASIL level (from // @asilD / @asilC / @asilB comments)
8
+ * - Source location (TS file + line)
9
+ * - Safety mechanisms used (safe.read, safe.write, SafeVariable, SafeInt)
10
+ * - Rule check results (B1–B6 pass/warning/error)
11
+ *
12
+ * The caller writes the returned metadata as a sidecar JSON file
13
+ * alongside the emitted C++ artifact. */
14
+ export function collectSafetyMetadata(program, ctx) {
15
+ const functions = [];
16
+ // Run the analyzers to get current rule results per function
17
+ const diagnostics = analyzeProgram(program, ctx);
18
+ const diagsByFunction = new Map();
19
+ for (const d of diagnostics) {
20
+ // Extract function name from the message (format: "Recursion detected: ..."
21
+ // or "Dynamic allocation in fnName(): ...")
22
+ const fnMatch = d.message.match(/in (\w+)\(\)/);
23
+ const fnName = fnMatch ? fnMatch[1] : "";
24
+ if (fnName) {
25
+ if (!diagsByFunction.has(fnName)) {
26
+ diagsByFunction.set(fnName, []);
27
+ }
28
+ diagsByFunction.get(fnName).push(d);
29
+ }
30
+ }
31
+ const allRuleIds = ["B1_RECURSION", "B2_DYNAMIC_ALLOC", "B3_UNBOUNDED_LOOP", "B5_INIT_COMPLETENESS", "B6_GOTO"];
32
+ for (const fn of program.functions) {
33
+ const level = asilLevel(fn.decorators);
34
+ if (level === 0)
35
+ continue;
36
+ const asilName = level === 4 ? "D" : level === 3 ? "C" : level === 2 ? "B" : level === 1 ? "A" : "QM";
37
+ // Detect safety mechanisms used in this function
38
+ const mechanisms = detectMechanisms(fn);
39
+ // Build rule results: pass by default, override with diagnostics
40
+ const rules = {};
41
+ for (const ruleId of allRuleIds) {
42
+ const fullCode = `ISO26262_${ruleId}`;
43
+ const matchingDiags = (diagsByFunction.get(fn.originalName) ?? [])
44
+ .filter(d => d.code === fullCode);
45
+ if (matchingDiags.length > 0) {
46
+ // Use the first matching diagnostic (they're all the same rule)
47
+ rules[ruleId] = {
48
+ severity: matchingDiags[0].severity,
49
+ message: matchingDiags[0].message,
50
+ };
51
+ }
52
+ else {
53
+ rules[ruleId] = "pass";
54
+ }
55
+ }
56
+ functions.push({
57
+ name: fn.originalName,
58
+ asilLevel: asilName,
59
+ source: fn.sourceSpan ? {
60
+ tsFile: fn.sourceSpan.filePath,
61
+ tsLine: fn.sourceSpan.startLine,
62
+ } : undefined,
63
+ mechanisms,
64
+ rules,
65
+ });
66
+ }
67
+ // Also scan class methods
68
+ for (const cls of program.classes) {
69
+ for (const method of cls.methods) {
70
+ if (!method.name)
71
+ continue;
72
+ const level = asilLevel(method.decorators);
73
+ if (level === 0)
74
+ continue;
75
+ const asilName = level === 4 ? "D" : level === 3 ? "C" : level === 2 ? "B" : level === 1 ? "A" : "QM";
76
+ const mechanisms = detectMechanisms({ parameters: [], statements: method.statements });
77
+ const rules = {};
78
+ for (const ruleId of allRuleIds) {
79
+ rules[ruleId] = "pass";
80
+ }
81
+ functions.push({
82
+ name: `${cls.name}::${method.name}`,
83
+ asilLevel: asilName,
84
+ mechanisms,
85
+ rules,
86
+ });
87
+ }
88
+ }
89
+ return [{ functions }];
90
+ }
91
+ /** Scan a function's statements for safety-mechanism usage. */
92
+ function detectMechanisms(fn) {
93
+ const mechanisms = new Set();
94
+ const scan = (stmt) => {
95
+ if (!stmt || typeof stmt !== "object")
96
+ return;
97
+ // HAL ops (safe.read → safety.read_safe, safe.write → safety.write_verify)
98
+ if (stmt.kind === "hal-op" && typeof stmt.operation === "string") {
99
+ if (stmt.operation === "safety.read_safe")
100
+ mechanisms.add("safe.read");
101
+ if (stmt.operation === "safety.write_verify")
102
+ mechanisms.add("safe.write");
103
+ }
104
+ // Raw expressions mentioning SafeVariable or SafeInt
105
+ if (stmt.kind === "raw" && typeof stmt.value === "string") {
106
+ if (/\bSafeVariable</.test(stmt.value))
107
+ mechanisms.add("SafeVariable");
108
+ if (/\bSafeInt/.test(stmt.value))
109
+ mechanisms.add("SafeInt");
110
+ }
111
+ // var_decl with cppType containing SafeVariable<SafeInt
112
+ if (stmt.kind === "var_decl" && typeof stmt.cppType === "string") {
113
+ if (/SafeVariable</.test(stmt.cppType))
114
+ mechanisms.add("SafeVariable");
115
+ if (/SafeInt/.test(stmt.cppType))
116
+ mechanisms.add("SafeInt");
117
+ }
118
+ // Recurse
119
+ for (const key of Object.keys(stmt)) {
120
+ const val = stmt[key];
121
+ if (Array.isArray(val)) {
122
+ for (const item of val) {
123
+ if (item && typeof item === "object" && typeof item.kind === "string") {
124
+ scan(item);
125
+ }
126
+ }
127
+ }
128
+ else if (val && typeof val === "object" && typeof val.kind === "string") {
129
+ scan(val);
130
+ }
131
+ }
132
+ };
133
+ for (const stmt of fn.statements) {
134
+ scan(stmt);
135
+ }
136
+ return [...mechanisms].sort();
137
+ }
@@ -0,0 +1,10 @@
1
+ import type { ProgramIR, Diagnostic } from "../../api/index.js";
2
+ import type { SafetyTransformContext } from "../../safety-hook.js";
3
+ /** B6: No unconstrained goto (ISO 26262 Part 6, §7.4.8 — ASIL C+).
4
+ *
5
+ * Scans for goto statements in emitted IR. Cuttlefish's only source of
6
+ * goto is labeled break lowering (TS `break labelName;` → C++ `goto
7
+ * __break_labelName;`). While this is a controlled use, ISO 26262 C+
8
+ * restricts goto to specific patterns (forward, within the same block).
9
+ * Reports each goto as an info-level diagnostic for awareness. */
10
+ export declare function checkGoto(program: ProgramIR, _ctx: SafetyTransformContext): Diagnostic[];
@@ -0,0 +1,72 @@
1
+ import { asilLevel, ASIL_THRESHOLDS } from "./asil.js";
2
+ /** B6: No unconstrained goto (ISO 26262 Part 6, §7.4.8 — ASIL C+).
3
+ *
4
+ * Scans for goto statements in emitted IR. Cuttlefish's only source of
5
+ * goto is labeled break lowering (TS `break labelName;` → C++ `goto
6
+ * __break_labelName;`). While this is a controlled use, ISO 26262 C+
7
+ * restricts goto to specific patterns (forward, within the same block).
8
+ * Reports each goto as an info-level diagnostic for awareness. */
9
+ export function checkGoto(program, _ctx) {
10
+ const diags = [];
11
+ for (const fn of program.functions) {
12
+ if (asilLevel(fn.decorators) < ASIL_THRESHOLDS.unboundedLoop)
13
+ continue;
14
+ for (const stmt of fn.statements) {
15
+ scanForGoto(stmt, fn.originalName, diags);
16
+ }
17
+ }
18
+ for (const cls of program.classes) {
19
+ for (const method of cls.methods) {
20
+ if (!method.name)
21
+ continue;
22
+ if (asilLevel(method.decorators) < ASIL_THRESHOLDS.unboundedLoop)
23
+ continue;
24
+ for (const stmt of method.statements) {
25
+ scanForGoto(stmt, method.name, diags);
26
+ }
27
+ }
28
+ }
29
+ return diags;
30
+ }
31
+ function scanForGoto(stmt, fnName, diags) {
32
+ if (!stmt || typeof stmt !== "object")
33
+ return;
34
+ // Check for goto in raw expressions (lowered from labeled break)
35
+ if (stmt.kind === "raw" && typeof stmt.value === "string") {
36
+ if (/\bgoto\s+\w+/.test(stmt.value)) {
37
+ const match = stmt.value.match(/\bgoto\s+(\w+)/);
38
+ const label = match ? match[1] : "unknown";
39
+ diags.push({
40
+ severity: "info",
41
+ code: "ISO26262_B6_GOTO",
42
+ message: `goto ${label} in ${fnName}() — lowered from labeled break`,
43
+ hint: "ISO 26262 C+ restricts goto. Consider restructuring with a flag variable or early return.",
44
+ });
45
+ }
46
+ }
47
+ // Check for the "labeled" statement kind (cuttlefish's IR representation
48
+ // of labeled break — the actual goto is emitted as a raw statement
49
+ // during rendering, but the labeled IR node is present at analysis time).
50
+ if (stmt.kind === "labeled" && typeof stmt.label === "string") {
51
+ diags.push({
52
+ severity: "info",
53
+ code: "ISO26262_B6_GOTO",
54
+ message: `Labeled break '${stmt.label}' in ${fnName}() will lower to goto`,
55
+ hint: "ISO 26262 C+ restricts goto. Consider restructuring with a flag variable or early return.",
56
+ });
57
+ }
58
+ // Recurse
59
+ for (const key of Object.keys(stmt)) {
60
+ const val = stmt[key];
61
+ if (Array.isArray(val)) {
62
+ for (const item of val) {
63
+ if (item && typeof item === "object" && typeof item.kind === "string") {
64
+ scanForGoto(item, fnName, diags);
65
+ }
66
+ }
67
+ }
68
+ else if (val && typeof val === "object" && typeof val.kind === "string") {
69
+ scanForGoto(val, fnName, diags);
70
+ }
71
+ }
72
+ }
@@ -0,0 +1,7 @@
1
+ import type { ProgramIR, Diagnostic } from "../../api/index.js";
2
+ import type { SafetyTransformContext } from "../../safety-hook.js";
3
+ /** B2: No dynamic allocation after init (ISO 26262 Part 6, §7.4.11 — ASIL D).
4
+ *
5
+ * Only checks functions decorated with @asilD.
6
+ * Lower ASIL levels and QM functions are skipped. */
7
+ export declare function checkDynamicAllocation(program: ProgramIR, _ctx: SafetyTransformContext): Diagnostic[];
@@ -0,0 +1,57 @@
1
+ import { asilLevel, ASIL_THRESHOLDS } from "./asil.js";
2
+ /** B2: No dynamic allocation after init (ISO 26262 Part 6, §7.4.11 — ASIL D).
3
+ *
4
+ * Only checks functions decorated with @asilD.
5
+ * Lower ASIL levels and QM functions are skipped. */
6
+ export function checkDynamicAllocation(program, _ctx) {
7
+ const diags = [];
8
+ const initFnNames = new Set(["setup", "main", "__top_level__"]);
9
+ for (const fn of program.functions) {
10
+ if (initFnNames.has(fn.originalName))
11
+ continue;
12
+ if (asilLevel(fn.decorators) < ASIL_THRESHOLDS.dynamicAlloc)
13
+ continue;
14
+ for (const stmt of fn.statements) {
15
+ scanForAllocation(stmt, fn.originalName, diags);
16
+ }
17
+ }
18
+ for (const cls of program.classes) {
19
+ for (const method of cls.methods) {
20
+ if (!method.name || initFnNames.has(method.name))
21
+ continue;
22
+ if (asilLevel(method.decorators) < ASIL_THRESHOLDS.dynamicAlloc)
23
+ continue;
24
+ for (const stmt of method.statements) {
25
+ scanForAllocation(stmt, method.name, diags);
26
+ }
27
+ }
28
+ }
29
+ return diags;
30
+ }
31
+ function scanForAllocation(stmt, fnName, diags) {
32
+ if (!stmt || typeof stmt !== "object")
33
+ return;
34
+ if (stmt.kind === "raw" && typeof stmt.value === "string") {
35
+ if (/\bnew\s+[A-Z_]/.test(stmt.value) || /\bmalloc\s*\(/.test(stmt.value) || /\bcalloc\s*\(/.test(stmt.value)) {
36
+ diags.push({
37
+ severity: "error",
38
+ code: "ISO26262_B2_DYNAMIC_ALLOC",
39
+ message: `Dynamic allocation in ${fnName}(): ${stmt.value.trim().slice(0, 80)}`,
40
+ hint: "ASIL D forbids dynamic allocation after initialization. Pre-allocate in setup() or use a fixed-size buffer.",
41
+ });
42
+ }
43
+ }
44
+ for (const key of Object.keys(stmt)) {
45
+ const val = stmt[key];
46
+ if (Array.isArray(val)) {
47
+ for (const item of val) {
48
+ if (item && typeof item === "object" && typeof item.kind === "string") {
49
+ scanForAllocation(item, fnName, diags);
50
+ }
51
+ }
52
+ }
53
+ else if (val && typeof val === "object" && typeof val.kind === "string") {
54
+ scanForAllocation(val, fnName, diags);
55
+ }
56
+ }
57
+ }
@@ -0,0 +1,13 @@
1
+ import type { ProgramIR, Diagnostic } from "../../api/index.js";
2
+ import type { SafetyTransformContext } from "../../safety-hook.js";
3
+ /** B5: Init completeness (ISO 26262 Part 6, §7.4.5 — ASIL D).
4
+ *
5
+ * Checks that every identifier used in a safety-critical function (ASIL D)
6
+ * was initialized in setup() or at file scope. An uninitialized variable
7
+ * in a safety-critical path is a potential source of undefined behavior.
8
+ *
9
+ * Approach: collect identifiers assigned/declared in setup() and top-level
10
+ * (the "init set"), then walk each ASIL D function's statements looking
11
+ * for identifiers used before any local assignment. Reports each as a
12
+ * warning. */
13
+ export declare function checkInitCompleteness(program: ProgramIR, _ctx: SafetyTransformContext): Diagnostic[];