@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,179 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// SymbolTable — the single ProgramIR-derived aggregation of cross-file type
|
|
3
|
+
// facts consumed by the emit phase.
|
|
4
|
+
//
|
|
5
|
+
// Phase 2 of the type-resolution consolidation. Previously the cross-file
|
|
6
|
+
// aggregation lived as hand-rolled ad-hoc loops in transpile.ts (the ~90-line
|
|
7
|
+
// block that built allClassFieldTypes / allClassAccessors /
|
|
8
|
+
// allFunctionReturnTypes / allVariableTypes / allClassNames) and was then
|
|
9
|
+
// duplicated again, per-file, in emit/emitters/setup.ts. This module is the
|
|
10
|
+
// canonical extraction of that aggregation: buildSymbolTable walks one
|
|
11
|
+
// ProgramIR, mergeSymbolTables folds many into the cross-module view, and the
|
|
12
|
+
// resulting SymbolTable projects onto the existing crossModule* emitter
|
|
13
|
+
// options without changing their shape (so renderers and EmitterContext fields
|
|
14
|
+
// are untouched).
|
|
15
|
+
//
|
|
16
|
+
// The construction rules here mirror the old transpile.ts block EXACTLY —
|
|
17
|
+
// including the two-pass extendsClass inheritance (own fields first, then a
|
|
18
|
+
// second pass that copies missing parent fields into children) — so emitted
|
|
19
|
+
// C++ is byte-identical. See the approved plan's Phase 2 risk note.
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
export function createSymbolTable() {
|
|
22
|
+
return {
|
|
23
|
+
classFieldTypes: new Map(),
|
|
24
|
+
classAccessors: new Map(),
|
|
25
|
+
functionReturnTypes: new Map(),
|
|
26
|
+
variableTypes: new Map(),
|
|
27
|
+
classNames: new Set(),
|
|
28
|
+
extends: new Map(),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Build a SymbolTable from a single file's ProgramIR. This is the per-file
|
|
33
|
+
* view; cross-file aggregation is done by mergeSymbolTable.
|
|
34
|
+
*
|
|
35
|
+
* Mirrors the old transpile.ts:612-666 first pass:
|
|
36
|
+
* - class fields, interface fields, accessors, function return types, and
|
|
37
|
+
* non-"auto" top-level variable types are collected
|
|
38
|
+
* - extendsClass relationships are recorded for the post-merge inheritance
|
|
39
|
+
* pass (the old code read them from programIR.classes directly)
|
|
40
|
+
* Accessor kind merge rule: getter+setter on the same name → "both".
|
|
41
|
+
*
|
|
42
|
+
* Does NOT fold parent fields into children yet — that happens once, after
|
|
43
|
+
* all files are merged, in resolveInheritance (mirroring the old two-pass
|
|
44
|
+
* structure where the second pass ran after the first pass over all files).
|
|
45
|
+
*/
|
|
46
|
+
export function buildSymbolTable(program) {
|
|
47
|
+
const table = createSymbolTable();
|
|
48
|
+
for (const cls of program.classes) {
|
|
49
|
+
table.classNames.add(cls.name);
|
|
50
|
+
if (cls.fields.length > 0 || cls.extendsClass) {
|
|
51
|
+
const fieldTypes = table.classFieldTypes.get(cls.name) ?? new Map();
|
|
52
|
+
for (const field of cls.fields) {
|
|
53
|
+
fieldTypes.set(field.name, field.cppType);
|
|
54
|
+
}
|
|
55
|
+
table.classFieldTypes.set(cls.name, fieldTypes);
|
|
56
|
+
}
|
|
57
|
+
if (cls.extendsClass) {
|
|
58
|
+
// NOTE: the old transpile.ts code used the RAW extendsClass string
|
|
59
|
+
// (including any template args, e.g. "Generic<std::string>") as the key
|
|
60
|
+
// into the field-type map — which is keyed by bare class names. Such a
|
|
61
|
+
// lookup silently fails for generic parents (no field entry under
|
|
62
|
+
// "Generic<std::string>"), so inheritance doesn't apply. We preserve
|
|
63
|
+
// that exact behavior here for byte-identical output rather than
|
|
64
|
+
// stripping template args (which would be "more correct" but would
|
|
65
|
+
// change which fields get inherited and thus the emitted C++).
|
|
66
|
+
table.extends.set(cls.name, cls.extendsClass);
|
|
67
|
+
}
|
|
68
|
+
if (cls.getters.length > 0 || cls.setters.length > 0) {
|
|
69
|
+
const accessors = table.classAccessors.get(cls.name) ?? new Map();
|
|
70
|
+
for (const g of cls.getters)
|
|
71
|
+
accessors.set(g.name, accessors.has(g.name) ? "both" : "getter");
|
|
72
|
+
for (const s of cls.setters)
|
|
73
|
+
accessors.set(s.name, accessors.has(s.name) ? "both" : "setter");
|
|
74
|
+
table.classAccessors.set(cls.name, accessors);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Interfaces lower to C++ structs, so their fields must be visible
|
|
78
|
+
// cross-module for type-driven emit decisions. Mirrors the old
|
|
79
|
+
// transpile.ts:650-658 interface aggregation.
|
|
80
|
+
for (const iface of program.interfaces) {
|
|
81
|
+
if (iface.fields.length > 0) {
|
|
82
|
+
const fieldTypes = table.classFieldTypes.get(iface.name) ?? new Map();
|
|
83
|
+
for (const field of iface.fields) {
|
|
84
|
+
fieldTypes.set(field.name, field.cppType);
|
|
85
|
+
}
|
|
86
|
+
table.classFieldTypes.set(iface.name, fieldTypes);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
for (const fn of program.functions) {
|
|
90
|
+
table.functionReturnTypes.set(fn.originalName, fn.returnType);
|
|
91
|
+
}
|
|
92
|
+
for (const stmt of program.topLevelStatements) {
|
|
93
|
+
if (stmt.kind === "var_decl" && stmt.cppType !== "auto") {
|
|
94
|
+
table.variableTypes.set(stmt.name, stmt.cppType);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return table;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Fold one SymbolTable into an accumulating cross-module table. This is the
|
|
101
|
+
* merge used during Pass 1 of transpile.ts to build the cross-file view from
|
|
102
|
+
* every file's per-file table.
|
|
103
|
+
*
|
|
104
|
+
* Field-type and accessor entries are merged (later files add to existing
|
|
105
|
+
* class entries); function return types and variable types are last-write-wins
|
|
106
|
+
* (matching the old Map.set behavior); class names are unioned; extends
|
|
107
|
+
* relationships are last-write-wins.
|
|
108
|
+
*/
|
|
109
|
+
export function mergeSymbolTable(target, source) {
|
|
110
|
+
for (const [className, fieldTypes] of source.classFieldTypes) {
|
|
111
|
+
const existing = target.classFieldTypes.get(className) ?? new Map();
|
|
112
|
+
for (const [fname, ftype] of fieldTypes) {
|
|
113
|
+
existing.set(fname, ftype);
|
|
114
|
+
}
|
|
115
|
+
target.classFieldTypes.set(className, existing);
|
|
116
|
+
}
|
|
117
|
+
for (const [className, accessors] of source.classAccessors) {
|
|
118
|
+
const existing = target.classAccessors.get(className) ?? new Map();
|
|
119
|
+
for (const [member, kind] of accessors) {
|
|
120
|
+
// Mirror buildSymbolTable's merge rule: if both getter and setter exist
|
|
121
|
+
// across the merge, the result is "both".
|
|
122
|
+
const prev = existing.get(member);
|
|
123
|
+
if (prev && prev !== kind) {
|
|
124
|
+
existing.set(member, "both");
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
existing.set(member, kind);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
target.classAccessors.set(className, existing);
|
|
131
|
+
}
|
|
132
|
+
for (const [fnName, retType] of source.functionReturnTypes) {
|
|
133
|
+
target.functionReturnTypes.set(fnName, retType);
|
|
134
|
+
}
|
|
135
|
+
for (const [varName, varType] of source.variableTypes) {
|
|
136
|
+
target.variableTypes.set(varName, varType);
|
|
137
|
+
}
|
|
138
|
+
for (const [child, parent] of source.extends) {
|
|
139
|
+
target.extends.set(child, parent);
|
|
140
|
+
}
|
|
141
|
+
for (const name of source.classNames) {
|
|
142
|
+
target.classNames.add(name);
|
|
143
|
+
}
|
|
144
|
+
return target;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Apply extendsClass field inheritance across an aggregated SymbolTable.
|
|
148
|
+
* Mirrors the old transpile.ts:668-688 SECOND pass: for each class that
|
|
149
|
+
* extends a parent present in the table, copy any parent fields the child does
|
|
150
|
+
* not already declare. Must run AFTER all files have been merged so cross-file
|
|
151
|
+
* parents are visible.
|
|
152
|
+
*
|
|
153
|
+
* Merge rule (preserved exactly): `!childFields.has(fname)` — a child's own
|
|
154
|
+
* field declaration wins over the parent's. If the child has no field entry at
|
|
155
|
+
* all but the parent does, a fresh entry seeded entirely from the parent is
|
|
156
|
+
* created (mirroring the old `else if (parentFields && !childFields)` branch).
|
|
157
|
+
*/
|
|
158
|
+
export function resolveInheritance(table) {
|
|
159
|
+
for (const [childName, parentName] of table.extends) {
|
|
160
|
+
const parentFields = table.classFieldTypes.get(parentName);
|
|
161
|
+
if (!parentFields)
|
|
162
|
+
continue;
|
|
163
|
+
const childFields = table.classFieldTypes.get(childName);
|
|
164
|
+
if (childFields) {
|
|
165
|
+
for (const [fname, ftype] of parentFields) {
|
|
166
|
+
if (!childFields.has(fname)) {
|
|
167
|
+
childFields.set(fname, ftype);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
const fieldTypes = new Map();
|
|
173
|
+
for (const [fname, ftype] of parentFields) {
|
|
174
|
+
fieldTypes.set(fname, ftype);
|
|
175
|
+
}
|
|
176
|
+
table.classFieldTypes.set(childName, fieldTypes);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export type CppTypeHint = string;
|
|
2
|
+
/**
|
|
3
|
+
* The bundle of type maps one IR-build scope consults. `locals` and
|
|
4
|
+
* `classFields` are deliberately separate Maps even though both were folded
|
|
5
|
+
* into the old activeLocalTypes at reset time — keeping them distinct makes
|
|
6
|
+
* the re-seed-on-reset step visible instead of implicit.
|
|
7
|
+
*/
|
|
8
|
+
export interface IrTypeScope {
|
|
9
|
+
/** Function-scoped variable types. Reset between functions, re-seeded from
|
|
10
|
+
* classFields (mirrors resetFunctionScopeState). */
|
|
11
|
+
locals: Map<string, CppTypeHint>;
|
|
12
|
+
/** File-scoped module-level variable types. Accumulates across functions. */
|
|
13
|
+
globals: Map<string, CppTypeHint>;
|
|
14
|
+
/** Class field types keyed `this->fieldName`. Populated once per class,
|
|
15
|
+
* survives function resets. */
|
|
16
|
+
classFields: Map<string, CppTypeHint>;
|
|
17
|
+
}
|
|
18
|
+
export declare function createIrTypeScope(): IrTypeScope;
|
|
19
|
+
/**
|
|
20
|
+
* Reset the function-scoped portion of a scope (locals only), then re-seed
|
|
21
|
+
* locals from classFields so `this->field` lookups keep resolving in the next
|
|
22
|
+
* method. Mirrors the old resetFunctionScopeState behavior exactly.
|
|
23
|
+
*/
|
|
24
|
+
export declare function resetIrTypeScopeFunctionState(scope: IrTypeScope): void;
|
|
25
|
+
/**
|
|
26
|
+
* Re-populate the scope's `locals` view from a caller-supplied Map, after
|
|
27
|
+
* resetFunctionScopeState has already cleared locals and re-seeded from
|
|
28
|
+
* classFields. Used by lowerStatementList at each entry to mirror the old
|
|
29
|
+
* behavior where activeLocalTypes was cleared, re-seeded from classFields,
|
|
30
|
+
* and then synced from the threaded localVariableTypes.
|
|
31
|
+
*
|
|
32
|
+
* IMPORTANT: this COPIES entries (it does not alias the maps). The threaded
|
|
33
|
+
* `localVariableTypes` map accumulates across nested lowerStatementList calls
|
|
34
|
+
* (if/for/while bodies pass it down by reference and must NOT be cleared by a
|
|
35
|
+
* nested reset); `scope.locals` is the function-resettable view that readers
|
|
36
|
+
* in expression-to-ir consult. Keeping them as distinct maps with a sync copy
|
|
37
|
+
* here, plus mirrored writes at every localVariableTypes.set site, preserves
|
|
38
|
+
* the original semantics exactly. Aliasing them would let a nested reset wipe
|
|
39
|
+
* the parent's accumulated locals.
|
|
40
|
+
*/
|
|
41
|
+
export declare function bindIrTypeScopeLocals(scope: IrTypeScope, locals: Map<string, CppTypeHint>): void;
|
|
42
|
+
/**
|
|
43
|
+
* Mirror a single write into the scope's locals view. Callers that write to
|
|
44
|
+
* the threaded localVariableTypes map must also call this so the
|
|
45
|
+
* getCurrentIrTypeScope().locals readers see the new entry. This replaces the
|
|
46
|
+
* old activeLocalTypes.set(...) calls that ran alongside localVariableTypes.set.
|
|
47
|
+
*/
|
|
48
|
+
export declare function setScopeLocalType(name: string, type: CppTypeHint): void;
|
|
49
|
+
export declare function setCurrentIrTypeScope(scope: IrTypeScope | undefined): void;
|
|
50
|
+
export declare function getCurrentIrTypeScope(): IrTypeScope | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* Returns the current scope, throwing if none is set. For call sites that are
|
|
53
|
+
* only reachable mid-lowering (the module-private readers in
|
|
54
|
+
* expression-to-ir.ts), where an unset scope would be a programming error.
|
|
55
|
+
*/
|
|
56
|
+
export declare function requireCurrentIrTypeScope(): IrTypeScope;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// IrTypeScope — the per-file, per-function type/symbol scratch space.
|
|
3
|
+
//
|
|
4
|
+
// Phase 1 of the type-resolution consolidation. Previously the IR build mutated
|
|
5
|
+
// three `AsyncLocalStorage`-proxied globals (activeLocalTypes,
|
|
6
|
+
// activeGlobalTypes, activeClassFieldTypes) exported from build-ir-state.ts.
|
|
7
|
+
// Those globals were a redundant shadow of the `localVariableTypes` parameter
|
|
8
|
+
// already threaded through control-flow.ts / expressions.ts / variables.ts /
|
|
9
|
+
// type-resolution.ts (see statement-to-ir.ts:397, which synced the threaded
|
|
10
|
+
// map back INTO the global on every function boundary).
|
|
11
|
+
//
|
|
12
|
+
// IrTypeScope replaces all three globals with an explicit object:
|
|
13
|
+
// - `locals` (was activeLocalTypes): function-scoped, reset between
|
|
14
|
+
// functions, re-seeded from `classFields` on reset (mirroring
|
|
15
|
+
// the old resetFunctionScopeState behavior at build-ir-state).
|
|
16
|
+
// - `globals` (was activeGlobalTypes): file-scoped, accumulates across
|
|
17
|
+
// functions; cleared once per file in resetBuildState.
|
|
18
|
+
// - `classFields` (was activeClassFieldTypes): keyed `this->fieldName`;
|
|
19
|
+
// populated by declaration-builders / function-builder and
|
|
20
|
+
// survives function resets so `this->x` resolves in every
|
|
21
|
+
// method of the class.
|
|
22
|
+
//
|
|
23
|
+
// Module-private readers in expression-to-ir.ts consult whichever IrTypeScope
|
|
24
|
+
// is "current" via getCurrentIrTypeScope(); the IR-build entry points push a
|
|
25
|
+
// scope as current before lowering and clear it on reset. This preserves the
|
|
26
|
+
// old global behavior exactly while making the data flow explicit.
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
export function createIrTypeScope() {
|
|
29
|
+
return {
|
|
30
|
+
locals: new Map(),
|
|
31
|
+
globals: new Map(),
|
|
32
|
+
classFields: new Map(),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Reset the function-scoped portion of a scope (locals only), then re-seed
|
|
37
|
+
* locals from classFields so `this->field` lookups keep resolving in the next
|
|
38
|
+
* method. Mirrors the old resetFunctionScopeState behavior exactly.
|
|
39
|
+
*/
|
|
40
|
+
export function resetIrTypeScopeFunctionState(scope) {
|
|
41
|
+
scope.locals.clear();
|
|
42
|
+
for (const [key, value] of scope.classFields) {
|
|
43
|
+
scope.locals.set(key, value);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Re-populate the scope's `locals` view from a caller-supplied Map, after
|
|
48
|
+
* resetFunctionScopeState has already cleared locals and re-seeded from
|
|
49
|
+
* classFields. Used by lowerStatementList at each entry to mirror the old
|
|
50
|
+
* behavior where activeLocalTypes was cleared, re-seeded from classFields,
|
|
51
|
+
* and then synced from the threaded localVariableTypes.
|
|
52
|
+
*
|
|
53
|
+
* IMPORTANT: this COPIES entries (it does not alias the maps). The threaded
|
|
54
|
+
* `localVariableTypes` map accumulates across nested lowerStatementList calls
|
|
55
|
+
* (if/for/while bodies pass it down by reference and must NOT be cleared by a
|
|
56
|
+
* nested reset); `scope.locals` is the function-resettable view that readers
|
|
57
|
+
* in expression-to-ir consult. Keeping them as distinct maps with a sync copy
|
|
58
|
+
* here, plus mirrored writes at every localVariableTypes.set site, preserves
|
|
59
|
+
* the original semantics exactly. Aliasing them would let a nested reset wipe
|
|
60
|
+
* the parent's accumulated locals.
|
|
61
|
+
*/
|
|
62
|
+
export function bindIrTypeScopeLocals(scope, locals) {
|
|
63
|
+
// Fold the threaded map's current entries into the already-re-seeded locals.
|
|
64
|
+
for (const [key, value] of locals) {
|
|
65
|
+
scope.locals.set(key, value);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Mirror a single write into the scope's locals view. Callers that write to
|
|
70
|
+
* the threaded localVariableTypes map must also call this so the
|
|
71
|
+
* getCurrentIrTypeScope().locals readers see the new entry. This replaces the
|
|
72
|
+
* old activeLocalTypes.set(...) calls that ran alongside localVariableTypes.set.
|
|
73
|
+
*/
|
|
74
|
+
export function setScopeLocalType(name, type) {
|
|
75
|
+
getCurrentIrTypeScope()?.locals.set(name, type);
|
|
76
|
+
}
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
// "Current" scope — the module-private readers in expression-to-ir.ts consult
|
|
79
|
+
// this when their caller did not pass an explicit scope. This keeps the ~25
|
|
80
|
+
// transformer call sites of expressionToIR(...) that don't carry a scope
|
|
81
|
+
// working unchanged, while still removing the AsyncLocalStorage global.
|
|
82
|
+
//
|
|
83
|
+
// The current-scope pointer is intentionally module-local (not async-local):
|
|
84
|
+
// the IR build is single-threaded and synchronous per file, and the entry
|
|
85
|
+
// points (build-ir.ts → lowerStatementList) always set the scope before any
|
|
86
|
+
// expression lowering happens within that file.
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
let currentIrTypeScope;
|
|
89
|
+
export function setCurrentIrTypeScope(scope) {
|
|
90
|
+
currentIrTypeScope = scope;
|
|
91
|
+
}
|
|
92
|
+
export function getCurrentIrTypeScope() {
|
|
93
|
+
return currentIrTypeScope;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Returns the current scope, throwing if none is set. For call sites that are
|
|
97
|
+
* only reachable mid-lowering (the module-private readers in
|
|
98
|
+
* expression-to-ir.ts), where an unset scope would be a programming error.
|
|
99
|
+
*/
|
|
100
|
+
export function requireCurrentIrTypeScope() {
|
|
101
|
+
const scope = currentIrTypeScope;
|
|
102
|
+
if (!scope) {
|
|
103
|
+
throw new Error("requireCurrentIrTypeScope: no IrTypeScope is active. An IR-build entry " +
|
|
104
|
+
"point must call setCurrentIrTypeScope() before lowering expressions.");
|
|
105
|
+
}
|
|
106
|
+
return scope;
|
|
107
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Diagnostic } from '../types.js';
|
|
2
|
+
import type { BoardConstants } from './board-resolver.js';
|
|
3
|
+
import type { PeripheralUsage } from './peripheral-usage.js';
|
|
4
|
+
export declare function validateTimer0PWMTimingConflict(usage: PeripheralUsage, boardConstants: BoardConstants | undefined): Diagnostic[];
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { findBoardPinByName, formatPinReference } from './board-pin-utils.js';
|
|
2
|
+
function getTimer0PwmPins(boardConstants) {
|
|
3
|
+
if (!boardConstants) {
|
|
4
|
+
return [];
|
|
5
|
+
}
|
|
6
|
+
const pinsByIndex = new Map();
|
|
7
|
+
for (const [key, value] of boardConstants) {
|
|
8
|
+
const match = key.match(/^pins\.all\.(\d+)\.name$/);
|
|
9
|
+
if (!match || typeof value !== 'string') {
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
const pinIndex = match[1];
|
|
13
|
+
const numberValue = boardConstants.get(`pins.all.${pinIndex}.number`);
|
|
14
|
+
const aliasesValue = boardConstants.get(`pins.all.${pinIndex}.aliases`);
|
|
15
|
+
const aliases = typeof aliasesValue === 'string' && aliasesValue.length > 0
|
|
16
|
+
? aliasesValue.split(',').map(entry => entry.trim()).filter(Boolean)
|
|
17
|
+
: [];
|
|
18
|
+
pinsByIndex.set(pinIndex, {
|
|
19
|
+
pinNumber: typeof numberValue === 'number' ? numberValue : Number(pinIndex),
|
|
20
|
+
canonicalName: value,
|
|
21
|
+
aliases,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
const timer0Pins = [];
|
|
25
|
+
for (const [key, value] of boardConstants) {
|
|
26
|
+
// Check for timer field first, fall back to OC register regex
|
|
27
|
+
const timerMatch = key.match(/^pins\.all\.(\d+)\.functions\.(\d+)\.timer$/);
|
|
28
|
+
if (timerMatch && value === 'timer0') {
|
|
29
|
+
const pin = pinsByIndex.get(timerMatch[1]);
|
|
30
|
+
if (pin) {
|
|
31
|
+
timer0Pins.push(pin);
|
|
32
|
+
}
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const match = key.match(/^pins\.all\.(\d+)\.functions\.\d+\.role$/);
|
|
36
|
+
if (!match || typeof value !== 'string' || !/^OC0[A-Z]?$/i.test(value)) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const pin = pinsByIndex.get(match[1]);
|
|
40
|
+
if (pin && !timer0Pins.some(p => p.pinNumber === pin.pinNumber)) {
|
|
41
|
+
timer0Pins.push(pin);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return timer0Pins;
|
|
45
|
+
}
|
|
46
|
+
export function validateTimer0PWMTimingConflict(usage, boardConstants) {
|
|
47
|
+
if (!usage.timer0 || usage.pwmPinsUsed.size === 0) {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
const timer0Pins = getTimer0PwmPins(boardConstants)
|
|
51
|
+
.filter(pin => usage.pwmPinsUsed.has(pin.pinNumber));
|
|
52
|
+
if (timer0Pins.length === 0) {
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
const boardName = boardConstants?.get('name');
|
|
56
|
+
const boardLabel = typeof boardName === 'string' && boardName.length > 0
|
|
57
|
+
? ` on ${boardName}`
|
|
58
|
+
: '';
|
|
59
|
+
const pinReferences = timer0Pins
|
|
60
|
+
.sort((left, right) => left.pinNumber - right.pinNumber)
|
|
61
|
+
.map((pin) => {
|
|
62
|
+
const usedName = [pin.canonicalName, ...pin.aliases].find(name => usage.pinsUsed.has(name)) ?? pin.canonicalName;
|
|
63
|
+
return formatPinReference(usedName, findBoardPinByName(pin.canonicalName, boardConstants));
|
|
64
|
+
});
|
|
65
|
+
return [{
|
|
66
|
+
severity: 'info',
|
|
67
|
+
code: 'timer0-pwm-timing-conflict',
|
|
68
|
+
source: 'timer0-pwm-timing-conflict',
|
|
69
|
+
message: `${pinReferences.join(', ')} use Timer0 PWM${boardLabel}, and your program also relies on Timer0-backed timing APIs such as delay(), millis(), or micros(). This coupling is common on AVR boards, so prefer non-Timer0 PWM pins when you want PWM behavior isolated from core timing.`,
|
|
70
|
+
}];
|
|
71
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ProgramIR } from '../api/index.js';
|
|
2
|
+
import type { Diagnostic } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Detect blocking delay() calls inside loop()'s body. Emits a warning for
|
|
5
|
+
* each, explaining the cooperative-async alternative.
|
|
6
|
+
*/
|
|
7
|
+
export declare function validateBlockingDelayInLoop(program: ProgramIR): Diagnostic[];
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Timing Validation
|
|
3
|
+
//
|
|
4
|
+
// Detects blocking delay() calls inside loop(). On Arduino, loop() runs
|
|
5
|
+
// repeatedly and must return promptly so the runtime can service the async
|
|
6
|
+
// microtask queue, UI rendering, and sensor polling. A delay() inside loop()
|
|
7
|
+
// freezes all of these for the delay duration — directly causing the UI
|
|
8
|
+
// tearing/scroll-responsiveness problems the AGENTS.md rendering guardrails
|
|
9
|
+
// address at the display layer.
|
|
10
|
+
//
|
|
11
|
+
// The transpiler knows what loop() semantically is (the repeated entry point);
|
|
12
|
+
// g++ sees only an ordinary function. This validator flags blocking delays in
|
|
13
|
+
// loop()'s direct body so the user can replace them with the cooperative
|
|
14
|
+
// Async.sleep() / millis()-comparison pattern.
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
/** Check a single statement for a blocking delay call or hal-op. */
|
|
17
|
+
function isBlockingDelay(stmt) {
|
|
18
|
+
const s = stmt;
|
|
19
|
+
// Direct call: delay(...) or delayMicroseconds(...)
|
|
20
|
+
if (stmt.kind === 'call' && typeof s.callee === 'string') {
|
|
21
|
+
if (s.callee === 'delay' || s.callee === 'delayMicroseconds')
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
// Hal-op: after HAL resolution, delay() becomes timing.delay /
|
|
25
|
+
// timing.delay_microseconds.
|
|
26
|
+
if (stmt.kind === 'hal-op' && s.operation?.operation) {
|
|
27
|
+
if (s.operation.operation === 'timing.delay' || s.operation.operation === 'timing.delay_microseconds') {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Detect blocking delay() calls inside loop()'s body. Emits a warning for
|
|
35
|
+
* each, explaining the cooperative-async alternative.
|
|
36
|
+
*/
|
|
37
|
+
export function validateBlockingDelayInLoop(program) {
|
|
38
|
+
const diagnostics = [];
|
|
39
|
+
const loopFn = program.functions.find(fn => fn.originalName === 'loop');
|
|
40
|
+
if (!loopFn || !loopFn.statements)
|
|
41
|
+
return diagnostics;
|
|
42
|
+
const visit = (stmts) => {
|
|
43
|
+
for (const stmt of stmts) {
|
|
44
|
+
if (isBlockingDelay(stmt)) {
|
|
45
|
+
const s = stmt;
|
|
46
|
+
diagnostics.push({
|
|
47
|
+
severity: 'warning',
|
|
48
|
+
message: `Blocking delay() inside loop() freezes the async microtask queue and UI rendering ` +
|
|
49
|
+
`for the delay duration. This causes display tearing and makes the sketch unresponsive.`,
|
|
50
|
+
hint: `Use the cooperative pattern instead: track elapsed time with millis() comparisons, ` +
|
|
51
|
+
`or use Async.sleep(ms) / Async.yield() to let other tasks run between checks.`,
|
|
52
|
+
line: stmt.sourceSpan?.startLine,
|
|
53
|
+
column: stmt.sourceSpan?.startColumn,
|
|
54
|
+
code: 'blocking-delay-in-loop',
|
|
55
|
+
source: 'timing-validation',
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
// Recurse into nested compound bodies (if/for/while/switch/try blocks).
|
|
59
|
+
const nested = getNested(stmt);
|
|
60
|
+
if (nested)
|
|
61
|
+
visit(nested);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
visit(loopFn.statements);
|
|
65
|
+
return diagnostics;
|
|
66
|
+
}
|
|
67
|
+
/** Get nested statement arrays from a compound statement. */
|
|
68
|
+
function getNested(stmt) {
|
|
69
|
+
const s = stmt;
|
|
70
|
+
const out = [];
|
|
71
|
+
if (Array.isArray(s.body))
|
|
72
|
+
out.push(...s.body);
|
|
73
|
+
if (Array.isArray(s.thenBranch))
|
|
74
|
+
out.push(...s.thenBranch);
|
|
75
|
+
if (Array.isArray(s.elseBranch))
|
|
76
|
+
out.push(...s.elseBranch);
|
|
77
|
+
if (Array.isArray(s.tryBlock))
|
|
78
|
+
out.push(...s.tryBlock);
|
|
79
|
+
if (Array.isArray(s.catchBlock))
|
|
80
|
+
out.push(...s.catchBlock);
|
|
81
|
+
if (Array.isArray(s.finallyBlock))
|
|
82
|
+
out.push(...s.finallyBlock);
|
|
83
|
+
if (Array.isArray(s.cases)) {
|
|
84
|
+
for (const c of s.cases) {
|
|
85
|
+
if (Array.isArray(c.body))
|
|
86
|
+
out.push(...c.body);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// for-loop initializer/increment are statements too.
|
|
90
|
+
if (s.initializer && typeof s.initializer === 'object' && s.initializer.kind)
|
|
91
|
+
out.push(s.initializer);
|
|
92
|
+
if (s.increment && typeof s.increment === 'object' && s.increment.kind)
|
|
93
|
+
out.push(s.increment);
|
|
94
|
+
return out.length > 0 ? out : null;
|
|
95
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import { Diagnostic } from "../../types.js";
|
|
3
|
+
import { StatementIR, ExpressionIR } from "../../api/index.js";
|
|
4
|
+
export declare const ARRAY_METHODS_REQUIRING_STATIC_ARRAY: Set<string>;
|
|
5
|
+
export declare function prescanArrayUsage(statement: ts.Statement): void;
|
|
6
|
+
export declare function prescanExprForArrayMethods(expr: ts.Expression): void;
|
|
7
|
+
export declare function buildInlineForLoop(span: any, srcSize: number, srcName: string, paramName: string, bodyExpr: ts.Expression, sourceText: string, diagnostics: Diagnostic[], assignTarget: string, _isFilter: boolean): StatementIR;
|
|
8
|
+
export declare function tryLowerArrayAndStringMethods(expr: ts.CallExpression, sourceText: string, diagnostics: Diagnostic[], pointerVars: any): ExpressionIR | null;
|