@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,428 @@
|
|
|
1
|
+
import { emitCommentLines, isRuntimeExpression, collectNestedStructDefs, inferObjectFieldType } from "../utils/index.js";
|
|
2
|
+
import { appendSourceLine, appendHeaderLine, appendRenderedStatement } from "./line-appender.js";
|
|
3
|
+
import { createChildEmissionScope } from "../snprintf-helpers.js";
|
|
4
|
+
import { escapeCppKeyword } from "../../utils/strings.js";
|
|
5
|
+
import { parsedIsPlainStructType } from "../../api/shared/cpp-type-ir.js";
|
|
6
|
+
import { entryHasUI } from "../../ui-hook.js";
|
|
7
|
+
import { activeNamespaceNames } from "../../ir/build-ir-state.js";
|
|
8
|
+
export function emitPostClassDeclarations(ctx) {
|
|
9
|
+
const { strategy, effectiveEmitMode, mappedFunctions, isEntryFile, topLevelScope } = ctx;
|
|
10
|
+
const platformReservedNames = strategy.reservedNames();
|
|
11
|
+
const normalizeCppTypeForTarget = (cppType) => strategy.normalizeCppType(cppType);
|
|
12
|
+
// Runtime variable declarations AFTER classes (for non-entry files)
|
|
13
|
+
if (!isEntryFile) {
|
|
14
|
+
for (const statement of ctx.emittedTopLevelStatements) {
|
|
15
|
+
if (statement.kind === "var_decl" && statement.initializer && isRuntimeExpression(statement.initializer)) {
|
|
16
|
+
appendRenderedStatement(ctx, statement, "", topLevelScope);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
// Forward declarations for promoted runtime var_decls.
|
|
21
|
+
//
|
|
22
|
+
// A promoted top-level variable (one classified runtime AND referenced by a
|
|
23
|
+
// free function, so it must live at file scope) is forward-declared here and
|
|
24
|
+
// assigned its real initializer inside the entrypoint. The default
|
|
25
|
+
// initializer must be value-initialization (`{}`), which is valid for every
|
|
26
|
+
// C++ type: scalars/pointers zero/null-initialize, class types
|
|
27
|
+
// (std::string, std::vector, std::map, user structs) default-construct.
|
|
28
|
+
// Previously this emitted `= 0` for every non-pointer type, which is invalid
|
|
29
|
+
// for class types (`std::vector<...>` has no implicit conversion from int)
|
|
30
|
+
// and failed at g++ time. Demo #28 Finding B.
|
|
31
|
+
if (ctx.promotedVarDecls.size > 0) {
|
|
32
|
+
for (const [varName, info] of ctx.promotedVarDecls) {
|
|
33
|
+
appendSourceLine(ctx, `${info.cppType} ${escapeCppKeyword(varName, platformReservedNames)} = {};`);
|
|
34
|
+
}
|
|
35
|
+
appendSourceLine(ctx, "");
|
|
36
|
+
}
|
|
37
|
+
// Object literal struct definitions (split mode)
|
|
38
|
+
const { program, exprRenderer } = ctx;
|
|
39
|
+
const renderExpression = (expr, calleeTransformer) => exprRenderer.render(expr, calleeTransformer);
|
|
40
|
+
for (const statement of ctx.emittedTopLevelStatements) {
|
|
41
|
+
if (effectiveEmitMode === "split" &&
|
|
42
|
+
statement.kind === "var_decl" &&
|
|
43
|
+
statement.initializer?.kind === "object") {
|
|
44
|
+
// When the source annotation names a concrete type (e.g. an exported
|
|
45
|
+
// interface referenced across modules: `const cfg: ThresholdConfig = {...}`),
|
|
46
|
+
// the variable's cppType already is that interface/struct name. The struct
|
|
47
|
+
// itself is declared by the interface declaration, and the extern + cpp
|
|
48
|
+
// definition are emitted by emitTypeDeclarations (via the extern block and
|
|
49
|
+
// appendRenderedStatement respectively). So we must skip synthesizing a
|
|
50
|
+
// local `_name_t` struct here — otherwise we'd emit a second, conflicting
|
|
51
|
+
// struct definition and a duplicate extern/definition.
|
|
52
|
+
const placeholderStructName = `_${statement.name}_t`;
|
|
53
|
+
// Compile-time-only namespace values (e.g. the `ui` handle) emit nothing.
|
|
54
|
+
if (activeNamespaceNames.has(statement.name)) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const declaredCppType = statement.cppType;
|
|
58
|
+
const hasExplicitNamedType = !!declaredCppType &&
|
|
59
|
+
declaredCppType !== "auto" &&
|
|
60
|
+
declaredCppType !== placeholderStructName &&
|
|
61
|
+
parsedIsPlainStructType(declaredCppType);
|
|
62
|
+
// Still register the field types so downstream rendering (e.g. string-concat
|
|
63
|
+
// wrapping via interfaceFieldTypes) can resolve property accesses on the var.
|
|
64
|
+
const fieldTypeEntries = statement.initializer.fields.map((field) => {
|
|
65
|
+
const inferred = inferObjectFieldType(field.value, ctx.globalPointerVarTypes, ctx.knownFunctionReturnTypes, ctx.knownTopLevelObjectTypes, ctx.knownTopLevelObjectFields, ctx.largeEnumNames, statement.name, field.name, strategy.defaultNumericType(), (o, n) => strategy.resolvePinType?.(o, n));
|
|
66
|
+
return [field.name, inferred];
|
|
67
|
+
});
|
|
68
|
+
if (hasExplicitNamedType) {
|
|
69
|
+
const namedType = declaredCppType;
|
|
70
|
+
ctx.knownTopLevelObjectTypes.set(statement.name, namedType);
|
|
71
|
+
ctx.knownTopLevelObjectFields.set(statement.name, new Map(fieldTypeEntries));
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const structName = placeholderStructName;
|
|
75
|
+
const nestedStructs = collectNestedStructDefs(statement.initializer, statement.name, ctx.globalPointerVarTypes, ctx.knownFunctionReturnTypes, ctx.knownTopLevelObjectTypes, ctx.knownTopLevelObjectFields, ctx.largeEnumNames);
|
|
76
|
+
for (const ns of nestedStructs) {
|
|
77
|
+
const nestedFieldDefs = ns.fields
|
|
78
|
+
.map((f) => `${f.type} ${strategy.renameStructField(f.name)};`)
|
|
79
|
+
.join(" ");
|
|
80
|
+
appendHeaderLine(ctx, `struct ${ns.structName} { ${nestedFieldDefs} };`);
|
|
81
|
+
}
|
|
82
|
+
const fieldDefs = fieldTypeEntries
|
|
83
|
+
.map(([fieldName, inferredType]) => {
|
|
84
|
+
const safeFieldName = strategy.renameStructField(fieldName);
|
|
85
|
+
return `${inferredType} ${safeFieldName};`;
|
|
86
|
+
})
|
|
87
|
+
.join(" ");
|
|
88
|
+
const initValues = statement.initializer.fields
|
|
89
|
+
.map((field) => {
|
|
90
|
+
const renderExpr = (e) => renderExpression(e, ctx.fixPointerFieldAccess);
|
|
91
|
+
const overridden = strategy.objectFieldInitializer(field.value, renderExpr);
|
|
92
|
+
if (overridden !== undefined)
|
|
93
|
+
return overridden;
|
|
94
|
+
const structInit = strategy.structFieldInitializer(field.value, ctx.compiletimeVarNames, renderExpr);
|
|
95
|
+
if (structInit !== undefined)
|
|
96
|
+
return structInit;
|
|
97
|
+
return renderExpression(field.value, ctx.fixPointerFieldAccess);
|
|
98
|
+
})
|
|
99
|
+
.join(", ");
|
|
100
|
+
ctx.knownTopLevelObjectTypes.set(statement.name, structName);
|
|
101
|
+
ctx.knownTopLevelObjectFields.set(statement.name, new Map(fieldTypeEntries));
|
|
102
|
+
emitCommentLines(statement.leadingComments, "", (line) => appendHeaderLine(ctx, line));
|
|
103
|
+
appendHeaderLine(ctx, `struct ${structName} { ${fieldDefs} };`);
|
|
104
|
+
appendHeaderLine(ctx, `extern ${structName} ${statement.name};`);
|
|
105
|
+
emitCommentLines(statement.trailingComments, "", (line) => appendHeaderLine(ctx, line));
|
|
106
|
+
emitCommentLines(statement.leadingComments, "", (line) => appendSourceLine(ctx, line));
|
|
107
|
+
appendSourceLine(ctx, `${structName} ${statement.name} = { ${initValues} };`, {
|
|
108
|
+
tsSpan: statement.sourceSpan,
|
|
109
|
+
nodeKind: statement.kind,
|
|
110
|
+
});
|
|
111
|
+
emitCommentLines(statement.trailingComments, "", (line) => appendSourceLine(ctx, line));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (ctx.emittedTopLevelStatements.some(s => s.kind === "var_decl" && s.initializer?.kind === "object")) {
|
|
115
|
+
appendSourceLine(ctx, "");
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
export function emitCallbackFunctions(ctx) {
|
|
119
|
+
const { strategy, effectiveEmitMode, topLevelScope } = ctx;
|
|
120
|
+
// NOTE: forward declarations for callbacks and free functions are now emitted
|
|
121
|
+
// BEFORE class bodies by emitFunctionForwardDeclarations (cpp-emitter step
|
|
122
|
+
// 6.5). This function emits only the callback DEFINITIONS (plus split-mode
|
|
123
|
+
// header prototypes, which belong with the public API).
|
|
124
|
+
// Emit callback functions
|
|
125
|
+
for (const callback of ctx.callbackFunctions) {
|
|
126
|
+
if (callback.debounceMs !== undefined && callback.debounceMs > 0) {
|
|
127
|
+
appendSourceLine(ctx, `volatile unsigned long ${callback.name}_lastTime = 0;`);
|
|
128
|
+
appendSourceLine(ctx, `const unsigned long ${callback.name}_debounce = ${callback.debounceMs};`);
|
|
129
|
+
appendSourceLine(ctx, "");
|
|
130
|
+
}
|
|
131
|
+
appendSourceLine(ctx, `${strategy.isrFunctionAttribute?.() ?? ""}${renderCallbackSignature(callback)} {`);
|
|
132
|
+
if (callback.debounceMs !== undefined && callback.debounceMs > 0) {
|
|
133
|
+
appendSourceLine(ctx, ` volatile unsigned long now = ${strategy.currentTimeMillis()};`);
|
|
134
|
+
appendSourceLine(ctx, ` if (now - ${callback.name}_lastTime < ${callback.name}_debounce) return;`);
|
|
135
|
+
appendSourceLine(ctx, ` ${callback.name}_lastTime = now;`);
|
|
136
|
+
}
|
|
137
|
+
const callbackScope = createChildEmissionScope(topLevelScope, callback.typedParams);
|
|
138
|
+
for (const stmt of callback.statements) {
|
|
139
|
+
appendRenderedStatement(ctx, stmt, " ", callbackScope);
|
|
140
|
+
}
|
|
141
|
+
appendSourceLine(ctx, "}");
|
|
142
|
+
appendSourceLine(ctx, "");
|
|
143
|
+
}
|
|
144
|
+
// Split-mode ISR callback forward declarations in header
|
|
145
|
+
if (effectiveEmitMode === "split") {
|
|
146
|
+
for (const callback of ctx.callbackFunctions) {
|
|
147
|
+
appendHeaderLine(ctx, `${strategy.isrFunctionAttribute?.() ?? ""}${renderCallbackSignature(callback)};`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Render the C++ signature of a synthesized callback (ISR) free function.
|
|
153
|
+
*
|
|
154
|
+
* Historically every hoisted callback emitted as `void name()` — fine for
|
|
155
|
+
* parameter-less ISRs (the `onFalling(() => {...})` case) but wrong for a
|
|
156
|
+
* typed lambda passed as a `std::function<R(args)>` argument, where the
|
|
157
|
+
* function must carry the same return type and parameter list. We fall back
|
|
158
|
+
* to the historical `void name()` shape when the callback carries no
|
|
159
|
+
* returnType/typedParams (the common ISR path that populates neither).
|
|
160
|
+
*/
|
|
161
|
+
function renderCallbackSignature(callback) {
|
|
162
|
+
const ret = callback.returnType && callback.returnType !== "void" ? callback.returnType : "void";
|
|
163
|
+
const params = (callback.typedParams ?? []).map(p => `${p.cppType} ${p.name}`).join(", ");
|
|
164
|
+
return `${ret} ${callback.name}(${params})`;
|
|
165
|
+
}
|
|
166
|
+
export function emitFunctions(ctx) {
|
|
167
|
+
const { strategy, effectiveEmitMode, mappedFunctions, topLevelScope, hasPromiseRuntime, asyncTaskClasses, usesTimers } = ctx;
|
|
168
|
+
// NOTE: source-level forward declarations (non-split free fns + split-mode
|
|
169
|
+
// static fns) are now emitted BEFORE class bodies by
|
|
170
|
+
// emitFunctionForwardDeclarations (cpp-emitter step 6.5). This function
|
|
171
|
+
// emits function DEFINITIONS and the split-mode header prototypes for
|
|
172
|
+
// exported functions (which ride along with their definition below).
|
|
173
|
+
for (let fi = 0; fi < mappedFunctions.length; fi++) {
|
|
174
|
+
const fn = mappedFunctions[fi];
|
|
175
|
+
const declarationParameterList = ctx.statementRenderer.renderParameters(fn.parameters, true);
|
|
176
|
+
const definitionParameterList = ctx.statementRenderer.renderParameters(fn.parameters, false);
|
|
177
|
+
const readonlyPrefix = fn.isReadonlyReturnType ? "const " : "";
|
|
178
|
+
const isExported = fn.isExported === true;
|
|
179
|
+
// A function is an entrypoint if it is the strategy's primary entrypoint
|
|
180
|
+
// (e.g. `setup` on Arduino, `main` on native) OR one of the platform's
|
|
181
|
+
// reserved entrypoint names the strategy excludes from forward declarations
|
|
182
|
+
// (e.g. `loop` on Arduino, whose `void loop(void)` is forward-declared
|
|
183
|
+
// extern by the Arduino core — emitting `static void loop()` redeclares it
|
|
184
|
+
// with conflicting linkage, which ESP32's GCC rejects; see
|
|
185
|
+
// arduino-loop-linkage.test.ts). Treating these as entrypoints drops the
|
|
186
|
+
// `static` qualifier, matching how `setup`/`main` already emit.
|
|
187
|
+
const platformEntrypoints = strategy.forwardDeclarationExclusions?.() ?? [];
|
|
188
|
+
const isEntrypoint = fn.name === strategy.entrypointFunctionName() ||
|
|
189
|
+
platformEntrypoints.includes(fn.name);
|
|
190
|
+
// Demo #18 Finding B: a non-exported free function that is CALLED from a
|
|
191
|
+
// class method body must be visible in the header (inline method bodies
|
|
192
|
+
// live there in split mode) and defined non-static in the .cpp (a `static`
|
|
193
|
+
// definition would clash with the header's extern prototype). The header
|
|
194
|
+
// prototype is emitted in emitFunctionForwardDeclarations (which runs
|
|
195
|
+
// before classes); here we only drop the `static` from the definition.
|
|
196
|
+
const calledFromClassMethod = ctx.freeFunctionsCalledFromClassMethods.has(fn.name);
|
|
197
|
+
const needsStatic = !isExported && !isEntrypoint && !calledFromClassMethod;
|
|
198
|
+
if (effectiveEmitMode === "split") {
|
|
199
|
+
if (isExported) {
|
|
200
|
+
emitCommentLines(fn.leadingComments, "", (line) => appendHeaderLine(ctx, line));
|
|
201
|
+
if (fn.typeParameters && fn.typeParameters.length > 0) {
|
|
202
|
+
appendHeaderLine(ctx, `template<typename ${fn.typeParameters.join(", typename ")}>`);
|
|
203
|
+
}
|
|
204
|
+
appendHeaderLine(ctx, `${readonlyPrefix}${ctx.statementRenderer.mapReturnTypeForEmit(fn.name, fn.returnType)} ${fn.name}(${declarationParameterList});`, {
|
|
205
|
+
tsSpan: fn.sourceSpan,
|
|
206
|
+
nodeKind: "function_declaration",
|
|
207
|
+
symbolName: fn.name,
|
|
208
|
+
});
|
|
209
|
+
emitCommentLines(fn.trailingComments, "", (line) => appendHeaderLine(ctx, line));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// Generic (templated) functions must be DEFINED in the header — a C++
|
|
213
|
+
// template definition in a .cpp is not visible to other translation
|
|
214
|
+
// units, producing `undefined reference` at link time. So for an exported
|
|
215
|
+
// generic function in split mode we route the full definition (template
|
|
216
|
+
// line + signature + body) into the header. We use the same buffer-swap
|
|
217
|
+
// trick the class emitter uses (class-emitter.ts:13-18), so that
|
|
218
|
+
// appendSourceLine / appendRenderedStatement (which are hardwired to the
|
|
219
|
+
// source buffer) write to the header while the swap is active. Non-generic
|
|
220
|
+
// exported functions keep their historical decl-in-.h / def-in-.cpp split.
|
|
221
|
+
const isExportedGeneric = effectiveEmitMode === "split" &&
|
|
222
|
+
isExported &&
|
|
223
|
+
!!fn.typeParameters && fn.typeParameters.length > 0 &&
|
|
224
|
+
!fn.isAsync; // async functions are driven via task classes, not templates
|
|
225
|
+
if (isExportedGeneric) {
|
|
226
|
+
const _swapLines = ctx.sourceLines;
|
|
227
|
+
ctx.sourceLines = ctx.headerLines;
|
|
228
|
+
ctx.headerLines = _swapLines;
|
|
229
|
+
const _swapMaps = ctx.sourceMapEntries;
|
|
230
|
+
ctx.sourceMapEntries = ctx.headerMapEntries;
|
|
231
|
+
ctx.headerMapEntries = _swapMaps;
|
|
232
|
+
}
|
|
233
|
+
emitCommentLines(fn.leadingComments, "", (line) => appendSourceLine(ctx, line));
|
|
234
|
+
if (fn.typeParameters && fn.typeParameters.length > 0) {
|
|
235
|
+
appendSourceLine(ctx, `template<typename ${fn.typeParameters.join(", typename ")}>`);
|
|
236
|
+
}
|
|
237
|
+
const fnReturnType = fn.isGenerator ? `__tc_Generator<${fn.returnType === "void" ? "void" : ctx.statementRenderer.mapReturnTypeForEmit(fn.name, fn.returnType)}>` : `${readonlyPrefix}${ctx.statementRenderer.mapReturnTypeForEmit(fn.name, fn.returnType)}`;
|
|
238
|
+
const linkagePrefix = needsStatic ? "static " : "";
|
|
239
|
+
appendSourceLine(ctx, `${linkagePrefix}${fnReturnType} ${fn.name}(${definitionParameterList})`, {
|
|
240
|
+
tsSpan: fn.sourceSpan,
|
|
241
|
+
nodeKind: "function_definition",
|
|
242
|
+
symbolName: fn.name,
|
|
243
|
+
});
|
|
244
|
+
appendSourceLine(ctx, "{");
|
|
245
|
+
const asyncDriverFn = strategy.asyncDriverFunctionName();
|
|
246
|
+
if (hasPromiseRuntime && fn.name === asyncDriverFn) {
|
|
247
|
+
appendSourceLine(ctx, " cuttlefish_pump_microtasks();");
|
|
248
|
+
}
|
|
249
|
+
if (fn.isAsync && ctx.hasAsyncRuntime) {
|
|
250
|
+
appendSourceLine(ctx, ` // driven as cooperative task in ${asyncDriverFn}()`);
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
if (fn.typeParameterConstraints) {
|
|
254
|
+
for (const [param, expr] of fn.typeParameterConstraints) {
|
|
255
|
+
appendSourceLine(ctx, ` static_assert(${expr}, "${param} constraint violated");`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
const functionScope = createChildEmissionScope(topLevelScope, fn.parameters);
|
|
259
|
+
ctx.cArrayVarNames = ctx.fnCArrayVarNames.get(String(fi)) ?? new Set();
|
|
260
|
+
const isLoopDriver = fn.name === asyncDriverFn;
|
|
261
|
+
const lastStmt = fn.statements.length > 0 ? fn.statements[fn.statements.length - 1] : null;
|
|
262
|
+
const lastIsReturn = lastStmt?.kind === "return";
|
|
263
|
+
const stmtsToEmit = (isLoopDriver && lastIsReturn)
|
|
264
|
+
? fn.statements.slice(0, -1)
|
|
265
|
+
: fn.statements;
|
|
266
|
+
for (const statement of stmtsToEmit) {
|
|
267
|
+
appendRenderedStatement(ctx, statement, " ", functionScope);
|
|
268
|
+
}
|
|
269
|
+
// Drive the UI runtime each frame. Fires only in the driver function when
|
|
270
|
+
// a UI is mounted (entryHasUI). Uses a separate gate from the async pump
|
|
271
|
+
// so a pure-UI program (no async/timers) still animates. When the strategy
|
|
272
|
+
// provides hostEventLoop, the per-frame work runs inside a while loop so a
|
|
273
|
+
// host target (SDL) can pump events and present between ticks. Emitted
|
|
274
|
+
// AFTER the function's init statements (ui_init/display_init/touch_init)
|
|
275
|
+
// so initialization precedes the loop.
|
|
276
|
+
if (entryHasUI() && fn.name === asyncDriverFn) {
|
|
277
|
+
const loop = strategy.hostEventLoop?.();
|
|
278
|
+
if (loop) {
|
|
279
|
+
appendSourceLine(ctx, ` bool ${loop.flagName} = true;`);
|
|
280
|
+
appendSourceLine(ctx, ` while (${loop.continueCondition}) {`);
|
|
281
|
+
appendSourceLine(ctx, ` ${loop.preIteration}`);
|
|
282
|
+
}
|
|
283
|
+
appendSourceLine(ctx, ` uint32_t __tc_ui_now = (uint32_t)${strategy.currentTimeMillis()};`);
|
|
284
|
+
appendSourceLine(ctx, " static uint32_t __tc_ui_last_tick = __tc_ui_now;");
|
|
285
|
+
appendSourceLine(ctx, " uint32_t __tc_ui_delta = __tc_ui_now - __tc_ui_last_tick;");
|
|
286
|
+
appendSourceLine(ctx, " __tc_ui_last_tick = __tc_ui_now;");
|
|
287
|
+
appendSourceLine(ctx, " if (__tc_ui_delta > 250) __tc_ui_delta = 250;");
|
|
288
|
+
appendSourceLine(ctx, " ui_tick((uint16_t)__tc_ui_delta);");
|
|
289
|
+
if (loop) {
|
|
290
|
+
appendSourceLine(ctx, ` ${loop.postIteration}`);
|
|
291
|
+
appendSourceLine(ctx, ` }`);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
if (isLoopDriver && (hasPromiseRuntime || asyncTaskClasses.length > 0 || usesTimers)) {
|
|
295
|
+
const taskNames = asyncTaskClasses.map(t => t.taskVarName);
|
|
296
|
+
const asyncConfig = strategy.getAsyncRuntimeConfig();
|
|
297
|
+
asyncConfig.hasPromiseRuntime = hasPromiseRuntime;
|
|
298
|
+
asyncConfig.hasTimers = usesTimers;
|
|
299
|
+
const injectionLines = strategy.asyncLoopInjection(taskNames, asyncConfig);
|
|
300
|
+
for (const line of injectionLines) {
|
|
301
|
+
appendSourceLine(ctx, ` ${line}`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
if (isLoopDriver && lastIsReturn) {
|
|
305
|
+
appendRenderedStatement(ctx, lastStmt, " ", functionScope);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
appendSourceLine(ctx, "}");
|
|
309
|
+
emitCommentLines(fn.trailingComments, "", (line) => appendSourceLine(ctx, line));
|
|
310
|
+
appendSourceLine(ctx, "");
|
|
311
|
+
// Restore the buffer swap we applied for exported generic functions (see
|
|
312
|
+
// isExportedGeneric above). After this point sourceLines/headerLines are
|
|
313
|
+
// back to their normal roles for the next function in the loop.
|
|
314
|
+
if (isExportedGeneric) {
|
|
315
|
+
const _swapLines = ctx.sourceLines;
|
|
316
|
+
ctx.sourceLines = ctx.headerLines;
|
|
317
|
+
ctx.headerLines = _swapLines;
|
|
318
|
+
const _swapMaps = ctx.sourceMapEntries;
|
|
319
|
+
ctx.sourceMapEntries = ctx.headerMapEntries;
|
|
320
|
+
ctx.headerMapEntries = _swapMaps;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Emit forward declarations for ALL free functions (and ISR callbacks) BEFORE
|
|
326
|
+
* class bodies. A class method may call a free function declared later in the
|
|
327
|
+
* same source file; if that function's forward declaration only appears after
|
|
328
|
+
* the class (as it did historically via emitCallbackFunctions/emitFunctions),
|
|
329
|
+
* g++ reports "'fn' was not declared in this scope" inside the class body.
|
|
330
|
+
*
|
|
331
|
+
* This runs at cpp-emitter.ts step 6.5, ahead of emitClasses (step 7). The
|
|
332
|
+
* definition-only emission in emitCallbackFunctions/emitFunctions below no
|
|
333
|
+
* longer re-emits these declarations (they are dropped there to avoid
|
|
334
|
+
* duplicates). Template/generic functions get template prototypes here so
|
|
335
|
+
* earlier functions can call them before their definitions later in the same
|
|
336
|
+
* translation unit.
|
|
337
|
+
*/
|
|
338
|
+
export function emitFunctionForwardDeclarations(ctx) {
|
|
339
|
+
const { strategy, effectiveEmitMode } = ctx;
|
|
340
|
+
const excludedNames = new Set(strategy.forwardDeclarationExclusions?.() ?? []);
|
|
341
|
+
// ISR callback forward declarations.
|
|
342
|
+
if (effectiveEmitMode !== "split") {
|
|
343
|
+
for (const callback of ctx.callbackFunctions) {
|
|
344
|
+
appendSourceLine(ctx, `${strategy.isrFunctionAttribute?.() ?? ""}${renderCallbackSignature(callback)};`);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
let emittedAnyFn = false;
|
|
348
|
+
for (const fn of ctx.mappedFunctions) {
|
|
349
|
+
if (excludedNames.has(fn.name))
|
|
350
|
+
continue;
|
|
351
|
+
const isExported = fn.isExported === true;
|
|
352
|
+
// A function is an entrypoint if it is the strategy's primary entrypoint
|
|
353
|
+
// (e.g. `setup` on Arduino, `main` on native) OR one of the platform's
|
|
354
|
+
// reserved entrypoint names the strategy excludes from forward declarations
|
|
355
|
+
// (e.g. `loop` on Arduino, whose `void loop(void)` is forward-declared
|
|
356
|
+
// extern by the Arduino core — emitting `static void loop()` redeclares it
|
|
357
|
+
// with conflicting linkage, which ESP32's GCC rejects; see
|
|
358
|
+
// arduino-loop-linkage.test.ts). Treating these as entrypoints drops the
|
|
359
|
+
// `static` qualifier, matching how `setup`/`main` already emit.
|
|
360
|
+
const platformEntrypoints = strategy.forwardDeclarationExclusions?.() ?? [];
|
|
361
|
+
const isEntrypoint = fn.name === strategy.entrypointFunctionName() ||
|
|
362
|
+
platformEntrypoints.includes(fn.name);
|
|
363
|
+
// Demo #18 Finding B: a free function called from a class method body is
|
|
364
|
+
// forward-declared in the HEADER (like an exported function) — this step
|
|
365
|
+
// runs BEFORE emitClasses, so the prototype precedes the class body that
|
|
366
|
+
// references it. It must NOT also get a `static` source-level forward decl.
|
|
367
|
+
const calledFromClassMethod = ctx.freeFunctionsCalledFromClassMethods.has(fn.name);
|
|
368
|
+
// Exported functions and class-method-called free functions are forward-
|
|
369
|
+
// declared in the HEADER (above). Only static (non-exported) functions
|
|
370
|
+
// that are NOT called from a class method need a source-level forward decl.
|
|
371
|
+
if (effectiveEmitMode === "split" && calledFromClassMethod) {
|
|
372
|
+
const declarationParameterList = ctx.statementRenderer.renderParameters(fn.parameters, true);
|
|
373
|
+
const readonlyPrefix = fn.isReadonlyReturnType ? "const " : "";
|
|
374
|
+
const fnReturnType = fn.isGenerator
|
|
375
|
+
? `__tc_Generator<${fn.returnType === "void" ? "void" : ctx.statementRenderer.mapTypeForEmit(fn.returnType)}>`
|
|
376
|
+
: `${readonlyPrefix}${ctx.statementRenderer.mapReturnTypeForEmit(fn.name, fn.returnType)}`;
|
|
377
|
+
if (fn.typeParameters && fn.typeParameters.length > 0) {
|
|
378
|
+
const typeParams = fn.typeParameters.join(", typename ");
|
|
379
|
+
appendHeaderLine(ctx, `template<typename ${typeParams}>`);
|
|
380
|
+
}
|
|
381
|
+
appendHeaderLine(ctx, `${fnReturnType} ${fn.name}(${declarationParameterList});`, {
|
|
382
|
+
tsSpan: fn.sourceSpan,
|
|
383
|
+
nodeKind: "function_declaration",
|
|
384
|
+
symbolName: fn.name,
|
|
385
|
+
});
|
|
386
|
+
emittedAnyFn = true;
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
if (effectiveEmitMode === "split" && (isExported || isEntrypoint))
|
|
390
|
+
continue;
|
|
391
|
+
const declarationParameterList = ctx.statementRenderer.renderParameters(fn.parameters, true);
|
|
392
|
+
const readonlyPrefix = fn.isReadonlyReturnType ? "const " : "";
|
|
393
|
+
const fnReturnType = fn.isGenerator
|
|
394
|
+
? `__tc_Generator<${fn.returnType === "void" ? "void" : ctx.statementRenderer.mapTypeForEmit(fn.returnType)}>`
|
|
395
|
+
: `${readonlyPrefix}${ctx.statementRenderer.mapReturnTypeForEmit(fn.name, fn.returnType)}`;
|
|
396
|
+
if (fn.typeParameters && fn.typeParameters.length > 0) {
|
|
397
|
+
const fnNeedsStatic = !isExported && !isEntrypoint;
|
|
398
|
+
const typeParams = fn.typeParameters.join(", typename ");
|
|
399
|
+
appendSourceLine(ctx, `template<typename ${typeParams}>`);
|
|
400
|
+
appendSourceLine(ctx, `${fnNeedsStatic ? "static " : ""}${fnReturnType} ${fn.name}(${declarationParameterList});`, {
|
|
401
|
+
tsSpan: fn.sourceSpan,
|
|
402
|
+
nodeKind: "function_declaration",
|
|
403
|
+
symbolName: fn.name,
|
|
404
|
+
});
|
|
405
|
+
emittedAnyFn = true;
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
if (effectiveEmitMode === "split") {
|
|
409
|
+
appendSourceLine(ctx, `static ${fnReturnType} ${fn.name}(${declarationParameterList});`, {
|
|
410
|
+
tsSpan: fn.sourceSpan,
|
|
411
|
+
nodeKind: "function_declaration",
|
|
412
|
+
symbolName: fn.name,
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
const fnNeedsStatic = !isExported && !isEntrypoint;
|
|
417
|
+
appendSourceLine(ctx, `${fnNeedsStatic ? "static " : ""}${fnReturnType} ${fn.name}(${declarationParameterList});`, {
|
|
418
|
+
tsSpan: fn.sourceSpan,
|
|
419
|
+
nodeKind: "function_declaration",
|
|
420
|
+
symbolName: fn.name,
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
emittedAnyFn = true;
|
|
424
|
+
}
|
|
425
|
+
if (ctx.callbackFunctions.length > 0 || emittedAnyFn) {
|
|
426
|
+
appendSourceLine(ctx, "");
|
|
427
|
+
}
|
|
428
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { StatementIR } from "../../api/index.js";
|
|
2
|
+
import type { SourceSpan } from "../../types.js";
|
|
3
|
+
import type { EmissionScopeState } from "../snprintf-helpers.js";
|
|
4
|
+
import type { EmitterContext } from "./emitter-context.js";
|
|
5
|
+
export declare function appendSourceLine(ctx: EmitterContext, line: string, entry?: {
|
|
6
|
+
tsSpan: SourceSpan;
|
|
7
|
+
nodeKind: string;
|
|
8
|
+
symbolName?: string;
|
|
9
|
+
}): void;
|
|
10
|
+
export declare function appendHeaderLine(ctx: EmitterContext, line: string, entry?: {
|
|
11
|
+
tsSpan: SourceSpan;
|
|
12
|
+
nodeKind: string;
|
|
13
|
+
symbolName?: string;
|
|
14
|
+
}): void;
|
|
15
|
+
export declare function appendRenderedStatement(ctx: EmitterContext, statement: StatementIR, indent: string, scopeState: EmissionScopeState): void;
|