@typecad/cuttlefish 1.0.0-alpha.13 → 1.0.0-alpha.15
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/README.md +82 -79
- package/assets/editor-extensions/typecad-debug/README.md +141 -0
- package/assets/editor-extensions/typecad-debug/out/extension.js +347 -0
- package/assets/editor-extensions/typecad-debug/out/extension.js.map +1 -0
- package/assets/editor-extensions/typecad-debug/package.json +76 -0
- package/assets/editor-extensions/typecad-ui/LICENSE +27 -0
- package/assets/editor-extensions/typecad-ui/README.md +52 -0
- package/assets/editor-extensions/typecad-ui/file-icon-dark.png +0 -0
- package/assets/editor-extensions/typecad-ui/file-icon-light.png +0 -0
- package/assets/editor-extensions/typecad-ui/icon.png +0 -0
- package/assets/editor-extensions/typecad-ui/language-configuration.json +43 -0
- package/assets/editor-extensions/typecad-ui/package.json +54 -0
- package/assets/editor-extensions/typecad-ui/snippets/typecad-ui.json +80 -0
- package/assets/editor-extensions/typecad-ui/syntaxes/markdown-ui.json +45 -0
- package/assets/editor-extensions/typecad-ui/syntaxes/typecad-ui.tmLanguage.json +1269 -0
- package/dist/api/config.d.ts +30 -27
- package/dist/api/schema/types.d.ts +20 -3
- package/dist/api/shared/async-runtime-static.d.ts +1 -1
- package/dist/api/shared/async-runtime-static.js +5 -5
- package/dist/api/shared/async-types.d.ts +3 -2
- package/dist/api/shared/board-catalog.d.ts +2 -0
- package/dist/api/shared/board-catalog.js +6 -0
- package/dist/api/shared/board-resolver.d.ts +4 -7
- package/dist/api/shared/board-resolver.js +2 -1
- package/dist/api/shared/coop-scheduler.d.ts +1 -1
- package/dist/api/shared/coop-scheduler.js +1 -1
- package/dist/api/shared/cpp-type-ir.d.ts +1 -1
- package/dist/api/shared/cpp-type-ir.js +1 -1
- package/dist/api/shared/display-profile.d.ts +1 -1
- package/dist/api/shared/display-profile.js +3 -5
- package/dist/api/shared/framework-manifest-registry.d.ts +1 -1
- package/dist/api/shared/framework-manifest-registry.js +0 -1
- package/dist/api/shared/framework-manifest.d.ts +65 -507
- package/dist/api/shared/framework-manifest.js +6 -11
- package/dist/api/shared/hal-op-ir.d.ts +294 -685
- package/dist/api/shared/hal-op-ir.js +31 -65
- package/dist/api/shared/index.d.ts +0 -4
- package/dist/api/shared/index.js +1 -7
- package/dist/api/shared/ir-core.d.ts +6 -0
- package/dist/api/shared/ir-declarations.d.ts +4 -0
- package/dist/api/shared/ir.d.ts +1 -3
- package/dist/api/shared/platform-strategy.d.ts +14 -37
- package/dist/api/shared/polyfill-helper-registry.js +0 -5
- package/dist/api/shared/polyfill-types.js +0 -27
- package/dist/api/shared/promise-runtime.js +3 -3
- package/dist/api/shared/spdx-licenses.d.ts +12 -10
- package/dist/api/shared/spdx-licenses.js +1 -1
- package/dist/api/shared/toolchain-types.d.ts +1 -1
- package/dist/api/shared/toolchain-types.js +3 -3
- package/dist/api/shared/types.d.ts +0 -3
- package/dist/api/shared/validate-framework-manifest.js +13 -33
- package/dist/board-catalog/dts-reader.d.ts +220 -0
- package/dist/board-catalog/dts-reader.js +1052 -0
- package/dist/board-catalog/index.d.ts +11 -0
- package/dist/board-catalog/index.js +12 -0
- package/dist/board-catalog/pinconfig.d.ts +48 -0
- package/dist/board-catalog/pinconfig.js +263 -0
- package/dist/board-catalog/sdk.d.ts +82 -0
- package/dist/board-catalog/sdk.js +180 -0
- package/dist/board-catalog/store.d.ts +196 -0
- package/dist/board-catalog/store.js +363 -0
- package/dist/board-catalog/types.d.ts +233 -0
- package/dist/board-catalog/types.js +7 -0
- package/dist/board-catalog/walker.d.ts +112 -0
- package/dist/board-catalog/walker.js +1101 -0
- package/dist/cli-utils.d.ts +2 -2
- package/dist/cli-utils.js +5 -5
- package/dist/cli.js +227 -244
- package/dist/config-loader.d.ts +14 -19
- package/dist/config-loader.js +242 -78
- package/dist/config-schema.d.ts +19 -227
- package/dist/config-schema.js +9 -8
- package/dist/contract/board-generator.d.ts +4 -4
- package/dist/contract/board-generator.js +16 -5
- package/dist/contract/contract-parser.d.ts +36 -127
- package/dist/contract/contract-parser.js +76 -0
- package/dist/contract/index.d.ts +1 -1
- package/dist/contract/index.js +70 -21
- package/dist/create/active-board-catalog.d.ts +9 -0
- package/dist/create/active-board-catalog.js +94 -0
- package/dist/create/board-catalog.generated.d.ts +96 -0
- package/dist/create/board-catalog.generated.js +128737 -0
- package/dist/create/board-search.d.ts +23 -0
- package/dist/create/board-search.js +88 -0
- package/dist/create/editor-integration.d.ts +32 -0
- package/dist/create/editor-integration.js +257 -0
- package/dist/create/eslint-rules-template.d.ts +2 -2
- package/dist/create/framework-catalog.d.ts +48 -8
- package/dist/create/framework-catalog.js +58 -44
- package/dist/create/index.d.ts +8 -13
- package/dist/create/index.js +5 -9
- package/dist/create/mcu-target.d.ts +39 -0
- package/dist/create/mcu-target.js +80 -0
- package/dist/create/pack-targets.d.ts +19 -0
- package/dist/create/pack-targets.js +56 -0
- package/dist/create/{init-scaffold.d.ts → scaffold.d.ts} +8 -11
- package/dist/create/{init-scaffold.js → scaffold.js} +28 -87
- package/dist/create/templates.d.ts +51 -0
- package/dist/create/{init-templates.js → templates.js} +135 -116
- package/dist/create/wizard.d.ts +19 -0
- package/dist/create/wizard.js +314 -0
- package/dist/debug/preprocessor.d.ts +5 -0
- package/dist/debug/preprocessor.js +31 -7
- package/dist/diagnostics/diagnostics-report.d.ts +1 -1
- package/dist/diagnostics/diagnostics-report.js +3 -11
- package/dist/diagnostics/json-schema.d.ts +1 -1
- package/dist/diagnostics/md-writer.js +2 -2
- package/dist/diagnostics/mermaid-builder.d.ts +1 -1
- package/dist/diagnostics/mermaid-builder.js +1 -1
- package/dist/emit/cpp-emitter.js +4 -1
- package/dist/emit/emitters/class-emitter.js +32 -4
- package/dist/emit/emitters/emitter-context.d.ts +11 -0
- package/dist/emit/emitters/entrypoint-synthesizer.js +1 -1
- package/dist/emit/emitters/function-emitter-impl.js +33 -17
- package/dist/emit/emitters/output-finalizer.d.ts +7 -0
- package/dist/emit/emitters/output-finalizer.js +31 -23
- package/dist/emit/emitters/setup.js +147 -63
- package/dist/emit/emitters/top-level-prep.js +1 -1
- package/dist/emit/emitters/type-decl-emitter.js +13 -8
- package/dist/emit/emitters/ui-emitter.js +1 -1
- package/dist/emit/expression-renderer.d.ts +3 -3
- package/dist/emit/expression-renderer.js +17 -7
- package/dist/emit/route-hal-op.js +17 -48
- package/dist/emit/snprintf-helpers.d.ts +1 -3
- package/dist/emit/snprintf-helpers.js +1 -39
- package/dist/emit/statement-renderer.d.ts +0 -4
- package/dist/emit/statement-renderer.js +54 -45
- package/dist/emit/utils/async-state-machine.d.ts +16 -9
- package/dist/emit/utils/async-state-machine.js +56 -54
- package/dist/emit/utils/comment-helpers.d.ts +0 -8
- package/dist/emit/utils/comment-helpers.js +1 -1
- package/dist/emit/utils/cpp-helpers.d.ts +2 -2
- package/dist/emit/utils/cpp-helpers.js +2 -2
- package/dist/emit/utils/hal-op-cpp-type.js +4 -6
- package/dist/emit/utils/index.d.ts +3 -3
- package/dist/emit/utils/index.js +3 -3
- package/dist/emit/utils/type-inference.d.ts +1 -29
- package/dist/emit/utils/type-inference.js +0 -75
- package/dist/framework-package.d.ts +3 -0
- package/dist/framework-package.js +23 -6
- package/dist/framework-registry.d.ts +5 -5
- package/dist/frameworks/native/graphics/terminal-preview.d.ts +5 -0
- package/dist/frameworks/native/graphics/terminal-preview.js +33 -0
- package/dist/frameworks/native/index.d.ts +3 -0
- package/dist/frameworks/native/index.js +15 -0
- package/dist/frameworks/native/native-compile.d.ts +17 -0
- package/dist/frameworks/native/native-compile.js +170 -0
- package/dist/frameworks/native/native-config.d.ts +41 -0
- package/dist/frameworks/native/native-config.js +7 -0
- package/dist/frameworks/native/strategy.d.ts +97 -0
- package/dist/frameworks/native/strategy.js +664 -0
- package/dist/ir/board-resolver.d.ts +18 -23
- package/dist/ir/board-resolver.js +43 -401
- package/dist/ir/build-ir-state.d.ts +3 -0
- package/dist/ir/build-ir-state.js +42 -0
- package/dist/ir/build-ir.d.ts +1 -1
- package/dist/ir/build-ir.js +64 -45
- package/dist/ir/declaration-builders.js +1 -0
- package/dist/ir/expression-to-ir.js +17 -10
- package/dist/ir/hal/hal-emitter.d.ts +0 -2
- package/dist/ir/hal/hal-emitter.js +92 -41
- package/dist/ir/hal/hal-parser.d.ts +5 -5
- package/dist/ir/hal/hal-parser.js +128 -36
- package/dist/ir/hal/hal-plugins.d.ts +0 -1
- package/dist/ir/hal/hal-plugins.js +425 -716
- package/dist/ir/heap-analysis.js +2 -41
- package/dist/ir/identifier-collector.js +32 -20
- package/dist/ir/network-validation.js +7 -11
- package/dist/ir/ownership-analysis.js +75 -13
- package/dist/ir/peripheral-usage.d.ts +8 -2
- package/dist/ir/peripheral-usage.js +78 -149
- package/dist/ir/peripheral-validation.js +23 -3
- package/dist/ir/pin-capability-validation.d.ts +12 -0
- package/dist/ir/pin-capability-validation.js +61 -97
- package/dist/ir/pin-mode-validation.js +5 -5
- package/dist/ir/program-analysis.d.ts +8 -15
- package/dist/ir/program-analysis.js +140 -323
- package/dist/ir/pulldown-validation.js +11 -4
- package/dist/ir/resource-analysis.js +15 -3
- package/dist/ir/statement-to-ir.js +0 -6
- package/dist/ir/timing-validation.js +1 -1
- package/dist/ir/transformers/array-methods.js +11 -5
- package/dist/ir/transformers/call-statement.js +20 -87
- package/dist/ir/transformers/callback-context-registry.d.ts +1 -1
- package/dist/ir/transformers/callback-context-registry.js +8 -16
- package/dist/ir/transformers/control-flow.js +0 -13
- package/dist/ir/transformers/expressions.js +10 -9
- package/dist/ir/transformers/hal-call-resolver.d.ts +2 -2
- package/dist/ir/transformers/hal-call-resolver.js +24 -10
- package/dist/ir/transformers/hal-emit-helpers.d.ts +2 -2
- package/dist/ir/transformers/hal-emit-helpers.js +2 -2
- package/dist/ir/transformers/namespace-methods.js +1 -1
- package/dist/ir/transformers/ui-callback-lowering.d.ts +0 -2
- package/dist/ir/transformers/ui-callback-lowering.js +0 -24
- package/dist/ir/transformers/variables.js +338 -42
- package/dist/ir/try-catch-validation.js +4 -3
- package/dist/ir/type-resolution.js +15 -4
- package/dist/ir/validation-orchestrator.js +0 -9
- package/dist/libdef/cpp-to-decl.d.ts +0 -9
- package/dist/libdef/cpp-to-decl.js +0 -72
- package/dist/libdef/registry.d.ts +0 -1
- package/dist/libdef/registry.js +1 -24
- package/dist/library/catalog.d.ts +35 -0
- package/dist/library/catalog.js +67 -0
- package/dist/library/cli.d.ts +2 -0
- package/dist/library/cli.js +168 -0
- package/dist/library/init.d.ts +25 -0
- package/dist/library/init.js +397 -0
- package/dist/library/install.d.ts +9 -0
- package/dist/library/install.js +80 -0
- package/dist/library/registry-search.d.ts +34 -0
- package/dist/library/registry-search.js +50 -0
- package/dist/library/validate.d.ts +17 -0
- package/dist/library/validate.js +175 -0
- package/dist/library-packages.d.ts +95 -0
- package/dist/library-packages.js +275 -0
- package/dist/mapping/peripheral-names.js +9 -4
- package/dist/mapping/source-map.d.ts +3 -4
- package/dist/mapping/source-map.js +12 -18
- package/dist/orchestrator/graph-builder.d.ts +3 -3
- package/dist/orchestrator/graph-builder.js +29 -12
- package/dist/orchestrator/type-checker.d.ts +3 -3
- package/dist/orchestrator/type-checker.js +3 -3
- package/dist/platform/async-runtime.js +1 -1
- package/dist/platform/coop-scheduler-runtime.js +2 -2
- package/dist/platform/generic-debug-codegen.d.ts +36 -0
- package/dist/platform/generic-debug-codegen.js +185 -0
- package/dist/platform/generic-strategy.d.ts +3 -4
- package/dist/platform/generic-strategy.js +5 -80
- package/dist/platform/index.js +1 -1
- package/dist/platform/registry.d.ts +2 -2
- package/dist/platform/registry.js +2 -2
- package/dist/preview/client.js +17 -3
- package/dist/safety/asil-decorators.d.ts +32 -0
- package/dist/safety/asil-decorators.js +32 -0
- package/dist/safety/authoring.d.ts +85 -0
- package/dist/safety/authoring.js +61 -0
- package/dist/safety/engine.d.ts +3 -0
- package/dist/safety/engine.js +83 -0
- package/dist/safety/hal/ops.d.ts +48 -0
- package/dist/safety/hal/ops.js +46 -0
- package/dist/safety/iso26262/analyze.d.ts +13 -0
- package/dist/safety/iso26262/analyze.js +29 -0
- package/dist/safety/iso26262/asil.d.ts +10 -0
- package/dist/safety/iso26262/asil.js +22 -0
- package/dist/safety/iso26262/collect.d.ts +14 -0
- package/dist/safety/iso26262/collect.js +137 -0
- package/dist/safety/iso26262/goto-checker.d.ts +10 -0
- package/dist/safety/iso26262/goto-checker.js +72 -0
- package/dist/safety/iso26262/heap-checker.d.ts +7 -0
- package/dist/safety/iso26262/heap-checker.js +57 -0
- package/dist/safety/iso26262/init-checker.d.ts +13 -0
- package/dist/safety/iso26262/init-checker.js +127 -0
- package/dist/safety/iso26262/loop-checker.d.ts +7 -0
- package/dist/safety/iso26262/loop-checker.js +86 -0
- package/dist/safety/iso26262/recursion-checker.d.ts +9 -0
- package/dist/safety/iso26262/recursion-checker.js +134 -0
- package/dist/safety/iso26262/sidecar-writer.d.ts +25 -0
- package/dist/safety/iso26262/sidecar-writer.js +13 -0
- package/dist/safety/passes/pinMode-intercept.d.ts +3 -0
- package/dist/safety/passes/pinMode-intercept.js +60 -0
- package/dist/safety/runtime/mode-table.d.ts +5 -0
- package/dist/safety/runtime/mode-table.js +55 -0
- package/dist/safety/runtime/polyfills.d.ts +6 -0
- package/dist/safety/runtime/polyfills.js +12 -0
- package/dist/safety/runtime/result-struct.d.ts +11 -0
- package/dist/safety/runtime/result-struct.js +98 -0
- package/dist/safety/runtime/safe-int.d.ts +33 -0
- package/dist/safety/runtime/safe-int.js +170 -0
- package/dist/safety/runtime/safe-traits.d.ts +4 -0
- package/dist/safety/runtime/safe-traits.js +95 -0
- package/dist/safety/runtime/safe-variable.d.ts +39 -0
- package/dist/safety/runtime/safe-variable.js +226 -0
- package/dist/safety/runtime/vote.d.ts +8 -0
- package/dist/safety/runtime/vote.js +92 -0
- package/dist/safety/runtime/write-verify.d.ts +8 -0
- package/dist/safety/runtime/write-verify.js +71 -0
- package/dist/safety/safe-int-types.d.ts +45 -0
- package/dist/safety/safe-int-types.js +25 -0
- package/dist/safety/safe-variable-types.d.ts +29 -0
- package/dist/safety/safe-variable-types.js +19 -0
- package/dist/safety/safety-bridge.d.ts +5 -6
- package/dist/safety/safety-bridge.js +15 -28
- package/dist/safety/sidecar-bridge.d.ts +1 -3
- package/dist/safety/sidecar-bridge.js +3 -20
- package/dist/safety/specifiers.d.ts +6 -0
- package/dist/safety/specifiers.js +14 -0
- package/dist/safety-hook.d.ts +8 -7
- package/dist/safety-hook.js +12 -13
- package/dist/testing.d.ts +5 -6
- package/dist/testing.js +5 -5
- package/dist/transpile/resolution.d.ts +1 -1
- package/dist/transpile/resolution.js +18 -9
- package/dist/transpile/test-pins.d.ts +18 -0
- package/dist/transpile/test-pins.js +142 -0
- package/dist/transpile.d.ts +1 -2
- package/dist/transpile.js +90 -29
- package/dist/types.d.ts +45 -26
- package/dist/ui-hook.d.ts +1 -1
- package/dist/utils/cli.d.ts +2 -2
- package/dist/utils/cli.js +160 -157
- package/dist/utils/fs.d.ts +3 -4
- package/dist/utils/fs.js +4 -5
- package/dist/utils/strings.d.ts +0 -1
- package/dist/utils/strings.js +0 -8
- package/dist/utils/ui.d.ts +5 -2
- package/dist/utils/ui.js +13 -3
- package/package.json +158 -149
- package/dist/add-preset.d.ts +0 -4
- package/dist/add-preset.js +0 -74
- package/dist/api/shared/async-symbol-detector.d.ts +0 -11
- package/dist/api/shared/async-symbol-detector.js +0 -140
- package/dist/api/shared/native-display-op-resolver.d.ts +0 -10
- package/dist/api/shared/native-display-op-resolver.js +0 -64
- package/dist/create/board-checklist.d.ts +0 -2
- package/dist/create/board-checklist.js +0 -52
- package/dist/create/board-codegen.d.ts +0 -9
- package/dist/create/board-codegen.js +0 -238
- package/dist/create/board-generators.d.ts +0 -12
- package/dist/create/board-generators.js +0 -651
- package/dist/create/board-spec.d.ts +0 -637
- package/dist/create/board-spec.js +0 -214
- package/dist/create/init-templates.d.ts +0 -28
- package/dist/create/init-wizard.d.ts +0 -8
- package/dist/create/init-wizard.js +0 -182
- package/dist/install/framework-catalog.d.ts +0 -53
- package/dist/install/framework-catalog.js +0 -107
- package/dist/install/handle-install.d.ts +0 -35
- package/dist/install/handle-install.js +0 -177
- package/dist/install/index.d.ts +0 -4
- package/dist/install/index.js +0 -3
- package/dist/ir/pin-state-tracking.d.ts +0 -58
- package/dist/ir/pin-state-tracking.js +0 -182
- package/dist/ir/pwm-timer-sharing.d.ts +0 -4
- package/dist/ir/pwm-timer-sharing.js +0 -94
- package/dist/ir/timer0-pwm-timing-conflict.d.ts +0 -4
- package/dist/ir/timer0-pwm-timing-conflict.js +0 -72
- package/dist/libdef/component-decls.d.ts +0 -2
- package/dist/libdef/component-decls.js +0 -6
- package/dist/libdef/component-discovery.d.ts +0 -43
- package/dist/libdef/component-discovery.js +0 -83
- package/dist/theme-tokens.d.ts +0 -22
- package/dist/theme-tokens.js +0 -172
|
@@ -311,36 +311,40 @@ export function emitFunctions(ctx) {
|
|
|
311
311
|
// Drive the UI runtime each frame. Fires only in the driver function when
|
|
312
312
|
// a UI is mounted (entryHasUI). Uses a separate gate from the async pump
|
|
313
313
|
// so a pure-UI program (no async/timers) still animates. When the strategy
|
|
314
|
-
// provides hostEventLoop, the per-frame work
|
|
315
|
-
//
|
|
316
|
-
//
|
|
317
|
-
//
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
314
|
+
// provides hostEventLoop, the per-frame work — ui_tick AND the async-task
|
|
315
|
+
// injections below — runs inside a while loop so a driver that is called
|
|
316
|
+
// once (a main() entrypoint: SDL native, Zephyr's scheduler loop) can pump
|
|
317
|
+
// events, tick the UI, and advance async tasks every frame. (A repeatedly-
|
|
318
|
+
// called driver like Arduino's loop() provides no hostEventLoop and the
|
|
319
|
+
// work stays flat.) Emitted AFTER the function's init statements
|
|
320
|
+
// (ui_init/display_init/touch_init) so initialization precedes the loop.
|
|
321
|
+
const hostLoop = entryHasUI() && fn.name === asyncDriverFn
|
|
322
|
+
? strategy.hostEventLoop?.()
|
|
323
|
+
: undefined;
|
|
324
|
+
if (hostLoop) {
|
|
325
|
+
appendSourceLine(ctx, ` bool ${hostLoop.flagName} = true;`);
|
|
326
|
+
appendSourceLine(ctx, ` while (${hostLoop.continueCondition}) {`);
|
|
327
|
+
if (hostLoop.preIteration) {
|
|
328
|
+
appendSourceLine(ctx, ` ${hostLoop.preIteration}`);
|
|
324
329
|
}
|
|
330
|
+
}
|
|
331
|
+
if (entryHasUI() && fn.name === asyncDriverFn) {
|
|
325
332
|
appendSourceLine(ctx, ` uint32_t __tc_ui_now = static_cast<uint32_t>(${strategy.currentTimeMillis()});`);
|
|
326
333
|
appendSourceLine(ctx, " static uint32_t __tc_ui_last_tick = __tc_ui_now;");
|
|
327
334
|
appendSourceLine(ctx, " uint32_t __tc_ui_delta = __tc_ui_now - __tc_ui_last_tick;");
|
|
328
335
|
appendSourceLine(ctx, " __tc_ui_last_tick = __tc_ui_now;");
|
|
329
336
|
appendSourceLine(ctx, " if (__tc_ui_delta > 250) __tc_ui_delta = 250;");
|
|
330
337
|
appendSourceLine(ctx, " ui_tick(static_cast<uint16_t>(__tc_ui_delta));");
|
|
331
|
-
if (loop) {
|
|
332
|
-
appendSourceLine(ctx, ` ${loop.postIteration}`);
|
|
333
|
-
appendSourceLine(ctx, ` }`);
|
|
334
|
-
}
|
|
335
338
|
}
|
|
336
339
|
if (isLoopDriver && (hasPromiseRuntime || asyncTaskClasses.length > 0 || usesTimers)) {
|
|
337
340
|
const taskNames = asyncTaskClasses.map(t => t.taskVarName);
|
|
338
341
|
const asyncConfig = strategy.getAsyncRuntimeConfig();
|
|
339
342
|
asyncConfig.hasPromiseRuntime = hasPromiseRuntime;
|
|
340
343
|
asyncConfig.hasTimers = usesTimers;
|
|
344
|
+
const injectionIndent = hostLoop ? " " : " ";
|
|
341
345
|
// Cooperative scheduler path (Phase 0): when opted in, replace the flat
|
|
342
346
|
// per-frame pump sequence with a single CoopSched dispatch. The work
|
|
343
|
-
// units mirror exactly what
|
|
347
|
+
// units mirror exactly what a strategy's asyncLoopInjection() would
|
|
344
348
|
// have emitted (so Zephyr, which omits the microtask pump, still omits
|
|
345
349
|
// it), but they are dispatched in priority order and budget-bounded.
|
|
346
350
|
if (asyncConfig.enablePriority || asyncConfig.enableTimeBudget) {
|
|
@@ -354,16 +358,22 @@ export function emitFunctions(ctx) {
|
|
|
354
358
|
// No work units: fall back to the strategy's own injection.
|
|
355
359
|
const injectionLines = strategy.asyncLoopInjection(taskNames, asyncConfig);
|
|
356
360
|
for (const line of injectionLines)
|
|
357
|
-
appendSourceLine(ctx,
|
|
361
|
+
appendSourceLine(ctx, `${injectionIndent}${line}`);
|
|
358
362
|
}
|
|
359
363
|
}
|
|
360
364
|
else {
|
|
361
365
|
const injectionLines = strategy.asyncLoopInjection(taskNames, asyncConfig);
|
|
362
366
|
for (const line of injectionLines) {
|
|
363
|
-
appendSourceLine(ctx,
|
|
367
|
+
appendSourceLine(ctx, `${injectionIndent}${line}`);
|
|
364
368
|
}
|
|
365
369
|
}
|
|
366
370
|
}
|
|
371
|
+
if (hostLoop) {
|
|
372
|
+
if (hostLoop.postIteration) {
|
|
373
|
+
appendSourceLine(ctx, ` ${hostLoop.postIteration}`);
|
|
374
|
+
}
|
|
375
|
+
appendSourceLine(ctx, " }");
|
|
376
|
+
}
|
|
367
377
|
if (isLoopDriver && lastIsReturn) {
|
|
368
378
|
appendRenderedStatement(ctx, lastStmt, " ", functionScope);
|
|
369
379
|
}
|
|
@@ -400,6 +410,12 @@ export function emitFunctions(ctx) {
|
|
|
400
410
|
export function emitFunctionForwardDeclarations(ctx) {
|
|
401
411
|
const { strategy, effectiveEmitMode } = ctx;
|
|
402
412
|
const excludedNames = new Set(strategy.forwardDeclarationExclusions?.() ?? []);
|
|
413
|
+
// Async-method starters: the owning class's method body calls these before
|
|
414
|
+
// the task class (and this definition) exists later in the TU. The class
|
|
415
|
+
// forward declarations emitted nearby make the <Class>* parameter valid.
|
|
416
|
+
for (const starter of ctx.asyncMethodStarters ?? []) {
|
|
417
|
+
appendSourceLine(ctx, starter.proto);
|
|
418
|
+
}
|
|
403
419
|
// Callback forward declarations (no IRAM_ATTR — ESP-IDF's attribute uses
|
|
404
420
|
// __COUNTER__, so decl+def would get conflicting .iram1.N sections).
|
|
405
421
|
if (effectiveEmitMode !== "split") {
|
|
@@ -7,4 +7,11 @@ export declare function emitPreamble(ctx: EmitterContext): void;
|
|
|
7
7
|
* from task bodies are already declared.
|
|
8
8
|
*/
|
|
9
9
|
export declare function emitAsyncTaskClasses(ctx: EmitterContext): void;
|
|
10
|
+
/**
|
|
11
|
+
* Emit async-METHOD task classes + instances + starter definitions. Must run
|
|
12
|
+
* AFTER emitClasses (segments dereference _owner->field on the now-complete
|
|
13
|
+
* owning class) and BEFORE emitFunctions (the loop pump references the
|
|
14
|
+
* instances; the starter definitions call .start on them).
|
|
15
|
+
*/
|
|
16
|
+
export declare function emitAsyncMethodTasks(ctx: EmitterContext): void;
|
|
10
17
|
export declare function finalizeOutput(ctx: EmitterContext): GeneratedOutputs;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { writeText, readText } from "../../utils/fs.js";
|
|
3
3
|
import { makeGeneratedMap, writeSourceMap } from "../../mapping/source-map.js";
|
|
4
|
-
import { dedupe,
|
|
4
|
+
import { dedupe, resolveTranspiledModuleInclude } from "../utils/index.js";
|
|
5
5
|
import { appendHeaderLine } from "./line-appender.js";
|
|
6
6
|
import { runSelfCheck } from "../compliance/rule-engine.js";
|
|
7
7
|
import { renderRegistryJson } from "../compliance/deviation-writer.js";
|
|
@@ -78,24 +78,6 @@ export function emitPreamble(ctx) {
|
|
|
78
78
|
}
|
|
79
79
|
// Async task classes are emitted later (emitAsyncTaskClasses) AFTER top-level
|
|
80
80
|
// globals so references like WIFI_SSID inside the state machine compile.
|
|
81
|
-
if (strategy.needsVectorOverload() && hasConsoleCalls(program, strategy) && (programAnalysis.usesVectorTypes || programAnalysis.hasArrayInObjectLiteral)) {
|
|
82
|
-
appendSourceLineLocal(ctx, "template <typename T>");
|
|
83
|
-
appendSourceLineLocal(ctx, "std::ostream& operator<<(std::ostream& os, const std::vector<T>& values)");
|
|
84
|
-
appendSourceLineLocal(ctx, "{");
|
|
85
|
-
appendSourceLineLocal(ctx, ' os << "[";');
|
|
86
|
-
appendSourceLineLocal(ctx, " for (size_t i = 0; i < values.size(); ++i)");
|
|
87
|
-
appendSourceLineLocal(ctx, " {");
|
|
88
|
-
appendSourceLineLocal(ctx, " if (i > 0)");
|
|
89
|
-
appendSourceLineLocal(ctx, " {");
|
|
90
|
-
appendSourceLineLocal(ctx, ' os << ", ";');
|
|
91
|
-
appendSourceLineLocal(ctx, " }");
|
|
92
|
-
appendSourceLineLocal(ctx, " os << values[i];");
|
|
93
|
-
appendSourceLineLocal(ctx, " }");
|
|
94
|
-
appendSourceLineLocal(ctx, ' os << "]";');
|
|
95
|
-
appendSourceLineLocal(ctx, " return os;");
|
|
96
|
-
appendSourceLineLocal(ctx, "}");
|
|
97
|
-
appendSourceLineLocal(ctx, "");
|
|
98
|
-
}
|
|
99
81
|
if (programAnalysis.hasGenerators) {
|
|
100
82
|
appendSourceLineLocal(ctx, "#include <coroutine>");
|
|
101
83
|
appendSourceLineLocal(ctx, "#include <optional>");
|
|
@@ -140,12 +122,38 @@ export function emitAsyncTaskClasses(ctx) {
|
|
|
140
122
|
const { asyncTaskClasses } = ctx;
|
|
141
123
|
if (asyncTaskClasses.length === 0)
|
|
142
124
|
return;
|
|
143
|
-
for (const
|
|
144
|
-
|
|
125
|
+
for (const t of asyncTaskClasses) {
|
|
126
|
+
// Async-METHOD tasks move to emitAsyncMethodTasks (after the user
|
|
127
|
+
// classes): their segment bodies dereference `_owner->field`, which
|
|
128
|
+
// needs the owning class COMPLETE — at this point only the forward
|
|
129
|
+
// declaration exists.
|
|
130
|
+
if (t.starterDef !== undefined)
|
|
131
|
+
continue;
|
|
132
|
+
for (const line of t.classDef.split("\n")) {
|
|
133
|
+
appendSourceLineLocal(ctx, line);
|
|
134
|
+
}
|
|
135
|
+
appendSourceLineLocal(ctx, "");
|
|
136
|
+
appendSourceLineLocal(ctx, t.instanceDecl);
|
|
137
|
+
appendSourceLineLocal(ctx, "");
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Emit async-METHOD task classes + instances + starter definitions. Must run
|
|
142
|
+
* AFTER emitClasses (segments dereference _owner->field on the now-complete
|
|
143
|
+
* owning class) and BEFORE emitFunctions (the loop pump references the
|
|
144
|
+
* instances; the starter definitions call .start on them).
|
|
145
|
+
*/
|
|
146
|
+
export function emitAsyncMethodTasks(ctx) {
|
|
147
|
+
const { asyncTaskClasses } = ctx;
|
|
148
|
+
for (const t of asyncTaskClasses) {
|
|
149
|
+
if (t.starterDef === undefined)
|
|
150
|
+
continue;
|
|
151
|
+
for (const line of t.classDef.split("\n")) {
|
|
145
152
|
appendSourceLineLocal(ctx, line);
|
|
146
153
|
}
|
|
147
154
|
appendSourceLineLocal(ctx, "");
|
|
148
|
-
appendSourceLineLocal(ctx, instanceDecl);
|
|
155
|
+
appendSourceLineLocal(ctx, t.instanceDecl);
|
|
156
|
+
appendSourceLineLocal(ctx, t.starterDef);
|
|
149
157
|
appendSourceLineLocal(ctx, "");
|
|
150
158
|
}
|
|
151
159
|
}
|
|
@@ -330,7 +338,7 @@ export function finalizeOutput(ctx) {
|
|
|
330
338
|
}
|
|
331
339
|
// Sidecar deviation registry — written for both warn and strict modes
|
|
332
340
|
// alongside the emitted artifact (mirrors how .thcppmap.json sits next
|
|
333
|
-
// to the .cpp
|
|
341
|
+
// to the .cpp today).
|
|
334
342
|
const toolVersion = options.toolVersion ?? "unknown";
|
|
335
343
|
const registryPath = path.join(outDir, `${baseName}.autosar-deviations.json`);
|
|
336
344
|
writeText(registryPath, renderRegistryJson(ctx.compliance, path.basename(sourcePath), toolVersion));
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { filterPolyfillHelpers, isStringEnum } from "../../api/shared/index.js";
|
|
3
3
|
import { hasSafetyHook, requireSafetyHook } from "../../safety-hook.js";
|
|
4
|
+
import { isSafetyImportSpecifier } from "../../safety/specifiers.js";
|
|
4
5
|
import { analyzeProgram } from "../../ir/program-analysis.js";
|
|
5
6
|
import { collectStatementIdentifiers } from "../../ir/identifier-collector.js";
|
|
6
7
|
import { ensureDir } from "../../utils/fs.js";
|
|
7
8
|
import { resolveImport } from "../../libdef/registry.js";
|
|
9
|
+
import { isRegisteredCuttlefishLibrary } from "../../library-packages.js";
|
|
8
10
|
import { emitPolyfillBoilerplate } from "../native-helpers-emitter.js";
|
|
9
11
|
import { resolveStrategy } from "../../platform/registry.js";
|
|
10
12
|
import { buildCoopSchedulerPolyfill } from "../../platform/coop-scheduler-runtime.js";
|
|
@@ -239,6 +241,11 @@ function extractShimMacro(lines, macroName) {
|
|
|
239
241
|
return lines.slice(ifndefIdx, endIdx + 1);
|
|
240
242
|
}
|
|
241
243
|
export function buildEmitterContext(program, options) {
|
|
244
|
+
// Framework strategies that resolve per-program chip data (Zephyr's chip
|
|
245
|
+
// view reconstructs from the generated manifest) must do it before any
|
|
246
|
+
// body rendering — hal-op lowering reads their cached descriptor.
|
|
247
|
+
options.strategy
|
|
248
|
+
?.prepareChip?.(program, options.platformContext);
|
|
242
249
|
const largeEnumNames = new Set();
|
|
243
250
|
const enumNames = new Set();
|
|
244
251
|
const stringEnumNames = new Set();
|
|
@@ -312,23 +319,6 @@ export function buildEmitterContext(program, options) {
|
|
|
312
319
|
})();
|
|
313
320
|
const programAnalysis = analyzeProgram(program, strategy);
|
|
314
321
|
if (options.platformContext) {
|
|
315
|
-
// The UI runtime's per-frame tick calls millis() (injected by the emitter,
|
|
316
|
-
// not present in user source), so a mounted UI needs the native millis ISR
|
|
317
|
-
// even when usesNativeTiming is false. OR entryHasUI() into the flag the
|
|
318
|
-
// AVR strategy reads when gating native_millis, so framework-avr doesn't
|
|
319
|
-
// drop the Timer0 ISR from a UI program.
|
|
320
|
-
if (!programAnalysis.usesNativeTiming && entryHasUI()) {
|
|
321
|
-
programAnalysis.usesNativeTiming = true;
|
|
322
|
-
}
|
|
323
|
-
// The UI runtime header calls constrain() in the progress/range node draw
|
|
324
|
-
// and touch-slider paths (injected by the emitter, not present in user
|
|
325
|
-
// source), so a mounted UI needs the constrain polyfill even when
|
|
326
|
-
// usesConstrain is false. OR entryHasUI() into the flag the native
|
|
327
|
-
// strategy reads when gating the constrain helper, mirroring the
|
|
328
|
-
// usesNativeTiming handling above.
|
|
329
|
-
if (!programAnalysis.usesConstrain && entryHasUI()) {
|
|
330
|
-
programAnalysis.usesConstrain = true;
|
|
331
|
-
}
|
|
332
322
|
options.platformContext.analysis = programAnalysis;
|
|
333
323
|
if (!options.platformContext.architecture && program.boardConstants) {
|
|
334
324
|
options.platformContext.architecture = program.boardConstants.get("architecture");
|
|
@@ -367,16 +357,11 @@ export function buildEmitterContext(program, options) {
|
|
|
367
357
|
if (!programAnalysis.usedPolyfillHelpers.has('__tc_StaticArray')) {
|
|
368
358
|
filteredNativePolyfills = filteredNativePolyfills.filter(p => p.id !== "static_array");
|
|
369
359
|
}
|
|
370
|
-
const usesTimers = programAnalysis.usedPolyfillHelpers.has('__tc_setInterval') ||
|
|
371
|
-
programAnalysis.usedPolyfillHelpers.has('__tc_setTimeout');
|
|
372
|
-
if (!usesTimers) {
|
|
373
|
-
filteredNativePolyfills = filteredNativePolyfills.filter(p => p.id !== "timer_methods");
|
|
374
|
-
}
|
|
375
360
|
// Safety polyfills (mode table + voter + SafeVariable + SafeInt). Gated on
|
|
376
|
-
// programUsesSafety(program) so they ONLY appear when the
|
|
361
|
+
// programUsesSafety(program) so they ONLY appear when the program actually
|
|
377
362
|
// references a safety construct — emitting them unconditionally (just because
|
|
378
363
|
// @typecad/safety is installed and registered its hook) leaks ~200 lines of
|
|
379
|
-
// polyfill into every
|
|
364
|
+
// polyfill into every program, and SafeInt's `return *this` chaining methods
|
|
380
365
|
// tripped byte-identity / lowering assertions that expect no `this` token.
|
|
381
366
|
// programUsesSafety walks the IR for any safety.* hal-op.
|
|
382
367
|
if (isEntryFile && hasSafetyHook() && programUsesSafety(program)) {
|
|
@@ -392,8 +377,7 @@ export function buildEmitterContext(program, options) {
|
|
|
392
377
|
// minimal-libc targets (Zephyr) where the Promise runtime does not.
|
|
393
378
|
const coopConfig = strategy.getAsyncRuntimeConfig?.();
|
|
394
379
|
const hasCoopWork = program.functions.some(fn => fn.isAsync) ||
|
|
395
|
-
|
|
396
|
-
programAnalysis.usedPolyfillHelpers.has('__tc_setTimeout');
|
|
380
|
+
program.classes.some(c => c.methods.some(m => m.isAsync));
|
|
397
381
|
if (isEntryFile && coopConfig && hasCoopWork) {
|
|
398
382
|
const coop = buildCoopSchedulerPolyfill(program, coopConfig, strategy.currentTimeMillis());
|
|
399
383
|
if (coop)
|
|
@@ -403,8 +387,13 @@ export function buildEmitterContext(program, options) {
|
|
|
403
387
|
const emittedPolyfills = allPolyfills.length > 0
|
|
404
388
|
? emitPolyfillBoilerplate(allPolyfills)
|
|
405
389
|
: undefined;
|
|
406
|
-
const hasAsyncRuntime = program.functions.some(fn => fn.isAsync);
|
|
390
|
+
const hasAsyncRuntime = program.functions.some(fn => fn.isAsync) || program.classes.some(c => c.methods.some(m => m.isAsync));
|
|
407
391
|
const hasPromiseRuntime = nativePolyfills.some((p) => p.id === "async_runtime" && p.hasPromiseRuntime === true);
|
|
392
|
+
// Native timer capability comes from the strategy's async config, not from
|
|
393
|
+
// scanning the program: platforms either provide native timer callbacks for
|
|
394
|
+
// the async runtime (host/native) or they do not (Zephyr — periodic work is
|
|
395
|
+
// a Thread or a Counter there).
|
|
396
|
+
const usesTimers = strategy.getAsyncRuntimeConfig?.()?.hasTimers === true;
|
|
408
397
|
if (!isNpmPackage) {
|
|
409
398
|
includes.push(...strategy.forcedIncludes(program, options.platformContext));
|
|
410
399
|
Object.assign(symbolMap, strategy.symbolAliases(program, options.platformContext));
|
|
@@ -423,16 +412,6 @@ export function buildEmitterContext(program, options) {
|
|
|
423
412
|
if (!programAnalysis.usesDateNow) {
|
|
424
413
|
shimLines = shimLines.filter(l => !l.includes('namespace Date'));
|
|
425
414
|
}
|
|
426
|
-
// The UI runtime's per-frame tick uses millis() (injected by the emitter,
|
|
427
|
-
// not authored in user source), so keep the millis() shim when a UI is
|
|
428
|
-
// mounted even if the source-level analysis didn't flag usesMillis. The
|
|
429
|
-
// async runtime and the setInterval/setTimeout scheduler also poll
|
|
430
|
-
// millis() without any user-source millis() call (Async.sleep lowers to a
|
|
431
|
-
// raw hal-op the timing scanners can't see) — mirror the usesNativeTiming
|
|
432
|
-
// derivation and keep the shim for those hidden consumers too.
|
|
433
|
-
if (!programAnalysis.usesMillis && !programAnalysis.hasAsync && programAnalysis.timerCallCount === 0 && !entryHasUI()) {
|
|
434
|
-
shimLines = shimLines.filter(l => !l.includes('millis()'));
|
|
435
|
-
}
|
|
436
415
|
// Strip the nullish helper FUNCTIONS (not the CUTTLEFISH_UNDEFINED macro)
|
|
437
416
|
// when the file doesn't actually emit cuttlefish_nullish(...) calls. A
|
|
438
417
|
// file that only references `null`/`undefined` literals needs just the
|
|
@@ -444,6 +423,14 @@ export function buildEmitterContext(program, options) {
|
|
|
444
423
|
// cuttlefish_nullish( call (a more reliable post-emit check than the
|
|
445
424
|
// per-file pre-emit analysis flag). The logic here governs the .cpp
|
|
446
425
|
// source shim only.
|
|
426
|
+
// The runtime clock (__tc_now_ms) is gated by the Zephyr strategy at
|
|
427
|
+
// emission; native emits its definition unconditionally. Strip it from
|
|
428
|
+
// programs that can never read the clock (no Time calls, async, timers,
|
|
429
|
+
// scheduler, or mounted UI) so the definition doesn't leak into the
|
|
430
|
+
// emitted header.
|
|
431
|
+
if (!programAnalysis.usesWallClock && !programAnalysis.hasAsync && !entryHasUI() && !hasPromiseRuntime) {
|
|
432
|
+
shimLines = shimLines.filter(l => !l.includes('__tc_now_ms'));
|
|
433
|
+
}
|
|
447
434
|
if (!programAnalysis.usesNullishHelper) {
|
|
448
435
|
const filtered = [];
|
|
449
436
|
for (let i = 0; i < shimLines.length; i++) {
|
|
@@ -457,9 +444,6 @@ export function buildEmitterContext(program, options) {
|
|
|
457
444
|
if (!programAnalysis.usesNum) {
|
|
458
445
|
shimLines = filterShimBlock(shimLines, 'struct __tc_Num {', '} Num;');
|
|
459
446
|
}
|
|
460
|
-
if (!programAnalysis.usesTiming) {
|
|
461
|
-
shimLines = filterShimBlock(shimLines, 'struct __tc_Timing {', '} Timing;');
|
|
462
|
-
}
|
|
463
447
|
if (!programAnalysis.usesWDT) {
|
|
464
448
|
shimLines = filterShimBlock(shimLines, '#include <avr/wdt.h>', '} WDT;');
|
|
465
449
|
}
|
|
@@ -472,9 +456,7 @@ export function buildEmitterContext(program, options) {
|
|
|
472
456
|
// these filters are no-ops there. The strategies also self-gate on the
|
|
473
457
|
// same flags; this is the defensive backstop (mirrors how usesWDT/etc.
|
|
474
458
|
// backstop the strategy-side gating above).
|
|
475
|
-
|
|
476
|
-
// call _uart_* functions) even if no direct uart.* HAL ops are used.
|
|
477
|
-
if (!programAnalysis.usesUart && !programAnalysis.hasConsoleCalls) {
|
|
459
|
+
if (!programAnalysis.usesUart) {
|
|
478
460
|
shimLines = filterShimBlock(shimLines, '// CUTTLEFISH_UART_BEGIN', '// CUTTLEFISH_UART_END');
|
|
479
461
|
shimLines = filterShimBlock(shimLines, '// CUTTLEFISH_UART_EXT_BEGIN', '// CUTTLEFISH_UART_EXT_END');
|
|
480
462
|
}
|
|
@@ -484,14 +466,8 @@ export function buildEmitterContext(program, options) {
|
|
|
484
466
|
if (!programAnalysis.usesI2C) {
|
|
485
467
|
shimLines = filterShimBlock(shimLines, '// CUTTLEFISH_TWI_BEGIN', '// CUTTLEFISH_TWI_END');
|
|
486
468
|
}
|
|
487
|
-
if (!programAnalysis.usesEEPROM && !programAnalysis.usesPreferences) {
|
|
488
|
-
shimLines = filterShimBlock(shimLines, '// CUTTLEFISH_EEPROM_BEGIN', '// CUTTLEFISH_EEPROM_END');
|
|
489
|
-
}
|
|
490
|
-
if (!programAnalysis.usesTone) {
|
|
491
|
-
shimLines = filterShimBlock(shimLines, '// CUTTLEFISH_TONE_BEGIN', '// CUTTLEFISH_TONE_END');
|
|
492
|
-
}
|
|
493
469
|
// framework-esp32 native peripheral driver shims. Same defensive-backstop
|
|
494
|
-
// pattern as the UART/SPI/TWI/EEPROM
|
|
470
|
+
// pattern as the UART/SPI/TWI/EEPROM blocks above. framework-arduino's
|
|
495
471
|
// and framework-avr's shimLines contain none of these markers, so these
|
|
496
472
|
// filters are no-ops there.
|
|
497
473
|
if (!programAnalysis.usesGPIO) {
|
|
@@ -506,9 +482,6 @@ export function buildEmitterContext(program, options) {
|
|
|
506
482
|
if (!programAnalysis.usesDAC) {
|
|
507
483
|
shimLines = filterShimBlock(shimLines, '// CUTTLEFISH_DAC_BEGIN', '// CUTTLEFISH_DAC_END');
|
|
508
484
|
}
|
|
509
|
-
if (!programAnalysis.usesPower) {
|
|
510
|
-
shimLines = filterShimBlock(shimLines, '// CUTTLEFISH_POWER_BEGIN', '// CUTTLEFISH_POWER_END');
|
|
511
|
-
}
|
|
512
485
|
if (!programAnalysis.usesWdt) {
|
|
513
486
|
shimLines = filterShimBlock(shimLines, '// CUTTLEFISH_WDT_BEGIN', '// CUTTLEFISH_WDT_END');
|
|
514
487
|
}
|
|
@@ -547,6 +520,14 @@ export function buildEmitterContext(program, options) {
|
|
|
547
520
|
if (!programAnalysis.usesPreferences) {
|
|
548
521
|
shimLines = filterShimBlock(shimLines, '// CUTTLEFISH_PREFERENCES_BEGIN', '// CUTTLEFISH_PREFERENCES_END');
|
|
549
522
|
}
|
|
523
|
+
// Entry-TU marker for framework shims: the UI runtime header (ui_tick) is
|
|
524
|
+
// emitted ONLY into the entry file (emitUIRuntime gates on isEntryFile), so
|
|
525
|
+
// shim helpers that keep the UI alive during bounded blocking waits (e.g.
|
|
526
|
+
// Zephyr's wifi connect) must compile those calls down everywhere else.
|
|
527
|
+
// Defined before the shim lines land in the preamble, after all filters.
|
|
528
|
+
if (isEntryFile && entryHasUI() && shimLines.length > 0) {
|
|
529
|
+
shimLines.unshift("#define CUTTLEFISH_ENTRY_UI_TU 1");
|
|
530
|
+
}
|
|
550
531
|
profileDiagnostics = [...strategy.profileDiagnostics(program, options.platformContext)];
|
|
551
532
|
}
|
|
552
533
|
for (const imported of program.imports) {
|
|
@@ -554,6 +535,19 @@ export function buildEmitterContext(program, options) {
|
|
|
554
535
|
// named imports — add it to the symbolMap so cross-module references
|
|
555
536
|
// resolve. Demo #12 Finding C — was skipped, so `encode` wasn't declared.
|
|
556
537
|
const defaultName = imported.defaultImportName;
|
|
538
|
+
// Cuttlefish library packages: the import emits the shim-header include
|
|
539
|
+
// (resolved through the libdef registry from the library manifest) and
|
|
540
|
+
// contributes native shims + build fragments. This must run BEFORE the
|
|
541
|
+
// SDK skip below — @typecad-scoped libraries would otherwise be treated
|
|
542
|
+
// as type-level-only like the rest of the SDK.
|
|
543
|
+
if (isRegisteredCuttlefishLibrary(imported.moduleSpecifier)) {
|
|
544
|
+
const resolved = resolveImport(imported, options.libdefs, options.target, options.platformContext, program.fileName);
|
|
545
|
+
includes.push(normalizeInclude(resolved.include));
|
|
546
|
+
Object.assign(symbolMap, resolved.symbolMap);
|
|
547
|
+
if (defaultName)
|
|
548
|
+
symbolMap[defaultName] = defaultName;
|
|
549
|
+
continue;
|
|
550
|
+
}
|
|
557
551
|
if (isCuttlefishSDKImport(imported.moduleSpecifier, program.fileName)) {
|
|
558
552
|
for (const symbol of imported.namedImports) {
|
|
559
553
|
symbolMap[symbol] = symbol;
|
|
@@ -586,7 +580,7 @@ export function buildEmitterContext(program, options) {
|
|
|
586
580
|
// time; the package emits NO C++ module/header. Register the imported
|
|
587
581
|
// symbols so references resolve, but skip the #include generation.
|
|
588
582
|
if (imported.moduleSpecifier === "@typecad/ui" ||
|
|
589
|
-
imported.moduleSpecifier
|
|
583
|
+
isSafetyImportSpecifier(imported.moduleSpecifier)) {
|
|
590
584
|
for (const symbol of imported.namedImports) {
|
|
591
585
|
symbolMap[symbol] = symbol;
|
|
592
586
|
}
|
|
@@ -680,11 +674,11 @@ export function buildEmitterContext(program, options) {
|
|
|
680
674
|
// Map a function's original TS name to its emitted C++ name, applying the
|
|
681
675
|
// strategy's user-function renames. The entrypoint sentinel
|
|
682
676
|
// `__cuttlefish_entrypoint__` maps to the strategy's entrypoint name
|
|
683
|
-
// (
|
|
677
|
+
// (per-target entrypoint names); every other name is routed through
|
|
684
678
|
// `strategy.mapFunctionName`, which is where a target renames a user
|
|
685
679
|
// function that would otherwise collide with a C++/framework reserved name
|
|
686
|
-
// — e.g.
|
|
687
|
-
// because
|
|
680
|
+
// — e.g. Targets without a user `main()` rename one to `cuttlefish_main`;
|
|
681
|
+
// because this target has no user `main()` (the entrypoints are the auto-generated
|
|
688
682
|
// `setup()`/`loop()`), and a file-scope `static void main()` collides with
|
|
689
683
|
// C++'s required `int main()` signature. Call-site renames are applied
|
|
690
684
|
// uniformly in StatementRenderer.renderCall (the single call-rendering
|
|
@@ -857,7 +851,7 @@ export function buildEmitterContext(program, options) {
|
|
|
857
851
|
// method/ctor parameter, or a top-level binding. Previously only local
|
|
858
852
|
// var_decls were registered (in class-emitter), which ran too late for the
|
|
859
853
|
// free-function pass — leaving `hero->alive` unrewritten and failing g++.
|
|
860
|
-
//
|
|
854
|
+
// (demo #4 fix.)
|
|
861
855
|
// `classAccessorNames` is built at the outer scope (not inside a nested
|
|
862
856
|
// block) so it can also be passed to the expression renderer as
|
|
863
857
|
// `typeAccessorNames` — the type-keyed fallback used when a getter access's
|
|
@@ -967,6 +961,7 @@ export function buildEmitterContext(program, options) {
|
|
|
967
961
|
const mapFunctionNameLocal = (originalName) => statementRenderer.mapFunctionName(originalName);
|
|
968
962
|
const asyncFunctionMappedNames = new Set(program.functions.filter((fn) => fn.isAsync).map((fn) => mapFunctionNameLocal(fn.originalName)));
|
|
969
963
|
const asyncTaskClasses = [];
|
|
964
|
+
const asyncMethodStarters = [];
|
|
970
965
|
if (hasAsyncRuntime) {
|
|
971
966
|
for (const fn of program.functions) {
|
|
972
967
|
if (fn.isAsync) {
|
|
@@ -992,21 +987,103 @@ export function buildEmitterContext(program, options) {
|
|
|
992
987
|
// Use renderWithPrelude so snprintf buffer declarations (e.g.
|
|
993
988
|
// char __cuttlefish_str_N[...]; snprintf(...)) are emitted before
|
|
994
989
|
// the statement that references them. Without this, template-literal
|
|
995
|
-
//
|
|
990
|
+
// string building inside async functions loses the buffer declaration.
|
|
996
991
|
const { prelude, statement } = contextRenderer.renderWithPrelude(stmt, forHeader, calleeTransformer);
|
|
997
992
|
if (prelude.length > 0) {
|
|
998
993
|
return prelude.join("\n") + "\n" + statement;
|
|
999
994
|
}
|
|
1000
995
|
return statement;
|
|
996
|
+
}, {
|
|
997
|
+
onUnsupportedAwait: (callee, span) => {
|
|
998
|
+
emitDiagnostics.push({
|
|
999
|
+
severity: "error",
|
|
1000
|
+
code: "await-unsupported-call",
|
|
1001
|
+
message: `await ${callee}(...) has no cooperative lowering here — the call would be dropped. Await is supported on Time.sleep, HAL ops (wifi.join / wifi.scan / http.send), ui.onTap(), and pin-edge waits.`,
|
|
1002
|
+
...(span ? { source: `${callee}(...)` } : {}),
|
|
1003
|
+
});
|
|
1004
|
+
},
|
|
1001
1005
|
});
|
|
1002
1006
|
asyncTaskClasses.push({ ...task, taskVarName: `${fn.originalName}Task` });
|
|
1003
1007
|
}
|
|
1004
1008
|
}
|
|
1009
|
+
// Async METHODS on user classes: the body becomes an owner-bound task
|
|
1010
|
+
// (this->x renders as _owner->x inside segments); the in-class method
|
|
1011
|
+
// body is replaced by a call to a forward-declared starter that binds
|
|
1012
|
+
// the receiver and arms the machine (see class-emitter.ts).
|
|
1013
|
+
for (const cls of program.classes) {
|
|
1014
|
+
for (const method of cls.methods) {
|
|
1015
|
+
if (!method.isAsync)
|
|
1016
|
+
continue;
|
|
1017
|
+
const fnName = `${cls.name}_${method.name}`;
|
|
1018
|
+
if (method.isStatic) {
|
|
1019
|
+
emitDiagnostics.push({
|
|
1020
|
+
severity: "error",
|
|
1021
|
+
code: "async-method-static",
|
|
1022
|
+
message: `static async method ${cls.name}.${method.name}() is not supported — hoist it to a free async function instead.`,
|
|
1023
|
+
});
|
|
1024
|
+
continue;
|
|
1025
|
+
}
|
|
1026
|
+
if (method.parameters.length > 0) {
|
|
1027
|
+
emitDiagnostics.push({
|
|
1028
|
+
severity: "error",
|
|
1029
|
+
code: "async-method-params",
|
|
1030
|
+
message: `async method ${cls.name}.${method.name}() takes parameters, which the cooperative state machine cannot capture — make it parameterless.`,
|
|
1031
|
+
});
|
|
1032
|
+
continue;
|
|
1033
|
+
}
|
|
1034
|
+
if (method.returnType !== "void" && !String(method.returnType).startsWith("Promise")) {
|
|
1035
|
+
emitDiagnostics.push({
|
|
1036
|
+
severity: "error",
|
|
1037
|
+
code: "async-method-return",
|
|
1038
|
+
message: `async method ${cls.name}.${method.name}() returns ${method.returnType}; async methods lower to fire-and-forget tasks and must return void (Promise<void>).`,
|
|
1039
|
+
});
|
|
1040
|
+
continue;
|
|
1041
|
+
}
|
|
1042
|
+
const task = generateAsyncTaskClass(fnName, method.statements, strategy, knownFunctionReturnTypes, (stmt, forHeader, strategy, pointerVarTypes, calleeTransformer, knownReturnTypes) => {
|
|
1043
|
+
const contextRenderer = new StatementRenderer({
|
|
1044
|
+
strategy,
|
|
1045
|
+
boardConstants: program.boardConstants,
|
|
1046
|
+
classNameMap,
|
|
1047
|
+
enumNames,
|
|
1048
|
+
stringEnumNames,
|
|
1049
|
+
largeEnumNames,
|
|
1050
|
+
knownFunctionReturnTypes: knownReturnTypes ?? knownFunctionReturnTypes,
|
|
1051
|
+
knownVariableTypes: topLevelScope.knownVariableTypes,
|
|
1052
|
+
globalPointerVarTypes,
|
|
1053
|
+
namespaceNames,
|
|
1054
|
+
snprintfCounter,
|
|
1055
|
+
stringVarNames,
|
|
1056
|
+
varAccessorNames,
|
|
1057
|
+
typeAccessorNames: classAccessorNames,
|
|
1058
|
+
pointerVarTypes,
|
|
1059
|
+
diagnostics: emitDiagnostics,
|
|
1060
|
+
});
|
|
1061
|
+
const { prelude, statement } = contextRenderer.renderWithPrelude(stmt, forHeader, calleeTransformer);
|
|
1062
|
+
const body = prelude.length > 0 ? prelude.join("\n") + "\n" + statement : statement;
|
|
1063
|
+
// The task class is not the receiver: rebind member accesses from
|
|
1064
|
+
// the owning instance to the task's _owner pointer. The renderer
|
|
1065
|
+
// emits every this-form as `this->`; a rendered string literal
|
|
1066
|
+
// containing that token would be rewritten too (accepted edge).
|
|
1067
|
+
return body.replace(/this->/g, "_owner->");
|
|
1068
|
+
}, {
|
|
1069
|
+
ownerClassName: cls.name,
|
|
1070
|
+
onUnsupportedAwait: (callee, span) => {
|
|
1071
|
+
emitDiagnostics.push({
|
|
1072
|
+
severity: "error",
|
|
1073
|
+
code: "await-unsupported-call",
|
|
1074
|
+
message: `await ${callee}(...) has no cooperative lowering here — the call would be dropped. Await is supported on Time.sleep, HAL ops (wifi.join / wifi.scan / http.send), ui.onTap(), and pin-edge waits.`,
|
|
1075
|
+
...(span ? { source: `${callee}(...)` } : {}),
|
|
1076
|
+
});
|
|
1077
|
+
},
|
|
1078
|
+
});
|
|
1079
|
+
asyncTaskClasses.push({ ...task, taskVarName: `${fnName}Task` });
|
|
1080
|
+
asyncMethodStarters.push({
|
|
1081
|
+
proto: `void __tc_async_start_${fnName}(${cls.name}* owner);`,
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1005
1085
|
}
|
|
1006
1086
|
// Additional includes computed from analysis
|
|
1007
|
-
if (strategy.needsIostream() && programAnalysis.hasConsoleCalls) {
|
|
1008
|
-
includes.push("<iostream>");
|
|
1009
|
-
}
|
|
1010
1087
|
const usesVectorTypes = programAnalysis.usesVectorTypes || programAnalysis.hasArrayInObjectLiteral;
|
|
1011
1088
|
if (programAnalysis.usesStdString && strategy.needsStdString()) {
|
|
1012
1089
|
includes.push("<string>");
|
|
@@ -1083,7 +1160,13 @@ export function buildEmitterContext(program, options) {
|
|
|
1083
1160
|
// include in the AVR profile (which leaked the header into every AVR
|
|
1084
1161
|
// program, even ones that never touch the watchdog like `led.toggle()`).
|
|
1085
1162
|
if (programUsesWdt(program)) {
|
|
1086
|
-
|
|
1163
|
+
// Strategy-vetoed: framework-zephyr lowers wdt.* to the Zephyr watchdog
|
|
1164
|
+
// driver (<zephyr/drivers/watchdog.h>, forced under usesWDT) and must not
|
|
1165
|
+
// carry the AVR-only header into a Zephyr build.
|
|
1166
|
+
const wdtInc = strategy.filterRequiredIncludes
|
|
1167
|
+
? strategy.filterRequiredIncludes(["<avr/wdt.h>"])
|
|
1168
|
+
: ["<avr/wdt.h>"];
|
|
1169
|
+
includes.push(...wdtInc);
|
|
1087
1170
|
}
|
|
1088
1171
|
// Placeholder defaults for fields that are computed later by other phases
|
|
1089
1172
|
const noopFixPointer = (c) => c;
|
|
@@ -1166,6 +1249,7 @@ export function buildEmitterContext(program, options) {
|
|
|
1166
1249
|
boardConstants: program.boardConstants,
|
|
1167
1250
|
restParamFunctions: program.restParamFunctions,
|
|
1168
1251
|
asyncTaskClasses,
|
|
1252
|
+
asyncMethodStarters,
|
|
1169
1253
|
asyncFunctionOriginalNames,
|
|
1170
1254
|
asyncFunctionMappedNames,
|
|
1171
1255
|
hasAsyncRuntime,
|
|
@@ -411,7 +411,7 @@ export function runTopLevelPreprocessing(ctx) {
|
|
|
411
411
|
// sees runtime mutations — e.g. `const reached = descended` freezes `reached`
|
|
412
412
|
// at `descended`'s initial value because both are emitted as file-scope globals
|
|
413
413
|
// initialized before main(), while the `descended = depth` assignments run
|
|
414
|
-
// inside main().
|
|
414
|
+
// inside main().
|
|
415
415
|
{
|
|
416
416
|
// Collect every variable name that is the target of an assignment anywhere
|
|
417
417
|
// in the program (top-level statements + function/method bodies). Such
|
|
@@ -2,6 +2,7 @@ import { emitCommentLines, isRuntimeExpression } from "../utils/index.js";
|
|
|
2
2
|
import { appendSourceLine, appendHeaderLine, appendRenderedStatement } from "./line-appender.js";
|
|
3
3
|
import { escapeCppKeyword } from "../../utils/strings.js";
|
|
4
4
|
import { isStringEnum } from "../../api/shared/index.js";
|
|
5
|
+
import { parsedIsVector } from "../../api/shared/cpp-type-ir.js";
|
|
5
6
|
import { resolveEnumValues, narrowestEnumUnderlying } from "../utils/cpp-helpers.js";
|
|
6
7
|
export function emitTypeDeclarations(ctx) {
|
|
7
8
|
const { program, strategy, effectiveEmitMode, reservedNames, emittedTopLevelStatements, topLevelScope } = ctx;
|
|
@@ -249,14 +250,18 @@ export function emitTypeDeclarations(ctx) {
|
|
|
249
250
|
const typeAlreadyConst = cppType.trimStart().startsWith("const");
|
|
250
251
|
const constPrefix = isConst && !typeAlreadyConst ? "const " : "";
|
|
251
252
|
const varName = escapeCppKeyword(statement.name, platformReservedNames);
|
|
252
|
-
// Array-typed top-level consts (e.g. `export const ARR: T[] = [...]`
|
|
253
|
-
//
|
|
254
|
-
//
|
|
255
|
-
//
|
|
256
|
-
//
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
|
|
253
|
+
// Array-typed top-level consts (e.g. `export const ARR: T[] = [...]`
|
|
254
|
+
// and `new Uint8Array(N)` buffers) lower with an `{ kind: "array",
|
|
255
|
+
// elementType }` initializer — typed arrays carry a pointer cppType
|
|
256
|
+
// (`uint8_t*`) even though renderVarDecl emits the DEFINITION as a
|
|
257
|
+
// C-style array (`T name[] = {...}`). The matching extern must use the
|
|
258
|
+
// same array form regardless of cppType — a pointer extern conflicts
|
|
259
|
+
// with the array definition. Vector-typed arrays are the exception: the
|
|
260
|
+
// definition emits `std::vector<T> name = {...}`, so the extern stays a
|
|
261
|
+
// vector extern. Without this, cross-file consumers fail with "was not
|
|
262
|
+
// declared in this scope" (the definition lives in the .cpp only).
|
|
263
|
+
// Mirror renderVarDecl's element-type fallback for "auto".
|
|
264
|
+
if (statement.initializer && statement.initializer.kind === "array" && !parsedIsVector(cppType)) {
|
|
260
265
|
const elemType = statement.initializer.elementType && statement.initializer.elementType !== "auto"
|
|
261
266
|
? strategy.normalizeCppType(statement.initializer.elementType)
|
|
262
267
|
: strategy.defaultNumericType(ctx.compliance.isEnabled() ? ctx.compliance : undefined);
|
|
@@ -163,7 +163,7 @@ export function emitUIRuntime(ctx) {
|
|
|
163
163
|
if (profile) {
|
|
164
164
|
const adapter = generateDisplayAdapter(profile, ctx.strategy);
|
|
165
165
|
// Prepend includes to the very front — Arduino's auto-prototyper scans
|
|
166
|
-
// the whole
|
|
166
|
+
// the whole translation unit and generates prototypes that reference GFXcanvas16
|
|
167
167
|
// etc. before any #include, so the GFX header must come first.
|
|
168
168
|
ctx.sourceLines.unshift(adapter.includes);
|
|
169
169
|
// Color-depth preamble: UI_COLOR_T is referenced by adapter draw
|