@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,153 @@
|
|
|
1
|
+
import { findBoardPinByName, formatPinReference, getBoardPins } from './board-pin-utils.js';
|
|
2
|
+
/**
|
|
3
|
+
* Unified hardware resource conflict analysis.
|
|
4
|
+
* Detects:
|
|
5
|
+
* 1. Pin Multiplexing Conflicts: Same pin used for GPIO and a Peripheral (I2C, SPI, UART).
|
|
6
|
+
* 2. Peripheral Instance Conflicts: Multiple peripherals sharing the same pins.
|
|
7
|
+
* 3. Board-Specific Hardware Warnings: Logic for specific pins (e.g. "Pin 13 has a built-in LED").
|
|
8
|
+
*/
|
|
9
|
+
export function analyzeResources(program, strategy) {
|
|
10
|
+
const diagnostics = [];
|
|
11
|
+
const usage = program.peripheralUsage;
|
|
12
|
+
const board = program.boardConstants;
|
|
13
|
+
if (!usage || !board)
|
|
14
|
+
return diagnostics;
|
|
15
|
+
// 1. Build Peripheral Pin Map from board definitions
|
|
16
|
+
const pinMap = buildPeripheralPinMap(board);
|
|
17
|
+
// 2. Track reported conflicts to avoid noise
|
|
18
|
+
const reported = new Set();
|
|
19
|
+
// 3. Check for GPIO vs Peripheral conflicts
|
|
20
|
+
for (const [pinName, functions] of pinMap) {
|
|
21
|
+
const boardPin = findBoardPinByName(pinName, board);
|
|
22
|
+
const pinNumber = boardPin?.number;
|
|
23
|
+
// Check if pin is used as GPIO
|
|
24
|
+
const isGpio = isPinUsedAsGpio(pinName, pinNumber, usage);
|
|
25
|
+
for (const func of functions) {
|
|
26
|
+
const isActive = isPeripheralActive(func.type, func.instance, usage);
|
|
27
|
+
if (isActive && isGpio && func.role !== 'cs') {
|
|
28
|
+
const peripheralName = getPeripheralName(func.type, func.instance);
|
|
29
|
+
const conflictKey = `gpio:${pinName}:${peripheralName}`;
|
|
30
|
+
if (!reported.has(conflictKey)) {
|
|
31
|
+
reported.add(conflictKey);
|
|
32
|
+
const pinRef = formatPinReference(pinName, boardPin);
|
|
33
|
+
const suggestion = generateActionableSuggestion(pinName, peripheralName, func.role, board);
|
|
34
|
+
diagnostics.push({
|
|
35
|
+
severity: 'warning',
|
|
36
|
+
message: `${pinRef} is configured as ${peripheralName} ${func.role.toUpperCase()}. Using it as GPIO may interfere with communication.\n → ${suggestion}`,
|
|
37
|
+
code: 'peripheral-pin-conflict',
|
|
38
|
+
source: 'resource-analysis',
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// 4. Check for Peripheral vs Peripheral conflicts (e.g. I2C0 and SPI0 sharing pins - rare but possible on some boards)
|
|
45
|
+
// This is partially covered by the board-definition logic, but we can detect it here if two active
|
|
46
|
+
// peripherals use the same canonical pin name.
|
|
47
|
+
const activePinsToPeripheral = new Map();
|
|
48
|
+
for (const [pinName, functions] of pinMap) {
|
|
49
|
+
for (const func of functions) {
|
|
50
|
+
if (isPeripheralActive(func.type, func.instance, usage)) {
|
|
51
|
+
const peripheralName = getPeripheralName(func.type, func.instance);
|
|
52
|
+
if (activePinsToPeripheral.has(pinName) && activePinsToPeripheral.get(pinName) !== peripheralName) {
|
|
53
|
+
const other = activePinsToPeripheral.get(pinName);
|
|
54
|
+
const conflictKey = `ppp:${pinName}:${peripheralName}:${other}`;
|
|
55
|
+
if (!reported.has(conflictKey)) {
|
|
56
|
+
reported.add(conflictKey);
|
|
57
|
+
diagnostics.push({
|
|
58
|
+
severity: 'error',
|
|
59
|
+
message: `Hardware Conflict: Pin '${pinName}' is required by both ${peripheralName} and ${other}.`,
|
|
60
|
+
hint: `Move one of the peripherals to different pins if your board supports remapping, or avoid using both simultaneously.`,
|
|
61
|
+
code: 'peripheral-peripheral-conflict',
|
|
62
|
+
source: 'resource-analysis',
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
activePinsToPeripheral.set(pinName, peripheralName);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return diagnostics;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Build a peripheral pin map from board constants.
|
|
74
|
+
*/
|
|
75
|
+
function buildPeripheralPinMap(boardConstants) {
|
|
76
|
+
const map = new Map();
|
|
77
|
+
const boardPins = getBoardPins(boardConstants);
|
|
78
|
+
const pinsByCanonicalName = new Map(boardPins.map(pin => [pin.name, pin]));
|
|
79
|
+
function addPin(pinName, func) {
|
|
80
|
+
const boardPin = pinsByCanonicalName.get(pinName);
|
|
81
|
+
const pinNames = boardPin ? [boardPin.name, ...boardPin.aliases] : [pinName];
|
|
82
|
+
for (const resolvedPinName of pinNames) {
|
|
83
|
+
const existing = map.get(resolvedPinName) ?? [];
|
|
84
|
+
existing.push(func);
|
|
85
|
+
map.set(resolvedPinName, existing);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Helper to parse "0:sda=A4,scl=A5;1:sda=...,scl=..."
|
|
89
|
+
const parseBusData = (data, type) => {
|
|
90
|
+
if (typeof data !== 'string' || data.length === 0)
|
|
91
|
+
return;
|
|
92
|
+
for (const busStr of data.split(';')) {
|
|
93
|
+
const colonIdx = busStr.indexOf(':');
|
|
94
|
+
if (colonIdx === -1)
|
|
95
|
+
continue;
|
|
96
|
+
const instance = parseInt(busStr.slice(0, colonIdx), 10);
|
|
97
|
+
const pinsStr = busStr.slice(colonIdx + 1);
|
|
98
|
+
for (const pair of pinsStr.split(',')) {
|
|
99
|
+
const eqIdx = pair.indexOf('=');
|
|
100
|
+
if (eqIdx === -1)
|
|
101
|
+
continue;
|
|
102
|
+
const role = pair.slice(0, eqIdx).trim();
|
|
103
|
+
const pinName = pair.slice(eqIdx + 1).trim();
|
|
104
|
+
if (pinName)
|
|
105
|
+
addPin(pinName, { type, instance, role });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
parseBusData(boardConstants.get('pins.i2c'), 'i2c');
|
|
110
|
+
parseBusData(boardConstants.get('pins.spi'), 'spi');
|
|
111
|
+
parseBusData(boardConstants.get('pins.uart'), 'uart');
|
|
112
|
+
return map;
|
|
113
|
+
}
|
|
114
|
+
function isPinUsedAsGpio(pinName, pinNumber, usage) {
|
|
115
|
+
if (usage.pinsUsed.has(pinName))
|
|
116
|
+
return true;
|
|
117
|
+
if (pinNumber !== undefined) {
|
|
118
|
+
if (usage.outputPins.has(pinNumber) || usage.inputPins.has(pinNumber) ||
|
|
119
|
+
usage.inputPullupPins.has(pinNumber) || usage.inputPulldownPins.has(pinNumber)) {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
function isPeripheralActive(type, instance, usage) {
|
|
126
|
+
switch (type) {
|
|
127
|
+
case 'i2c': return usage.i2c || usage.i2cInstancesUsed.has(instance);
|
|
128
|
+
case 'spi': return usage.spi || usage.spiInstancesUsed.has(instance);
|
|
129
|
+
case 'uart': return usage.uart || usage.uartInstancesUsed.has(instance);
|
|
130
|
+
default: return false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function getPeripheralName(type, instance) {
|
|
134
|
+
switch (type) {
|
|
135
|
+
case 'i2c': return `I2C${instance}`;
|
|
136
|
+
case 'spi': return `SPI${instance}`;
|
|
137
|
+
case 'uart': return instance === 0 ? 'Serial' : `Serial${instance}`;
|
|
138
|
+
default: return 'Peripheral';
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function generateActionableSuggestion(pinName, peripheralName, role, board) {
|
|
142
|
+
const roleUpper = role.toUpperCase();
|
|
143
|
+
if (peripheralName.startsWith('Serial')) {
|
|
144
|
+
return `Consider using a different pin for GPIO, or avoid calling ${peripheralName}.begin() if you need ${pinName} as GPIO.`;
|
|
145
|
+
}
|
|
146
|
+
if (roleUpper === 'SDA' || roleUpper === 'SCL') {
|
|
147
|
+
return `I2C requires ${roleUpper} on ${pinName}. Avoid using this pin for GPIO while I2C is active.`;
|
|
148
|
+
}
|
|
149
|
+
if (roleUpper === 'MOSI' || roleUpper === 'MISO' || roleUpper === 'SCK') {
|
|
150
|
+
return `SPI requires ${roleUpper} on ${pinName}. Use a different pin for GPIO, or avoid calling SPI.begin().`;
|
|
151
|
+
}
|
|
152
|
+
return `Avoid initializing ${peripheralName} if you need ${pinName} as GPIO.`;
|
|
153
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import { Diagnostic } from "../types.js";
|
|
3
|
+
import { StatementIR } from "../api/index.js";
|
|
4
|
+
import { CppTypeHint } from "./type-resolution.js";
|
|
5
|
+
import { PointerTracker } from "./build-ir-state.js";
|
|
6
|
+
import { forInitializerToIR, incrementorToIR, lowerControlFlowStatement } from "./transformers/control-flow.js";
|
|
7
|
+
export { forInitializerToIR, incrementorToIR, lowerControlFlowStatement };
|
|
8
|
+
import { tryResolveHALMethod, resolveHALCallForVarInit, tryResolveHALExpression } from "./transformers/hal-call-resolver.js";
|
|
9
|
+
export { tryResolveHALMethod, resolveHALCallForVarInit, tryResolveHALExpression };
|
|
10
|
+
import { prescanArrayUsage, buildInlineForLoop } from "./transformers/array-methods.js";
|
|
11
|
+
export { prescanArrayUsage, buildInlineForLoop };
|
|
12
|
+
import { callToStatement } from "./transformers/call-statement.js";
|
|
13
|
+
export { callToStatement };
|
|
14
|
+
import { assignmentOperatorToString, updateLocalTypeFromAssignment, extractForInKeys, variableStatementToIR, collectPointerVars } from "./transformers/variables.js";
|
|
15
|
+
export { assignmentOperatorToString, updateLocalTypeFromAssignment, extractForInKeys, variableStatementToIR, collectPointerVars };
|
|
16
|
+
export declare function expressionStatementToIR(statement: ts.ExpressionStatement, fileName: string, sourceText: string, diagnostics: Diagnostic[], functionReturnTypes: Map<string, CppTypeHint>, localVariableTypes: Map<string, CppTypeHint>, pointerVars?: PointerTracker): StatementIR | undefined;
|
|
17
|
+
export declare function lowerStatement(statement: ts.Statement, fileName: string, sourceText: string, diagnostics: Diagnostic[], functionReturnTypes: Map<string, CppTypeHint>, localVariableTypes: Map<string, CppTypeHint>, functionNameForDiagnostics: string, typeAliases?: Map<string, ts.TypeNode>, pointerVars?: PointerTracker): StatementIR[] | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Hoist a nested function declaration to file scope.
|
|
20
|
+
* Creates a mangled name (parent__inner) and registers it in the alias map
|
|
21
|
+
* so that call sites within the parent function get rewritten.
|
|
22
|
+
*/
|
|
23
|
+
export declare function lowerStatementList(statements: readonly ts.Statement[] | ts.NodeArray<ts.Statement>, fileName: string, sourceText: string, diagnostics: Diagnostic[], functionReturnTypes: Map<string, CppTypeHint>, localVariableTypes: Map<string, CppTypeHint>, functionNameForDiagnostics: string, typeAliases?: Map<string, ts.TypeNode>, pointerVars?: PointerTracker): StatementIR[];
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import { isStringEnum } from "../api/shared/index.js";
|
|
3
|
+
import { extractNodeComments, makeDiagnostic, makeSourceSpan } from "./ast-node-utils.js";
|
|
4
|
+
import { isCompileTimeOnlyCallName, isCompileTimeOnlyClassName } from "./compile-time-only.js";
|
|
5
|
+
import { TYPED_ARRAY_ELEMENT_MAP, hoistedNestedEnums, hoistedNestedInterfaces, hoistedNestedTypeAliases, nestedFunctionAliases, nestedClassAliases, mutableArrayVars, arrayLiteralSizes, activeEnumNames, activeStringEnumNames, resetFunctionScopeState } from "./build-ir-state.js";
|
|
6
|
+
import { getCurrentIrTypeScope, bindIrTypeScopeLocals } from "./symbol-types.js";
|
|
7
|
+
import { renderExprAsText } from "./render-expr.js";
|
|
8
|
+
import { expressionToIR } from "./expression-to-ir.js";
|
|
9
|
+
import { enumDeclarationToIR, interfaceDeclarationToIR, typeAliasDeclarationToIR } from "./declaration-builders.js";
|
|
10
|
+
import { forInitializerToIR, incrementorToIR, lowerControlFlowStatement } from "./transformers/control-flow.js";
|
|
11
|
+
export { forInitializerToIR, incrementorToIR, lowerControlFlowStatement };
|
|
12
|
+
import { expressionStatementToIR as delegateExpressionStatementToIR } from "./transformers/expressions.js";
|
|
13
|
+
import { tryResolveHALMethod, resolveHALCallForVarInit, tryResolveHALExpression } from "./transformers/hal-call-resolver.js";
|
|
14
|
+
import { resolveElementValue } from "./transformers/ui-call-resolver.js";
|
|
15
|
+
export { tryResolveHALMethod, resolveHALCallForVarInit, tryResolveHALExpression };
|
|
16
|
+
import { hoistNestedFunction, hoistNestedClass } from "./function-builder.js";
|
|
17
|
+
import { prescanArrayUsage, buildInlineForLoop } from "./transformers/array-methods.js";
|
|
18
|
+
export { prescanArrayUsage, buildInlineForLoop };
|
|
19
|
+
import { callToStatement } from "./transformers/call-statement.js";
|
|
20
|
+
export { callToStatement };
|
|
21
|
+
import { assignmentOperatorToString, updateLocalTypeFromAssignment, extractForInKeys, variableStatementToIR, collectPointerVars } from "./transformers/variables.js";
|
|
22
|
+
export { assignmentOperatorToString, updateLocalTypeFromAssignment, extractForInKeys, variableStatementToIR, collectPointerVars };
|
|
23
|
+
export function expressionStatementToIR(statement, fileName, sourceText, diagnostics, functionReturnTypes, localVariableTypes, pointerVars = new Map()) {
|
|
24
|
+
return delegateExpressionStatementToIR(statement, fileName, sourceText, diagnostics, functionReturnTypes, localVariableTypes, pointerVars);
|
|
25
|
+
}
|
|
26
|
+
export function lowerStatement(statement, fileName, sourceText, diagnostics, functionReturnTypes, localVariableTypes, functionNameForDiagnostics, typeAliases, pointerVars = new Map()) {
|
|
27
|
+
if (ts.isExpressionStatement(statement)) {
|
|
28
|
+
// Handle arr.forEach(arrowFn) as a standalone statement → inline loop
|
|
29
|
+
if (ts.isCallExpression(statement.expression) &&
|
|
30
|
+
ts.isPropertyAccessExpression(statement.expression.expression) &&
|
|
31
|
+
statement.expression.expression.name.text === "forEach" &&
|
|
32
|
+
ts.isIdentifier(statement.expression.expression.expression)) {
|
|
33
|
+
const srcName = statement.expression.expression.expression.text;
|
|
34
|
+
const srcSize = arrayLiteralSizes.get(srcName);
|
|
35
|
+
const arrowFn = statement.expression.arguments[0];
|
|
36
|
+
if (srcSize !== undefined && arrowFn && (ts.isArrowFunction(arrowFn) || ts.isFunctionExpression(arrowFn))) {
|
|
37
|
+
const param = arrowFn.parameters[0];
|
|
38
|
+
const paramName = param && ts.isIdentifier(param.name) ? param.name.text : "__x";
|
|
39
|
+
const span = makeSourceSpan(statement, fileName, sourceText);
|
|
40
|
+
const comments = extractNodeComments(statement, sourceText);
|
|
41
|
+
if (!ts.isBlock(arrowFn.body)) {
|
|
42
|
+
// Expression body
|
|
43
|
+
const bodyIR = expressionToIR(arrowFn.body, sourceText, diagnostics);
|
|
44
|
+
return [{
|
|
45
|
+
kind: "for",
|
|
46
|
+
sourceSpan: span,
|
|
47
|
+
leadingComments: comments.leadingComments,
|
|
48
|
+
trailingComments: comments.trailingComments,
|
|
49
|
+
initializer: { kind: "var_decl", sourceSpan: span, name: "__tc_i", storage: "let", cppType: "int", initializer: { kind: "number", value: 0 } },
|
|
50
|
+
condition: { kind: "binary", left: { kind: "identifier", value: "__tc_i" }, operator: "<", right: { kind: "number", value: srcSize } },
|
|
51
|
+
increment: { kind: "update", sourceSpan: span, target: "__tc_i", operator: "++", prefix: false },
|
|
52
|
+
body: [
|
|
53
|
+
{ kind: "var_decl", sourceSpan: span, name: paramName, storage: "const", cppType: "auto",
|
|
54
|
+
initializer: { kind: "raw", value: `${srcName}[__tc_i]` } },
|
|
55
|
+
{ kind: "var_decl", sourceSpan: span, name: "__tc_result", storage: "let", cppType: "auto", initializer: bodyIR },
|
|
56
|
+
],
|
|
57
|
+
}];
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
// Block body — lower statements and prepend param decl
|
|
61
|
+
const blockStatements = lowerStatementList(arrowFn.body.statements, fileName, sourceText, diagnostics, functionReturnTypes, localVariableTypes, functionNameForDiagnostics, typeAliases, pointerVars);
|
|
62
|
+
return [{
|
|
63
|
+
kind: "for",
|
|
64
|
+
sourceSpan: span,
|
|
65
|
+
leadingComments: comments.leadingComments,
|
|
66
|
+
trailingComments: comments.trailingComments,
|
|
67
|
+
initializer: { kind: "var_decl", sourceSpan: span, name: "__tc_i", storage: "let", cppType: "int", initializer: { kind: "number", value: 0 } },
|
|
68
|
+
condition: { kind: "binary", left: { kind: "identifier", value: "__tc_i" }, operator: "<", right: { kind: "number", value: srcSize } },
|
|
69
|
+
increment: { kind: "update", sourceSpan: span, target: "__tc_i", operator: "++", prefix: false },
|
|
70
|
+
body: [
|
|
71
|
+
{ kind: "var_decl", sourceSpan: span, name: paramName, storage: "const", cppType: "auto",
|
|
72
|
+
initializer: { kind: "raw", value: `${srcName}[__tc_i]` } },
|
|
73
|
+
...blockStatements,
|
|
74
|
+
],
|
|
75
|
+
}];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Check for compile-time-only calls first (e.g., registerPlatformStrategy())
|
|
80
|
+
// These are registration calls that don't need C++ emission
|
|
81
|
+
if (ts.isCallExpression(statement.expression)) {
|
|
82
|
+
const call = statement.expression;
|
|
83
|
+
if (ts.isIdentifier(call.expression)) {
|
|
84
|
+
const calleeName = call.expression.text;
|
|
85
|
+
if (isCompileTimeOnlyCallName(calleeName)) {
|
|
86
|
+
return []; // Skip silently - no C++ emission needed
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Also check for method calls like "something.register()" that are compile-time only
|
|
90
|
+
if (ts.isPropertyAccessExpression(call.expression)) {
|
|
91
|
+
const method = call.expression.name.text;
|
|
92
|
+
if (isCompileTimeOnlyCallName(method)) {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Check for new expressions that are compile-time only (e.g., new NativeStrategy())
|
|
98
|
+
if (ts.isNewExpression(statement.expression)) {
|
|
99
|
+
// New expressions at top level in board packages are typically compile-time only
|
|
100
|
+
// Check if it's a known strategy type
|
|
101
|
+
if (ts.isIdentifier(statement.expression.expression)) {
|
|
102
|
+
const className = statement.expression.expression.text;
|
|
103
|
+
if (isCompileTimeOnlyClassName(className)) {
|
|
104
|
+
return []; // Skip silently
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// ── UI element .value write: screen.led.value = 1 ────────────────────
|
|
109
|
+
// Lowers to __ui_nodes[N].value = X; ui_mark_dirty(N);
|
|
110
|
+
if (ts.isBinaryExpression(statement.expression) &&
|
|
111
|
+
statement.expression.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
|
|
112
|
+
ts.isPropertyAccessExpression(statement.expression.left) &&
|
|
113
|
+
statement.expression.left.name.text === "value" &&
|
|
114
|
+
ts.isPropertyAccessExpression(statement.expression.left.expression) &&
|
|
115
|
+
ts.isIdentifier(statement.expression.left.expression.expression)) {
|
|
116
|
+
const treeName = statement.expression.left.expression.expression.text;
|
|
117
|
+
const elemId = statement.expression.left.expression.name.text;
|
|
118
|
+
const nodeIdx = resolveElementValue(treeName, elemId);
|
|
119
|
+
if (nodeIdx !== undefined) {
|
|
120
|
+
const valIR = expressionToIR(statement.expression.right, sourceText, diagnostics, pointerVars);
|
|
121
|
+
const valText = renderExprAsText(valIR);
|
|
122
|
+
return [{
|
|
123
|
+
kind: "call",
|
|
124
|
+
sourceSpan: makeSourceSpan(statement, fileName, sourceText),
|
|
125
|
+
callee: `__RAW_STMT____ui_nodes[${nodeIdx}].value = ${valText}; ui_mark_dirty(${nodeIdx});`,
|
|
126
|
+
args: [],
|
|
127
|
+
}];
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// ── UI element .text write: screen.ssid.text = "x" ──────────────────
|
|
131
|
+
// Lowers to strncpy(__ui_nodes[N].textBuffer, "x", UI_TEXT_BUF);
|
|
132
|
+
// __ui_nodes[N].textBuffer[UI_TEXT_BUF] = 0; ui_mark_dirty(N);
|
|
133
|
+
if (ts.isBinaryExpression(statement.expression) &&
|
|
134
|
+
statement.expression.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
|
|
135
|
+
ts.isPropertyAccessExpression(statement.expression.left) &&
|
|
136
|
+
statement.expression.left.name.text === "text" &&
|
|
137
|
+
ts.isPropertyAccessExpression(statement.expression.left.expression) &&
|
|
138
|
+
ts.isIdentifier(statement.expression.left.expression.expression)) {
|
|
139
|
+
const treeName = statement.expression.left.expression.expression.text;
|
|
140
|
+
const elemId = statement.expression.left.expression.name.text;
|
|
141
|
+
const nodeIdx = resolveElementValue(treeName, elemId);
|
|
142
|
+
if (nodeIdx !== undefined) {
|
|
143
|
+
const valIR = expressionToIR(statement.expression.right, sourceText, diagnostics, pointerVars);
|
|
144
|
+
const valText = renderExprAsText(valIR);
|
|
145
|
+
return [{
|
|
146
|
+
kind: "call",
|
|
147
|
+
sourceSpan: makeSourceSpan(statement, fileName, sourceText),
|
|
148
|
+
callee: `__RAW_STMT__strncpy(__ui_nodes[${nodeIdx}].textBuffer, ${valText}, UI_TEXT_BUF); __ui_nodes[${nodeIdx}].textBuffer[UI_TEXT_BUF] = 0; ui_mark_dirty(${nodeIdx});`,
|
|
149
|
+
args: [],
|
|
150
|
+
}];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const loweredExpression = expressionStatementToIR(statement, fileName, sourceText, diagnostics, functionReturnTypes, localVariableTypes, pointerVars);
|
|
154
|
+
return loweredExpression ? [loweredExpression] : undefined;
|
|
155
|
+
}
|
|
156
|
+
if (ts.isVariableStatement(statement)) {
|
|
157
|
+
return variableStatementToIR(statement, fileName, sourceText, diagnostics, functionReturnTypes, localVariableTypes, typeAliases, pointerVars, functionNameForDiagnostics, lowerStatementList);
|
|
158
|
+
}
|
|
159
|
+
const controlFlowLowered = lowerControlFlowStatement(statement, fileName, sourceText, diagnostics, functionReturnTypes, localVariableTypes, functionNameForDiagnostics, typeAliases, pointerVars);
|
|
160
|
+
if (controlFlowLowered !== null) {
|
|
161
|
+
return controlFlowLowered;
|
|
162
|
+
}
|
|
163
|
+
diagnostics.push(makeDiagnostic(sourceText, statement.pos, `Unsupported statement in function '${functionNameForDiagnostics}'.`, "error", "TS2CPP_UNSUPPORTED_STMT"));
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Hoist a nested function declaration to file scope.
|
|
168
|
+
* Creates a mangled name (parent__inner) and registers it in the alias map
|
|
169
|
+
* so that call sites within the parent function get rewritten.
|
|
170
|
+
*/
|
|
171
|
+
// ---------------------------------------------------------------------------
|
|
172
|
+
// Array method pre-scan
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
// Methods that require StaticArray promotion (not all are mutating — indexOf is read-only
|
|
175
|
+
// but needs StaticArray since C arrays don't have an indexOf method).
|
|
176
|
+
export function lowerStatementList(statements, fileName, sourceText, diagnostics, functionReturnTypes, localVariableTypes, functionNameForDiagnostics, typeAliases, pointerVars = new Map()) {
|
|
177
|
+
const lowered = [];
|
|
178
|
+
const nestedNames = [];
|
|
179
|
+
const nestedClassNames = [];
|
|
180
|
+
// Phase 1: Pre-scan for nested function declarations — register aliases only.
|
|
181
|
+
// This ensures sibling functions can reference each other.
|
|
182
|
+
for (const statement of statements) {
|
|
183
|
+
if (ts.isFunctionDeclaration(statement) && statement.name) {
|
|
184
|
+
const originalName = statement.name.text;
|
|
185
|
+
const safeParentName = functionNameForDiagnostics.replace(/\./g, "_");
|
|
186
|
+
const mangledName = `${safeParentName}__${originalName}`;
|
|
187
|
+
nestedFunctionAliases.set(originalName, mangledName);
|
|
188
|
+
nestedNames.push(originalName);
|
|
189
|
+
}
|
|
190
|
+
if (ts.isClassDeclaration(statement) && statement.name) {
|
|
191
|
+
const originalName = statement.name.text;
|
|
192
|
+
const safeParentName = functionNameForDiagnostics.replace(/\./g, "_");
|
|
193
|
+
if (safeParentName) {
|
|
194
|
+
const mangledName = `${safeParentName}__${originalName}`;
|
|
195
|
+
nestedClassAliases.set(originalName, mangledName);
|
|
196
|
+
nestedClassNames.push(originalName);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// Phase 1.5: Collect local type aliases into the shared map so that
|
|
201
|
+
// nested function return types can resolve generic mapped types etc.
|
|
202
|
+
if (typeAliases) {
|
|
203
|
+
for (const statement of statements) {
|
|
204
|
+
if (ts.isTypeAliasDeclaration(statement)) {
|
|
205
|
+
typeAliases.set(statement.name.text, statement.type);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
// Phase 1.6: Pre-scan for enum declarations (top-level within this scope and
|
|
210
|
+
// nested inside functions) so that string-concat chain detection during
|
|
211
|
+
// lowering knows which enum-typed variables are string-bearing (string enums
|
|
212
|
+
// lower to const char*). Must run BEFORE hoisting/lowers.
|
|
213
|
+
for (const statement of statements) {
|
|
214
|
+
const collectEnums = (node) => {
|
|
215
|
+
if (ts.isEnumDeclaration(node) && node.name) {
|
|
216
|
+
activeEnumNames.add(node.name.text);
|
|
217
|
+
// Determine string-enum-ness from the declaration.
|
|
218
|
+
let allString = true;
|
|
219
|
+
let any = false;
|
|
220
|
+
for (const member of node.members) {
|
|
221
|
+
if (member.initializer && ts.isStringLiteral(member.initializer)) {
|
|
222
|
+
any = true;
|
|
223
|
+
}
|
|
224
|
+
else if (member.initializer && !ts.isStringLiteral(member.initializer)) {
|
|
225
|
+
allString = false;
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
allString = false;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (any && allString) {
|
|
232
|
+
activeStringEnumNames.add(node.name.text);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
collectEnums(statement);
|
|
237
|
+
ts.forEachChild(statement, collectEnums);
|
|
238
|
+
}
|
|
239
|
+
// Phase 2: Hoist nested functions (process their bodies).
|
|
240
|
+
for (const statement of statements) {
|
|
241
|
+
if (ts.isFunctionDeclaration(statement) && statement.name) {
|
|
242
|
+
hoistNestedFunction(statement, fileName, sourceText, diagnostics, functionReturnTypes, functionNameForDiagnostics, typeAliases, pointerVars, lowerStatementList);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
// Phase 2.5: Hoist nested class declarations.
|
|
246
|
+
for (const statement of statements) {
|
|
247
|
+
if (ts.isClassDeclaration(statement) && statement.name) {
|
|
248
|
+
hoistNestedClass(statement, fileName, sourceText, diagnostics, functionReturnTypes, functionNameForDiagnostics, typeAliases, pointerVars, lowerStatementList);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
// Phase 2.6: Hoist nested enum declarations.
|
|
252
|
+
for (const statement of statements) {
|
|
253
|
+
if (ts.isEnumDeclaration(statement)) {
|
|
254
|
+
const enumIR = enumDeclarationToIR(statement, fileName, sourceText);
|
|
255
|
+
if (enumIR && !hoistedNestedEnums.some(e => e.name === enumIR.name)) {
|
|
256
|
+
hoistedNestedEnums.push(enumIR);
|
|
257
|
+
// Register string-enum-ness so concat-chain detection (expression-to-ir)
|
|
258
|
+
// recognizes variables of this type as string-bearing.
|
|
259
|
+
if (isStringEnum(enumIR)) {
|
|
260
|
+
activeStringEnumNames.add(enumIR.name);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
// Phase 2.6b: Hoist local interface and type alias declarations.
|
|
266
|
+
// These are type-only but needed for C++ struct generation when used as return types.
|
|
267
|
+
const scopeName = functionNameForDiagnostics
|
|
268
|
+
? `${functionNameForDiagnostics.replace(/\./g, "_")}__types`
|
|
269
|
+
: undefined;
|
|
270
|
+
for (const statement of statements) {
|
|
271
|
+
if (ts.isInterfaceDeclaration(statement) && statement.name) {
|
|
272
|
+
const ifaceIR = interfaceDeclarationToIR(statement, fileName, sourceText, typeAliases ?? new Map());
|
|
273
|
+
if (ifaceIR && !hoistedNestedInterfaces.some(i => i.name === ifaceIR.name)) {
|
|
274
|
+
if (scopeName)
|
|
275
|
+
ifaceIR.parentScope = scopeName;
|
|
276
|
+
hoistedNestedInterfaces.push(ifaceIR);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (ts.isTypeAliasDeclaration(statement)) {
|
|
280
|
+
const aliasIR = typeAliasDeclarationToIR(statement, fileName, sourceText, typeAliases ?? new Map());
|
|
281
|
+
if (aliasIR && !hoistedNestedTypeAliases.some(a => a.name === aliasIR.name)) {
|
|
282
|
+
hoistedNestedTypeAliases.push(aliasIR);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
// Collect pointer variables from this scope (vars initialized with 'new')
|
|
287
|
+
const scopePointerVars = new Map();
|
|
288
|
+
for (const statement of statements) {
|
|
289
|
+
if (ts.isVariableStatement(statement)) {
|
|
290
|
+
for (const decl of statement.declarationList.declarations) {
|
|
291
|
+
if (ts.isIdentifier(decl.name) && decl.initializer && ts.isNewExpression(decl.initializer)) {
|
|
292
|
+
const ctorText = decl.initializer.expression && ts.isIdentifier(decl.initializer.expression)
|
|
293
|
+
? decl.initializer.expression.text : "";
|
|
294
|
+
if (!TYPED_ARRAY_ELEMENT_MAP[ctorText]) {
|
|
295
|
+
scopePointerVars.set(decl.name.text, ctorText);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// Phase 2.7: Pre-scan for array methods requiring StaticArray promotion.
|
|
302
|
+
// Clear function-scoped state so variables from previous functions don't leak,
|
|
303
|
+
// but preserve file-level mutable array tracking (populated by build-ir.ts pre-scan).
|
|
304
|
+
const savedMutableArrayVars = new Set(mutableArrayVars);
|
|
305
|
+
const savedArrayLiteralSizes = new Map(arrayLiteralSizes);
|
|
306
|
+
resetFunctionScopeState();
|
|
307
|
+
for (const v of savedMutableArrayVars)
|
|
308
|
+
mutableArrayVars.add(v);
|
|
309
|
+
for (const [k, v] of savedArrayLiteralSizes)
|
|
310
|
+
arrayLiteralSizes.set(k, v);
|
|
311
|
+
// resetFunctionScopeState re-seeded scope.locals from classFields. Now bind
|
|
312
|
+
// the threaded localVariableTypes map as the scope's locals storage (folding
|
|
313
|
+
// both the re-seeded classFields entries and any entries the threaded map
|
|
314
|
+
// already carried, e.g. function parameters). After this, the threaded
|
|
315
|
+
// `localVariableTypes` param and getCurrentIrTypeScope().locals are the SAME
|
|
316
|
+
// Map, so writes through either are visible to both — eliminating the old
|
|
317
|
+
// shadow-sync that copied localVariableTypes into the global activeLocalTypes.
|
|
318
|
+
const scope = getCurrentIrTypeScope();
|
|
319
|
+
if (scope) {
|
|
320
|
+
bindIrTypeScopeLocals(scope, localVariableTypes);
|
|
321
|
+
}
|
|
322
|
+
for (const statement of statements) {
|
|
323
|
+
prescanArrayUsage(statement);
|
|
324
|
+
}
|
|
325
|
+
// Phase 3: Process remaining (non-function, non-class) statements.
|
|
326
|
+
for (const statement of statements) {
|
|
327
|
+
if (ts.isFunctionDeclaration(statement)) {
|
|
328
|
+
continue; // Already hoisted
|
|
329
|
+
}
|
|
330
|
+
if (ts.isClassDeclaration(statement)) {
|
|
331
|
+
continue; // Already hoisted
|
|
332
|
+
}
|
|
333
|
+
if (ts.isEnumDeclaration(statement)) {
|
|
334
|
+
continue; // Already hoisted
|
|
335
|
+
}
|
|
336
|
+
const result = lowerStatement(statement, fileName, sourceText, diagnostics, functionReturnTypes, localVariableTypes, functionNameForDiagnostics, typeAliases, scopePointerVars);
|
|
337
|
+
if (result) {
|
|
338
|
+
lowered.push(...result);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
// Phase 4: Clean up aliases so they don't leak to sibling scopes.
|
|
342
|
+
for (const name of nestedNames) {
|
|
343
|
+
nestedFunctionAliases.delete(name);
|
|
344
|
+
}
|
|
345
|
+
for (const name of nestedClassNames) {
|
|
346
|
+
nestedClassAliases.delete(name);
|
|
347
|
+
}
|
|
348
|
+
return lowered;
|
|
349
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { ProgramIR } from "../api/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Per-class accessor map: member name → whether it is a getter, setter, or
|
|
4
|
+
* both. Keyed by class name, matching the old allClassAccessors shape.
|
|
5
|
+
*/
|
|
6
|
+
export type ClassAccessors = Map<string, "getter" | "setter" | "both">;
|
|
7
|
+
export interface SymbolTable {
|
|
8
|
+
/** className/interfaceName → fieldName → cppType. Replaces allClassFieldTypes
|
|
9
|
+
* and the per-file interfaceFieldTypes cross-module portion. Includes
|
|
10
|
+
* extendsClass-inherited fields once resolveInheritance runs. */
|
|
11
|
+
classFieldTypes: Map<string, Map<string, string>>;
|
|
12
|
+
/** className → accessor map. Replaces allClassAccessors. */
|
|
13
|
+
classAccessors: Map<string, ClassAccessors>;
|
|
14
|
+
/** function name → return cppType. Replaces allFunctionReturnTypes. */
|
|
15
|
+
functionReturnTypes: Map<string, string>;
|
|
16
|
+
/** top-level variable name → cppType (non-"auto" only). Replaces
|
|
17
|
+
* allVariableTypes. */
|
|
18
|
+
variableTypes: Map<string, string>;
|
|
19
|
+
/** All class names across the aggregated files. Replaces allClassNames. */
|
|
20
|
+
classNames: Set<string>;
|
|
21
|
+
/** className → parent class name (the `extends X` target). Needed by
|
|
22
|
+
* resolveInheritance to copy parent fields into children; not present in
|
|
23
|
+
* the old ad-hoc maps (it was read from programIR.classes in the second
|
|
24
|
+
* pass) so it is retained here to keep inheritance resolvable from the
|
|
25
|
+
* aggregated table alone. */
|
|
26
|
+
extends: Map<string, string>;
|
|
27
|
+
}
|
|
28
|
+
export declare function createSymbolTable(): SymbolTable;
|
|
29
|
+
/**
|
|
30
|
+
* Build a SymbolTable from a single file's ProgramIR. This is the per-file
|
|
31
|
+
* view; cross-file aggregation is done by mergeSymbolTable.
|
|
32
|
+
*
|
|
33
|
+
* Mirrors the old transpile.ts:612-666 first pass:
|
|
34
|
+
* - class fields, interface fields, accessors, function return types, and
|
|
35
|
+
* non-"auto" top-level variable types are collected
|
|
36
|
+
* - extendsClass relationships are recorded for the post-merge inheritance
|
|
37
|
+
* pass (the old code read them from programIR.classes directly)
|
|
38
|
+
* Accessor kind merge rule: getter+setter on the same name → "both".
|
|
39
|
+
*
|
|
40
|
+
* Does NOT fold parent fields into children yet — that happens once, after
|
|
41
|
+
* all files are merged, in resolveInheritance (mirroring the old two-pass
|
|
42
|
+
* structure where the second pass ran after the first pass over all files).
|
|
43
|
+
*/
|
|
44
|
+
export declare function buildSymbolTable(program: ProgramIR): SymbolTable;
|
|
45
|
+
/**
|
|
46
|
+
* Fold one SymbolTable into an accumulating cross-module table. This is the
|
|
47
|
+
* merge used during Pass 1 of transpile.ts to build the cross-file view from
|
|
48
|
+
* every file's per-file table.
|
|
49
|
+
*
|
|
50
|
+
* Field-type and accessor entries are merged (later files add to existing
|
|
51
|
+
* class entries); function return types and variable types are last-write-wins
|
|
52
|
+
* (matching the old Map.set behavior); class names are unioned; extends
|
|
53
|
+
* relationships are last-write-wins.
|
|
54
|
+
*/
|
|
55
|
+
export declare function mergeSymbolTable(target: SymbolTable, source: SymbolTable): SymbolTable;
|
|
56
|
+
/**
|
|
57
|
+
* Apply extendsClass field inheritance across an aggregated SymbolTable.
|
|
58
|
+
* Mirrors the old transpile.ts:668-688 SECOND pass: for each class that
|
|
59
|
+
* extends a parent present in the table, copy any parent fields the child does
|
|
60
|
+
* not already declare. Must run AFTER all files have been merged so cross-file
|
|
61
|
+
* parents are visible.
|
|
62
|
+
*
|
|
63
|
+
* Merge rule (preserved exactly): `!childFields.has(fname)` — a child's own
|
|
64
|
+
* field declaration wins over the parent's. If the child has no field entry at
|
|
65
|
+
* all but the parent does, a fresh entry seeded entirely from the parent is
|
|
66
|
+
* created (mirroring the old `else if (parentFields && !childFields)` branch).
|
|
67
|
+
*/
|
|
68
|
+
export declare function resolveInheritance(table: SymbolTable): void;
|