@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,244 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Shared Promise runtime C++ code generator
|
|
3
|
+
//
|
|
4
|
+
// Generates a cooperative microtask queue + minimal Promise<T> runtime
|
|
5
|
+
// for embedded C++ targets. Used by both the generic transpiler strategy
|
|
6
|
+
// and the Arduino framework strategy.
|
|
7
|
+
//
|
|
8
|
+
// Functions named __typecad_async_* and __cuttlefish_wait_pin_edge are the
|
|
9
|
+
// runtime implementations that the HAL Async module's emit() calls resolve to.
|
|
10
|
+
// They are defined inside the typecad_async namespace (to see Promise<T> and
|
|
11
|
+
// enqueueMicrotask), and also have unscoped global aliases so the emitted
|
|
12
|
+
// C++ code can call them directly.
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
/**
|
|
15
|
+
* Generate the cooperative microtask queue + minimal Promise runtime for C++.
|
|
16
|
+
*
|
|
17
|
+
* @param queueCapacity Maximum number of pending microtasks in the queue.
|
|
18
|
+
* Use a smaller value (e.g. 32) for memory-constrained targets like AVR,
|
|
19
|
+
* and a larger value (e.g. 256) for targets with more RAM.
|
|
20
|
+
* @param includeWaitForPinEdge Whether to include the `waitForPinEdge` stub
|
|
21
|
+
* (used by Arduino targets).
|
|
22
|
+
*/
|
|
23
|
+
export function generatePromiseRuntime(queueCapacity, includeWaitForPinEdge = false) {
|
|
24
|
+
const waitForPinEdge = includeWaitForPinEdge ? `
|
|
25
|
+
// HAL-level wait for pin edge — polling-based implementation.
|
|
26
|
+
// Detects an actual transition (idle→target), not just the current level.
|
|
27
|
+
// Uses a two-phase approach: phase 1 waits for the idle level, phase 2 waits
|
|
28
|
+
// for the target level (the edge). Each phase re-enqueues on the microtask
|
|
29
|
+
// queue so other tasks can run between polls.
|
|
30
|
+
inline Promise<void> __cuttlefish_wait_pin_edge(int pin, int mode, long timeout) {
|
|
31
|
+
return Promise<void>([pin, mode, timeout](std::function<void(const void*)> resolve, std::function<void(const std::string&)> reject) {
|
|
32
|
+
int targetState = (mode == RISING) ? HIGH : LOW;
|
|
33
|
+
int idleState = (mode == RISING) ? LOW : HIGH;
|
|
34
|
+
unsigned long start = millis();
|
|
35
|
+
// Phase 2 poller: waits for the pin to reach the target state (the edge).
|
|
36
|
+
auto pollTarget = [pin, targetState, timeout, start, resolve]() {
|
|
37
|
+
if (digitalRead(pin) == targetState) {
|
|
38
|
+
resolve(nullptr);
|
|
39
|
+
} else if (timeout >= 0 && (millis() - start >= (unsigned long)timeout)) {
|
|
40
|
+
resolve(nullptr);
|
|
41
|
+
} else {
|
|
42
|
+
enqueueMicrotask([pin, targetState, timeout, start, resolve]() {
|
|
43
|
+
if (digitalRead(pin) == targetState) {
|
|
44
|
+
resolve(nullptr);
|
|
45
|
+
} else if (timeout >= 0 && (millis() - start >= (unsigned long)timeout)) {
|
|
46
|
+
resolve(nullptr);
|
|
47
|
+
} else {
|
|
48
|
+
enqueueMicrotask([pin, targetState, timeout, start, resolve]() {});
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
// Phase 1: wait for idle state before watching for the edge.
|
|
54
|
+
enqueueMicrotask([pin, idleState, timeout, start, resolve, pollTarget]() {
|
|
55
|
+
if (digitalRead(pin) == idleState) {
|
|
56
|
+
pollTarget();
|
|
57
|
+
} else if (timeout >= 0 && (millis() - start >= (unsigned long)timeout)) {
|
|
58
|
+
resolve(nullptr);
|
|
59
|
+
} else {
|
|
60
|
+
enqueueMicrotask([pin, idleState, timeout, start, resolve, pollTarget]() {});
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
` : "";
|
|
66
|
+
return `
|
|
67
|
+
// Cooperative microtask queue + minimal Promise runtime
|
|
68
|
+
namespace typecad_async {
|
|
69
|
+
using Microtask = std::function<void()>;
|
|
70
|
+
|
|
71
|
+
class MicrotaskQueue {
|
|
72
|
+
public:
|
|
73
|
+
static MicrotaskQueue& instance() {
|
|
74
|
+
static MicrotaskQueue queue;
|
|
75
|
+
return queue;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
bool enqueue(Microtask task) {
|
|
79
|
+
if (_queue.size() >= ${queueCapacity}) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
_queue.push_back(std::move(task));
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
void pump() {
|
|
87
|
+
const size_t total = _queue.size();
|
|
88
|
+
for (size_t i = 0; i < total; ++i) {
|
|
89
|
+
Microtask task = std::move(_queue[i]);
|
|
90
|
+
task();
|
|
91
|
+
}
|
|
92
|
+
if (total > 0) {
|
|
93
|
+
_queue.erase(_queue.begin(), _queue.begin() + static_cast<long long>(total));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private:
|
|
98
|
+
std::vector<Microtask> _queue;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
inline void enqueueMicrotask(Microtask task) {
|
|
102
|
+
MicrotaskQueue::instance().enqueue(std::move(task));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
inline void pumpMicrotasks() {
|
|
106
|
+
MicrotaskQueue::instance().pump();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
template <typename T>
|
|
110
|
+
class Promise {
|
|
111
|
+
public:
|
|
112
|
+
enum class State { Pending, Fulfilled, Rejected };
|
|
113
|
+
|
|
114
|
+
Promise() : _state(State::Pending), _value{}, _error{} {}
|
|
115
|
+
|
|
116
|
+
explicit Promise(std::function<void(std::function<void(const T&)>, std::function<void(const std::string&)>)> executor)
|
|
117
|
+
: _state(State::Pending), _value{}, _error{} {
|
|
118
|
+
executor(
|
|
119
|
+
[this](const T& value) { this->resolve(value); },
|
|
120
|
+
[this](const std::string& error) { this->reject(error); }
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
static Promise<T> resolveValue(const T& value) {
|
|
125
|
+
Promise<T> promise;
|
|
126
|
+
promise.resolve(value);
|
|
127
|
+
return promise;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
static Promise<T> rejectValue(const std::string& error) {
|
|
131
|
+
Promise<T> promise;
|
|
132
|
+
promise.reject(error);
|
|
133
|
+
return promise;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
void resolve(const T& value) {
|
|
137
|
+
if (_state != State::Pending) return;
|
|
138
|
+
_state = State::Fulfilled;
|
|
139
|
+
_value = value;
|
|
140
|
+
auto callbacks = _onFulfilled;
|
|
141
|
+
enqueueMicrotask([callbacks, value]() mutable {
|
|
142
|
+
for (auto& callback : callbacks) { callback(value); }
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
void reject(const std::string& error) {
|
|
147
|
+
if (_state != State::Pending) return;
|
|
148
|
+
_state = State::Rejected;
|
|
149
|
+
_error = error;
|
|
150
|
+
auto callbacks = _onRejected;
|
|
151
|
+
enqueueMicrotask([callbacks, error]() mutable {
|
|
152
|
+
for (auto& callback : callbacks) { callback(error); }
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
Promise<T>& then(std::function<void(const T&)> onFulfilled) {
|
|
157
|
+
if (_state == State::Fulfilled) {
|
|
158
|
+
const T value = _value;
|
|
159
|
+
enqueueMicrotask([onFulfilled, value]() mutable { onFulfilled(value); });
|
|
160
|
+
} else if (_state == State::Pending) {
|
|
161
|
+
_onFulfilled.push_back(std::move(onFulfilled));
|
|
162
|
+
}
|
|
163
|
+
return *this;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
Promise<T>& catchError(std::function<void(const std::string&)> onRejected) {
|
|
167
|
+
if (_state == State::Rejected) {
|
|
168
|
+
const std::string error = _error;
|
|
169
|
+
enqueueMicrotask([onRejected, error]() mutable { onRejected(error); });
|
|
170
|
+
} else if (_state == State::Pending) {
|
|
171
|
+
_onRejected.push_back(std::move(onRejected));
|
|
172
|
+
}
|
|
173
|
+
return *this;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private:
|
|
177
|
+
State _state;
|
|
178
|
+
T _value;
|
|
179
|
+
std::string _error;
|
|
180
|
+
std::vector<std::function<void(const T&)>> _onFulfilled;
|
|
181
|
+
std::vector<std::function<void(const std::string&)>> _onRejected;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// ── HAL-level implementations (inside namespace so they see Promise<T> and enqueueMicrotask) ──
|
|
185
|
+
|
|
186
|
+
// Async.sleep() — cooperative delay using millis polling
|
|
187
|
+
inline Promise<void> __cuttlefish_async_sleep(unsigned long ms) {
|
|
188
|
+
return Promise<void>([ms](std::function<void(const void*)> resolve, std::function<void(const std::string&)> reject) {
|
|
189
|
+
unsigned long start = millis();
|
|
190
|
+
if (millis() - start >= ms) {
|
|
191
|
+
resolve(nullptr);
|
|
192
|
+
} else {
|
|
193
|
+
enqueueMicrotask([ms, start, resolve]() {
|
|
194
|
+
if (millis() - start >= ms) {
|
|
195
|
+
resolve(nullptr);
|
|
196
|
+
} else {
|
|
197
|
+
enqueueMicrotask([ms, start, resolve]() { /* will be re-checked next cycle */ });
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Async.yield() — defer to next microtask pump cycle
|
|
205
|
+
inline Promise<void> __cuttlefish_async_yield() {
|
|
206
|
+
return Promise<void>([](std::function<void(const void*)> resolve, std::function<void(const std::string&)> reject) {
|
|
207
|
+
enqueueMicrotask([resolve]() { resolve(nullptr); });
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Async.sleepUntil() — poll condition every interval ms
|
|
212
|
+
inline Promise<void> __cuttlefish_async_sleep_until(unsigned long pollIntervalMs) {
|
|
213
|
+
return Promise<void>([pollIntervalMs](std::function<void(const void*)> resolve, std::function<void(const std::string&)> reject) {
|
|
214
|
+
unsigned long start = millis();
|
|
215
|
+
enqueueMicrotask([pollIntervalMs, start, resolve]() {
|
|
216
|
+
if (millis() - start >= pollIntervalMs) {
|
|
217
|
+
resolve(nullptr); // caller re-checks condition
|
|
218
|
+
} else {
|
|
219
|
+
enqueueMicrotask([pollIntervalMs, start, resolve]() { /* re-check next cycle */ });
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Async.currentTask() — return task description string
|
|
226
|
+
inline const char* __cuttlefish_async_current_task() {
|
|
227
|
+
return "main";
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
${waitForPinEdge}
|
|
231
|
+
} // namespace typecad_async
|
|
232
|
+
|
|
233
|
+
// ── Global-scope aliases so HAL emit() calls resolve ──
|
|
234
|
+
using typecad_async::__cuttlefish_async_sleep;
|
|
235
|
+
using typecad_async::__cuttlefish_async_yield;
|
|
236
|
+
using typecad_async::__cuttlefish_async_sleep_until;
|
|
237
|
+
using typecad_async::__cuttlefish_async_current_task;
|
|
238
|
+
${includeWaitForPinEdge ? `using typecad_async::__cuttlefish_wait_pin_edge;` : ``}
|
|
239
|
+
|
|
240
|
+
inline void cuttlefish_pump_microtasks() {
|
|
241
|
+
typecad_async::pumpMicrotasks();
|
|
242
|
+
}
|
|
243
|
+
`;
|
|
244
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface KnownVariableInfo {
|
|
2
|
+
cppType: string;
|
|
3
|
+
floatPrecision?: number;
|
|
4
|
+
/**
|
|
5
|
+
* The initializer expression for `auto`-deduced locals, retained so the
|
|
6
|
+
* snprintf specifier picker can infer the real C++ type (e.g. resolve
|
|
7
|
+
* `const name = loot.name` to `std::string` even though the decl emits as
|
|
8
|
+
* `auto`). Undefined for explicitly-typed decls and parameters.
|
|
9
|
+
*/
|
|
10
|
+
initializer?: import('./ir-core.js').ExpressionIR;
|
|
11
|
+
}
|
|
12
|
+
export interface SnprintfArgRenderResult {
|
|
13
|
+
format: string;
|
|
14
|
+
arg: string;
|
|
15
|
+
estimatedLength: number;
|
|
16
|
+
preludeLines: string[];
|
|
17
|
+
}
|
|
18
|
+
export interface SnprintfRenderResult {
|
|
19
|
+
formatString: string;
|
|
20
|
+
args: string[];
|
|
21
|
+
estimatedLength: number;
|
|
22
|
+
preludeLines: string[];
|
|
23
|
+
}
|
|
24
|
+
export interface EmissionScopeState {
|
|
25
|
+
readonly knownVariableTypes: Map<string, KnownVariableInfo>;
|
|
26
|
+
readonly snprintfBuffers: Set<string>;
|
|
27
|
+
nextSnprintfTempId: number;
|
|
28
|
+
}
|
|
29
|
+
export type SnprintfExpressionRenderer = (expr: import('./ir-core.js').ExpressionIR) => string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Snprintf types for emission scope state and render results
|
|
3
|
+
//
|
|
4
|
+
// These types describe the data structures used by the snprintf-based
|
|
5
|
+
// template literal lowering system. Defined here so both CLI and framework
|
|
6
|
+
// packages can reference them without a circular dependency.
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Argument shape for a string method, determining how the call is rewritten.
|
|
3
|
+
* - `receiverOnly`: no args, e.g. `s.toUpperCase()`
|
|
4
|
+
* - `unary`: one arg, e.g. `s.charAt(2)`
|
|
5
|
+
* - `binary`: two args, e.g. `s.substring(0, 2)`
|
|
6
|
+
* - `unaryDefault`: one-arg form that has a default (e.g. padStart),
|
|
7
|
+
* emitted via a `_default` helper variant
|
|
8
|
+
*/
|
|
9
|
+
export type StringMethodArgForm = "receiverOnly" | "unary" | "binary" | "unaryDefault";
|
|
10
|
+
export interface StringMethodSpec {
|
|
11
|
+
/** The exact `__tc_*` helper name emitted for this form (e.g. `__tc_substring2`). */
|
|
12
|
+
helper: string;
|
|
13
|
+
argForm: StringMethodArgForm;
|
|
14
|
+
/**
|
|
15
|
+
* The JS method name this spec lowers. Defaults to the helper name with the
|
|
16
|
+
* `__tc_` prefix and any trailing arity suffix (`1`/`2`) stripped.
|
|
17
|
+
*/
|
|
18
|
+
methodName?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Ordered table of JS string methods → `__tc_*` lowering specs.
|
|
22
|
+
* Order matters: 2-arg (binary) forms MUST precede their 1-arg (unary)
|
|
23
|
+
* counterparts so that `substring(0, 2)` isn't partially matched by the
|
|
24
|
+
* 1-arg rule first. Each spec names the EXACT helper for its arity.
|
|
25
|
+
*/
|
|
26
|
+
export declare const STRING_METHODS: StringMethodSpec[];
|
|
27
|
+
/**
|
|
28
|
+
* The set of JS string-method names this registry knows how to lower.
|
|
29
|
+
* Used by program analysis to detect which polyfill helpers are needed.
|
|
30
|
+
*/
|
|
31
|
+
export declare const STRING_METHOD_NAMES: ReadonlySet<string>;
|
|
32
|
+
/**
|
|
33
|
+
* Apply all string-method rewrites to a raw C++ expression string.
|
|
34
|
+
*
|
|
35
|
+
* This is the shared lowering that both the native and Arduino strategies
|
|
36
|
+
* call from their `normalizeRawExpression()`. Each strategy may perform
|
|
37
|
+
* additional platform-specific rewrites (pin modes, HAL, etc.) before/after.
|
|
38
|
+
*
|
|
39
|
+
* The `options.receiverWrapper` lets a strategy wrap the receiver when it
|
|
40
|
+
* becomes a helper argument — e.g. Arduino wraps `indexOf` receivers in
|
|
41
|
+
* `__tc_str_ptr(...)`. Methods listed in `options.special` are replaced
|
|
42
|
+
* entirely (Arduino uses `strstr`/`strncmp` for `includes`/`startsWith`).
|
|
43
|
+
*/
|
|
44
|
+
export declare function applyStringMethodRewrites(value: string, options?: {
|
|
45
|
+
/** Methods whose helper the receiver should be wrapped in (e.g. indexOf → __tc_str_ptr). */
|
|
46
|
+
wrapReceiverFor?: ReadonlySet<string>;
|
|
47
|
+
/**
|
|
48
|
+
* Per-method custom rewrites that bypass the standard helper form.
|
|
49
|
+
* Keyed by JS method name → function(receiver, args[]) returning the
|
|
50
|
+
* replacement string, or undefined to fall back to the standard form.
|
|
51
|
+
*/
|
|
52
|
+
special?: Record<string, (receiver: string, args: string[]) => string | undefined>;
|
|
53
|
+
}): string;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Shared string-method lowering registry
|
|
3
|
+
//
|
|
4
|
+
// Single source of truth for rewriting JS string method calls
|
|
5
|
+
// (`s.toUpperCase()`, `s.substring(0, 2)`, …) into the `__tc_*` C++ helper
|
|
6
|
+
// calls that both the native and Arduino/AVR strategies emit.
|
|
7
|
+
//
|
|
8
|
+
// Both platform strategies previously maintained their own (drifting) regex
|
|
9
|
+
// tables inside normalizeRawExpression(). The native table additionally had a
|
|
10
|
+
// latent bug: its receiver-capture group `R` used nested capturing groups,
|
|
11
|
+
// which shifted the backreferences and caused methods like substring/slice/
|
|
12
|
+
// charCodeAt to emit the receiver twice and drop an argument
|
|
13
|
+
// (e.g. `frame.substring(0, 2)` → `__tc_substring2(frame, frame, 0)`).
|
|
14
|
+
//
|
|
15
|
+
// This module centralises the lowering with a receiver pattern that captures
|
|
16
|
+
// the receiver as a single group, fixing that bug for every target.
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
/**
|
|
19
|
+
* Derive the JS method name from a helper name: strip `__tc_`, then strip a
|
|
20
|
+
* trailing `_default` or arity digit (so `__tc_substring2` → `substring`,
|
|
21
|
+
* `__tc_padStart_default` → `padStart`).
|
|
22
|
+
*/
|
|
23
|
+
function methodNameFromHelper(helper) {
|
|
24
|
+
return helper.replace(/^__tc_/, "").replace(/_default$/, "").replace(/\d+$/, "");
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Ordered table of JS string methods → `__tc_*` lowering specs.
|
|
28
|
+
* Order matters: 2-arg (binary) forms MUST precede their 1-arg (unary)
|
|
29
|
+
* counterparts so that `substring(0, 2)` isn't partially matched by the
|
|
30
|
+
* 1-arg rule first. Each spec names the EXACT helper for its arity.
|
|
31
|
+
*/
|
|
32
|
+
export const STRING_METHODS = [
|
|
33
|
+
// ── No-arg methods (receiver only) ───────────────────────────────────────
|
|
34
|
+
{ helper: "__tc_toUpperCase", argForm: "receiverOnly" },
|
|
35
|
+
{ helper: "__tc_toLowerCase", argForm: "receiverOnly" },
|
|
36
|
+
{ helper: "__tc_trim", argForm: "receiverOnly" },
|
|
37
|
+
// ── Two-arg methods (must precede 1-arg forms) ───────────────────────────
|
|
38
|
+
{ helper: "__tc_substring2", argForm: "binary" },
|
|
39
|
+
{ helper: "__tc_slice2", argForm: "binary" },
|
|
40
|
+
{ helper: "__tc_padStart", argForm: "binary" },
|
|
41
|
+
{ helper: "__tc_padEnd", argForm: "binary" },
|
|
42
|
+
{ helper: "__tc_replace", argForm: "binary" },
|
|
43
|
+
// ── One-arg methods ──────────────────────────────────────────────────────
|
|
44
|
+
{ helper: "__tc_substring1", argForm: "unary" },
|
|
45
|
+
{ helper: "__tc_slice1", argForm: "unary" },
|
|
46
|
+
{ helper: "__tc_padStart_default", argForm: "unaryDefault" },
|
|
47
|
+
{ helper: "__tc_padEnd_default", argForm: "unaryDefault" },
|
|
48
|
+
{ helper: "__tc_charAt", argForm: "unary" },
|
|
49
|
+
{ helper: "__tc_charCodeAt", argForm: "unary" },
|
|
50
|
+
{ helper: "__tc_endsWith", argForm: "unary" },
|
|
51
|
+
{ helper: "__tc_startsWith", argForm: "unary" },
|
|
52
|
+
{ helper: "__tc_includes", argForm: "unary" },
|
|
53
|
+
{ helper: "__tc_indexOf", argForm: "unary" },
|
|
54
|
+
{ helper: "__tc_lastIndexOf", argForm: "unary" },
|
|
55
|
+
{ helper: "__tc_repeat", argForm: "unary" },
|
|
56
|
+
{ helper: "__tc_split", argForm: "unary" },
|
|
57
|
+
// NOTE: `__tc_join` is intentionally NOT in this table. `.join(sep)` is a
|
|
58
|
+
// std::VECTOR method (it returns a std::string built from the vector's
|
|
59
|
+
// elements), NOT a std::string method. Listing it here previously caused
|
|
60
|
+
// `parts.join(' ')` on a `mutableArrayVars` receiver (a string[] built via
|
|
61
|
+
// .push) to fall through BOTH lowering paths: `shouldLowerAsStringMethod`
|
|
62
|
+
// returns false for a known array (correct), and the vector-method table
|
|
63
|
+
// `VECTOR_VALUE_METHOD_LOWERINGS` had no `join` entry, so the call was
|
|
64
|
+
// emitted verbatim (`parts.join(" ")`) and g++ rejected it ("no member
|
|
65
|
+
// named 'join'"). `join` is now lowered in the VECTOR path
|
|
66
|
+
// (ir/transformers/array-methods.ts), and the polyfill helper is still
|
|
67
|
+
// registered via POLYFILL_HELPER_MAP['.join(']. Demo #31 Finding B.
|
|
68
|
+
];
|
|
69
|
+
/** JS method name → spec (for the names set). */
|
|
70
|
+
const STRING_METHOD_BY_NAME = new Map();
|
|
71
|
+
for (const spec of STRING_METHODS) {
|
|
72
|
+
const name = spec.methodName ?? methodNameFromHelper(spec.helper);
|
|
73
|
+
STRING_METHOD_BY_NAME.set(name, spec);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The set of JS string-method names this registry knows how to lower.
|
|
77
|
+
* Used by program analysis to detect which polyfill helpers are needed.
|
|
78
|
+
*/
|
|
79
|
+
export const STRING_METHOD_NAMES = new Set(STRING_METHOD_BY_NAME.keys());
|
|
80
|
+
/**
|
|
81
|
+
* Receiver-capture pattern shared across targets. Captures the receiver as
|
|
82
|
+
* group 1 (the ONLY group before the method arguments), so backreferences for
|
|
83
|
+
* arguments always start at $2.
|
|
84
|
+
*
|
|
85
|
+
* The outer group is CAPTURING (so it is $1); the inner alternation between
|
|
86
|
+
* `std::string(...)` and identifier-chains is NON-capturing so it does not
|
|
87
|
+
* shift the group numbering. (The old native `R` pattern used a nested
|
|
88
|
+
* capturing alternation, which shifted backreferences and caused the
|
|
89
|
+
* receiver to be emitted twice — the substring/slice/charCodeAt bug.)
|
|
90
|
+
*
|
|
91
|
+
* Matches:
|
|
92
|
+
* - `std::string(...)` constructor calls, or
|
|
93
|
+
* - an identifier optionally followed by `.member` chains.
|
|
94
|
+
*/
|
|
95
|
+
const RECEIVER_PATTERN = "((?:std::string\\([^)]*\\)|(?:[A-Za-z_]\\w*(?:\\.[A-Za-z_]\\w*)*)))";
|
|
96
|
+
/**
|
|
97
|
+
* Apply all string-method rewrites to a raw C++ expression string.
|
|
98
|
+
*
|
|
99
|
+
* This is the shared lowering that both the native and Arduino strategies
|
|
100
|
+
* call from their `normalizeRawExpression()`. Each strategy may perform
|
|
101
|
+
* additional platform-specific rewrites (pin modes, HAL, etc.) before/after.
|
|
102
|
+
*
|
|
103
|
+
* The `options.receiverWrapper` lets a strategy wrap the receiver when it
|
|
104
|
+
* becomes a helper argument — e.g. Arduino wraps `indexOf` receivers in
|
|
105
|
+
* `__tc_str_ptr(...)`. Methods listed in `options.special` are replaced
|
|
106
|
+
* entirely (Arduino uses `strstr`/`strncmp` for `includes`/`startsWith`).
|
|
107
|
+
*/
|
|
108
|
+
export function applyStringMethodRewrites(value, options = {}) {
|
|
109
|
+
const wrapReceiverFor = options.wrapReceiverFor ?? new Set();
|
|
110
|
+
const special = options.special ?? {};
|
|
111
|
+
let v = value;
|
|
112
|
+
let prev = "";
|
|
113
|
+
// Loop because one rewrite can expose another (e.g. chained calls). Bound
|
|
114
|
+
// to avoid infinite loops: each pass either changes the string or stops.
|
|
115
|
+
let guard = 0;
|
|
116
|
+
while (prev !== v && guard < 8) {
|
|
117
|
+
prev = v;
|
|
118
|
+
guard++;
|
|
119
|
+
for (const spec of STRING_METHODS) {
|
|
120
|
+
const name = spec.methodName ?? methodNameFromHelper(spec.helper);
|
|
121
|
+
v = rewriteMethod(v, name, spec, wrapReceiverFor, special);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return v;
|
|
125
|
+
}
|
|
126
|
+
/** Rewrite a single method name according to its spec. */
|
|
127
|
+
function rewriteMethod(v, name, spec, wrapReceiverFor, special) {
|
|
128
|
+
const R = RECEIVER_PATTERN;
|
|
129
|
+
const wrap = (recv) => wrapReceiverFor.has(name) ? `__tc_str_ptr(${recv})` : recv;
|
|
130
|
+
if (spec.argForm === "receiverOnly") {
|
|
131
|
+
// s.name() → __tc_name(s)
|
|
132
|
+
const re = new RegExp(`${R}\\.${escapeRegex(name)}\\(\\)`, "g");
|
|
133
|
+
v = v.replace(re, (_m, receiver) => {
|
|
134
|
+
const custom = special[name]?.(receiver, []);
|
|
135
|
+
return custom ?? `${spec.helper}(${wrap(receiver)})`;
|
|
136
|
+
});
|
|
137
|
+
return v;
|
|
138
|
+
}
|
|
139
|
+
if (spec.argForm === "unary") {
|
|
140
|
+
// s.name(arg) → __tc_name(s, arg)
|
|
141
|
+
const re = new RegExp(`${R}\\.${escapeRegex(name)}\\(([^)]+)\\)`, "g");
|
|
142
|
+
v = v.replace(re, (_m, receiver, arg) => {
|
|
143
|
+
const custom = special[name]?.(receiver, [arg]);
|
|
144
|
+
return custom ?? `${spec.helper}(${wrap(receiver)}, ${arg})`;
|
|
145
|
+
});
|
|
146
|
+
return v;
|
|
147
|
+
}
|
|
148
|
+
if (spec.argForm === "binary") {
|
|
149
|
+
// s.name(a, b) → __tc_nameN(s, a, b). The helper name carries the arity
|
|
150
|
+
// suffix already (e.g. __tc_substring2, __tc_slice2).
|
|
151
|
+
const re = new RegExp(`${R}\\.${escapeRegex(name)}\\(([^,]+),\\s*([^)]+)\\)`, "g");
|
|
152
|
+
v = v.replace(re, (_m, receiver, a, b) => {
|
|
153
|
+
const custom = special[name]?.(receiver, [a, b]);
|
|
154
|
+
return custom ?? `${spec.helper}(${wrap(receiver)}, ${a}, ${b})`;
|
|
155
|
+
});
|
|
156
|
+
return v;
|
|
157
|
+
}
|
|
158
|
+
// unaryDefault: s.name(arg) → __tc_name_default(s, arg)
|
|
159
|
+
const re = new RegExp(`${R}\\.${escapeRegex(name)}\\(([^)]+)\\)`, "g");
|
|
160
|
+
v = v.replace(re, (_m, receiver, arg) => {
|
|
161
|
+
const custom = special[name]?.(receiver, [arg]);
|
|
162
|
+
return custom ?? `${spec.helper}(${wrap(receiver)}, ${arg})`;
|
|
163
|
+
});
|
|
164
|
+
return v;
|
|
165
|
+
}
|
|
166
|
+
function escapeRegex(s) {
|
|
167
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
168
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compile error structure
|
|
3
|
+
*/
|
|
4
|
+
export interface CompileError {
|
|
5
|
+
filePath: string;
|
|
6
|
+
line: number;
|
|
7
|
+
column: number;
|
|
8
|
+
severity: "error" | "warning" | "note";
|
|
9
|
+
message: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Memory usage details
|
|
13
|
+
*/
|
|
14
|
+
export interface MemoryUsage {
|
|
15
|
+
flashUsed?: number;
|
|
16
|
+
flashTotal?: number;
|
|
17
|
+
ramUsed?: number;
|
|
18
|
+
ramTotal?: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Generic compile options bag. Each framework reads what it needs
|
|
22
|
+
* and ignores the rest. The CLI populates whichever fields are
|
|
23
|
+
* available from CLI flags and config.
|
|
24
|
+
*/
|
|
25
|
+
export interface ToolchainOptions {
|
|
26
|
+
outputDir: string;
|
|
27
|
+
sourcePath: string;
|
|
28
|
+
buildTarget?: string;
|
|
29
|
+
port?: string;
|
|
30
|
+
baud?: number;
|
|
31
|
+
optimize?: string;
|
|
32
|
+
extraFlags?: string[];
|
|
33
|
+
defines?: Record<string, string>;
|
|
34
|
+
/**
|
|
35
|
+
* Framework-specific config from `cuttlefish.config.ts`.
|
|
36
|
+
* Each framework casts this to its own typed interface.
|
|
37
|
+
*/
|
|
38
|
+
frameworkConfig?: Record<string, unknown>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Generic compile result. All frameworks return this shape.
|
|
42
|
+
*/
|
|
43
|
+
export interface CompileResult {
|
|
44
|
+
success: boolean;
|
|
45
|
+
output: string;
|
|
46
|
+
errors: CompileError[];
|
|
47
|
+
memoryUsage?: MemoryUsage;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Generic upload result. All frameworks return this shape.
|
|
51
|
+
*/
|
|
52
|
+
export interface UploadResult {
|
|
53
|
+
success: boolean;
|
|
54
|
+
output: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Parse compile errors from output (GCC and Clang formats)
|
|
58
|
+
*/
|
|
59
|
+
export declare function parseCompileErrors(output: string, sketchDir?: string): CompileError[];
|
|
60
|
+
/**
|
|
61
|
+
* Collect all .cpp files in a directory (non-recursive).
|
|
62
|
+
*/
|
|
63
|
+
export declare function collectCppFiles(rootDir: string): string[];
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Shared toolchain types and utilities
|
|
3
|
+
//
|
|
4
|
+
// Compile error types, parsing utilities, and file collection helpers
|
|
5
|
+
// shared across toolchain implementations.
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
import fs from "node:fs";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
/**
|
|
10
|
+
* GCC-style error regex
|
|
11
|
+
*/
|
|
12
|
+
const GCC_STYLE = /^(.*?):(\d+):(\d+):\s*(fatal error|error|warning|note):\s*(.*)$/i;
|
|
13
|
+
/**
|
|
14
|
+
* Clang-style error regex
|
|
15
|
+
*/
|
|
16
|
+
const CLANG_ERROR = /^(.*?):(\d+):(\d+):\s*(error|warning|note):\s*(.*)$/i;
|
|
17
|
+
/**
|
|
18
|
+
* Parse compile errors from output (GCC and Clang formats)
|
|
19
|
+
*/
|
|
20
|
+
export function parseCompileErrors(output, sketchDir) {
|
|
21
|
+
const errors = [];
|
|
22
|
+
for (const rawLine of output.split(/\r?\n/)) {
|
|
23
|
+
const line = rawLine.trim();
|
|
24
|
+
if (!line)
|
|
25
|
+
continue;
|
|
26
|
+
let match = line.match(GCC_STYLE);
|
|
27
|
+
if (!match) {
|
|
28
|
+
match = line.match(CLANG_ERROR);
|
|
29
|
+
}
|
|
30
|
+
if (!match) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const severityRaw = match[4].toLowerCase();
|
|
34
|
+
const severity = severityRaw.includes("error") ? "error" : severityRaw === "warning" ? "warning" : "note";
|
|
35
|
+
let filePath = match[1];
|
|
36
|
+
// Normalize file paths
|
|
37
|
+
if (sketchDir) {
|
|
38
|
+
if (!path.isAbsolute(filePath)) {
|
|
39
|
+
const resolved = path.resolve(sketchDir, filePath);
|
|
40
|
+
if (fs.existsSync(resolved)) {
|
|
41
|
+
filePath = resolved;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
errors.push({
|
|
46
|
+
filePath: path.resolve(filePath),
|
|
47
|
+
line: parseInt(match[2], 10),
|
|
48
|
+
column: parseInt(match[3], 10),
|
|
49
|
+
severity,
|
|
50
|
+
message: match[5],
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return errors;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Collect all .cpp files in a directory (non-recursive).
|
|
57
|
+
*/
|
|
58
|
+
export function collectCppFiles(rootDir) {
|
|
59
|
+
const results = [];
|
|
60
|
+
if (!fs.existsSync(rootDir)) {
|
|
61
|
+
return results;
|
|
62
|
+
}
|
|
63
|
+
for (const entry of fs.readdirSync(rootDir, { withFileTypes: true })) {
|
|
64
|
+
if (!entry.isFile() || !entry.name.toLowerCase().endsWith(".cpp")) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
results.push(path.join(rootDir, entry.name));
|
|
68
|
+
}
|
|
69
|
+
results.sort((a, b) => a.localeCompare(b));
|
|
70
|
+
return results;
|
|
71
|
+
}
|