@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,11 @@
|
|
|
1
|
+
import type { RuntimePolyfillIR } from "../api/shared/index.js";
|
|
2
|
+
interface EmittedPolyfillCode {
|
|
3
|
+
includes: string[];
|
|
4
|
+
declarations: string[];
|
|
5
|
+
definitions: string[];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Emit C++ boilerplate from native helper IR (formerly polyfill IR).
|
|
9
|
+
*/
|
|
10
|
+
export declare function emitPolyfillBoilerplate(polyfills: RuntimePolyfillIR[]): EmittedPolyfillCode;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { normalizeInclude } from "./utils/include-resolver.js";
|
|
2
|
+
/**
|
|
3
|
+
* Emit C++ boilerplate from native helper IR (formerly polyfill IR).
|
|
4
|
+
*/
|
|
5
|
+
export function emitPolyfillBoilerplate(polyfills) {
|
|
6
|
+
const result = {
|
|
7
|
+
includes: [],
|
|
8
|
+
declarations: [],
|
|
9
|
+
definitions: [],
|
|
10
|
+
};
|
|
11
|
+
const includedHeaders = new Set();
|
|
12
|
+
for (const polyfill of polyfills) {
|
|
13
|
+
for (const include of polyfill.requiredIncludes) {
|
|
14
|
+
const normalizedInclude = normalizeInclude(include);
|
|
15
|
+
if (!includedHeaders.has(normalizedInclude)) {
|
|
16
|
+
includedHeaders.add(normalizedInclude);
|
|
17
|
+
result.includes.push(normalizedInclude);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
for (const decl of polyfill.forwardDeclarations) {
|
|
21
|
+
result.declarations.push(decl);
|
|
22
|
+
}
|
|
23
|
+
for (const struct of polyfill.helperStructs) {
|
|
24
|
+
result.definitions.push(struct.trim());
|
|
25
|
+
}
|
|
26
|
+
for (const func of polyfill.helperFunctions) {
|
|
27
|
+
result.definitions.push(func.trim());
|
|
28
|
+
}
|
|
29
|
+
for (const macro of polyfill.shimMacros) {
|
|
30
|
+
result.declarations.push(macro);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Op routing — dispatch a HALOpIR to the right strategy resolver.
|
|
3
|
+
//
|
|
4
|
+
// display.* ops go to resolveDisplayOp (graphics-specific); everything else
|
|
5
|
+
// goes to resolveHALOperation (the existing generic seam). Keeps the consumer
|
|
6
|
+
// sites (expression-renderer, statement-renderer, render-expr) DRY.
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
export function routeHALOp(op, strategy) {
|
|
9
|
+
if (typeof op.operation === "string" && op.operation.startsWith("display.")) {
|
|
10
|
+
return strategy.resolveDisplayOp?.(op);
|
|
11
|
+
}
|
|
12
|
+
return strategy.resolveHALOperation?.(op);
|
|
13
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AssignmentIR, ExpressionIR, StatementIR, VariableDeclarationIR } from "../api/shared/index.js";
|
|
2
|
+
import type { PlatformStrategy } from "../api/shared/index.js";
|
|
3
|
+
import type { KnownVariableInfo, SnprintfArgRenderResult, SnprintfRenderResult, EmissionScopeState, SnprintfExpressionRenderer } from "../api/shared/index.js";
|
|
4
|
+
import { escapeCppStringLiteral } from "../utils/strings.js";
|
|
5
|
+
export type { KnownVariableInfo, SnprintfArgRenderResult, SnprintfRenderResult, EmissionScopeState, SnprintfExpressionRenderer };
|
|
6
|
+
export declare function createEmissionScopeState(initialTypes?: Map<string, KnownVariableInfo>): EmissionScopeState;
|
|
7
|
+
export declare function cloneEmissionScopeState(state: EmissionScopeState): EmissionScopeState;
|
|
8
|
+
export declare function createChildEmissionScope(baseScope: EmissionScopeState, parameters?: readonly {
|
|
9
|
+
name: string;
|
|
10
|
+
cppType: string;
|
|
11
|
+
}[]): EmissionScopeState;
|
|
12
|
+
export declare function recordVariableType(statement: VariableDeclarationIR, scopeState: EmissionScopeState): void;
|
|
13
|
+
export { escapeCppStringLiteral };
|
|
14
|
+
export declare function inferSnprintfArg(expr: ExpressionIR, strategy: PlatformStrategy, scopeState: EmissionScopeState, renderExpression: SnprintfExpressionRenderer, pointerVarTypes?: Map<string, string>, knownFunctionReturnTypes?: Map<string, string>, stringVarNames?: Set<string>): SnprintfArgRenderResult | undefined;
|
|
15
|
+
export declare function buildSnprintfRenderResult(expr: ExpressionIR, strategy: PlatformStrategy, scopeState: EmissionScopeState, renderExpression: SnprintfExpressionRenderer, pointerVarTypes?: Map<string, string>, knownFunctionReturnTypes?: Map<string, string>, stringVarNames?: Set<string>): SnprintfRenderResult | undefined;
|
|
16
|
+
export declare function shouldUseSnprintfForString(statement: VariableDeclarationIR | AssignmentIR, strategy: PlatformStrategy): boolean;
|
|
17
|
+
export declare function statementNeedsSnprintf(statement: StatementIR, strategy: PlatformStrategy): boolean;
|
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Snprintf helpers for template literal / string-concat lowering
|
|
3
|
+
//
|
|
4
|
+
// Generates snprintf-based C++ code for string concatenation expressions on
|
|
5
|
+
// platforms whose C++ runtime lacks std::string (e.g. AVR).
|
|
6
|
+
//
|
|
7
|
+
// All logic lives in the CLI; no framework package dependency.
|
|
8
|
+
// Types are imported from @typecad/cuttlefish/api/shared.
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
import { escapeCppStringLiteral, escapeSnprintfFormatFragment } from "../utils/strings.js";
|
|
11
|
+
import { parsedElementString, parsedIsStringLike } from "../api/shared/cpp-type-ir.js";
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// Scope state management
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
export function createEmissionScopeState(initialTypes) {
|
|
16
|
+
return {
|
|
17
|
+
knownVariableTypes: initialTypes ? new Map(initialTypes) : new Map(),
|
|
18
|
+
snprintfBuffers: new Set(),
|
|
19
|
+
nextSnprintfTempId: 0,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export function cloneEmissionScopeState(state) {
|
|
23
|
+
return {
|
|
24
|
+
knownVariableTypes: new Map(state.knownVariableTypes),
|
|
25
|
+
snprintfBuffers: new Set(state.snprintfBuffers),
|
|
26
|
+
nextSnprintfTempId: state.nextSnprintfTempId,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export function createChildEmissionScope(baseScope, parameters) {
|
|
30
|
+
const childScope = cloneEmissionScopeState(baseScope);
|
|
31
|
+
for (const parameter of parameters ?? []) {
|
|
32
|
+
childScope.knownVariableTypes.set(parameter.name, { cppType: parameter.cppType });
|
|
33
|
+
}
|
|
34
|
+
return childScope;
|
|
35
|
+
}
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Variable tracking
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
function getFloatPrecisionFromNumber(value) {
|
|
40
|
+
if (!Number.isFinite(value) || Number.isInteger(value))
|
|
41
|
+
return undefined;
|
|
42
|
+
const text = `${value}`;
|
|
43
|
+
const decimalIndex = text.indexOf(".");
|
|
44
|
+
if (decimalIndex === -1)
|
|
45
|
+
return undefined;
|
|
46
|
+
return text.length - decimalIndex - 1;
|
|
47
|
+
}
|
|
48
|
+
function expressionInvolvesFloat(expr) {
|
|
49
|
+
if (!expr)
|
|
50
|
+
return false;
|
|
51
|
+
switch (expr.kind) {
|
|
52
|
+
case "number":
|
|
53
|
+
return !Number.isInteger(expr.value);
|
|
54
|
+
case "binary":
|
|
55
|
+
return expressionInvolvesFloat(expr.left) || expressionInvolvesFloat(expr.right);
|
|
56
|
+
case "unary":
|
|
57
|
+
return expressionInvolvesFloat(expr.operand);
|
|
58
|
+
case "paren":
|
|
59
|
+
return expressionInvolvesFloat(expr.inner);
|
|
60
|
+
case "ternary":
|
|
61
|
+
return expressionInvolvesFloat(expr.condition) || expressionInvolvesFloat(expr.whenTrue) || expressionInvolvesFloat(expr.whenFalse);
|
|
62
|
+
case "method-call":
|
|
63
|
+
return expr.args.some(expressionInvolvesFloat);
|
|
64
|
+
case "property-access":
|
|
65
|
+
return expressionInvolvesFloat(expr.object);
|
|
66
|
+
case "element-access":
|
|
67
|
+
return expressionInvolvesFloat(expr.object) || expressionInvolvesFloat(expr.index);
|
|
68
|
+
case "template_string":
|
|
69
|
+
return expressionInvolvesFloat(expr.expression);
|
|
70
|
+
case "string_concat":
|
|
71
|
+
return expr.parts.some(expressionInvolvesFloat);
|
|
72
|
+
case "raw":
|
|
73
|
+
return /\b\d+\.\d+\b/.test(expr.value);
|
|
74
|
+
default:
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function findFloatPrecision(expr) {
|
|
79
|
+
if (!expr)
|
|
80
|
+
return undefined;
|
|
81
|
+
if (expr.kind === "number")
|
|
82
|
+
return getFloatPrecisionFromNumber(expr.value);
|
|
83
|
+
if (expr.kind === "binary")
|
|
84
|
+
return findFloatPrecision(expr.left) ?? findFloatPrecision(expr.right);
|
|
85
|
+
if (expr.kind === "unary")
|
|
86
|
+
return findFloatPrecision(expr.operand);
|
|
87
|
+
if (expr.kind === "paren")
|
|
88
|
+
return findFloatPrecision(expr.inner);
|
|
89
|
+
if (expr.kind === "raw") {
|
|
90
|
+
const match = expr.value.match(/\b(\d+\.\d+)\b/);
|
|
91
|
+
if (match)
|
|
92
|
+
return getFloatPrecisionFromNumber(parseFloat(match[1]));
|
|
93
|
+
}
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
export function recordVariableType(statement, scopeState) {
|
|
97
|
+
const involvesFloat = expressionInvolvesFloat(statement.initializer);
|
|
98
|
+
const effectiveCppType = statement.cppType === "auto" && involvesFloat ? "float" : statement.cppType;
|
|
99
|
+
scopeState.knownVariableTypes.set(statement.name, {
|
|
100
|
+
cppType: effectiveCppType,
|
|
101
|
+
floatPrecision: statement.initializer?.kind === "number"
|
|
102
|
+
? getFloatPrecisionFromNumber(statement.initializer.value)
|
|
103
|
+
: (effectiveCppType === "float" || effectiveCppType === "double") ? findFloatPrecision(statement.initializer) : undefined,
|
|
104
|
+
// Retain the initializer for auto-deduced locals so the specifier picker
|
|
105
|
+
// can resolve the real C++ type lazily (e.g. `const name = loot.name`
|
|
106
|
+
// emits as `auto` but resolves to std::string).
|
|
107
|
+
initializer: effectiveCppType === "auto" ? statement.initializer : undefined,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
// Internal helpers
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
export { escapeCppStringLiteral };
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
// Snprintf arg inference
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
export function inferSnprintfArg(expr, strategy, scopeState, renderExpression, pointerVarTypes, knownFunctionReturnTypes, stringVarNames) {
|
|
118
|
+
switch (expr.kind) {
|
|
119
|
+
case "number": {
|
|
120
|
+
if (expr.cppType === "float" || expr.cppType === "double" || !Number.isInteger(expr.value)) {
|
|
121
|
+
const str = `${expr.value}`;
|
|
122
|
+
const rendered = str.includes('.') || str.includes('e') || str.includes('E')
|
|
123
|
+
? `${str}f`
|
|
124
|
+
: `${str}.0f`;
|
|
125
|
+
const precision = getFloatPrecisionFromNumber(expr.value);
|
|
126
|
+
const floatArgN = strategy.floatToSnprintfArg?.(rendered, precision, ++scopeState.nextSnprintfTempId);
|
|
127
|
+
if (floatArgN !== undefined)
|
|
128
|
+
return floatArgN;
|
|
129
|
+
return {
|
|
130
|
+
format: precision !== undefined ? `%.${precision}f` : "%g",
|
|
131
|
+
arg: rendered,
|
|
132
|
+
estimatedLength: 8,
|
|
133
|
+
preludeLines: [],
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return { format: "%d", arg: `${expr.value}`, estimatedLength: 12, preludeLines: [] };
|
|
137
|
+
}
|
|
138
|
+
case "boolean":
|
|
139
|
+
return {
|
|
140
|
+
format: "%s",
|
|
141
|
+
arg: expr.value ? '"true"' : '"false"',
|
|
142
|
+
estimatedLength: 5,
|
|
143
|
+
preludeLines: [],
|
|
144
|
+
};
|
|
145
|
+
case "string":
|
|
146
|
+
return {
|
|
147
|
+
format: "%s",
|
|
148
|
+
arg: `"${escapeCppStringLiteral(expr.value)}"`,
|
|
149
|
+
estimatedLength: Math.max(expr.value.length, 1),
|
|
150
|
+
preludeLines: [],
|
|
151
|
+
};
|
|
152
|
+
case "identifier": {
|
|
153
|
+
const knownVar = scopeState.knownVariableTypes.get(expr.value);
|
|
154
|
+
const cppType = knownVar?.cppType ?? knownFunctionReturnTypes?.get(expr.value);
|
|
155
|
+
if (cppType && strategy.isStringLikeType(cppType)) {
|
|
156
|
+
const normalized = strategy.normalizeCppType(cppType);
|
|
157
|
+
const needsCStr = parsedIsStringLike(normalized);
|
|
158
|
+
const arg = needsCStr ? `${expr.value}.c_str()` : expr.value;
|
|
159
|
+
return { format: "%s", arg, estimatedLength: 24, preludeLines: [] };
|
|
160
|
+
}
|
|
161
|
+
// Format-specifier ladder. Kept as explicit per-name branches because
|
|
162
|
+
// printf specifiers distinguish widths that a coarse kind-bucket would
|
|
163
|
+
// collapse (e.g. `unsigned long` → %lu vs `long long` → %lld).
|
|
164
|
+
if (cppType === "bool") {
|
|
165
|
+
return { format: "%s", arg: `(${expr.value} ? "true" : "false")`, estimatedLength: 5, preludeLines: [] };
|
|
166
|
+
}
|
|
167
|
+
if (cppType === "float" || cppType === "double") {
|
|
168
|
+
const floatArgI = strategy.floatToSnprintfArg?.(expr.value, knownVar?.floatPrecision, ++scopeState.nextSnprintfTempId);
|
|
169
|
+
if (floatArgI !== undefined)
|
|
170
|
+
return floatArgI;
|
|
171
|
+
return {
|
|
172
|
+
format: knownVar?.floatPrecision !== undefined ? `%.${knownVar.floatPrecision}f` : "%g",
|
|
173
|
+
arg: expr.value,
|
|
174
|
+
estimatedLength: 8,
|
|
175
|
+
preludeLines: [],
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
if (cppType === "int" || cppType === "short" || cppType === "int16_t" || cppType === "int32_t" || cppType === "auto") {
|
|
179
|
+
return { format: "%d", arg: expr.value, estimatedLength: 12, preludeLines: [] };
|
|
180
|
+
}
|
|
181
|
+
if (cppType === "uint16_t" || cppType === "uint32_t") {
|
|
182
|
+
return { format: "%u", arg: expr.value, estimatedLength: 12, preludeLines: [] };
|
|
183
|
+
}
|
|
184
|
+
if (cppType === "long") {
|
|
185
|
+
return { format: "%ld", arg: expr.value, estimatedLength: 12, preludeLines: [] };
|
|
186
|
+
}
|
|
187
|
+
if (cppType === "unsigned long") {
|
|
188
|
+
return { format: "%lu", arg: expr.value, estimatedLength: 12, preludeLines: [] };
|
|
189
|
+
}
|
|
190
|
+
if (cppType === "long long" || cppType === "unsigned long long" || cppType === "int64_t" || cppType === "uint64_t") {
|
|
191
|
+
return { format: "%lld", arg: expr.value, estimatedLength: 20, preludeLines: [] };
|
|
192
|
+
}
|
|
193
|
+
if (pointerVarTypes?.has(expr.value)) {
|
|
194
|
+
const pointerType = pointerVarTypes.get(expr.value);
|
|
195
|
+
if (strategy.isStringLikeType(pointerType)) {
|
|
196
|
+
return { format: "%s", arg: expr.value, estimatedLength: 24, preludeLines: [] };
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (stringVarNames?.has(expr.value)) {
|
|
200
|
+
return { format: "%s", arg: expr.value, estimatedLength: 32, preludeLines: [] };
|
|
201
|
+
}
|
|
202
|
+
return { format: "%d", arg: expr.value, estimatedLength: 12, preludeLines: [] };
|
|
203
|
+
}
|
|
204
|
+
case "template_string":
|
|
205
|
+
return inferSnprintfArg(expr.expression, strategy, scopeState, renderExpression, pointerVarTypes, knownFunctionReturnTypes, stringVarNames);
|
|
206
|
+
case "paren":
|
|
207
|
+
return inferSnprintfArg(expr.inner, strategy, scopeState, renderExpression, pointerVarTypes, knownFunctionReturnTypes, stringVarNames);
|
|
208
|
+
case "raw": {
|
|
209
|
+
if (/^__tc_/.test(expr.value)) {
|
|
210
|
+
return { format: "%s", arg: renderExpression(expr), estimatedLength: 32, preludeLines: [] };
|
|
211
|
+
}
|
|
212
|
+
if (/^std::string\(/.test(expr.value)) {
|
|
213
|
+
return { format: "%s", arg: renderExpression(expr), estimatedLength: 32, preludeLines: [] };
|
|
214
|
+
}
|
|
215
|
+
const callMatch = expr.value.match(/^([A-Za-z_][A-Za-z0-9_]*)\s*\(/);
|
|
216
|
+
if (callMatch) {
|
|
217
|
+
const funcName = callMatch[1];
|
|
218
|
+
if (knownFunctionReturnTypes) {
|
|
219
|
+
const returnType = knownFunctionReturnTypes.get(funcName);
|
|
220
|
+
if (returnType && strategy.isStringLikeType(returnType)) {
|
|
221
|
+
return { format: "%s", arg: renderExpression(expr), estimatedLength: 24, preludeLines: [] };
|
|
222
|
+
}
|
|
223
|
+
if (returnType === "bool") {
|
|
224
|
+
const rendered = renderExpression(expr);
|
|
225
|
+
return { format: "%s", arg: `(${rendered} ? "true" : "false")`, estimatedLength: 5, preludeLines: [] };
|
|
226
|
+
}
|
|
227
|
+
if (returnType === "float" || returnType === "double") {
|
|
228
|
+
const rendered = renderExpression(expr);
|
|
229
|
+
const floatArgR = strategy.floatToSnprintfArg?.(rendered, undefined, ++scopeState.nextSnprintfTempId);
|
|
230
|
+
if (floatArgR !== undefined)
|
|
231
|
+
return floatArgR;
|
|
232
|
+
return { format: "%g", arg: rendered, estimatedLength: 8, preludeLines: [] };
|
|
233
|
+
}
|
|
234
|
+
if (returnType === "int" || returnType === "long" || returnType === "short") {
|
|
235
|
+
return { format: "%d", arg: renderExpression(expr), estimatedLength: 12, preludeLines: [] };
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
const arduinoIntFunctions = new Set([
|
|
239
|
+
"digitalRead", "analogRead", "pulseIn", "pulseInLong",
|
|
240
|
+
"Wire_available", "Serial_available",
|
|
241
|
+
]);
|
|
242
|
+
if (arduinoIntFunctions.has(funcName)) {
|
|
243
|
+
return { format: "%d", arg: renderExpression(expr), estimatedLength: 12, preludeLines: [] };
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
// Namespace-const access lowers to a raw `Ns::member` string (see
|
|
247
|
+
// expression-to-ir.ts ~line 398). Resolve the member's type from
|
|
248
|
+
// knownVariableTypes (namespace consts are registered there by bare
|
|
249
|
+
// name in setup.ts) so a namespace `const string` formats as %s with
|
|
250
|
+
// .c_str(), not the %d default (namespace stress test Finding 3b).
|
|
251
|
+
const nsConstMatch = expr.value.match(/^[A-Za-z_$][\w$]*::([A-Za-z_$][\w$]*)$/);
|
|
252
|
+
if (nsConstMatch) {
|
|
253
|
+
const memberType = scopeState.knownVariableTypes.get(nsConstMatch[1]);
|
|
254
|
+
if (memberType) {
|
|
255
|
+
const rendered = renderExpression(expr);
|
|
256
|
+
if (strategy.isStringLikeType(memberType.cppType)) {
|
|
257
|
+
const normalized = strategy.normalizeCppType(memberType.cppType);
|
|
258
|
+
const needsCStr = parsedIsStringLike(normalized);
|
|
259
|
+
return { format: "%s", arg: needsCStr ? `${rendered}.c_str()` : rendered, estimatedLength: 32, preludeLines: [] };
|
|
260
|
+
}
|
|
261
|
+
if (memberType.cppType === "bool") {
|
|
262
|
+
return { format: "%s", arg: `(${rendered} ? "true" : "false")`, estimatedLength: 5, preludeLines: [] };
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return undefined;
|
|
267
|
+
}
|
|
268
|
+
case "property-access": {
|
|
269
|
+
const rendered = renderExpression(expr);
|
|
270
|
+
if (rendered.startsWith('"')) {
|
|
271
|
+
return { format: "%s", arg: rendered, estimatedLength: Math.max(rendered.length - 2, 1), preludeLines: [] };
|
|
272
|
+
}
|
|
273
|
+
if (expr.property === "length" || expr.property === "size") {
|
|
274
|
+
return { format: "%d", arg: rendered, estimatedLength: 10, preludeLines: [] };
|
|
275
|
+
}
|
|
276
|
+
const numVal = Number(rendered);
|
|
277
|
+
if (!isNaN(numVal)) {
|
|
278
|
+
if (Number.isInteger(numVal) && (numVal > 32767 || numVal < -32768)) {
|
|
279
|
+
return { format: "%ld", arg: `${rendered}L`, estimatedLength: 12, preludeLines: [] };
|
|
280
|
+
}
|
|
281
|
+
if (!Number.isInteger(numVal)) {
|
|
282
|
+
const precision = getFloatPrecisionFromNumber(numVal);
|
|
283
|
+
const floatArg = strategy.floatToSnprintfArg?.(rendered, precision, ++scopeState.nextSnprintfTempId);
|
|
284
|
+
if (floatArg !== undefined)
|
|
285
|
+
return floatArg;
|
|
286
|
+
return {
|
|
287
|
+
format: precision !== undefined ? `%.${precision}f` : "%g",
|
|
288
|
+
arg: rendered,
|
|
289
|
+
estimatedLength: 8,
|
|
290
|
+
preludeLines: [],
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
// Namespace-const (or other registered) member access: resolve the
|
|
295
|
+
// member's type from knownVariableTypes (namespace consts are
|
|
296
|
+
// registered there by their bare name in setup.ts). Without this, a
|
|
297
|
+
// namespace `const string` used in a concat fell through to the %d
|
|
298
|
+
// default below (namespace stress test Finding 3b).
|
|
299
|
+
const nsMemberType = scopeState.knownVariableTypes.get(expr.property);
|
|
300
|
+
if (nsMemberType) {
|
|
301
|
+
const normalized = strategy.normalizeCppType(nsMemberType.cppType);
|
|
302
|
+
if (strategy.isStringLikeType(nsMemberType.cppType)) {
|
|
303
|
+
const needsCStr = parsedIsStringLike(normalized);
|
|
304
|
+
return { format: "%s", arg: needsCStr ? `${rendered}.c_str()` : rendered, estimatedLength: 32, preludeLines: [] };
|
|
305
|
+
}
|
|
306
|
+
if (nsMemberType.cppType === "bool") {
|
|
307
|
+
return { format: "%s", arg: `(${rendered} ? "true" : "false")`, estimatedLength: 5, preludeLines: [] };
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return { format: "%d", arg: rendered, estimatedLength: 12, preludeLines: [] };
|
|
311
|
+
}
|
|
312
|
+
case "binary":
|
|
313
|
+
case "unary":
|
|
314
|
+
case "ternary":
|
|
315
|
+
if (expressionInvolvesFloat(expr)) {
|
|
316
|
+
const rendered = renderExpression(expr);
|
|
317
|
+
return { format: "%g", arg: rendered, estimatedLength: 16, preludeLines: [] };
|
|
318
|
+
}
|
|
319
|
+
return { format: "%d", arg: renderExpression(expr), estimatedLength: 12, preludeLines: [] };
|
|
320
|
+
case "method-call": {
|
|
321
|
+
const rendered = renderExpression(expr);
|
|
322
|
+
if (/^__tc_(toUpperCase|toLowerCase|trim|replace|charAt|substring|slice|endsWith|toUpperCaseChar)\b/.test(rendered)) {
|
|
323
|
+
return { format: "%s", arg: rendered, estimatedLength: 32, preludeLines: [] };
|
|
324
|
+
}
|
|
325
|
+
const numVal = Number(rendered);
|
|
326
|
+
if (!isNaN(numVal) && rendered.trim() !== "") {
|
|
327
|
+
if (!Number.isInteger(numVal)) {
|
|
328
|
+
const precision = getFloatPrecisionFromNumber(numVal);
|
|
329
|
+
const floatArg = strategy.floatToSnprintfArg?.(rendered, precision, ++scopeState.nextSnprintfTempId);
|
|
330
|
+
if (floatArg !== undefined)
|
|
331
|
+
return floatArg;
|
|
332
|
+
return {
|
|
333
|
+
format: precision !== undefined ? `%.${precision}f` : "%g",
|
|
334
|
+
arg: rendered,
|
|
335
|
+
estimatedLength: 8,
|
|
336
|
+
preludeLines: [],
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
if (typeof expr.callee === "string") {
|
|
341
|
+
const methodNameMatch = expr.callee.match(/->(\w+)\(\)$/);
|
|
342
|
+
if (methodNameMatch && knownFunctionReturnTypes) {
|
|
343
|
+
const methodReturn = knownFunctionReturnTypes.get(methodNameMatch[1]);
|
|
344
|
+
if (methodReturn && strategy.isStringLikeType(methodReturn)) {
|
|
345
|
+
return { format: "%s", arg: rendered, estimatedLength: 32, preludeLines: [] };
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return { format: "%d", arg: rendered, estimatedLength: 12, preludeLines: [] };
|
|
350
|
+
}
|
|
351
|
+
case "element-access": {
|
|
352
|
+
const rendered = renderExpression(expr);
|
|
353
|
+
if (expr.elementType && strategy.isStringLikeType(expr.elementType)) {
|
|
354
|
+
return { format: "%s", arg: rendered, estimatedLength: 32, preludeLines: [] };
|
|
355
|
+
}
|
|
356
|
+
if (expr.object.kind === "identifier") {
|
|
357
|
+
const objInfo = scopeState.knownVariableTypes.get(expr.object.value);
|
|
358
|
+
if (objInfo) {
|
|
359
|
+
const elemStr = parsedElementString(objInfo.cppType);
|
|
360
|
+
if (elemStr && strategy.isStringLikeType(elemStr)) {
|
|
361
|
+
return { format: "%s", arg: rendered, estimatedLength: 32, preludeLines: [] };
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return { format: "%d", arg: rendered, estimatedLength: 12, preludeLines: [] };
|
|
366
|
+
}
|
|
367
|
+
case "hal-expr": {
|
|
368
|
+
const rendered = renderExpression(expr);
|
|
369
|
+
if (rendered.startsWith('"') || stringVarNames?.has(rendered)) {
|
|
370
|
+
return { format: "%s", arg: rendered, estimatedLength: 32, preludeLines: [] };
|
|
371
|
+
}
|
|
372
|
+
return { format: "%d", arg: rendered, estimatedLength: 12, preludeLines: [] };
|
|
373
|
+
}
|
|
374
|
+
default:
|
|
375
|
+
return undefined;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
// ---------------------------------------------------------------------------
|
|
379
|
+
// Snprintf render result builder
|
|
380
|
+
// ---------------------------------------------------------------------------
|
|
381
|
+
export function buildSnprintfRenderResult(expr, strategy, scopeState, renderExpression, pointerVarTypes, knownFunctionReturnTypes, stringVarNames) {
|
|
382
|
+
if (expr.kind !== "string_concat") {
|
|
383
|
+
return undefined;
|
|
384
|
+
}
|
|
385
|
+
let formatString = "";
|
|
386
|
+
const args = [];
|
|
387
|
+
let estimatedLength = 1;
|
|
388
|
+
const preludeLines = [];
|
|
389
|
+
for (const part of expr.parts) {
|
|
390
|
+
if (part.kind === "string") {
|
|
391
|
+
// These literal parts are concatenated into the snprintf *format* string,
|
|
392
|
+
// so any embedded `%` must be doubled or snprintf misreads it on hardware.
|
|
393
|
+
formatString += escapeSnprintfFormatFragment(part.value);
|
|
394
|
+
estimatedLength += part.value.length;
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
397
|
+
const innerExpr = part.kind === "template_string" ? part.expression : part;
|
|
398
|
+
const arg = inferSnprintfArg(innerExpr, strategy, scopeState, renderExpression, pointerVarTypes, knownFunctionReturnTypes, stringVarNames);
|
|
399
|
+
if (!arg) {
|
|
400
|
+
return undefined;
|
|
401
|
+
}
|
|
402
|
+
formatString += arg.format;
|
|
403
|
+
args.push(arg.arg);
|
|
404
|
+
estimatedLength += arg.estimatedLength;
|
|
405
|
+
preludeLines.push(...arg.preludeLines);
|
|
406
|
+
}
|
|
407
|
+
return { formatString, args, estimatedLength: Math.max(estimatedLength, 16), preludeLines };
|
|
408
|
+
}
|
|
409
|
+
// ---------------------------------------------------------------------------
|
|
410
|
+
// Snprintf usage detection
|
|
411
|
+
// ---------------------------------------------------------------------------
|
|
412
|
+
export function shouldUseSnprintfForString(statement, strategy) {
|
|
413
|
+
if (!strategy.useSnprintfForStrings()) {
|
|
414
|
+
return false;
|
|
415
|
+
}
|
|
416
|
+
const value = statement.kind === "var_decl" ? statement.initializer : statement.value;
|
|
417
|
+
return value?.kind === "string_concat";
|
|
418
|
+
}
|
|
419
|
+
export function statementNeedsSnprintf(statement, strategy) {
|
|
420
|
+
if (!strategy.useSnprintfForStrings()) {
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
423
|
+
if (statement.kind === "var_decl" && statement.initializer?.kind === "string_concat") {
|
|
424
|
+
return true;
|
|
425
|
+
}
|
|
426
|
+
if (statement.kind === "assign" && statement.value?.kind === "string_concat") {
|
|
427
|
+
return true;
|
|
428
|
+
}
|
|
429
|
+
if (statement.kind === "call" && statement.args.length > 0) {
|
|
430
|
+
// __EMIT__ calls resolve their args inline as raw C++ text — they never
|
|
431
|
+
// use snprintf, even when the arg is a string_concat from a template literal.
|
|
432
|
+
if (statement.callee === "__EMIT__")
|
|
433
|
+
return false;
|
|
434
|
+
if (statement.args.some((arg) => arg.kind === "string_concat" || arg.kind === "template_string")) {
|
|
435
|
+
return true;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
if (statement.kind === "return" && statement.value?.kind === "string_concat") {
|
|
439
|
+
return true;
|
|
440
|
+
}
|
|
441
|
+
switch (statement.kind) {
|
|
442
|
+
case "while":
|
|
443
|
+
case "for":
|
|
444
|
+
case "for_of":
|
|
445
|
+
case "for_in":
|
|
446
|
+
case "do_while":
|
|
447
|
+
case "block":
|
|
448
|
+
case "labeled":
|
|
449
|
+
return statement.body.some((nested) => statementNeedsSnprintf(nested, strategy));
|
|
450
|
+
case "if":
|
|
451
|
+
return statement.thenBranch.some((nested) => statementNeedsSnprintf(nested, strategy)) ||
|
|
452
|
+
(statement.elseBranch?.some((nested) => statementNeedsSnprintf(nested, strategy)) ?? false);
|
|
453
|
+
case "switch":
|
|
454
|
+
return statement.cases.some((caseClause) => caseClause.body.some((nested) => statementNeedsSnprintf(nested, strategy)));
|
|
455
|
+
case "try":
|
|
456
|
+
return statement.tryBlock.some((nested) => statementNeedsSnprintf(nested, strategy)) ||
|
|
457
|
+
(statement.catchBlock?.some((nested) => statementNeedsSnprintf(nested, strategy)) ?? false) ||
|
|
458
|
+
(statement.finallyBlock?.some((nested) => statementNeedsSnprintf(nested, strategy)) ?? false);
|
|
459
|
+
default:
|
|
460
|
+
return false;
|
|
461
|
+
}
|
|
462
|
+
}
|