@typecad/cuttlefish 0.1.0-alpha.1
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.
- package/LICENSE +21 -0
- package/README.md +79 -0
- package/dist/api/board-types.d.ts +1 -0
- package/dist/api/board-types.js +4 -0
- package/dist/api/capabilities.d.ts +12 -0
- package/dist/api/capabilities.js +1 -0
- package/dist/api/config.d.ts +120 -0
- package/dist/api/config.js +7 -0
- package/dist/api/index.d.ts +5 -0
- package/dist/api/index.js +2 -0
- package/dist/api/schema/builder.d.ts +14 -0
- package/dist/api/schema/builder.js +15 -0
- package/dist/api/schema/index.d.ts +2 -0
- package/dist/api/schema/index.js +1 -0
- package/dist/api/schema/types.d.ts +257 -0
- package/dist/api/schema/types.js +4 -0
- package/dist/api/shared/async-runtime-static.d.ts +8 -0
- package/dist/api/shared/async-runtime-static.js +201 -0
- package/dist/api/shared/async-types.d.ts +42 -0
- package/dist/api/shared/async-types.js +8 -0
- package/dist/api/shared/board-resolver.d.ts +12 -0
- package/dist/api/shared/board-resolver.js +7 -0
- package/dist/api/shared/cpp-type-ir.d.ts +229 -0
- package/dist/api/shared/cpp-type-ir.js +672 -0
- package/dist/api/shared/display-adapter.d.ts +12 -0
- package/dist/api/shared/display-adapter.js +145 -0
- package/dist/api/shared/display-adapters/eink-mono.d.ts +2 -0
- package/dist/api/shared/display-adapters/eink-mono.js +53 -0
- package/dist/api/shared/display-adapters/sdl.d.ts +2 -0
- package/dist/api/shared/display-adapters/sdl.js +452 -0
- package/dist/api/shared/display-adapters/ssd1309.d.ts +2 -0
- package/dist/api/shared/display-adapters/ssd1309.js +136 -0
- package/dist/api/shared/display-adapters/st7796.d.ts +2 -0
- package/dist/api/shared/display-adapters/st7796.js +132 -0
- package/dist/api/shared/display-capabilities.d.ts +45 -0
- package/dist/api/shared/display-capabilities.js +54 -0
- package/dist/api/shared/display-op-ir.d.ts +62 -0
- package/dist/api/shared/display-op-ir.js +19 -0
- package/dist/api/shared/display-profile.d.ts +265 -0
- package/dist/api/shared/display-profile.js +338 -0
- package/dist/api/shared/graphics-strategy.d.ts +29 -0
- package/dist/api/shared/graphics-strategy.js +11 -0
- package/dist/api/shared/hal-op-ir.d.ts +393 -0
- package/dist/api/shared/hal-op-ir.js +18 -0
- package/dist/api/shared/index.d.ts +26 -0
- package/dist/api/shared/index.js +21 -0
- package/dist/api/shared/ir-core.d.ts +363 -0
- package/dist/api/shared/ir-core.js +8 -0
- package/dist/api/shared/ir-declarations.d.ts +201 -0
- package/dist/api/shared/ir-declarations.js +26 -0
- package/dist/api/shared/ir.d.ts +85 -0
- package/dist/api/shared/ir.js +13 -0
- package/dist/api/shared/platform-strategy.d.ts +402 -0
- package/dist/api/shared/platform-strategy.js +14 -0
- package/dist/api/shared/polyfill-helper-registry.d.ts +11 -0
- package/dist/api/shared/polyfill-helper-registry.js +86 -0
- package/dist/api/shared/polyfill-types.d.ts +33 -0
- package/dist/api/shared/polyfill-types.js +76 -0
- package/dist/api/shared/promise-runtime.d.ts +10 -0
- package/dist/api/shared/promise-runtime.js +244 -0
- package/dist/api/shared/snprintf-types.d.ts +29 -0
- package/dist/api/shared/snprintf-types.js +8 -0
- package/dist/api/shared/string-method-registry.d.ts +53 -0
- package/dist/api/shared/string-method-registry.js +168 -0
- package/dist/api/shared/toolchain-types.d.ts +63 -0
- package/dist/api/shared/toolchain-types.js +71 -0
- package/dist/api/shared/types.d.ts +50 -0
- package/dist/api/shared/types.js +6 -0
- package/dist/ast/parse.d.ts +2 -0
- package/dist/ast/parse.js +4 -0
- package/dist/cache.d.ts +26 -0
- package/dist/cache.js +95 -0
- package/dist/cli-utils.d.ts +37 -0
- package/dist/cli-utils.js +250 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +635 -0
- package/dist/config-loader.d.ts +78 -0
- package/dist/config-loader.js +508 -0
- package/dist/config-schema.d.ts +233 -0
- package/dist/config-schema.js +83 -0
- package/dist/create/board-checklist.d.ts +2 -0
- package/dist/create/board-checklist.js +52 -0
- package/dist/create/board-codegen.d.ts +9 -0
- package/dist/create/board-codegen.js +238 -0
- package/dist/create/board-generators.d.ts +12 -0
- package/dist/create/board-generators.js +652 -0
- package/dist/create/board-spec.d.ts +640 -0
- package/dist/create/board-spec.js +215 -0
- package/dist/create/eslint-rules-template.d.ts +2 -0
- package/dist/create/eslint-rules-template.js +672 -0
- package/dist/create/index.d.ts +11 -0
- package/dist/create/index.js +8 -0
- package/dist/create/init-scaffold.d.ts +27 -0
- package/dist/create/init-scaffold.js +150 -0
- package/dist/create/init-templates.d.ts +24 -0
- package/dist/create/init-templates.js +379 -0
- package/dist/create/init-wizard.d.ts +8 -0
- package/dist/create/init-wizard.js +168 -0
- package/dist/debug/breakpoint-loader.d.ts +24 -0
- package/dist/debug/breakpoint-loader.js +137 -0
- package/dist/debug/index.d.ts +3 -0
- package/dist/debug/index.js +7 -0
- package/dist/debug/preprocessor.d.ts +9 -0
- package/dist/debug/preprocessor.js +214 -0
- package/dist/debug/types.d.ts +32 -0
- package/dist/debug/types.js +6 -0
- package/dist/diagnostics/diagnostics-report.d.ts +51 -0
- package/dist/diagnostics/diagnostics-report.js +333 -0
- package/dist/diagnostics/json-schema.d.ts +138 -0
- package/dist/diagnostics/json-schema.js +27 -0
- package/dist/diagnostics/md-writer.d.ts +10 -0
- package/dist/diagnostics/md-writer.js +336 -0
- package/dist/diagnostics/mermaid-builder.d.ts +65 -0
- package/dist/diagnostics/mermaid-builder.js +681 -0
- package/dist/emit/cpp-emitter.d.ts +6 -0
- package/dist/emit/cpp-emitter.js +48 -0
- package/dist/emit/emitters/class-emitter.d.ts +2 -0
- package/dist/emit/emitters/class-emitter.js +523 -0
- package/dist/emit/emitters/emitter-context.d.ts +174 -0
- package/dist/emit/emitters/emitter-context.js +1 -0
- package/dist/emit/emitters/entrypoint-synthesizer.d.ts +2 -0
- package/dist/emit/emitters/entrypoint-synthesizer.js +175 -0
- package/dist/emit/emitters/function-emitter-impl.d.ts +19 -0
- package/dist/emit/emitters/function-emitter-impl.js +428 -0
- package/dist/emit/emitters/line-appender.d.ts +15 -0
- package/dist/emit/emitters/line-appender.js +344 -0
- package/dist/emit/emitters/namespace-emitter.d.ts +2 -0
- package/dist/emit/emitters/namespace-emitter.js +324 -0
- package/dist/emit/emitters/output-finalizer.d.ts +4 -0
- package/dist/emit/emitters/output-finalizer.js +267 -0
- package/dist/emit/emitters/setup.d.ts +3 -0
- package/dist/emit/emitters/setup.js +851 -0
- package/dist/emit/emitters/top-level-prep.d.ts +2 -0
- package/dist/emit/emitters/top-level-prep.js +706 -0
- package/dist/emit/emitters/type-decl-emitter.d.ts +2 -0
- package/dist/emit/emitters/type-decl-emitter.js +251 -0
- package/dist/emit/emitters/ui-emitter.d.ts +21 -0
- package/dist/emit/emitters/ui-emitter.js +564 -0
- package/dist/emit/enum-emitter.d.ts +1 -0
- package/dist/emit/enum-emitter.js +1 -0
- package/dist/emit/expression-renderer.d.ts +283 -0
- package/dist/emit/expression-renderer.js +1477 -0
- package/dist/emit/native-helpers-emitter.d.ts +11 -0
- package/dist/emit/native-helpers-emitter.js +34 -0
- package/dist/emit/route-hal-op.d.ts +5 -0
- package/dist/emit/route-hal-op.js +13 -0
- package/dist/emit/snprintf-helpers.d.ts +17 -0
- package/dist/emit/snprintf-helpers.js +462 -0
- package/dist/emit/statement-renderer.d.ts +189 -0
- package/dist/emit/statement-renderer.js +948 -0
- package/dist/emit/utils/async-state-machine.d.ts +42 -0
- package/dist/emit/utils/async-state-machine.js +343 -0
- package/dist/emit/utils/comment-helpers.d.ts +20 -0
- package/dist/emit/utils/comment-helpers.js +31 -0
- package/dist/emit/utils/cpp-helpers.d.ts +47 -0
- package/dist/emit/utils/cpp-helpers.js +85 -0
- package/dist/emit/utils/include-resolver.d.ts +58 -0
- package/dist/emit/utils/include-resolver.js +155 -0
- package/dist/emit/utils/index.d.ts +8 -0
- package/dist/emit/utils/index.js +12 -0
- package/dist/emit/utils/type-inference.d.ts +159 -0
- package/dist/emit/utils/type-inference.js +559 -0
- package/dist/eslint-check.d.ts +10 -0
- package/dist/eslint-check.js +102 -0
- package/dist/framework-package.d.ts +10 -0
- package/dist/framework-package.js +58 -0
- package/dist/framework-registry.d.ts +39 -0
- package/dist/framework-registry.js +30 -0
- package/dist/incremental-cache.d.ts +116 -0
- package/dist/incremental-cache.js +335 -0
- package/dist/ir/adc-range-validation.d.ts +11 -0
- package/dist/ir/adc-range-validation.js +250 -0
- package/dist/ir/ast-node-utils.d.ts +8 -0
- package/dist/ir/ast-node-utils.js +32 -0
- package/dist/ir/board-pin-utils.d.ts +13 -0
- package/dist/ir/board-pin-utils.js +65 -0
- package/dist/ir/board-resolver.d.ts +36 -0
- package/dist/ir/board-resolver.js +437 -0
- package/dist/ir/build-ir-state.d.ts +167 -0
- package/dist/ir/build-ir-state.js +306 -0
- package/dist/ir/build-ir.d.ts +2 -0
- package/dist/ir/build-ir.js +808 -0
- package/dist/ir/call-graph.d.ts +35 -0
- package/dist/ir/call-graph.js +194 -0
- package/dist/ir/compile-time-only.d.ts +2 -0
- package/dist/ir/compile-time-only.js +16 -0
- package/dist/ir/declaration-builders.d.ts +9 -0
- package/dist/ir/declaration-builders.js +608 -0
- package/dist/ir/entry-points.d.ts +30 -0
- package/dist/ir/entry-points.js +191 -0
- package/dist/ir/expression-to-ir.d.ts +5 -0
- package/dist/ir/expression-to-ir.js +2249 -0
- package/dist/ir/extract-property-chain.d.ts +10 -0
- package/dist/ir/extract-property-chain.js +30 -0
- package/dist/ir/feature-prescan.d.ts +3 -0
- package/dist/ir/feature-prescan.js +43 -0
- package/dist/ir/feature-registry.d.ts +30 -0
- package/dist/ir/feature-registry.js +816 -0
- package/dist/ir/filter.d.ts +7 -0
- package/dist/ir/filter.js +85 -0
- package/dist/ir/function-builder.d.ts +19 -0
- package/dist/ir/function-builder.js +670 -0
- package/dist/ir/hal/hal-emitter.d.ts +62 -0
- package/dist/ir/hal/hal-emitter.js +735 -0
- package/dist/ir/hal/hal-parser.d.ts +61 -0
- package/dist/ir/hal/hal-parser.js +473 -0
- package/dist/ir/hal/hal-plugins.d.ts +34 -0
- package/dist/ir/hal/hal-plugins.js +706 -0
- package/dist/ir/hal-resolver.d.ts +5 -0
- package/dist/ir/hal-resolver.js +5 -0
- package/dist/ir/heap-analysis.d.ts +8 -0
- package/dist/ir/heap-analysis.js +350 -0
- package/dist/ir/heap-array-validation.d.ts +24 -0
- package/dist/ir/heap-array-validation.js +29 -0
- package/dist/ir/identifier-collector.d.ts +18 -0
- package/dist/ir/identifier-collector.js +439 -0
- package/dist/ir/interrupt-analysis.d.ts +39 -0
- package/dist/ir/interrupt-analysis.js +467 -0
- package/dist/ir/memory-budget-validation.d.ts +10 -0
- package/dist/ir/memory-budget-validation.js +86 -0
- package/dist/ir/namespace-builder.d.ts +7 -0
- package/dist/ir/namespace-builder.js +152 -0
- package/dist/ir/ownership-analysis.d.ts +9 -0
- package/dist/ir/ownership-analysis.js +1207 -0
- package/dist/ir/peripheral-ownership.d.ts +3 -0
- package/dist/ir/peripheral-ownership.js +152 -0
- package/dist/ir/peripheral-symbols.d.ts +7 -0
- package/dist/ir/peripheral-symbols.js +57 -0
- package/dist/ir/peripheral-usage.d.ts +54 -0
- package/dist/ir/peripheral-usage.js +691 -0
- package/dist/ir/peripheral-validation.d.ts +8 -0
- package/dist/ir/peripheral-validation.js +77 -0
- package/dist/ir/pin-alias-conflict.d.ts +4 -0
- package/dist/ir/pin-alias-conflict.js +34 -0
- package/dist/ir/pin-capability-validation.d.ts +6 -0
- package/dist/ir/pin-capability-validation.js +413 -0
- package/dist/ir/pin-mode-validation.d.ts +10 -0
- package/dist/ir/pin-mode-validation.js +301 -0
- package/dist/ir/pin-safety.d.ts +11 -0
- package/dist/ir/pin-safety.js +58 -0
- package/dist/ir/program-analysis.d.ts +44 -0
- package/dist/ir/program-analysis.js +589 -0
- package/dist/ir/pulldown-validation.d.ts +7 -0
- package/dist/ir/pulldown-validation.js +49 -0
- package/dist/ir/pwm-timer-sharing.d.ts +4 -0
- package/dist/ir/pwm-timer-sharing.js +93 -0
- package/dist/ir/reachability.d.ts +68 -0
- package/dist/ir/reachability.js +224 -0
- package/dist/ir/register-decorators.d.ts +6 -0
- package/dist/ir/register-decorators.js +49 -0
- package/dist/ir/render-expr.d.ts +4 -0
- package/dist/ir/render-expr.js +127 -0
- package/dist/ir/resource-analysis.d.ts +19 -0
- package/dist/ir/resource-analysis.js +153 -0
- package/dist/ir/statement-to-ir.d.ts +23 -0
- package/dist/ir/statement-to-ir.js +349 -0
- package/dist/ir/symbol-table.d.ts +68 -0
- package/dist/ir/symbol-table.js +179 -0
- package/dist/ir/symbol-types.d.ts +56 -0
- package/dist/ir/symbol-types.js +107 -0
- package/dist/ir/timer0-pwm-timing-conflict.d.ts +4 -0
- package/dist/ir/timer0-pwm-timing-conflict.js +71 -0
- package/dist/ir/timing-validation.d.ts +7 -0
- package/dist/ir/timing-validation.js +95 -0
- package/dist/ir/transformers/array-methods.d.ts +8 -0
- package/dist/ir/transformers/array-methods.js +493 -0
- package/dist/ir/transformers/call-statement.d.ts +5 -0
- package/dist/ir/transformers/call-statement.js +758 -0
- package/dist/ir/transformers/callback-context-registry.d.ts +20 -0
- package/dist/ir/transformers/callback-context-registry.js +55 -0
- package/dist/ir/transformers/canvas-lowering.d.ts +42 -0
- package/dist/ir/transformers/canvas-lowering.js +249 -0
- package/dist/ir/transformers/control-flow.d.ts +8 -0
- package/dist/ir/transformers/control-flow.js +508 -0
- package/dist/ir/transformers/expressions.d.ts +7 -0
- package/dist/ir/transformers/expressions.js +406 -0
- package/dist/ir/transformers/hal-call-resolver.d.ts +29 -0
- package/dist/ir/transformers/hal-call-resolver.js +274 -0
- package/dist/ir/transformers/hal-emit-helpers.d.ts +14 -0
- package/dist/ir/transformers/hal-emit-helpers.js +63 -0
- package/dist/ir/transformers/namespace-methods.d.ts +20 -0
- package/dist/ir/transformers/namespace-methods.js +110 -0
- package/dist/ir/transformers/register-assignment.d.ts +5 -0
- package/dist/ir/transformers/register-assignment.js +56 -0
- package/dist/ir/transformers/ui-call-resolver.d.ts +149 -0
- package/dist/ir/transformers/ui-call-resolver.js +1136 -0
- package/dist/ir/transformers/ui-callback-lowering.d.ts +62 -0
- package/dist/ir/transformers/ui-callback-lowering.js +623 -0
- package/dist/ir/transformers/ui-mount.d.ts +20 -0
- package/dist/ir/transformers/ui-mount.js +35 -0
- package/dist/ir/transformers/ui-reactive.d.ts +68 -0
- package/dist/ir/transformers/ui-reactive.js +129 -0
- package/dist/ir/transformers/variables.d.ts +14 -0
- package/dist/ir/transformers/variables.js +1045 -0
- package/dist/ir/try-catch-validation.d.ts +26 -0
- package/dist/ir/try-catch-validation.js +128 -0
- package/dist/ir/type-resolution.d.ts +31 -0
- package/dist/ir/type-resolution.js +977 -0
- package/dist/ir/ui-element-auto-wire.d.ts +50 -0
- package/dist/ir/ui-element-auto-wire.js +218 -0
- package/dist/ir/unit-suspicion-validation.d.ts +12 -0
- package/dist/ir/unit-suspicion-validation.js +296 -0
- package/dist/ir/utils/walk-ir.d.ts +6 -0
- package/dist/ir/utils/walk-ir.js +162 -0
- package/dist/ir/validation-orchestrator.d.ts +4 -0
- package/dist/ir/validation-orchestrator.js +45 -0
- package/dist/libdef/base-class-resolver.d.ts +23 -0
- package/dist/libdef/base-class-resolver.js +50 -0
- package/dist/libdef/cpp-to-decl.d.ts +34 -0
- package/dist/libdef/cpp-to-decl.js +584 -0
- package/dist/libdef/header-parser.d.ts +53 -0
- package/dist/libdef/header-parser.js +269 -0
- package/dist/libdef/registry.d.ts +10 -0
- package/dist/libdef/registry.js +142 -0
- package/dist/mapping/peripheral-names.d.ts +23 -0
- package/dist/mapping/peripheral-names.js +63 -0
- package/dist/mapping/source-map.d.ts +46 -0
- package/dist/mapping/source-map.js +207 -0
- package/dist/orchestrator/dts-generator.d.ts +17 -0
- package/dist/orchestrator/dts-generator.js +83 -0
- package/dist/orchestrator/graph-builder.d.ts +18 -0
- package/dist/orchestrator/graph-builder.js +218 -0
- package/dist/orchestrator/semantic-facts-verifier.d.ts +38 -0
- package/dist/orchestrator/semantic-facts-verifier.js +121 -0
- package/dist/orchestrator/semantic-facts.d.ts +141 -0
- package/dist/orchestrator/semantic-facts.js +652 -0
- package/dist/orchestrator/type-checker.d.ts +39 -0
- package/dist/orchestrator/type-checker.js +760 -0
- package/dist/platform/async-runtime.d.ts +8 -0
- package/dist/platform/async-runtime.js +26 -0
- package/dist/platform/generic-strategy.d.ts +101 -0
- package/dist/platform/generic-strategy.js +289 -0
- package/dist/platform/index.d.ts +4 -0
- package/dist/platform/index.js +9 -0
- package/dist/platform/registry.d.ts +21 -0
- package/dist/platform/registry.js +42 -0
- package/dist/platform/toolchain.d.ts +4 -0
- package/dist/platform/toolchain.js +43 -0
- package/dist/preview/client.d.ts +1 -0
- package/dist/preview/client.js +137 -0
- package/dist/preview/server.d.ts +5 -0
- package/dist/preview/server.js +199 -0
- package/dist/profiler/index.d.ts +28 -0
- package/dist/profiler/index.js +28 -0
- package/dist/profiler/profiler.d.ts +95 -0
- package/dist/profiler/profiler.js +338 -0
- package/dist/profiler/types.d.ts +87 -0
- package/dist/profiler/types.js +12 -0
- package/dist/stores/display-profile-store.d.ts +16 -0
- package/dist/stores/display-profile-store.js +48 -0
- package/dist/stores/theme-store.d.ts +13 -0
- package/dist/stores/theme-store.js +30 -0
- package/dist/testing.d.ts +45 -0
- package/dist/testing.js +47 -0
- package/dist/transpile/resolution.d.ts +29 -0
- package/dist/transpile/resolution.js +282 -0
- package/dist/transpile.d.ts +3 -0
- package/dist/transpile.js +722 -0
- package/dist/types.d.ts +217 -0
- package/dist/types.js +1 -0
- package/dist/ui/ui-bridge.d.ts +4 -0
- package/dist/ui/ui-bridge.js +34 -0
- package/dist/ui-hook.d.ts +84 -0
- package/dist/ui-hook.js +45 -0
- package/dist/utils/cli.d.ts +3 -0
- package/dist/utils/cli.js +463 -0
- package/dist/utils/fs.d.ts +4 -0
- package/dist/utils/fs.js +23 -0
- package/dist/utils/logger.d.ts +2 -0
- package/dist/utils/logger.js +8 -0
- package/dist/utils/strings.d.ts +35 -0
- package/dist/utils/strings.js +142 -0
- package/dist/utils/ui.d.ts +66 -0
- package/dist/utils/ui.js +149 -0
- package/dist/watch.d.ts +35 -0
- package/dist/watch.js +111 -0
- package/package.json +127 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
interface AutoWireNode {
|
|
2
|
+
tag: string;
|
|
3
|
+
id?: string;
|
|
4
|
+
text?: string;
|
|
5
|
+
children?: AutoWireNode[];
|
|
6
|
+
options?: Array<{
|
|
7
|
+
value: string;
|
|
8
|
+
text: string;
|
|
9
|
+
}>;
|
|
10
|
+
name?: string;
|
|
11
|
+
checked?: boolean;
|
|
12
|
+
href?: string;
|
|
13
|
+
/** Rich-text runs (present only for text nodes with mixed inline content).
|
|
14
|
+
* A run may carry an href (inline <a href>); those make the node a link
|
|
15
|
+
* target that needs a click handler so it's hit-testable. */
|
|
16
|
+
runs?: Array<{
|
|
17
|
+
href?: string;
|
|
18
|
+
}>;
|
|
19
|
+
/** True when text contains a `{expr}` interpolation; auto-wire synthesizes an
|
|
20
|
+
* implicit text binding for it (no id required — {expr} references a signal). */
|
|
21
|
+
hasInterpolation?: boolean;
|
|
22
|
+
/** Declarative on:* event handlers (named-function references). Each value
|
|
23
|
+
* names an exported TS function emitted as a standalone C++ function. */
|
|
24
|
+
events?: {
|
|
25
|
+
click?: string;
|
|
26
|
+
hold?: string;
|
|
27
|
+
release?: string;
|
|
28
|
+
change?: string;
|
|
29
|
+
};
|
|
30
|
+
/** Declarative bind:* two-way bindings (signal names). bind:text on <input>
|
|
31
|
+
* composes a text binding + an input binding; bind:value on <range>/<check>
|
|
32
|
+
* composes a value binding + a change/click handler. */
|
|
33
|
+
bind?: {
|
|
34
|
+
text?: string;
|
|
35
|
+
value?: string;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export declare function getRadioGroups(): Map<string, {
|
|
39
|
+
id: string;
|
|
40
|
+
nodeIndex: number;
|
|
41
|
+
}[]>;
|
|
42
|
+
/** Register a screen ID → index mapping (called during multi-screen setup). */
|
|
43
|
+
export declare function registerScreenId(id: string, index: number): void;
|
|
44
|
+
/** Resolve a href="#screenId" to a screen index, or undefined if unknown. */
|
|
45
|
+
export declare function resolveScreenHref(href: string | undefined): number | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Walk the styled tree and auto-wire built-in element behaviors.
|
|
48
|
+
*/
|
|
49
|
+
export declare function autoWireElements(treeName: string, root: AutoWireNode, startIndex?: number): number;
|
|
50
|
+
export {};
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Auto-wire built-in elements — when the transpiler encounters <check>,
|
|
3
|
+
// <select>, or <button> in the HTML, it automatically registers the default
|
|
4
|
+
// behavior (onClick handlers, visual bindings) so the author doesn't have to.
|
|
5
|
+
//
|
|
6
|
+
// Authors can still override or add to this behavior in their TS code.
|
|
7
|
+
// For custom elements, use <view> + <text> + manual bindings.
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
import { recordClickHandler, recordBinding, markRunNode, lowerInterpolationText } from "./transformers/ui-call-resolver.js";
|
|
10
|
+
import { recordInputBinding } from "./transformers/ui-reactive.js";
|
|
11
|
+
// Track radio groups for mutual exclusion
|
|
12
|
+
const radioGroups = new Map();
|
|
13
|
+
// Track screen IDs → screen indices for link navigation.
|
|
14
|
+
const screenIdMap = new Map();
|
|
15
|
+
export function getRadioGroups() { return radioGroups; }
|
|
16
|
+
/** Register a screen ID → index mapping (called during multi-screen setup). */
|
|
17
|
+
export function registerScreenId(id, index) {
|
|
18
|
+
screenIdMap.set(id, index);
|
|
19
|
+
}
|
|
20
|
+
/** Resolve a href="#screenId" to a screen index, or undefined if unknown. */
|
|
21
|
+
export function resolveScreenHref(href) {
|
|
22
|
+
if (!href)
|
|
23
|
+
return undefined;
|
|
24
|
+
const target = href.startsWith("#") ? href.slice(1) : href;
|
|
25
|
+
return screenIdMap.get(target);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Walk the styled tree and auto-wire built-in element behaviors.
|
|
29
|
+
*/
|
|
30
|
+
export function autoWireElements(treeName, root, startIndex = 0) {
|
|
31
|
+
if (startIndex === 0)
|
|
32
|
+
radioGroups.clear();
|
|
33
|
+
let nodeIndex = startIndex;
|
|
34
|
+
const walk = (node) => {
|
|
35
|
+
const currentIndex = nodeIndex++;
|
|
36
|
+
// Record run-bearing node indices so the binding resolver can reject
|
|
37
|
+
// PROP_TEXT bindings on them (runs are static-only).
|
|
38
|
+
if (node.runs && node.runs.length > 0)
|
|
39
|
+
markRunNode(currentIndex);
|
|
40
|
+
// Auto-wire nodes with an id, <a href> links, run-bearing link nodes
|
|
41
|
+
// (an inline <a href> inside a paragraph makes the paragraph a tap target),
|
|
42
|
+
// {expr} text interpolations, and on:* declarative event handlers. The last
|
|
43
|
+
// two may have no id — {expr} references a signal; on:* names a function.
|
|
44
|
+
const hasLinkRun = !!node.runs?.some(r => r.href);
|
|
45
|
+
const hasEvents = !!node.events && Object.keys(node.events).length > 0;
|
|
46
|
+
const hasBind = !!node.bind && Object.keys(node.bind).length > 0;
|
|
47
|
+
if (node.id || node.href || hasLinkRun || node.hasInterpolation || hasEvents || hasBind) {
|
|
48
|
+
autoWireNode(treeName, node, currentIndex);
|
|
49
|
+
}
|
|
50
|
+
node.children?.forEach(walk);
|
|
51
|
+
};
|
|
52
|
+
walk(root);
|
|
53
|
+
return nodeIndex;
|
|
54
|
+
}
|
|
55
|
+
function autoWireNode(treeName, node, nodeIndex) {
|
|
56
|
+
// {expr} text interpolation → synthesize an implicit text binding. This runs
|
|
57
|
+
// before the id/href guard below because an interpolation node may have no id
|
|
58
|
+
// ({expr} references a signal, not a screen.<id> handle). recordBinding rejects
|
|
59
|
+
// run-bearing nodes via the run-text-binding-conflict guard, so inline+interp
|
|
60
|
+
// combinations are caught there rather than here.
|
|
61
|
+
if (node.hasInterpolation && node.text) {
|
|
62
|
+
const cppBody = lowerInterpolationText(node.text);
|
|
63
|
+
if (cppBody) {
|
|
64
|
+
recordBinding({
|
|
65
|
+
nodeIndex,
|
|
66
|
+
property: "text",
|
|
67
|
+
fnName: `__ui_interp_${nodeIndex}`,
|
|
68
|
+
cppBody,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// bind:* declarative two-way bindings → compose a read-binding (signal→node)
|
|
73
|
+
// with a write-callback (node→signal). bind:text on <input> uses a text
|
|
74
|
+
// binding + an input binding (fires on keyboard commit). bind:value on
|
|
75
|
+
// <range>/<check> uses a value binding + a change/click handler.
|
|
76
|
+
if (node.bind) {
|
|
77
|
+
if (node.bind.text) {
|
|
78
|
+
const sig = node.bind.text;
|
|
79
|
+
// Read: signal → node text (reuses the binding table).
|
|
80
|
+
recordBinding({
|
|
81
|
+
nodeIndex,
|
|
82
|
+
property: "text",
|
|
83
|
+
fnName: `__ui_bindtext_${nodeIndex}`,
|
|
84
|
+
cppBody: `snprintf(buf, size, "%s", ${sig});`,
|
|
85
|
+
});
|
|
86
|
+
// Write: keyboard commit → signal.set(text).
|
|
87
|
+
recordInputBinding({
|
|
88
|
+
nodeIndex,
|
|
89
|
+
cbFnName: `__ui_bindtext_cb_${nodeIndex}`,
|
|
90
|
+
cbFnBody: `${sig}.set(std::string(text));`,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
if (node.bind.value) {
|
|
94
|
+
const sig = node.bind.value;
|
|
95
|
+
// Read: signal → node value.
|
|
96
|
+
recordBinding({
|
|
97
|
+
nodeIndex,
|
|
98
|
+
property: "value",
|
|
99
|
+
fnName: `__ui_bindval_${nodeIndex}`,
|
|
100
|
+
cppExpr: sig,
|
|
101
|
+
});
|
|
102
|
+
// Write: range drag / check toggle → signal.set(value).
|
|
103
|
+
recordClickHandler({
|
|
104
|
+
nodeIndex,
|
|
105
|
+
kind: node.tag === "check" ? "click" : "rangechange",
|
|
106
|
+
fnName: `__ui_bindval_cb_${nodeIndex}`,
|
|
107
|
+
callbackBody: `${sig}.set(__ui_nodes[${nodeIndex}].value);`,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// on:* declarative event handlers → record click/hold/release/change handlers
|
|
112
|
+
// that reference the named C++ function by name (no inlined body). The named
|
|
113
|
+
// function comes from the author's `export function name() {...}` in TS,
|
|
114
|
+
// which the transpiler emits as a standalone C++ function.
|
|
115
|
+
if (node.events) {
|
|
116
|
+
const kindMap = { click: "click", hold: "hold", release: "release", change: "change" };
|
|
117
|
+
for (const key of Object.keys(node.events)) {
|
|
118
|
+
const fnName = node.events[key];
|
|
119
|
+
if (fnName) {
|
|
120
|
+
recordClickHandler({
|
|
121
|
+
nodeIndex,
|
|
122
|
+
kind: kindMap[key],
|
|
123
|
+
fnName,
|
|
124
|
+
callbackBody: "",
|
|
125
|
+
isNamedRef: true,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// The check/select/radio branches generate fnNames from node.id, so they
|
|
131
|
+
// require one. The href (navigation) branch below works with or without id.
|
|
132
|
+
// Run-bearing link nodes also work without id (handler body is a no-op; the
|
|
133
|
+
// real navigation happens via the run hit-test in the tap path).
|
|
134
|
+
const hasLinkRun = !!node.runs?.some(r => r.href);
|
|
135
|
+
if (!node.id && !node.href && !hasLinkRun)
|
|
136
|
+
return;
|
|
137
|
+
if (node.tag === "check") {
|
|
138
|
+
// Auto-wire: onClick toggles value 0↔1
|
|
139
|
+
recordClickHandler({
|
|
140
|
+
nodeIndex,
|
|
141
|
+
kind: "click",
|
|
142
|
+
fnName: `__ui_${node.id}_autoclick`,
|
|
143
|
+
callbackBody: `__ui_nodes[${nodeIndex}].value = (__ui_nodes[${nodeIndex}].value > 0 ? 0 : 1);`,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
if (node.tag === "select") {
|
|
147
|
+
// Use parsed options (from <option> children) or fallback to comma text
|
|
148
|
+
const options = node.options && node.options.length > 0
|
|
149
|
+
? node.options.map(o => o.text)
|
|
150
|
+
: (node.text || "").split(",").map(s => s.trim()).filter(Boolean);
|
|
151
|
+
const count = Math.max(options.length, 2);
|
|
152
|
+
// Auto-wire: onClick cycles value 0..count-1
|
|
153
|
+
recordClickHandler({
|
|
154
|
+
nodeIndex,
|
|
155
|
+
kind: "click",
|
|
156
|
+
fnName: `__ui_${node.id}_autoclick`,
|
|
157
|
+
callbackBody: `__ui_nodes[${nodeIndex}].value = (__ui_nodes[${nodeIndex}].value + 1) % ${count};`,
|
|
158
|
+
});
|
|
159
|
+
// Auto-bind text to show the current option via snprintf if/else chain
|
|
160
|
+
const branches = options.map((opt, i) => {
|
|
161
|
+
if (i === 0)
|
|
162
|
+
return `if (__ui_nodes[${nodeIndex}].value == 0) { snprintf(buf, size, "%s", "${opt}"); }`;
|
|
163
|
+
return `else if (__ui_nodes[${nodeIndex}].value == ${i}) { snprintf(buf, size, "%s", "${opt}"); }`;
|
|
164
|
+
}).join(" ");
|
|
165
|
+
const elseBranch = `else { snprintf(buf, size, "%s", "${options[0] || ""}"); }`;
|
|
166
|
+
recordBinding({
|
|
167
|
+
nodeIndex,
|
|
168
|
+
property: "text",
|
|
169
|
+
fnName: `__ui_${node.id}_autotext`,
|
|
170
|
+
cppBody: branches + " " + elseBranch,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
if (node.tag === "radio" && node.name) {
|
|
174
|
+
// Register this radio in its group
|
|
175
|
+
const groupName = node.name;
|
|
176
|
+
if (!radioGroups.has(groupName))
|
|
177
|
+
radioGroups.set(groupName, []);
|
|
178
|
+
const group = radioGroups.get(groupName);
|
|
179
|
+
group.push({ id: node.id, nodeIndex });
|
|
180
|
+
// Auto-wire: onClick clears all radios in the group, then selects this one.
|
|
181
|
+
// The generated C++ references the radio group table by index.
|
|
182
|
+
const groupIdx = Array.from(radioGroups.keys()).indexOf(groupName);
|
|
183
|
+
recordClickHandler({
|
|
184
|
+
nodeIndex,
|
|
185
|
+
kind: "click",
|
|
186
|
+
fnName: `__ui_${node.id}_autoclick`,
|
|
187
|
+
callbackBody: `for (uint8_t __r = 0; __r < __ui_radio_groups[${groupIdx}].count; __r++) { uint16_t __rn = __ui_radio_groups[${groupIdx}].nodeIndices[__r]; __ui_nodes[__rn].value = 0; ui_mark_dirty(__rn); } __ui_nodes[${nodeIndex}].value = 1; ui_mark_dirty(${nodeIndex});`,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
// Auto-wire <a href="#screenId"> links: onClick navigates to the target screen.
|
|
191
|
+
if (node.href) {
|
|
192
|
+
const targetScreen = resolveScreenHref(node.href);
|
|
193
|
+
if (targetScreen !== undefined) {
|
|
194
|
+
recordClickHandler({
|
|
195
|
+
nodeIndex,
|
|
196
|
+
kind: "click",
|
|
197
|
+
fnName: `__ui_${node.id ?? "link" + nodeIndex}_nav`,
|
|
198
|
+
callbackBody: `ui_navigate(${targetScreen});`,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
console.error(`[auto-wire] WARNING: <a href="${node.href}"> (id=${node.id}) target screen not found. Known screens: ${[...screenIdMap.keys()].join(", ")}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
else if (hasLinkRun) {
|
|
206
|
+
// Run-bearing link node (an inline <a href> inside a paragraph). The link
|
|
207
|
+
// targets live on the runs and are resolved into the model at lower time;
|
|
208
|
+
// the tap path calls ui_rich_link_hit / richLinkHit to pick the target.
|
|
209
|
+
// Register a no-op click handler so the node is hit-testable in the first
|
|
210
|
+
// place (hit-test only considers nodes with a registered handler).
|
|
211
|
+
recordClickHandler({
|
|
212
|
+
nodeIndex,
|
|
213
|
+
kind: "click",
|
|
214
|
+
fnName: `__ui_${node.id ?? "richlink" + nodeIndex}_nav`,
|
|
215
|
+
callbackBody: `/* rich-text link; target resolved by ui_rich_link_hit */`,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ProgramIR } from '../api/index.js';
|
|
2
|
+
import { Diagnostic } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Validate peripheral config values for common unit mistakes.
|
|
5
|
+
*
|
|
6
|
+
* Scans the program IR for cuttlefish-call nodes that configure peripherals
|
|
7
|
+
* with bare numbers and emits warnings when values look suspicious.
|
|
8
|
+
*
|
|
9
|
+
* @param program - The program IR to validate
|
|
10
|
+
* @returns Array of diagnostics for suspicious peripheral config values
|
|
11
|
+
*/
|
|
12
|
+
export declare function validateUnitSuspicion(program: ProgramIR): Diagnostic[];
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Unit Suspicion Validation
|
|
3
|
+
//
|
|
4
|
+
// Warns when bare numbers passed to peripheral config methods look suspicious.
|
|
5
|
+
// For example, passing 9600 to an SPI frequency (which expects Hz, not baud)
|
|
6
|
+
// or passing 100 to I2C speed (which expects Hz, not kHz).
|
|
7
|
+
//
|
|
8
|
+
// This validator complements the two-tier peripheral config approach:
|
|
9
|
+
// - Enum values (BaudRate._9600, I2CSpeed.FAST, etc.) are always safe
|
|
10
|
+
// - Bare numbers in .config builders are validated here for common mistakes
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Standard baud rates for UART
|
|
13
|
+
const KNOWN_BAUD_RATES = new Set([
|
|
14
|
+
300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200,
|
|
15
|
+
230400, 460800, 921600,
|
|
16
|
+
]);
|
|
17
|
+
// Standard I2C clock speeds in Hz
|
|
18
|
+
const KNOWN_I2C_SPEEDS = new Set([
|
|
19
|
+
100_000, // Standard (100 kHz)
|
|
20
|
+
400_000, // Fast (400 kHz)
|
|
21
|
+
1_000_000, // Fast Plus (1 MHz)
|
|
22
|
+
3_400_000, // High Speed (3.4 MHz)
|
|
23
|
+
]);
|
|
24
|
+
// Standard SPI clock frequencies in Hz
|
|
25
|
+
const KNOWN_SPI_FREQUENCIES = new Set([
|
|
26
|
+
125_000, // 125 kHz
|
|
27
|
+
250_000, // 250 kHz
|
|
28
|
+
500_000, // 500 kHz
|
|
29
|
+
1_000_000, // 1 MHz
|
|
30
|
+
2_000_000, // 2 MHz
|
|
31
|
+
4_000_000, // 4 MHz
|
|
32
|
+
8_000_000, // 8 MHz
|
|
33
|
+
16_000_000, // 16 MHz
|
|
34
|
+
]);
|
|
35
|
+
/**
|
|
36
|
+
* Extract a numeric value from an expression IR node.
|
|
37
|
+
* Returns `undefined` if the expression is not a simple numeric literal.
|
|
38
|
+
*/
|
|
39
|
+
function extractNumericValue(expr) {
|
|
40
|
+
if (!expr || typeof expr !== 'object')
|
|
41
|
+
return undefined;
|
|
42
|
+
// Direct numeric literal
|
|
43
|
+
if (expr.kind === 'number') {
|
|
44
|
+
return expr.value;
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Check if a baud rate value is suspicious.
|
|
50
|
+
* Warns if the value is not a standard baud rate.
|
|
51
|
+
*/
|
|
52
|
+
function checkBaudRate(value) {
|
|
53
|
+
if (KNOWN_BAUD_RATES.has(value))
|
|
54
|
+
return undefined;
|
|
55
|
+
// Check for common mistakes
|
|
56
|
+
// User might have intended a standard rate but typo'd
|
|
57
|
+
for (const known of KNOWN_BAUD_RATES) {
|
|
58
|
+
// Close to a standard rate (within 10%)
|
|
59
|
+
if (value > known * 0.9 && value < known * 1.1) {
|
|
60
|
+
return `Baud rate ${value} is close to standard rate ${known}. Did you mean ${known}?`;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Very low values might be confused with kHz
|
|
64
|
+
if (value > 0 && value < 100) {
|
|
65
|
+
return `Baud rate ${value} is unusually low. UART baud rates are typically ≥ 300.`;
|
|
66
|
+
}
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Check if an I2C speed value is suspicious.
|
|
71
|
+
* Warns if the value looks like it's in kHz instead of Hz.
|
|
72
|
+
*/
|
|
73
|
+
function checkI2CSpeed(value) {
|
|
74
|
+
if (KNOWN_I2C_SPEEDS.has(value))
|
|
75
|
+
return undefined;
|
|
76
|
+
// Common mistake: passing kHz value instead of Hz
|
|
77
|
+
// e.g., 100 instead of 100000, 400 instead of 400000
|
|
78
|
+
if (value > 0 && value < 10000) {
|
|
79
|
+
// Check if multiplying by 1000 gives a known speed
|
|
80
|
+
const asHz = value * 1000;
|
|
81
|
+
if (KNOWN_I2C_SPEEDS.has(asHz)) {
|
|
82
|
+
return `I2C speed ${value} looks like a kHz value. Did you mean ${asHz} (${value} kHz)? I2C speed is specified in Hz.`;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Check for close matches to standard speeds
|
|
86
|
+
for (const known of KNOWN_I2C_SPEEDS) {
|
|
87
|
+
if (value > known * 0.9 && value < known * 1.1) {
|
|
88
|
+
return `I2C speed ${value} is close to standard speed ${known}. Did you mean ${known}?`;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Check if an SPI frequency value is suspicious.
|
|
95
|
+
* Warns if the value looks like it's in kHz or MHz instead of Hz,
|
|
96
|
+
* or if it's a standard baud rate mistakenly used for SPI.
|
|
97
|
+
*/
|
|
98
|
+
function checkSPIFrequency(value) {
|
|
99
|
+
if (KNOWN_SPI_FREQUENCIES.has(value))
|
|
100
|
+
return undefined;
|
|
101
|
+
// Common mistake: passing kHz value instead of Hz
|
|
102
|
+
if (value > 0 && value < 100000) {
|
|
103
|
+
const asHz = value * 1000;
|
|
104
|
+
if (KNOWN_SPI_FREQUENCIES.has(asHz)) {
|
|
105
|
+
return `SPI frequency ${value} looks like a kHz value. Did you mean ${asHz}? SPI frequency is specified in Hz.`;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Common mistake: passing MHz value instead of Hz
|
|
109
|
+
if (value > 0 && value <= 16) {
|
|
110
|
+
const asHz = value * 1_000_000;
|
|
111
|
+
if (KNOWN_SPI_FREQUENCIES.has(asHz)) {
|
|
112
|
+
return `SPI frequency ${value} looks like an MHz value. Did you mean ${asHz}? SPI frequency is specified in Hz.`;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Check if a standard baud rate was mistakenly used for SPI
|
|
116
|
+
if (KNOWN_BAUD_RATES.has(value)) {
|
|
117
|
+
return `Value ${value} is a standard UART baud rate, not a typical SPI clock frequency. SPI frequencies are usually powers-of-two divisors of the system clock.`;
|
|
118
|
+
}
|
|
119
|
+
// Check for close matches to standard frequencies
|
|
120
|
+
for (const known of KNOWN_SPI_FREQUENCIES) {
|
|
121
|
+
if (value > known * 0.9 && value < known * 1.1) {
|
|
122
|
+
return `SPI frequency ${value} is close to standard frequency ${known}. Did you mean ${known}?`;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Check a peripheral config value via the appropriate checker. Emits a
|
|
129
|
+
* diagnostic if the value looks like a unit mistake (kHz instead of Hz, a
|
|
130
|
+
* baud rate used as SPI freq, etc.). Only literal numbers are checked —
|
|
131
|
+
* expressions/variables are opaque to this validator.
|
|
132
|
+
*/
|
|
133
|
+
function checkConfigValue(kind, rawValue, diagnostics) {
|
|
134
|
+
// HAL ops carry resolved numeric values as `number` when the source arg was
|
|
135
|
+
// a literal, or as `string` expression text otherwise. Only check numbers.
|
|
136
|
+
const value = typeof rawValue === 'number' ? rawValue
|
|
137
|
+
: typeof rawValue === 'string' && /^\d+$/.test(rawValue) ? parseInt(rawValue, 10)
|
|
138
|
+
: null;
|
|
139
|
+
if (value === null)
|
|
140
|
+
return;
|
|
141
|
+
const message = kind === 'baud' ? checkBaudRate(value)
|
|
142
|
+
: kind === 'i2c' ? checkI2CSpeed(value)
|
|
143
|
+
: checkSPIFrequency(value);
|
|
144
|
+
if (message) {
|
|
145
|
+
diagnostics.push({
|
|
146
|
+
severity: 'warning',
|
|
147
|
+
message,
|
|
148
|
+
code: 'unit-suspicion',
|
|
149
|
+
source: 'unit-suspicion-validation',
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Recursively scan a statement and its children for suspicious peripheral
|
|
155
|
+
* config values. Recognizes the HAL ops that carry clock/baud/frequency
|
|
156
|
+
* values (i2c.set_clock, uart.begin, spi.begin_transaction) and call
|
|
157
|
+
* statements whose callee matches known config method names.
|
|
158
|
+
*/
|
|
159
|
+
function scanStatement(stmt, diagnostics) {
|
|
160
|
+
if (!stmt || typeof stmt !== 'object')
|
|
161
|
+
return;
|
|
162
|
+
const s = stmt;
|
|
163
|
+
// HAL-op statements carry structured operations with resolved values.
|
|
164
|
+
if (stmt.kind === 'hal-op' && s.operation) {
|
|
165
|
+
const op = s.operation;
|
|
166
|
+
switch (op.operation) {
|
|
167
|
+
case 'i2c.set_clock':
|
|
168
|
+
checkConfigValue('i2c', op.hz, diagnostics);
|
|
169
|
+
break;
|
|
170
|
+
case 'uart.begin':
|
|
171
|
+
checkConfigValue('baud', op.baud, diagnostics);
|
|
172
|
+
break;
|
|
173
|
+
// SPI frequency flows through SPISettings construction text, which the
|
|
174
|
+
// HAL op carries as a string — the numeric extraction in
|
|
175
|
+
// checkConfigValue handles bare-digit strings.
|
|
176
|
+
case 'spi.begin_transaction':
|
|
177
|
+
if (typeof op.settings === 'string') {
|
|
178
|
+
// SPISettings({freq}, ...) — try to extract the leading frequency.
|
|
179
|
+
const m = op.settings.match(/^\s*(\d+)/);
|
|
180
|
+
if (m)
|
|
181
|
+
checkConfigValue('spi', parseInt(m[1], 10), diagnostics);
|
|
182
|
+
}
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// Call statements: match config method names with a numeric literal arg.
|
|
187
|
+
// This catches pre-HAL-resolution calls and library-level config helpers.
|
|
188
|
+
if (stmt.kind === 'call' && typeof s.callee === 'string' && Array.isArray(s.args)) {
|
|
189
|
+
const method = s.callee.split('.').pop() ?? s.callee;
|
|
190
|
+
if (method === 'setClock' && s.args.length >= 2) {
|
|
191
|
+
checkConfigValue('i2c', extractNumericValue(s.args[1]), diagnostics);
|
|
192
|
+
}
|
|
193
|
+
else if (method === 'setBaudRate' || method === 'begin') {
|
|
194
|
+
// Serial.begin(baud) / setBaudRate(baud) — last numeric arg is the baud.
|
|
195
|
+
for (const arg of s.args) {
|
|
196
|
+
const v = extractNumericValue(arg);
|
|
197
|
+
if (v !== undefined)
|
|
198
|
+
checkConfigValue('baud', v, diagnostics);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
else if (method === 'setFrequency' && s.args.length >= 2) {
|
|
202
|
+
checkConfigValue('spi', extractNumericValue(s.args[1]), diagnostics);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// Recurse into nested statements
|
|
206
|
+
if (s.body && Array.isArray(s.body)) {
|
|
207
|
+
for (const child of s.body)
|
|
208
|
+
scanStatement(child, diagnostics);
|
|
209
|
+
}
|
|
210
|
+
if (s.thenBranch && Array.isArray(s.thenBranch)) {
|
|
211
|
+
for (const child of s.thenBranch)
|
|
212
|
+
scanStatement(child, diagnostics);
|
|
213
|
+
}
|
|
214
|
+
if (s.elseBranch && Array.isArray(s.elseBranch)) {
|
|
215
|
+
for (const child of s.elseBranch)
|
|
216
|
+
scanStatement(child, diagnostics);
|
|
217
|
+
}
|
|
218
|
+
if (s.statements && Array.isArray(s.statements)) {
|
|
219
|
+
for (const child of s.statements)
|
|
220
|
+
scanStatement(child, diagnostics);
|
|
221
|
+
}
|
|
222
|
+
if (s.initializer && typeof s.initializer === 'object' && s.initializer.kind) {
|
|
223
|
+
scanStatement(s.initializer, diagnostics);
|
|
224
|
+
}
|
|
225
|
+
if (s.increment && typeof s.increment === 'object' && s.increment.kind) {
|
|
226
|
+
scanStatement(s.increment, diagnostics);
|
|
227
|
+
}
|
|
228
|
+
if (s.cases && Array.isArray(s.cases)) {
|
|
229
|
+
for (const c of s.cases) {
|
|
230
|
+
if (c.body && Array.isArray(c.body)) {
|
|
231
|
+
for (const child of c.body)
|
|
232
|
+
scanStatement(child, diagnostics);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (s.tryBlock && Array.isArray(s.tryBlock)) {
|
|
237
|
+
for (const child of s.tryBlock)
|
|
238
|
+
scanStatement(child, diagnostics);
|
|
239
|
+
}
|
|
240
|
+
if (s.catchBlock && Array.isArray(s.catchBlock)) {
|
|
241
|
+
for (const child of s.catchBlock)
|
|
242
|
+
scanStatement(child, diagnostics);
|
|
243
|
+
}
|
|
244
|
+
if (s.finallyBlock && Array.isArray(s.finallyBlock)) {
|
|
245
|
+
for (const child of s.finallyBlock)
|
|
246
|
+
scanStatement(child, diagnostics);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Validate peripheral config values for common unit mistakes.
|
|
251
|
+
*
|
|
252
|
+
* Scans the program IR for cuttlefish-call nodes that configure peripherals
|
|
253
|
+
* with bare numbers and emits warnings when values look suspicious.
|
|
254
|
+
*
|
|
255
|
+
* @param program - The program IR to validate
|
|
256
|
+
* @returns Array of diagnostics for suspicious peripheral config values
|
|
257
|
+
*/
|
|
258
|
+
export function validateUnitSuspicion(program) {
|
|
259
|
+
const diagnostics = [];
|
|
260
|
+
// Scan top-level statements
|
|
261
|
+
if (program.topLevelStatements) {
|
|
262
|
+
for (const stmt of program.topLevelStatements) {
|
|
263
|
+
scanStatement(stmt, diagnostics);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
// Scan function bodies
|
|
267
|
+
if (program.functions) {
|
|
268
|
+
for (const fn of program.functions) {
|
|
269
|
+
if (fn.statements) {
|
|
270
|
+
for (const stmt of fn.statements) {
|
|
271
|
+
scanStatement(stmt, diagnostics);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
// Scan class methods
|
|
277
|
+
if (program.classes) {
|
|
278
|
+
for (const cls of program.classes) {
|
|
279
|
+
if (cls.methods) {
|
|
280
|
+
for (const method of cls.methods) {
|
|
281
|
+
if (method.statements) {
|
|
282
|
+
for (const stmt of method.statements) {
|
|
283
|
+
scanStatement(stmt, diagnostics);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (cls.constructor?.statements) {
|
|
289
|
+
for (const stmt of cls.constructor.statements) {
|
|
290
|
+
scanStatement(stmt, diagnostics);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return diagnostics;
|
|
296
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { StatementIR, ExpressionIR, ProgramIR } from "../../api/index.js";
|
|
2
|
+
export declare function walkNestedStatements(stmt: StatementIR, visitor: (s: StatementIR) => void): void;
|
|
3
|
+
export declare function walkStatements(stmts: StatementIR[], visitor: (stmt: StatementIR) => void): void;
|
|
4
|
+
export declare function walkExpressionsInExpression(expr: ExpressionIR, visitor: (expr: ExpressionIR) => void): void;
|
|
5
|
+
export declare function walkExpressions(stmts: StatementIR[], visitor: (expr: ExpressionIR) => void): void;
|
|
6
|
+
export declare function walkProgramIR(program: ProgramIR, visitor: (stmt: StatementIR) => void): void;
|