@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,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Async state machine generation utilities.
|
|
3
|
+
* Handles conversion of async functions to cooperative state machines.
|
|
4
|
+
* Extracted from cpp-emitter.ts
|
|
5
|
+
*/
|
|
6
|
+
import type { StatementIR } from "../../api/index.js";
|
|
7
|
+
import type { PlatformStrategy } from "../../api/shared/index.js";
|
|
8
|
+
/**
|
|
9
|
+
* Converts a string to PascalCase.
|
|
10
|
+
* Used for generating class names from function names.
|
|
11
|
+
*
|
|
12
|
+
* @param str The input string (e.g., "my_function" or "myFunction")
|
|
13
|
+
* @returns PascalCase string (e.g., "MyFunction")
|
|
14
|
+
*/
|
|
15
|
+
export declare function toPascalCaseLocal(str: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Result of generating an async task class.
|
|
18
|
+
*/
|
|
19
|
+
export interface AsyncTaskClassResult {
|
|
20
|
+
/** The class definition as a string */
|
|
21
|
+
classDef: string;
|
|
22
|
+
/** The instance declaration (e.g., "blinkTask blinkTask;") */
|
|
23
|
+
instanceDecl: string;
|
|
24
|
+
/** The task variable name for use in loop() */
|
|
25
|
+
taskVarName: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Generates a cooperative state-machine class for an async function.
|
|
29
|
+
*
|
|
30
|
+
* Handles two patterns:
|
|
31
|
+
* 1. Cyclic: single `while(true)` body containing `await delay()` calls.
|
|
32
|
+
* 2. Linear: sequential statements with `await delay()` calls.
|
|
33
|
+
*
|
|
34
|
+
* Each `await delay(ms)` call becomes a timed wait state that polls `millis()`.
|
|
35
|
+
*
|
|
36
|
+
* @param fnName The original function name
|
|
37
|
+
* @param fnStatements The function body statements
|
|
38
|
+
* @param strategy The platform strategy for rendering
|
|
39
|
+
* @param knownFunctionReturnTypes Map of function names to their return types
|
|
40
|
+
* @returns The class definition, instance declaration, and task variable name
|
|
41
|
+
*/
|
|
42
|
+
export declare function generateAsyncTaskClass(fnName: string, fnStatements: StatementIR[], strategy: PlatformStrategy, knownFunctionReturnTypes: Map<string, string>, renderStatement: (stmt: StatementIR, forHeader: boolean, strategy: PlatformStrategy, pointerVarTypes?: Map<string, string>, calleeTransformer?: (callee: string) => string, knownFunctionReturnTypes?: Map<string, string>) => string): AsyncTaskClassResult;
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Async state machine generation utilities.
|
|
3
|
+
* Handles conversion of async functions to cooperative state machines.
|
|
4
|
+
* Extracted from cpp-emitter.ts
|
|
5
|
+
*/
|
|
6
|
+
import { escapeCppStringLiteral } from "../../utils/strings.js";
|
|
7
|
+
/**
|
|
8
|
+
* Converts a string to PascalCase.
|
|
9
|
+
* Used for generating class names from function names.
|
|
10
|
+
*
|
|
11
|
+
* @param str The input string (e.g., "my_function" or "myFunction")
|
|
12
|
+
* @returns PascalCase string (e.g., "MyFunction")
|
|
13
|
+
*/
|
|
14
|
+
export function toPascalCaseLocal(str) {
|
|
15
|
+
return str
|
|
16
|
+
.split(/[_\s]+/)
|
|
17
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
18
|
+
.join("");
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Generates a cooperative state-machine class for an async function.
|
|
22
|
+
*
|
|
23
|
+
* Handles two patterns:
|
|
24
|
+
* 1. Cyclic: single `while(true)` body containing `await delay()` calls.
|
|
25
|
+
* 2. Linear: sequential statements with `await delay()` calls.
|
|
26
|
+
*
|
|
27
|
+
* Each `await delay(ms)` call becomes a timed wait state that polls `millis()`.
|
|
28
|
+
*
|
|
29
|
+
* @param fnName The original function name
|
|
30
|
+
* @param fnStatements The function body statements
|
|
31
|
+
* @param strategy The platform strategy for rendering
|
|
32
|
+
* @param knownFunctionReturnTypes Map of function names to their return types
|
|
33
|
+
* @returns The class definition, instance declaration, and task variable name
|
|
34
|
+
*/
|
|
35
|
+
export function generateAsyncTaskClass(fnName, fnStatements, strategy, knownFunctionReturnTypes, renderStatement) {
|
|
36
|
+
const className = toPascalCaseLocal(fnName) + "Task";
|
|
37
|
+
const instanceName = `${fnName}Task`;
|
|
38
|
+
// Detect whether the body is a single while-loop (cyclic) or linear statements
|
|
39
|
+
let bodyStatements;
|
|
40
|
+
let isCyclic = false;
|
|
41
|
+
if (fnStatements.length === 1 && fnStatements[0].kind === "while") {
|
|
42
|
+
isCyclic = true;
|
|
43
|
+
bodyStatements = fnStatements[0].body;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
bodyStatements = fnStatements;
|
|
47
|
+
}
|
|
48
|
+
// Split body into segments at each awaited call
|
|
49
|
+
const segments = [];
|
|
50
|
+
let currentPre = [];
|
|
51
|
+
for (const stmt of bodyStatements) {
|
|
52
|
+
if (stmt.kind === "call" && stmt.isAwaited) {
|
|
53
|
+
segments.push({ preStatements: currentPre, awaitedCallee: stmt.callee, awaitedArgs: stmt.args });
|
|
54
|
+
currentPre = [];
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
currentPre.push(stmt);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Terminal segment (trailing statements after the last await, or the whole body if no awaits)
|
|
61
|
+
segments.push({ preStatements: currentPre, awaitedArgs: [] });
|
|
62
|
+
const awaitCount = segments.filter((s) => s.awaitedCallee !== undefined).length;
|
|
63
|
+
const stateCount = awaitCount + 1; // STATE_0 … STATE_{awaitCount}; cyclic loops back, linear adds STATE_DONE
|
|
64
|
+
const stateNames = [];
|
|
65
|
+
for (let i = 0; i < stateCount; i++)
|
|
66
|
+
stateNames.push(`STATE_${i}`);
|
|
67
|
+
if (!isCyclic)
|
|
68
|
+
stateNames.push("STATE_DONE");
|
|
69
|
+
// Helper: render a non-await statement as a single C++ line
|
|
70
|
+
const renderStmt = (stmt) => renderStatement(stmt, false, strategy, undefined, undefined, knownFunctionReturnTypes);
|
|
71
|
+
// Collect edge-detection markers from segments
|
|
72
|
+
const edgeInfoMap = new Map();
|
|
73
|
+
const edgeMembers = new Set();
|
|
74
|
+
for (let i = 0; i < segments.length; i++) {
|
|
75
|
+
const seg = segments[i];
|
|
76
|
+
if (seg.awaitedCallee === "__EMIT__" && seg.awaitedArgs.length > 0) {
|
|
77
|
+
const argText = seg.awaitedArgs[0].kind === "string"
|
|
78
|
+
? seg.awaitedArgs[0].value
|
|
79
|
+
: renderExpression(seg.awaitedArgs[0], strategy);
|
|
80
|
+
const info = parseEdgeMarker(argText);
|
|
81
|
+
if (info) {
|
|
82
|
+
edgeInfoMap.set(i, info);
|
|
83
|
+
edgeMembers.add(`_edgePrev_p${info.pin}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Collect awaitable-tap markers (await ui.onTap()). args[0] is the node
|
|
88
|
+
// filter: -1 = any tap, >=0 = a specific node index. Each tap-await needs a
|
|
89
|
+
// per-await snapshot of __ui_tap_seq to detect the NEXT bump.
|
|
90
|
+
const tapInfoMap = new Map();
|
|
91
|
+
const tapMembers = new Map(); // member name → segment index
|
|
92
|
+
for (let i = 0; i < segments.length; i++) {
|
|
93
|
+
const seg = segments[i];
|
|
94
|
+
if (seg.awaitedCallee === "__UI_TAP__" && seg.awaitedArgs.length > 0) {
|
|
95
|
+
const nodeArg = seg.awaitedArgs[0];
|
|
96
|
+
const nodeIndex = nodeArg.kind === "number"
|
|
97
|
+
? nodeArg.value
|
|
98
|
+
: -1;
|
|
99
|
+
const member = `_tapPrev_${i}`;
|
|
100
|
+
tapInfoMap.set(i, { nodeIndex });
|
|
101
|
+
tapMembers.set(member, i);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const caseLines = [];
|
|
105
|
+
for (let i = 0; i < segments.length; i++) {
|
|
106
|
+
const seg = segments[i];
|
|
107
|
+
const stateName = `STATE_${i}`;
|
|
108
|
+
const isTerminal = seg.awaitedCallee === undefined;
|
|
109
|
+
const body = [];
|
|
110
|
+
const edgeSetup = edgeInfoMap.get(i);
|
|
111
|
+
const edgePoll = i > 0 ? edgeInfoMap.get(i - 1) : undefined;
|
|
112
|
+
const tapSetup = tapInfoMap.get(i);
|
|
113
|
+
const tapPoll = i > 0 ? tapInfoMap.get(i - 1) : undefined;
|
|
114
|
+
if (edgePoll) {
|
|
115
|
+
// Poll state: check pin transition via digitalRead
|
|
116
|
+
const prevVar = `_edgePrev_p${edgePoll.pin}`;
|
|
117
|
+
const cond = edgePoll.edge === "rising"
|
|
118
|
+
? `${prevVar} == LOW && _cur == HIGH`
|
|
119
|
+
: `${prevVar} == HIGH && _cur == LOW`;
|
|
120
|
+
const fullCond = edgePoll.timeout !== null
|
|
121
|
+
? `(${cond}) || ${strategy.currentTimeMillis()} >= _waitUntil`
|
|
122
|
+
: cond;
|
|
123
|
+
body.push(` {`);
|
|
124
|
+
body.push(` int _cur = digitalRead(${edgePoll.pin});`);
|
|
125
|
+
body.push(` if (${fullCond}) {`);
|
|
126
|
+
body.push(` ${prevVar} = _cur;`);
|
|
127
|
+
for (const stmt of seg.preStatements)
|
|
128
|
+
body.push(` ${renderStmt(stmt)}`);
|
|
129
|
+
if (edgeSetup) {
|
|
130
|
+
// Next await is also edge detection — set up its pin tracking
|
|
131
|
+
body.push(` _edgePrev_p${edgeSetup.pin} = digitalRead(${edgeSetup.pin});`);
|
|
132
|
+
if (edgeSetup.timeout !== null) {
|
|
133
|
+
body.push(` _waitUntil = ${strategy.currentTimeMillis()} + ${edgeSetup.timeout};`);
|
|
134
|
+
}
|
|
135
|
+
body.push(` _state = STATE_${i + 1};`);
|
|
136
|
+
}
|
|
137
|
+
else if (!isTerminal) {
|
|
138
|
+
const ms = seg.awaitedArgs[0] ? renderExpression(seg.awaitedArgs[0], strategy) : "0";
|
|
139
|
+
body.push(` _waitUntil = ${strategy.currentTimeMillis()} + ${ms};`);
|
|
140
|
+
body.push(` _state = STATE_${i + 1};`);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
body.push(` _state = ${isCyclic ? "STATE_0" : "STATE_DONE"};`);
|
|
144
|
+
}
|
|
145
|
+
body.push(` } else {`);
|
|
146
|
+
body.push(` ${prevVar} = _cur;`);
|
|
147
|
+
body.push(` }`);
|
|
148
|
+
body.push(` }`);
|
|
149
|
+
}
|
|
150
|
+
else if (edgeSetup) {
|
|
151
|
+
// Setup state: capture initial pin state before polling
|
|
152
|
+
const prevVar = `_edgePrev_p${edgeSetup.pin}`;
|
|
153
|
+
if (i === 0) {
|
|
154
|
+
for (const stmt of seg.preStatements)
|
|
155
|
+
body.push(` ${renderStmt(stmt)}`);
|
|
156
|
+
body.push(` ${prevVar} = digitalRead(${edgeSetup.pin});`);
|
|
157
|
+
if (edgeSetup.timeout !== null) {
|
|
158
|
+
body.push(` _waitUntil = ${strategy.currentTimeMillis()} + ${edgeSetup.timeout};`);
|
|
159
|
+
}
|
|
160
|
+
body.push(` _state = STATE_${i + 1};`);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
body.push(` if (${strategy.currentTimeMillis()} >= _waitUntil) {`);
|
|
164
|
+
for (const stmt of seg.preStatements)
|
|
165
|
+
body.push(` ${renderStmt(stmt)}`);
|
|
166
|
+
body.push(` ${prevVar} = digitalRead(${edgeSetup.pin});`);
|
|
167
|
+
if (edgeSetup.timeout !== null) {
|
|
168
|
+
body.push(` _waitUntil = ${strategy.currentTimeMillis()} + ${edgeSetup.timeout};`);
|
|
169
|
+
}
|
|
170
|
+
body.push(` _state = STATE_${i + 1};`);
|
|
171
|
+
body.push(` }`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
else if (tapPoll) {
|
|
175
|
+
// Tap-poll state: a previous segment ended with `await ui.onTap()`.
|
|
176
|
+
// Wait until __ui_tap_seq bumps from the captured snapshot. A per-node
|
|
177
|
+
// await also requires __ui_tap_node to match the awaited node index.
|
|
178
|
+
const prevVar = `_tapPrev_${i - 1}`;
|
|
179
|
+
const nodeFilter = tapPoll.nodeIndex;
|
|
180
|
+
const cond = nodeFilter < 0
|
|
181
|
+
? `__ui_tap_seq != ${prevVar}`
|
|
182
|
+
: `(__ui_tap_seq != ${prevVar}) && (__ui_tap_node == ${nodeFilter})`;
|
|
183
|
+
body.push(` if (${cond}) {`);
|
|
184
|
+
for (const stmt of seg.preStatements)
|
|
185
|
+
body.push(` ${renderStmt(stmt)}`);
|
|
186
|
+
// What does the NEXT await (ending this segment) look like? Re-derive
|
|
187
|
+
// from the maps via a fresh lookup so TS doesn't narrow edgeSetup away.
|
|
188
|
+
const nextEdge = edgeInfoMap.get(i) ?? null;
|
|
189
|
+
if (tapSetup) {
|
|
190
|
+
// Next await is also a tap — capture its snapshot now.
|
|
191
|
+
body.push(` _tapPrev_${i} = __ui_tap_seq;`);
|
|
192
|
+
body.push(` _state = STATE_${i + 1};`);
|
|
193
|
+
}
|
|
194
|
+
else if (nextEdge) {
|
|
195
|
+
body.push(` _edgePrev_p${nextEdge.pin} = digitalRead(${nextEdge.pin});`);
|
|
196
|
+
if (nextEdge.timeout !== null) {
|
|
197
|
+
body.push(` _waitUntil = ${strategy.currentTimeMillis()} + ${nextEdge.timeout};`);
|
|
198
|
+
}
|
|
199
|
+
body.push(` _state = STATE_${i + 1};`);
|
|
200
|
+
}
|
|
201
|
+
else if (!isTerminal) {
|
|
202
|
+
// Next await is a normal timed wait (delay) — arm its deadline.
|
|
203
|
+
const ms = seg.awaitedArgs[0] ? renderExpression(seg.awaitedArgs[0], strategy) : "0";
|
|
204
|
+
body.push(` _waitUntil = ${strategy.currentTimeMillis()} + ${ms};`);
|
|
205
|
+
body.push(` _state = STATE_${i + 1};`);
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
body.push(` _state = ${isCyclic ? "STATE_0" : "STATE_DONE"};`);
|
|
209
|
+
}
|
|
210
|
+
body.push(` }`);
|
|
211
|
+
}
|
|
212
|
+
else if (tapSetup && !edgePoll) {
|
|
213
|
+
// Tap-setup state: this segment ends with `await ui.onTap()`. Capture the
|
|
214
|
+
// current tap counter so the poll state can detect the NEXT bump.
|
|
215
|
+
// (edgePoll takes precedence when the previous await was an edge.)
|
|
216
|
+
if (i === 0) {
|
|
217
|
+
for (const stmt of seg.preStatements)
|
|
218
|
+
body.push(` ${renderStmt(stmt)}`);
|
|
219
|
+
body.push(` _tapPrev_${i} = __ui_tap_seq;`);
|
|
220
|
+
body.push(` _state = STATE_${i + 1};`);
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
body.push(` if (${strategy.currentTimeMillis()} >= _waitUntil) {`);
|
|
224
|
+
for (const stmt of seg.preStatements)
|
|
225
|
+
body.push(` ${renderStmt(stmt)}`);
|
|
226
|
+
body.push(` _tapPrev_${i} = __ui_tap_seq;`);
|
|
227
|
+
body.push(` _state = STATE_${i + 1};`);
|
|
228
|
+
body.push(` }`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
// Normal timed-wait state
|
|
233
|
+
if (i === 0) {
|
|
234
|
+
for (const stmt of seg.preStatements)
|
|
235
|
+
body.push(` ${renderStmt(stmt)}`);
|
|
236
|
+
if (!isTerminal) {
|
|
237
|
+
const ms = seg.awaitedArgs[0] ? renderExpression(seg.awaitedArgs[0], strategy) : "0";
|
|
238
|
+
body.push(` _waitUntil = ${strategy.currentTimeMillis()} + ${ms};`);
|
|
239
|
+
body.push(` _state = STATE_${i + 1};`);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
body.push(` _state = ${isCyclic ? "STATE_0" : "STATE_DONE"};`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
body.push(` if (${strategy.currentTimeMillis()} >= _waitUntil) {`);
|
|
247
|
+
for (const stmt of seg.preStatements)
|
|
248
|
+
body.push(` ${renderStmt(stmt)}`);
|
|
249
|
+
if (!isTerminal) {
|
|
250
|
+
const ms = seg.awaitedArgs[0] ? renderExpression(seg.awaitedArgs[0], strategy) : "0";
|
|
251
|
+
body.push(` _waitUntil = ${strategy.currentTimeMillis()} + ${ms};`);
|
|
252
|
+
body.push(` _state = STATE_${i + 1};`);
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
body.push(` _state = ${isCyclic ? "STATE_0" : "STATE_DONE"};`);
|
|
256
|
+
}
|
|
257
|
+
body.push(` }`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
caseLines.push(` case ${stateName}:`, ` {`, ...body, ` }`, ` break;`);
|
|
261
|
+
}
|
|
262
|
+
if (!isCyclic)
|
|
263
|
+
caseLines.push(` case STATE_DONE:`, ` break;`);
|
|
264
|
+
const stateEnumList = stateNames.join(", ");
|
|
265
|
+
const isCompleteExpr = isCyclic ? "false" : "_state == STATE_DONE";
|
|
266
|
+
// Build constructor initializer list and edge/tap member declarations
|
|
267
|
+
const edgeMemberArr = Array.from(edgeMembers);
|
|
268
|
+
const tapMemberArr = Array.from(tapMembers.keys());
|
|
269
|
+
const inits = [`_state(STATE_0)`, `_waitUntil(0)`];
|
|
270
|
+
for (const m of edgeMemberArr)
|
|
271
|
+
inits.push(`${m}(LOW)`);
|
|
272
|
+
for (const m of tapMemberArr)
|
|
273
|
+
inits.push(`${m}(0)`);
|
|
274
|
+
const ctorInitList = inits.join(", ");
|
|
275
|
+
const edgeResetList = edgeMemberArr.map(m => ` ${m} = LOW;`).join("");
|
|
276
|
+
const tapResetList = tapMemberArr.map(m => ` ${m} = 0;`).join("");
|
|
277
|
+
const edgeMemberDecls = edgeMemberArr.map(m => ` int ${m};`);
|
|
278
|
+
// __ui_tap_seq is uint32_t; the snapshot must match to detect bumps correctly.
|
|
279
|
+
const tapMemberDecls = tapMemberArr.map(m => ` uint32_t ${m};`);
|
|
280
|
+
const classDef = [
|
|
281
|
+
`// Async state machine for ${fnName}`,
|
|
282
|
+
`class ${className} {`,
|
|
283
|
+
`public:`,
|
|
284
|
+
` enum State { ${stateEnumList} };`,
|
|
285
|
+
` ${className}() : ${ctorInitList} {}`,
|
|
286
|
+
` void run() {`,
|
|
287
|
+
` switch (_state) {`,
|
|
288
|
+
...caseLines,
|
|
289
|
+
` }`,
|
|
290
|
+
` }`,
|
|
291
|
+
` bool isComplete() const { return ${isCompleteExpr}; }`,
|
|
292
|
+
` void reset() { _state = STATE_0; _waitUntil = 0;${edgeResetList}${tapResetList} }`,
|
|
293
|
+
`private:`,
|
|
294
|
+
` State _state;`,
|
|
295
|
+
` unsigned long _waitUntil;`,
|
|
296
|
+
...edgeMemberDecls,
|
|
297
|
+
...tapMemberDecls,
|
|
298
|
+
`};`,
|
|
299
|
+
].join("\n");
|
|
300
|
+
return { classDef, instanceDecl: `${className} ${instanceName};`, taskVarName: instanceName };
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Renders an expression to a string (simplified version for async state machine).
|
|
304
|
+
* This is a minimal implementation - full rendering should use ExpressionRenderer.
|
|
305
|
+
*/
|
|
306
|
+
function renderExpression(expr, strategy) {
|
|
307
|
+
switch (expr.kind) {
|
|
308
|
+
case "number": {
|
|
309
|
+
if (expr.cppType === "float" || expr.cppType === "double" || !Number.isInteger(expr.value)) {
|
|
310
|
+
const str = `${expr.value}`;
|
|
311
|
+
return str.includes('.') || str.includes('e') || str.includes('E')
|
|
312
|
+
? `${str}f`
|
|
313
|
+
: `${str}.0f`;
|
|
314
|
+
}
|
|
315
|
+
return `${expr.value}`;
|
|
316
|
+
}
|
|
317
|
+
case "string":
|
|
318
|
+
// Shared escaper — see render-expr.ts / expression-renderer.ts (demo #29
|
|
319
|
+
// Finding A family). The prior quote-only escape emitted a raw control
|
|
320
|
+
// char inside the C++ string literal for any `\n`/`\t`/`\\` value.
|
|
321
|
+
return `"${escapeCppStringLiteral(expr.value)}"`;
|
|
322
|
+
case "boolean":
|
|
323
|
+
return expr.value ? "true" : "false";
|
|
324
|
+
case "identifier":
|
|
325
|
+
return expr.value;
|
|
326
|
+
case "raw":
|
|
327
|
+
return expr.value;
|
|
328
|
+
case "hal-expr":
|
|
329
|
+
return `/* hal-expr: ${expr.operation.operation} */`;
|
|
330
|
+
default:
|
|
331
|
+
return "/* complex expr */";
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
function parseEdgeMarker(argText) {
|
|
335
|
+
const match = argText.match(/^__EDGE_(RISING|FALLING)__([a-zA-Z0-9_]+)__T(.*)$/);
|
|
336
|
+
if (!match)
|
|
337
|
+
return null;
|
|
338
|
+
const edge = match[1] === "RISING" ? "rising" : "falling";
|
|
339
|
+
const pin = match[2];
|
|
340
|
+
const timeoutStr = match[3];
|
|
341
|
+
const timeout = !isNaN(Number(timeoutStr)) && Number(timeoutStr) > 0 ? Number(timeoutStr) : null;
|
|
342
|
+
return { pin, edge, timeout };
|
|
343
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comment handling utilities for C++ code emission.
|
|
3
|
+
* Extracted from cpp-emitter.ts
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Normalizes a comment string into an array of trimmed lines.
|
|
7
|
+
* Removes empty lines and trailing whitespace.
|
|
8
|
+
*
|
|
9
|
+
* @param comment The comment string (may contain newlines)
|
|
10
|
+
* @returns Array of normalized comment lines
|
|
11
|
+
*/
|
|
12
|
+
export declare function normalizeComment(comment: string): string[];
|
|
13
|
+
/**
|
|
14
|
+
* Emits comment lines with proper indentation.
|
|
15
|
+
*
|
|
16
|
+
* @param comments Optional array of comment strings to emit
|
|
17
|
+
* @param indent The indentation string to prepend to each line
|
|
18
|
+
* @param appendLine Function to call for each output line
|
|
19
|
+
*/
|
|
20
|
+
export declare function emitCommentLines(comments: string[] | undefined, indent: string, appendLine: (line: string) => void): void;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comment handling utilities for C++ code emission.
|
|
3
|
+
* Extracted from cpp-emitter.ts
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Normalizes a comment string into an array of trimmed lines.
|
|
7
|
+
* Removes empty lines and trailing whitespace.
|
|
8
|
+
*
|
|
9
|
+
* @param comment The comment string (may contain newlines)
|
|
10
|
+
* @returns Array of normalized comment lines
|
|
11
|
+
*/
|
|
12
|
+
export function normalizeComment(comment) {
|
|
13
|
+
return comment
|
|
14
|
+
.split(/\r?\n/)
|
|
15
|
+
.map((line) => line.trimEnd())
|
|
16
|
+
.filter((line) => line.length > 0);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Emits comment lines with proper indentation.
|
|
20
|
+
*
|
|
21
|
+
* @param comments Optional array of comment strings to emit
|
|
22
|
+
* @param indent The indentation string to prepend to each line
|
|
23
|
+
* @param appendLine Function to call for each output line
|
|
24
|
+
*/
|
|
25
|
+
export function emitCommentLines(comments, indent, appendLine) {
|
|
26
|
+
for (const comment of comments ?? []) {
|
|
27
|
+
for (const line of normalizeComment(comment)) {
|
|
28
|
+
appendLine(`${indent}${line}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export declare function accessorGetterName(prop: string): string;
|
|
2
|
+
export declare function accessorSetterName(prop: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* Matches a C++ INTEGRAL scalar type (the enum↔integral storage boundary in
|
|
5
|
+
* SUPPORT_MATRIX §1.7). Used by the enum-storage cast sites to decide whether
|
|
6
|
+
* a value/target is on the integral side of an `enum class` boundary that
|
|
7
|
+
* needs a `static_cast`. Covers the signed/unsigned `char`/`short`/`int`/
|
|
8
|
+
* `long` spellings, the fixed-width `<cstdint>` aliases, `size_t`, and `bool`
|
|
9
|
+
* (bool participates: `Cell c = someBool` is the same boundary). Anchored so
|
|
10
|
+
* it does not match container/pointer spellings (`std::vector<...>` etc.).
|
|
11
|
+
*
|
|
12
|
+
* Single source of truth — emit sites route through this instead of each
|
|
13
|
+
* keeping their own inline regex (the prior `isNumericTarget` regex in
|
|
14
|
+
* statement-renderer was one such divergent copy). Demo #32 Finding A.
|
|
15
|
+
*/
|
|
16
|
+
export declare const INTEGRAL_CPP_TYPE_RE: RegExp;
|
|
17
|
+
/**
|
|
18
|
+
* Resolve the actual numeric value of every member in a numeric enum, applying
|
|
19
|
+
* the TS/C++ auto-increment rule: an explicit value sets the counter, members
|
|
20
|
+
* without one get the current counter then increment. Mirrors the per-member
|
|
21
|
+
* logic the three emit sites use when emitting `= <value>`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveEnumValues(members: ReadonlyArray<{
|
|
24
|
+
value?: number | string;
|
|
25
|
+
}>): number[];
|
|
26
|
+
/**
|
|
27
|
+
* Compute the narrowest C++ underlying type for a numeric `enum class`, given
|
|
28
|
+
* the resolved member values. Returns the `: <type>` suffix string (or `""`
|
|
29
|
+
* for the default `int`).
|
|
30
|
+
*
|
|
31
|
+
* The transpiler knows the full, closed value range of every enum at emit
|
|
32
|
+
* time — something g++ cannot recover. Picking the narrowest type halves
|
|
33
|
+
* storage for small enums on AVR (`enum class X` defaults to `int` = 2 bytes;
|
|
34
|
+
* `enum class X : uint8_t` = 1 byte), which matters for state-machine fields,
|
|
35
|
+
* opcodes, and pin-role arrays common on small-RAM targets.
|
|
36
|
+
*
|
|
37
|
+
* Narrowing is strictly safe: the values provably fit, and `enum class`
|
|
38
|
+
* underlying-type specification is standard C++11. Widening to `: long` still
|
|
39
|
+
* applies when a value exceeds the default-int range on targets where
|
|
40
|
+
* `needsLargeEnumUnderlying` is true (AVR's 16-bit `int`).
|
|
41
|
+
*
|
|
42
|
+
* @param values The resolved numeric values of all enum members.
|
|
43
|
+
* @param needsLargeEnumUnderlying Whether the target's `int` is smaller than
|
|
44
|
+
* 32 bits (true on AVR). When true, values outside `[-32768, 32767]` widen
|
|
45
|
+
* to `: long`. When false (32-bit int), no widening is needed.
|
|
46
|
+
*/
|
|
47
|
+
export declare function narrowestEnumUnderlying(values: readonly number[], needsLargeEnumUnderlying: boolean): string;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
export function accessorGetterName(prop) {
|
|
2
|
+
return `get${prop.charAt(0).toUpperCase()}${prop.slice(1)}`;
|
|
3
|
+
}
|
|
4
|
+
export function accessorSetterName(prop) {
|
|
5
|
+
return `set${prop.charAt(0).toUpperCase()}${prop.slice(1)}`;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Matches a C++ INTEGRAL scalar type (the enum↔integral storage boundary in
|
|
9
|
+
* SUPPORT_MATRIX §1.7). Used by the enum-storage cast sites to decide whether
|
|
10
|
+
* a value/target is on the integral side of an `enum class` boundary that
|
|
11
|
+
* needs a `static_cast`. Covers the signed/unsigned `char`/`short`/`int`/
|
|
12
|
+
* `long` spellings, the fixed-width `<cstdint>` aliases, `size_t`, and `bool`
|
|
13
|
+
* (bool participates: `Cell c = someBool` is the same boundary). Anchored so
|
|
14
|
+
* it does not match container/pointer spellings (`std::vector<...>` etc.).
|
|
15
|
+
*
|
|
16
|
+
* Single source of truth — emit sites route through this instead of each
|
|
17
|
+
* keeping their own inline regex (the prior `isNumericTarget` regex in
|
|
18
|
+
* statement-renderer was one such divergent copy). Demo #32 Finding A.
|
|
19
|
+
*/
|
|
20
|
+
export const INTEGRAL_CPP_TYPE_RE = /^(?:unsigned\s+|signed\s+)?(?:bool|char|short|int|long(?:\s+long)?|float|double|u?int(?:8|16|32|64)_t|size_t)$/;
|
|
21
|
+
/**
|
|
22
|
+
* Resolve the actual numeric value of every member in a numeric enum, applying
|
|
23
|
+
* the TS/C++ auto-increment rule: an explicit value sets the counter, members
|
|
24
|
+
* without one get the current counter then increment. Mirrors the per-member
|
|
25
|
+
* logic the three emit sites use when emitting `= <value>`.
|
|
26
|
+
*/
|
|
27
|
+
export function resolveEnumValues(members) {
|
|
28
|
+
const values = [];
|
|
29
|
+
let autoValue = 0;
|
|
30
|
+
for (const m of members) {
|
|
31
|
+
if (typeof m.value === "number") {
|
|
32
|
+
values.push(m.value);
|
|
33
|
+
autoValue = m.value + 1;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
// String-valued member (mixed enum) or auto-increment numeric.
|
|
37
|
+
values.push(autoValue);
|
|
38
|
+
autoValue++;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return values;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Compute the narrowest C++ underlying type for a numeric `enum class`, given
|
|
45
|
+
* the resolved member values. Returns the `: <type>` suffix string (or `""`
|
|
46
|
+
* for the default `int`).
|
|
47
|
+
*
|
|
48
|
+
* The transpiler knows the full, closed value range of every enum at emit
|
|
49
|
+
* time — something g++ cannot recover. Picking the narrowest type halves
|
|
50
|
+
* storage for small enums on AVR (`enum class X` defaults to `int` = 2 bytes;
|
|
51
|
+
* `enum class X : uint8_t` = 1 byte), which matters for state-machine fields,
|
|
52
|
+
* opcodes, and pin-role arrays common on small-RAM targets.
|
|
53
|
+
*
|
|
54
|
+
* Narrowing is strictly safe: the values provably fit, and `enum class`
|
|
55
|
+
* underlying-type specification is standard C++11. Widening to `: long` still
|
|
56
|
+
* applies when a value exceeds the default-int range on targets where
|
|
57
|
+
* `needsLargeEnumUnderlying` is true (AVR's 16-bit `int`).
|
|
58
|
+
*
|
|
59
|
+
* @param values The resolved numeric values of all enum members.
|
|
60
|
+
* @param needsLargeEnumUnderlying Whether the target's `int` is smaller than
|
|
61
|
+
* 32 bits (true on AVR). When true, values outside `[-32768, 32767]` widen
|
|
62
|
+
* to `: long`. When false (32-bit int), no widening is needed.
|
|
63
|
+
*/
|
|
64
|
+
export function narrowestEnumUnderlying(values, needsLargeEnumUnderlying) {
|
|
65
|
+
if (values.length === 0)
|
|
66
|
+
return "";
|
|
67
|
+
let min = Infinity;
|
|
68
|
+
let max = -Infinity;
|
|
69
|
+
for (const v of values) {
|
|
70
|
+
if (v < min)
|
|
71
|
+
min = v;
|
|
72
|
+
if (v > max)
|
|
73
|
+
max = v;
|
|
74
|
+
}
|
|
75
|
+
// Widen to long first if any value overflows the target's default int range.
|
|
76
|
+
if (needsLargeEnumUnderlying && (max > 32767 || min < -32768)) {
|
|
77
|
+
return " : long";
|
|
78
|
+
}
|
|
79
|
+
// Narrow to the smallest type that fits the full [min, max] range.
|
|
80
|
+
if (min >= 0 && max <= 255)
|
|
81
|
+
return " : uint8_t";
|
|
82
|
+
if (min >= -128 && max <= 127)
|
|
83
|
+
return " : int8_t";
|
|
84
|
+
return "";
|
|
85
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Include resolution utilities for C++ code emission.
|
|
3
|
+
* Handles import resolution, SDK detection, and header normalization.
|
|
4
|
+
* Extracted from cpp-emitter.ts
|
|
5
|
+
*/
|
|
6
|
+
import type { ResolvedNpmPackage } from "../../transpile/resolution.js";
|
|
7
|
+
/**
|
|
8
|
+
* Checks if a module specifier resolves to a TypeCAD SDK path.
|
|
9
|
+
* Cuttlefish SDK files (code/core/*, code/board-*, @typecad/* packages) are
|
|
10
|
+
* type-level only and should produce no C++ output or #include directives.
|
|
11
|
+
*
|
|
12
|
+
* @param moduleSpecifier The import specifier (e.g., "@typecad/hal" or "./pins")
|
|
13
|
+
* @param fromFile The file path from which the import originates
|
|
14
|
+
* @returns true if this is a TypeCAD SDK import
|
|
15
|
+
*/
|
|
16
|
+
export declare function isCuttlefishSDKImport(moduleSpecifier: string, fromFile: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Normalizes an include path to proper C++ include format.
|
|
19
|
+
*
|
|
20
|
+
* @param include The include path (e.g., "Arduino.h" or "<vector>")
|
|
21
|
+
* @returns Properly formatted include (e.g., "<Arduino.h>" or "<vector>")
|
|
22
|
+
*/
|
|
23
|
+
export declare function normalizeInclude(include: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Deduplicates an array while preserving order.
|
|
26
|
+
*
|
|
27
|
+
* @param items The array to deduplicate
|
|
28
|
+
* @returns A new array with duplicates removed
|
|
29
|
+
*/
|
|
30
|
+
export declare function dedupe<T>(items: T[]): T[];
|
|
31
|
+
/**
|
|
32
|
+
* Result of resolving a transpiled module include.
|
|
33
|
+
*/
|
|
34
|
+
interface TranspiledIncludeResult {
|
|
35
|
+
/** The include path (e.g., "\"./pins.h\"") or empty string if not transpiled */
|
|
36
|
+
include: string;
|
|
37
|
+
/** Whether this import was resolved as a transpiled npm package */
|
|
38
|
+
isTranspiled: boolean;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Resolves an import to a local header file if it's from a transpiled npm package.
|
|
42
|
+
*
|
|
43
|
+
* @param moduleSpecifier The import specifier
|
|
44
|
+
* @param npmPackages Map of source paths to npm package info
|
|
45
|
+
* @param fromFilePath The file path from which the import originates
|
|
46
|
+
* @returns Information about the resolved include
|
|
47
|
+
*/
|
|
48
|
+
export declare function resolveTranspiledModuleInclude(moduleSpecifier: string, npmPackages: Map<string, ResolvedNpmPackage> | undefined, fromFilePath: string): TranspiledIncludeResult;
|
|
49
|
+
/**
|
|
50
|
+
* Applies a symbol map to a callee string.
|
|
51
|
+
* Transforms root identifiers according to the mapping.
|
|
52
|
+
*
|
|
53
|
+
* @param callee The original callee (e.g., "console.log" or "myFunc")
|
|
54
|
+
* @param symbolMap Map of original names to transformed names
|
|
55
|
+
* @returns The transformed callee
|
|
56
|
+
*/
|
|
57
|
+
export declare function applySymbolMap(callee: string, symbolMap: Record<string, string>): string;
|
|
58
|
+
export {};
|