@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,589 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Combined program analysis - single-pass detection of multiple features.
|
|
3
|
+
*
|
|
4
|
+
* Instead of traversing the IR multiple times for different checks
|
|
5
|
+
* (hasConsoleCalls, hasArrayInObjectLiteral, hasThrowStatements, etc.),
|
|
6
|
+
* this module performs all checks in a single traversal.
|
|
7
|
+
*/
|
|
8
|
+
import { POLYFILL_HELPER_MAP } from "../api/shared/index.js";
|
|
9
|
+
import { parseCppType } from "../api/shared/cpp-type-ir.js";
|
|
10
|
+
import { loweredConsoleInCallback } from "./transformers/ui-callback-lowering.js";
|
|
11
|
+
import { watchPinSpecs, clickHandlers } from "./transformers/ui-call-resolver.js";
|
|
12
|
+
import { canvasBindings } from "./transformers/canvas-lowering.js";
|
|
13
|
+
import { getInputBindings, getListBindings } from "./transformers/ui-reactive.js";
|
|
14
|
+
// Regex for std:: math calls
|
|
15
|
+
const MATH_PATTERN = /\bstd::(floor|ceil|round|trunc|sqrt|pow|sin|cos|tan|asin|acos|atan|abs|max|min)\b/;
|
|
16
|
+
/**
|
|
17
|
+
* Analyze an expression for all features in a single pass.
|
|
18
|
+
*/
|
|
19
|
+
function analyzeExpression(expr, result, strategy) {
|
|
20
|
+
if (!expr || typeof expr !== 'object' || !expr.kind) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
switch (expr.kind) {
|
|
24
|
+
case "raw":
|
|
25
|
+
if (MATH_PATTERN.test(expr.value)) {
|
|
26
|
+
result.hasStdMathCalls = true;
|
|
27
|
+
}
|
|
28
|
+
for (const [pattern, helperNames] of Object.entries(POLYFILL_HELPER_MAP)) {
|
|
29
|
+
if (expr.value.includes(pattern)) {
|
|
30
|
+
for (const name of helperNames) {
|
|
31
|
+
result.usedPolyfillHelpers.add(name);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// Also check for already-lowered __tc_ names
|
|
35
|
+
for (const name of helperNames) {
|
|
36
|
+
if (expr.value.includes(name)) {
|
|
37
|
+
result.usedPolyfillHelpers.add(name);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (/\bString\s*\(/.test(expr.value)) {
|
|
42
|
+
result.usesStringConversion = true;
|
|
43
|
+
}
|
|
44
|
+
if (/Date\.now\s*\(/.test(expr.value) || /Date::now\s*\(/.test(expr.value)) {
|
|
45
|
+
result.usesDateNow = true;
|
|
46
|
+
}
|
|
47
|
+
if (/\bmillis\s*\(/.test(expr.value)) {
|
|
48
|
+
result.usesMillis = true;
|
|
49
|
+
}
|
|
50
|
+
if (expr.value.includes('cuttlefish_nullish(') || expr.value.includes('cuttlefish_exists(') || expr.value.includes('cuttlefish_is_nullish(')) {
|
|
51
|
+
result.usesNullish = true;
|
|
52
|
+
result.usesNullishHelper = true;
|
|
53
|
+
}
|
|
54
|
+
if (/\bNum\b/.test(expr.value)) {
|
|
55
|
+
result.usesNum = true;
|
|
56
|
+
}
|
|
57
|
+
if (/\bTiming\b/.test(expr.value)) {
|
|
58
|
+
result.usesTiming = true;
|
|
59
|
+
}
|
|
60
|
+
if (/\bWDT\b/.test(expr.value)) {
|
|
61
|
+
result.usesWDT = true;
|
|
62
|
+
}
|
|
63
|
+
if (expr.value.includes('__tc_str_ptr')) {
|
|
64
|
+
result.usesStrPtr = true;
|
|
65
|
+
}
|
|
66
|
+
break;
|
|
67
|
+
case "method-call":
|
|
68
|
+
if (strategy.isConsoleCall(expr.callee)) {
|
|
69
|
+
result.hasConsoleCalls = true;
|
|
70
|
+
}
|
|
71
|
+
if (/\bmillis\b/.test(expr.callee) || /\bdelay\b/.test(expr.callee) || /\bmicros\b/.test(expr.callee)) {
|
|
72
|
+
result.usesMillis = true;
|
|
73
|
+
}
|
|
74
|
+
if (expr.callee === "Date.now" || expr.callee === "Date::now") {
|
|
75
|
+
result.usesDateNow = true;
|
|
76
|
+
}
|
|
77
|
+
if (expr.callee === "String") {
|
|
78
|
+
result.usesStringConversion = true;
|
|
79
|
+
}
|
|
80
|
+
if (MATH_PATTERN.test(expr.callee)) {
|
|
81
|
+
result.hasStdMathCalls = true;
|
|
82
|
+
}
|
|
83
|
+
for (const [pattern, helperNames] of Object.entries(POLYFILL_HELPER_MAP)) {
|
|
84
|
+
const methodName = pattern.startsWith('.') ? pattern.slice(1, -1) : pattern.slice(0, -1);
|
|
85
|
+
if (expr.callee.includes(pattern) || expr.callee.endsWith("." + methodName) || expr.callee === methodName) {
|
|
86
|
+
for (const name of helperNames) {
|
|
87
|
+
result.usedPolyfillHelpers.add(name);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
for (const name of helperNames) {
|
|
91
|
+
if (expr.callee.includes(name)) {
|
|
92
|
+
result.usedPolyfillHelpers.add(name);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (expr.callee.startsWith("Num.") || expr.callee === "Num") {
|
|
97
|
+
result.usesNum = true;
|
|
98
|
+
}
|
|
99
|
+
if (expr.callee.startsWith("Timing.") || expr.callee === "Timing") {
|
|
100
|
+
result.usesTiming = true;
|
|
101
|
+
}
|
|
102
|
+
if (expr.callee.startsWith("WDT.") || expr.callee === "WDT") {
|
|
103
|
+
result.usesWDT = true;
|
|
104
|
+
}
|
|
105
|
+
// Count setInterval/setTimeout call sites (post-rename callee names) so
|
|
106
|
+
// __tc_TimerRuntime::MAX_TIMERS can be sized to the observed count.
|
|
107
|
+
if (expr.callee === "__tc_setInterval" || expr.callee === "__tc_setTimeout"
|
|
108
|
+
|| expr.callee === "setInterval" || expr.callee === "setTimeout") {
|
|
109
|
+
result.timerCallCount++;
|
|
110
|
+
}
|
|
111
|
+
for (const arg of expr.args) {
|
|
112
|
+
analyzeExpression(arg, result, strategy);
|
|
113
|
+
}
|
|
114
|
+
break;
|
|
115
|
+
case "identifier":
|
|
116
|
+
// expression-to-ir lowers the TS `null` literal to the "nullptr" sentinel
|
|
117
|
+
// (routed through nullValue() at render time, which yields CUTTLEFISH_UNDEFINED
|
|
118
|
+
// on native/arduino). Include it so usesNullish triggers the defining shim.
|
|
119
|
+
if (expr.value === "null" || expr.value === "undefined" || expr.value === "nullptr" || expr.value === "CUTTLEFISH_UNDEFINED") {
|
|
120
|
+
result.usesNullish = true;
|
|
121
|
+
}
|
|
122
|
+
break;
|
|
123
|
+
case "string":
|
|
124
|
+
for (const [pattern, helperNames] of Object.entries(POLYFILL_HELPER_MAP)) {
|
|
125
|
+
if (expr.value.includes(pattern)) {
|
|
126
|
+
for (const name of helperNames) {
|
|
127
|
+
result.usedPolyfillHelpers.add(name);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Also check for already-lowered __tc_ names (e.g. in __EMIT__ calls from HAL resolver)
|
|
131
|
+
for (const name of helperNames) {
|
|
132
|
+
if (expr.value.includes(name)) {
|
|
133
|
+
result.usedPolyfillHelpers.add(name);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
break;
|
|
138
|
+
case "array":
|
|
139
|
+
result.usesVectorTypes = true;
|
|
140
|
+
for (const element of expr.elements) {
|
|
141
|
+
analyzeExpression(element, result, strategy);
|
|
142
|
+
}
|
|
143
|
+
break;
|
|
144
|
+
case "object":
|
|
145
|
+
for (const field of expr.fields) {
|
|
146
|
+
analyzeExpression(field.value, result, strategy);
|
|
147
|
+
}
|
|
148
|
+
break;
|
|
149
|
+
case "ternary":
|
|
150
|
+
analyzeExpression(expr.condition, result, strategy);
|
|
151
|
+
analyzeExpression(expr.whenTrue, result, strategy);
|
|
152
|
+
analyzeExpression(expr.whenFalse, result, strategy);
|
|
153
|
+
break;
|
|
154
|
+
case "await":
|
|
155
|
+
analyzeExpression(expr.value, result, strategy);
|
|
156
|
+
break;
|
|
157
|
+
case "instanceof":
|
|
158
|
+
analyzeExpression(expr.object, result, strategy);
|
|
159
|
+
break;
|
|
160
|
+
case "spread_array":
|
|
161
|
+
analyzeExpression(expr.spreadExpr, result, strategy);
|
|
162
|
+
for (const element of expr.additionalElements) {
|
|
163
|
+
analyzeExpression(element, result, strategy);
|
|
164
|
+
}
|
|
165
|
+
break;
|
|
166
|
+
case "binary":
|
|
167
|
+
if (expr.operator === "**") {
|
|
168
|
+
result.hasStdMathCalls = true;
|
|
169
|
+
}
|
|
170
|
+
analyzeExpression(expr.left, result, strategy);
|
|
171
|
+
analyzeExpression(expr.right, result, strategy);
|
|
172
|
+
break;
|
|
173
|
+
case "unary":
|
|
174
|
+
analyzeExpression(expr.operand, result, strategy);
|
|
175
|
+
break;
|
|
176
|
+
case "property-access":
|
|
177
|
+
analyzeExpression(expr.object, result, strategy);
|
|
178
|
+
break;
|
|
179
|
+
case "element-access":
|
|
180
|
+
analyzeExpression(expr.object, result, strategy);
|
|
181
|
+
analyzeExpression(expr.index, result, strategy);
|
|
182
|
+
break;
|
|
183
|
+
case "string_concat":
|
|
184
|
+
case "template_string":
|
|
185
|
+
result.usesStringConversion = true;
|
|
186
|
+
if (expr.kind === "string_concat") {
|
|
187
|
+
for (const part of expr.parts) {
|
|
188
|
+
analyzeExpression(part, result, strategy);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
analyzeExpression(expr.expression, result, strategy);
|
|
193
|
+
}
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Analyze a statement for all features in a single pass.
|
|
199
|
+
*/
|
|
200
|
+
function analyzeStatement(statement, result, strategy) {
|
|
201
|
+
if (!statement || typeof statement !== 'object' || !statement.kind) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
switch (statement.kind) {
|
|
205
|
+
case "call":
|
|
206
|
+
if (strategy.isConsoleCall(statement.callee)) {
|
|
207
|
+
result.hasConsoleCalls = true;
|
|
208
|
+
}
|
|
209
|
+
if (statement.callee === "Serial.begin" || statement.callee.endsWith(".begin")) {
|
|
210
|
+
result.hasSerialBegin = true;
|
|
211
|
+
}
|
|
212
|
+
if (statement.callee === "String") {
|
|
213
|
+
result.usesStringConversion = true;
|
|
214
|
+
}
|
|
215
|
+
if (statement.callee === "Date.now" || statement.callee === "Date::now") {
|
|
216
|
+
result.usesDateNow = true;
|
|
217
|
+
}
|
|
218
|
+
if (statement.callee === "millis" || statement.callee === "delay") {
|
|
219
|
+
result.usesMillis = true;
|
|
220
|
+
}
|
|
221
|
+
// Namespace-qualified polyfill entry points used as bare call statements
|
|
222
|
+
// (e.g. `Timing.delay(5);`). The expression-level analyzer (case
|
|
223
|
+
// "method-call") already checks these prefixes, but a statement-form call
|
|
224
|
+
// never becomes a method-call expression — it stays a `call` statement —
|
|
225
|
+
// so without these mirrors `usesTiming`/`usesNum`/`usesWDT` stayed false
|
|
226
|
+
// and the defining shim was filtered out (avr-g++: "'Timing' was not
|
|
227
|
+
// declared in this scope"). Demo #30 Finding A.
|
|
228
|
+
if (statement.callee.startsWith("Timing.") || statement.callee === "Timing") {
|
|
229
|
+
result.usesTiming = true;
|
|
230
|
+
}
|
|
231
|
+
if (statement.callee.startsWith("Num.") || statement.callee === "Num") {
|
|
232
|
+
result.usesNum = true;
|
|
233
|
+
}
|
|
234
|
+
if (statement.callee.startsWith("WDT.") || statement.callee === "WDT") {
|
|
235
|
+
result.usesWDT = true;
|
|
236
|
+
}
|
|
237
|
+
// The HAL resolver lowers WDT.*/Timing.* namespace calls to bare AVR
|
|
238
|
+
// library functions (WDT.reset() → wdt_reset(), Timing.delay() → delay(),
|
|
239
|
+
// Timing.millis() → millis()). When that happens the `WDT.`/`Timing.`
|
|
240
|
+
// prefix is gone, so the namespace checks above miss it and the defining
|
|
241
|
+
// shim gets filtered out (avr-g++: "'wdt_reset' was not declared in this
|
|
242
|
+
// scope"). Detect the lowered names directly. Demo #32 Finding A.
|
|
243
|
+
if (statement.callee === "wdt_reset" || statement.callee === "wdt_enable" || statement.callee === "wdt_disable") {
|
|
244
|
+
result.usesWDT = true;
|
|
245
|
+
}
|
|
246
|
+
for (const [pattern, helperNames] of Object.entries(POLYFILL_HELPER_MAP)) {
|
|
247
|
+
const methodName = pattern.startsWith('.') ? pattern.slice(1, -1) : pattern.slice(0, -1);
|
|
248
|
+
if (statement.callee === methodName || statement.callee.endsWith("." + methodName)) {
|
|
249
|
+
for (const name of helperNames) {
|
|
250
|
+
result.usedPolyfillHelpers.add(name);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
// Also detect already-lowered __tc_* helper calls — including raw-statement
|
|
254
|
+
// wrappers (`__RAW_STMT____tc_pop(...)`) produced by the structural
|
|
255
|
+
// vector-method lowering in call-statement.ts. Without this, a statement
|
|
256
|
+
// form like `arr.pop();` (lowered to `__RAW_STMT____tc_pop(arr)`) wouldn't
|
|
257
|
+
// register the polyfill, and the helper definition would be filtered out.
|
|
258
|
+
for (const name of helperNames) {
|
|
259
|
+
if (statement.callee.includes(name)) {
|
|
260
|
+
result.usedPolyfillHelpers.add(name);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
for (const arg of statement.args) {
|
|
265
|
+
analyzeExpression(arg, result, strategy);
|
|
266
|
+
}
|
|
267
|
+
break;
|
|
268
|
+
case "var_decl":
|
|
269
|
+
result.declaredTypes.push(statement.cppType);
|
|
270
|
+
if (parseCppType(statement.cppType).kind === "strPtr") {
|
|
271
|
+
result.usesStrPtr = true;
|
|
272
|
+
}
|
|
273
|
+
if (statement.initializer) {
|
|
274
|
+
analyzeExpression(statement.initializer, result, strategy);
|
|
275
|
+
// Check for array in object literal
|
|
276
|
+
if (statement.initializer.kind === "array") {
|
|
277
|
+
result.hasArrayInObjectLiteral = true;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
break;
|
|
281
|
+
case "assign":
|
|
282
|
+
analyzeExpression(statement.value, result, strategy);
|
|
283
|
+
break;
|
|
284
|
+
case "return":
|
|
285
|
+
if (statement.value) {
|
|
286
|
+
analyzeExpression(statement.value, result, strategy);
|
|
287
|
+
}
|
|
288
|
+
break;
|
|
289
|
+
case "throw":
|
|
290
|
+
result.hasThrowStatements = true;
|
|
291
|
+
analyzeExpression(statement.value, result, strategy);
|
|
292
|
+
break;
|
|
293
|
+
case "while":
|
|
294
|
+
case "do_while":
|
|
295
|
+
analyzeExpression(statement.condition, result, strategy);
|
|
296
|
+
for (const nested of statement.body) {
|
|
297
|
+
analyzeStatement(nested, result, strategy);
|
|
298
|
+
}
|
|
299
|
+
break;
|
|
300
|
+
case "if":
|
|
301
|
+
analyzeExpression(statement.condition, result, strategy);
|
|
302
|
+
for (const nested of statement.thenBranch) {
|
|
303
|
+
analyzeStatement(nested, result, strategy);
|
|
304
|
+
}
|
|
305
|
+
for (const nested of statement.elseBranch ?? []) {
|
|
306
|
+
analyzeStatement(nested, result, strategy);
|
|
307
|
+
}
|
|
308
|
+
break;
|
|
309
|
+
case "for":
|
|
310
|
+
if (statement.initializer) {
|
|
311
|
+
analyzeStatement(statement.initializer, result, strategy);
|
|
312
|
+
}
|
|
313
|
+
if (statement.condition) {
|
|
314
|
+
analyzeExpression(statement.condition, result, strategy);
|
|
315
|
+
}
|
|
316
|
+
if (statement.increment) {
|
|
317
|
+
analyzeStatement(statement.increment, result, strategy);
|
|
318
|
+
}
|
|
319
|
+
for (const nested of statement.body) {
|
|
320
|
+
analyzeStatement(nested, result, strategy);
|
|
321
|
+
}
|
|
322
|
+
break;
|
|
323
|
+
case "for_of":
|
|
324
|
+
analyzeStatement(statement.variable, result, strategy);
|
|
325
|
+
analyzeExpression(statement.iterable, result, strategy);
|
|
326
|
+
for (const nested of statement.body) {
|
|
327
|
+
analyzeStatement(nested, result, strategy);
|
|
328
|
+
}
|
|
329
|
+
break;
|
|
330
|
+
case "for_in":
|
|
331
|
+
analyzeStatement(statement.variable, result, strategy);
|
|
332
|
+
analyzeExpression(statement.object, result, strategy);
|
|
333
|
+
for (const nested of statement.body) {
|
|
334
|
+
analyzeStatement(nested, result, strategy);
|
|
335
|
+
}
|
|
336
|
+
break;
|
|
337
|
+
case "switch":
|
|
338
|
+
analyzeExpression(statement.expression, result, strategy);
|
|
339
|
+
for (const caseClause of statement.cases) {
|
|
340
|
+
if (caseClause.value) {
|
|
341
|
+
analyzeExpression(caseClause.value, result, strategy);
|
|
342
|
+
}
|
|
343
|
+
for (const nested of caseClause.body) {
|
|
344
|
+
analyzeStatement(nested, result, strategy);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
break;
|
|
348
|
+
case "try":
|
|
349
|
+
for (const nested of statement.tryBlock) {
|
|
350
|
+
analyzeStatement(nested, result, strategy);
|
|
351
|
+
}
|
|
352
|
+
for (const nested of statement.catchBlock ?? []) {
|
|
353
|
+
analyzeStatement(nested, result, strategy);
|
|
354
|
+
}
|
|
355
|
+
for (const nested of statement.finallyBlock ?? []) {
|
|
356
|
+
analyzeStatement(nested, result, strategy);
|
|
357
|
+
}
|
|
358
|
+
break;
|
|
359
|
+
case "hal-op":
|
|
360
|
+
// Scan raw C++ code in HAL ops for polyfill helper usage
|
|
361
|
+
if (statement.operation && statement.operation.operation === "raw" && typeof statement.operation.code === "string") {
|
|
362
|
+
const code = statement.operation.code;
|
|
363
|
+
for (const [pattern, helperNames] of Object.entries(POLYFILL_HELPER_MAP)) {
|
|
364
|
+
if (code.includes(pattern)) {
|
|
365
|
+
for (const name of helperNames) {
|
|
366
|
+
result.usedPolyfillHelpers.add(name);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
for (const name of helperNames) {
|
|
370
|
+
if (code.includes(name)) {
|
|
371
|
+
result.usedPolyfillHelpers.add(name);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
// The HAL resolver lowers WDT.*/Timing.* namespace calls to bare AVR
|
|
376
|
+
// library functions inside hal-op raw code (WDT.reset() → wdt_reset(),
|
|
377
|
+
// Timing.delay() → delay()). The namespace prefix is gone, so detect
|
|
378
|
+
// the lowered names to keep the defining shim/include alive.
|
|
379
|
+
// Demo #32 Finding B.
|
|
380
|
+
if (/\bwdt_(reset|enable|disable)\b/.test(code)) {
|
|
381
|
+
result.usesWDT = true;
|
|
382
|
+
}
|
|
383
|
+
if (/\b(millis|micros|delay|delayMicroseconds)\s*\(/.test(code)) {
|
|
384
|
+
result.usesTiming = true;
|
|
385
|
+
result.usesMillis = true;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
break;
|
|
389
|
+
case "update":
|
|
390
|
+
// update statements just increment/decrement a variable
|
|
391
|
+
break;
|
|
392
|
+
case "break":
|
|
393
|
+
case "continue":
|
|
394
|
+
// no expressions to analyze
|
|
395
|
+
break;
|
|
396
|
+
case "super_call":
|
|
397
|
+
for (const arg of statement.args) {
|
|
398
|
+
analyzeExpression(arg, result, strategy);
|
|
399
|
+
}
|
|
400
|
+
break;
|
|
401
|
+
case "labeled":
|
|
402
|
+
case "block":
|
|
403
|
+
const body = statement.kind === "labeled" ? statement.body : statement.body;
|
|
404
|
+
for (const nested of body) {
|
|
405
|
+
analyzeStatement(nested, result, strategy);
|
|
406
|
+
}
|
|
407
|
+
break;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Analyze a program IR in a single pass to detect all features.
|
|
412
|
+
* This replaces multiple separate traversals with one combined traversal.
|
|
413
|
+
*/
|
|
414
|
+
export function analyzeProgram(program, strategy) {
|
|
415
|
+
const result = {
|
|
416
|
+
hasConsoleCalls: false,
|
|
417
|
+
hasArrayInObjectLiteral: false,
|
|
418
|
+
hasThrowStatements: false,
|
|
419
|
+
hasStdMathCalls: false,
|
|
420
|
+
usesVectorTypes: false,
|
|
421
|
+
usesStdString: false,
|
|
422
|
+
usesStdFunction: false,
|
|
423
|
+
declaredTypes: [],
|
|
424
|
+
usedPolyfillHelpers: new Set(),
|
|
425
|
+
usesStringConversion: false,
|
|
426
|
+
usesDateNow: false,
|
|
427
|
+
usesMillis: false,
|
|
428
|
+
usesNullish: false,
|
|
429
|
+
usesNullishHelper: false,
|
|
430
|
+
usesNum: false,
|
|
431
|
+
usesTiming: false,
|
|
432
|
+
usesWDT: false,
|
|
433
|
+
usesStrPtr: false,
|
|
434
|
+
hasSerialBegin: false,
|
|
435
|
+
hasGenerators: false,
|
|
436
|
+
usesStdMap: false,
|
|
437
|
+
timerCallCount: 0,
|
|
438
|
+
};
|
|
439
|
+
// Analyze type aliases
|
|
440
|
+
for (const typeAlias of program.typeAliases) {
|
|
441
|
+
result.declaredTypes.push(typeAlias.cppType);
|
|
442
|
+
if (typeAlias.structFields) {
|
|
443
|
+
for (const field of typeAlias.structFields) {
|
|
444
|
+
result.declaredTypes.push(field.cppType);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
if (typeAlias.variantStructs) {
|
|
448
|
+
for (const variant of typeAlias.variantStructs) {
|
|
449
|
+
for (const field of variant.fields) {
|
|
450
|
+
result.declaredTypes.push(field.cppType);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
// Analyze interfaces for field types and index signatures
|
|
456
|
+
for (const iface of program.interfaces) {
|
|
457
|
+
for (const field of iface.fields) {
|
|
458
|
+
result.declaredTypes.push(field.cppType);
|
|
459
|
+
}
|
|
460
|
+
if (iface.indexSignature) {
|
|
461
|
+
result.usesStdMap = true;
|
|
462
|
+
result.declaredTypes.push(iface.indexSignature.keyType);
|
|
463
|
+
result.declaredTypes.push(iface.indexSignature.valueType);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
// Analyze functions
|
|
467
|
+
for (const fn of program.functions) {
|
|
468
|
+
if (fn.isGenerator)
|
|
469
|
+
result.hasGenerators = true;
|
|
470
|
+
result.declaredTypes.push(fn.returnType);
|
|
471
|
+
for (const parameter of fn.parameters) {
|
|
472
|
+
result.declaredTypes.push(parameter.cppType);
|
|
473
|
+
}
|
|
474
|
+
for (const statement of fn.statements) {
|
|
475
|
+
analyzeStatement(statement, result, strategy);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
// Analyze top-level statements
|
|
479
|
+
for (const statement of program.topLevelStatements) {
|
|
480
|
+
analyzeStatement(statement, result, strategy);
|
|
481
|
+
}
|
|
482
|
+
// Analyze classes
|
|
483
|
+
for (const classDef of program.classes) {
|
|
484
|
+
for (const field of classDef.fields) {
|
|
485
|
+
result.declaredTypes.push(field.cppType);
|
|
486
|
+
if (field.initializer) {
|
|
487
|
+
analyzeExpression(field.initializer, result, strategy);
|
|
488
|
+
if (field.initializer.kind === "array") {
|
|
489
|
+
result.hasArrayInObjectLiteral = true;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
for (const method of classDef.methods) {
|
|
494
|
+
result.declaredTypes.push(method.returnType);
|
|
495
|
+
for (const parameter of method.parameters) {
|
|
496
|
+
result.declaredTypes.push(parameter.cppType);
|
|
497
|
+
}
|
|
498
|
+
for (const statement of method.statements) {
|
|
499
|
+
analyzeStatement(statement, result, strategy);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
if (classDef.constructor) {
|
|
503
|
+
for (const parameter of classDef.constructor.parameters) {
|
|
504
|
+
result.declaredTypes.push(parameter.cppType);
|
|
505
|
+
}
|
|
506
|
+
for (const statement of classDef.constructor.statements) {
|
|
507
|
+
analyzeStatement(statement, result, strategy);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
// Post-process declared types to detect std:: usage
|
|
512
|
+
for (const typeName of result.declaredTypes) {
|
|
513
|
+
if (typeName.includes("std::vector<")) {
|
|
514
|
+
result.usesVectorTypes = true;
|
|
515
|
+
}
|
|
516
|
+
if (strategy.needsStdVector() && typeName.includes("__tc_StaticArray<")) {
|
|
517
|
+
result.usesVectorTypes = true;
|
|
518
|
+
}
|
|
519
|
+
// Track __tc_StaticArray type usage on ALL targets so the defining
|
|
520
|
+
// polyfill is retained by filterPolyfillHelpers (the struct's constructor
|
|
521
|
+
// matches the helper-name regex but is never a user call site, so without
|
|
522
|
+
// this the struct would be filtered out and `__tc_StaticArray<int,N>`
|
|
523
|
+
// undeclared — avr-g++: "'__tc_StaticArray' was not declared"). Demo #23.
|
|
524
|
+
if (typeName.includes("__tc_StaticArray<")) {
|
|
525
|
+
result.usedPolyfillHelpers.add("__tc_StaticArray");
|
|
526
|
+
}
|
|
527
|
+
if (typeName.includes("std::string")) {
|
|
528
|
+
result.usesStdString = true;
|
|
529
|
+
// The Arduino/AVR strategy normalizes `std::string` → `__tc_str_ptr` at
|
|
530
|
+
// emit time (Strategy.normalizeCppType). The `usesStrPtr` flag gates
|
|
531
|
+
// emission of the `__tc_str_ptr` shim block, but the per-statement
|
|
532
|
+
// detector at the `var_decl` arm compares the PRE-normalization cppType
|
|
533
|
+
// (still `std::string`) against `parseCppType(...).kind === "strPtr"` —
|
|
534
|
+
// which never matches, so a string-typed LOCAL/field/return that emits
|
|
535
|
+
// as `__tc_str_ptr` silently drops its own shim and fails at g++ time
|
|
536
|
+
// ("'__tc_str_ptr' does not name a type"). Resolving the type through
|
|
537
|
+
// the strategy's normalizer here — the single broadest chokepoint over
|
|
538
|
+
// every declared type (locals, fields, params, returns, aliases) — makes
|
|
539
|
+
// the analysis agree with the emit path on every target. On native the
|
|
540
|
+
// normalizer leaves `std::string` alone, so this is a no-op there.
|
|
541
|
+
if (strategy.normalizeCppType("std::string") === "__tc_str_ptr") {
|
|
542
|
+
result.usesStrPtr = true;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
if (typeName.includes("std::function<")) {
|
|
546
|
+
result.usesStdFunction = true;
|
|
547
|
+
}
|
|
548
|
+
if (typeName.includes("std::map<")) {
|
|
549
|
+
result.usesStdMap = true;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
// Analyze UI callback bodies that live outside program.functions
|
|
553
|
+
// (onClick / watchPin / drawCanvas / bindInput / bindList). They now carry
|
|
554
|
+
// StatementIR[] from the main lowerStatementList pipeline, so console /
|
|
555
|
+
// helper usage is visible here the same way setInterval bodies are.
|
|
556
|
+
for (const wp of watchPinSpecs()) {
|
|
557
|
+
for (const stmt of wp.bodyStatements ?? [])
|
|
558
|
+
analyzeStatement(stmt, result, strategy);
|
|
559
|
+
}
|
|
560
|
+
for (const ch of clickHandlers()) {
|
|
561
|
+
for (const stmt of ch.bodyStatements ?? [])
|
|
562
|
+
analyzeStatement(stmt, result, strategy);
|
|
563
|
+
}
|
|
564
|
+
for (const spec of canvasBindings()) {
|
|
565
|
+
for (const stmt of spec.bodyStatements ?? [])
|
|
566
|
+
analyzeStatement(stmt, result, strategy);
|
|
567
|
+
}
|
|
568
|
+
for (const spec of getInputBindings()) {
|
|
569
|
+
for (const stmt of spec.bodyStatements ?? [])
|
|
570
|
+
analyzeStatement(stmt, result, strategy);
|
|
571
|
+
}
|
|
572
|
+
for (const spec of getListBindings()) {
|
|
573
|
+
for (const stmt of spec.countStatements ?? [])
|
|
574
|
+
analyzeStatement(stmt, result, strategy);
|
|
575
|
+
for (const stmt of spec.itemStatements ?? [])
|
|
576
|
+
analyzeStatement(stmt, result, strategy);
|
|
577
|
+
for (const stmt of spec.tapStatements ?? [])
|
|
578
|
+
analyzeStatement(stmt, result, strategy);
|
|
579
|
+
}
|
|
580
|
+
// Console calls lowered inside leftover string-baked UI callbacks are baked
|
|
581
|
+
// into callbackBody strings, not IR nodes, so the statement walk above can't
|
|
582
|
+
// see them. Consult the flag recorded during lowering so hasConsoleCalls
|
|
583
|
+
// reflects them — this is what gates auto-injected Serial.begin(baud) and
|
|
584
|
+
// <iostream>.
|
|
585
|
+
if (loweredConsoleInCallback()) {
|
|
586
|
+
result.hasConsoleCalls = true;
|
|
587
|
+
}
|
|
588
|
+
return result;
|
|
589
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Diagnostic } from '../types.js';
|
|
2
|
+
import type { PeripheralUsage } from './peripheral-usage.js';
|
|
3
|
+
import type { BoardConstants } from './board-resolver.js';
|
|
4
|
+
/**
|
|
5
|
+
* Validate that pins used with inputPullDown() support pulldown on this board.
|
|
6
|
+
*/
|
|
7
|
+
export declare function validatePulldownSupport(usage: PeripheralUsage, boardConstants: BoardConstants | undefined): Diagnostic[];
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Pulldown Capability Validation
|
|
3
|
+
//
|
|
4
|
+
// Checks that pins configured with inputPullDown() actually support
|
|
5
|
+
// hardware pulldown on the target board. Emits a compile-time error if not.
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
/**
|
|
8
|
+
* Validate that pins used with inputPullDown() support pulldown on this board.
|
|
9
|
+
*/
|
|
10
|
+
export function validatePulldownSupport(usage, boardConstants) {
|
|
11
|
+
const diagnostics = [];
|
|
12
|
+
if (usage.inputPulldownPins.size === 0) {
|
|
13
|
+
return diagnostics;
|
|
14
|
+
}
|
|
15
|
+
for (const pinNumber of usage.inputPulldownPins) {
|
|
16
|
+
// Check the pin's own pullDown capability from board definition
|
|
17
|
+
// undefined or false both mean pulldown is not supported on this pin
|
|
18
|
+
const supportsPullDown = boardConstants?.get(`pins.all.${pinNumber}.capabilities.pullDown`);
|
|
19
|
+
if (supportsPullDown !== true) {
|
|
20
|
+
const pinName = getPinName(pinNumber, boardConstants);
|
|
21
|
+
const arch = boardConstants?.get('architecture');
|
|
22
|
+
diagnostics.push({
|
|
23
|
+
code: 'pulldown-not-supported',
|
|
24
|
+
message: `${pinName ?? `pin ${pinNumber}`} does not support hardware pulldown${arch ? ` on ${arch.toUpperCase()} boards` : ''}. Use ${pinName ?? 'pin'}.asInput() or ${pinName ?? 'pin'}.inputPullUp() instead.`,
|
|
25
|
+
source: 'pulldown-validation',
|
|
26
|
+
severity: 'error',
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return diagnostics;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get the human-readable pin name (e.g., "D3", "A0") from pin number.
|
|
34
|
+
*/
|
|
35
|
+
function getPinName(pinNumber, boardConstants) {
|
|
36
|
+
if (!boardConstants) {
|
|
37
|
+
if (pinNumber >= 14 && pinNumber <= 19)
|
|
38
|
+
return `A${pinNumber - 14}`;
|
|
39
|
+
return `D${pinNumber}`;
|
|
40
|
+
}
|
|
41
|
+
const name = boardConstants.get(`pins.all.${pinNumber}.name`);
|
|
42
|
+
if (typeof name === 'string')
|
|
43
|
+
return name;
|
|
44
|
+
// Fallback naming
|
|
45
|
+
if (pinNumber >= 14 && pinNumber <= 19) {
|
|
46
|
+
return `A${pinNumber - 14}`;
|
|
47
|
+
}
|
|
48
|
+
return `D${pinNumber}`;
|
|
49
|
+
}
|
|
@@ -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 validatePWMTimerSharing(usage: PeripheralUsage, boardConstants: BoardConstants | undefined): Diagnostic[];
|