@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
package/dist/ir/build-ir.js
CHANGED
|
@@ -5,11 +5,10 @@ import { parseSource } from "../ast/parse.js";
|
|
|
5
5
|
import { isStringEnum } from "../api/shared/index.js";
|
|
6
6
|
import { makeDiagnostic } from "./ast-node-utils.js";
|
|
7
7
|
import { buildFunctionReturnTypeMap } from "./type-resolution.js";
|
|
8
|
-
import {
|
|
8
|
+
import { tryResolveBoardDefFile, findGeneratedBoard, readGeneratedBoardConstants } from "./board-resolver.js";
|
|
9
9
|
import { analyzePeripheralUsage, createEmptyPeripheralUsage } from "./peripheral-usage.js";
|
|
10
10
|
import { runProgramValidations } from "./validation-orchestrator.js";
|
|
11
|
-
import { registerFieldMap, hoistedNestedFunctions, hoistedNestedClasses, hoistedNestedEnums, hoistedNestedInterfaces, hoistedNestedTypeAliases, activeNamespaceNames, activeEnumNames, activeStringEnumNames, peripheralAliasMap, pinAliasMap, mcuPinReverseMap, topLevelClassNames, topLevelInterfaceNames, classTypeNames, topLevelClasses, requiredIncludes, resetBuildState, getCurrentBoardConstants, setCurrentBoardConstants, contextStorage, CompilationContext, registeredCallbacks, getContext, discriminatedUnionVariantNames, restParamFunctions, topLevelAliasReceivers } from "./build-ir-state.js";
|
|
12
|
-
import { pinShadowVarName, takeShadowDeclarations, resetPinStateTracking, markShadowUpdatingOps } from "./pin-state-tracking.js";
|
|
11
|
+
import { registerFieldMap, hoistedNestedFunctions, hoistedNestedClasses, hoistedNestedEnums, hoistedNestedInterfaces, hoistedNestedTypeAliases, activeNamespaceNames, activeEnumNames, activeStringEnumNames, peripheralAliasMap, pinAliasMap, mcuPinForwardMap, mcuPinReverseMap, topLevelClassNames, topLevelInterfaceNames, classTypeNames, topLevelClasses, requiredIncludes, resetBuildState, getCurrentBoardConstants, setCurrentBoardConstants, contextStorage, CompilationContext, registeredCallbacks, getContext, discriminatedUnionVariantNames, restParamFunctions, topLevelAliasReceivers } from "./build-ir-state.js";
|
|
13
12
|
import { collectPointerVars, expressionStatementToIR, lowerStatement, variableStatementToIR, prescanArrayUsage, lowerStatementList } from "./statement-to-ir.js";
|
|
14
13
|
import { registerUIModuleImport, registerElementValue } from "./transformers/ui-call-resolver.js";
|
|
15
14
|
import { requireUIHook } from "../ui-hook.js";
|
|
@@ -141,7 +140,7 @@ function resolveUIImportPath(fromFile, moduleSpecifier) {
|
|
|
141
140
|
catch { /* skip */ }
|
|
142
141
|
return undefined;
|
|
143
142
|
}
|
|
144
|
-
export function buildProgramIR(fileName, sourceText,
|
|
143
|
+
export function buildProgramIR(fileName, sourceText, boardTarget, prebuiltClassMap) {
|
|
145
144
|
const parentStrategy = getContext().activeStrategy;
|
|
146
145
|
return contextStorage.run(new CompilationContext(), () => {
|
|
147
146
|
getContext().activeStrategy = parentStrategy;
|
|
@@ -182,7 +181,6 @@ export function buildProgramIR(fileName, sourceText, boardPackage, prebuiltClass
|
|
|
182
181
|
// Reset module-level state for this file
|
|
183
182
|
resetBuildState();
|
|
184
183
|
resetHALResolver();
|
|
185
|
-
resetPinStateTracking();
|
|
186
184
|
registerFieldMap.clear();
|
|
187
185
|
// Phase 0: Pre-scan for top-level classes and register them so type inference can resolve them.
|
|
188
186
|
// Also register classes from other files in the transpile graph so that property accesses
|
|
@@ -299,7 +297,7 @@ export function buildProgramIR(fileName, sourceText, boardPackage, prebuiltClass
|
|
|
299
297
|
// lowered to IR, but `ui` itself must NOT be emitted as a C++ value
|
|
300
298
|
// (it would synthesize a bogus _ui_t struct). Drop it from the imports
|
|
301
299
|
// IR so the emit path never sees it as an imported value.
|
|
302
|
-
const isUiPackage = moduleSpecifier === '@typecad/ui'
|
|
300
|
+
const isUiPackage = moduleSpecifier === '@typecad/ui';
|
|
303
301
|
const filteredImports = isUiPackage
|
|
304
302
|
? namedImports.filter((n) => n !== 'ui')
|
|
305
303
|
: namedImports;
|
|
@@ -307,10 +305,10 @@ export function buildProgramIR(fileName, sourceText, boardPackage, prebuiltClass
|
|
|
307
305
|
}
|
|
308
306
|
}
|
|
309
307
|
for (const imp of earlyImports) {
|
|
310
|
-
const boardFile = tryResolveBoardDefFile(fileName, imp.moduleSpecifier,
|
|
308
|
+
const boardFile = tryResolveBoardDefFile(fileName, imp.moduleSpecifier, boardTarget);
|
|
311
309
|
if (boardFile) {
|
|
312
310
|
try {
|
|
313
|
-
setCurrentBoardConstants(
|
|
311
|
+
setCurrentBoardConstants(readGeneratedBoardConstants(boardFile));
|
|
314
312
|
}
|
|
315
313
|
catch {
|
|
316
314
|
// Non-fatal
|
|
@@ -319,20 +317,21 @@ export function buildProgramIR(fileName, sourceText, boardPackage, prebuiltClass
|
|
|
319
317
|
}
|
|
320
318
|
}
|
|
321
319
|
// If only the default board constants are loaded (4 keys from getDefaultBoardConstants),
|
|
322
|
-
//
|
|
323
|
-
// is imported from @typecad/hal but no @typecad/board
|
|
320
|
+
// load the generated board manifest directly — covers the case where board()/boardResolve()
|
|
321
|
+
// is imported from @typecad/hal but no @typecad/board import is present in the user's code.
|
|
324
322
|
const currentBC = getCurrentBoardConstants();
|
|
325
|
-
if (currentBC && currentBC.size <= 4
|
|
326
|
-
const
|
|
327
|
-
if (
|
|
323
|
+
if (currentBC && currentBC.size <= 4) {
|
|
324
|
+
const generated = findGeneratedBoard(fileName);
|
|
325
|
+
if (generated) {
|
|
328
326
|
try {
|
|
329
|
-
setCurrentBoardConstants(
|
|
327
|
+
setCurrentBoardConstants(readGeneratedBoardConstants(generated.boardJson));
|
|
330
328
|
}
|
|
331
329
|
catch {
|
|
332
330
|
// Non-fatal
|
|
333
331
|
}
|
|
334
332
|
}
|
|
335
333
|
}
|
|
334
|
+
void boardTarget;
|
|
336
335
|
// Phase 0c-bis: register UI module imports (name → .ui.html path) so
|
|
337
336
|
// ui.mount(screen, ...) can resolve `screen` back to its source tree.
|
|
338
337
|
// Only .ui.html specifiers are registered; their named imports are the UI
|
|
@@ -387,8 +386,7 @@ export function buildProgramIR(fileName, sourceText, boardPackage, prebuiltClass
|
|
|
387
386
|
"asOutput", "asInput", "asInputPullUp", "asInputPullDown",
|
|
388
387
|
"output", "inputPullUp", "inputPullDown",
|
|
389
388
|
"device", // I2CBus.device(addr) / SPIBus.device(cs) → device instance
|
|
390
|
-
"
|
|
391
|
-
"begin", // I2CBus.begin() / SPIBus.begin() / SerialPort.begin() → same instance
|
|
389
|
+
"begin", // I2CBus.begin() / SPIBus.begin() → same instance
|
|
392
390
|
"take", // Bus.take() → same instance (ownership is compile-time only)
|
|
393
391
|
]);
|
|
394
392
|
for (const node of source.statements) {
|
|
@@ -402,7 +400,7 @@ export function buildProgramIR(fileName, sourceText, boardPackage, prebuiltClass
|
|
|
402
400
|
&& HAL_ALIASING_METHODS.has(init.expression.name.text)
|
|
403
401
|
&& ts.isIdentifier(init.expression.expression)) {
|
|
404
402
|
// Capture call arguments for factory methods like device(0x76) that
|
|
405
|
-
// need the arg to construct the derived instance (
|
|
403
|
+
// need the arg to construct the derived instance (I2CTarget._address).
|
|
406
404
|
const argTexts = init.arguments.map(a => {
|
|
407
405
|
if (ts.isNumericLiteral(a))
|
|
408
406
|
return a.text;
|
|
@@ -445,20 +443,20 @@ export function buildProgramIR(fileName, sourceText, boardPackage, prebuiltClass
|
|
|
445
443
|
}
|
|
446
444
|
}
|
|
447
445
|
}
|
|
448
|
-
// Track HAL instances imported from board
|
|
449
|
-
//
|
|
450
|
-
//
|
|
451
|
-
//
|
|
446
|
+
// Track HAL instances imported from the board module (virtual
|
|
447
|
+
// `@typecad/board`, or a legacy `@typecad/board-*` package import from
|
|
448
|
+
// pre-boardgen projects, which resolves against the project's generated
|
|
449
|
+
// board constants) so the HAL resolver can resolve them to framework
|
|
450
|
+
// C++ names. Case-insensitive.
|
|
452
451
|
const lowerSpecifier = moduleSpecifier.toLowerCase();
|
|
453
452
|
const isHALSource = lowerSpecifier.startsWith('@typecad/board-')
|
|
454
|
-
|| lowerSpecifier === '@typecad/board'
|
|
455
|
-
|| /^@typecad\/framework-[a-z0-9-]+\/(arduino|hal|gpio)$/.test(lowerSpecifier);
|
|
453
|
+
|| lowerSpecifier === '@typecad/board';
|
|
456
454
|
// UI authoring namespace: `import { ui } from "@typecad/ui"`. The `ui`
|
|
457
455
|
// value is a compile-time construct (its calls are intercepted by
|
|
458
456
|
// tryResolveUICall); it must NOT be emitted as a C++ struct/value.
|
|
459
457
|
// Treat it like the HAL namespace imports (Pulse/Shift/Random): register
|
|
460
458
|
// as a namespace name and skip, so no struct is synthesized.
|
|
461
|
-
if (moduleSpecifier === '@typecad/ui'
|
|
459
|
+
if (moduleSpecifier === '@typecad/ui') {
|
|
462
460
|
for (const name of namedImports) {
|
|
463
461
|
if (name === 'ui') {
|
|
464
462
|
activeNamespaceNames.add(name);
|
|
@@ -497,10 +495,31 @@ export function buildProgramIR(fileName, sourceText, boardPackage, prebuiltClass
|
|
|
497
495
|
halInstances.set(name, { className: "Pin", fieldValues: fields });
|
|
498
496
|
continue;
|
|
499
497
|
}
|
|
500
|
-
// A-pins: A0
|
|
498
|
+
// A-pins: A0, A1, … → resolve through the board manifest's analog
|
|
499
|
+
// pin list first (A-ordered on every board package: A<n> →
|
|
500
|
+
// pins.analog[n] → the MCU port name → pin number). Only when the
|
|
501
|
+
// list is absent (bare Arduino-style boards) fall back to the
|
|
502
|
+
// analogOffset convention (A0 = 14) — on port-named boards that
|
|
503
|
+
// fallback resolves A1 to a random GPIO (Black Pill PA15, a
|
|
504
|
+
// non-analog pin, was the first to surface it via a capability
|
|
505
|
+
// error).
|
|
501
506
|
const aMatch = name.match(/^A(\d+)$/);
|
|
502
507
|
if (aMatch) {
|
|
503
|
-
|
|
508
|
+
let pinNum;
|
|
509
|
+
// The flattener stores the manifest's analog pin list as a
|
|
510
|
+
// comma-joined string under `pins.analog`.
|
|
511
|
+
const analogList = boardConstants.get("pins.analog");
|
|
512
|
+
if (typeof analogList === "string") {
|
|
513
|
+
const analogName = analogList.split(",")[parseInt(aMatch[1], 10)];
|
|
514
|
+
if (analogName) {
|
|
515
|
+
const byName = mcuPinForwardMap.get(analogName);
|
|
516
|
+
if (byName !== undefined)
|
|
517
|
+
pinNum = String(byName);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
if (pinNum === undefined) {
|
|
521
|
+
pinNum = String(analogOffset + parseInt(aMatch[1]));
|
|
522
|
+
}
|
|
504
523
|
const fields = new Map([["_pin", pinNum]]);
|
|
505
524
|
const portName = mcuPinReverseMap.get(pinNum);
|
|
506
525
|
if (portName)
|
|
@@ -511,22 +530,36 @@ export function buildProgramIR(fileName, sourceText, boardPackage, prebuiltClass
|
|
|
511
530
|
// I2C buses: I2C0, I2C1, ...
|
|
512
531
|
const i2cMatch = name.match(/^I2C(\d+)$/);
|
|
513
532
|
if (i2cMatch) {
|
|
514
|
-
const alias = peripheralAliasMap.get(name) ??
|
|
533
|
+
const alias = peripheralAliasMap.get(name) ?? `I2C${i2cMatch[1]}`;
|
|
515
534
|
halInstances.set(name, { className: "I2CBus", fieldValues: new Map([["_bus", alias]]) });
|
|
516
535
|
continue;
|
|
517
536
|
}
|
|
518
537
|
// SPI buses: SPI0, SPI1, ...
|
|
519
538
|
const spiMatch = name.match(/^SPI(\d+)$/);
|
|
520
539
|
if (spiMatch) {
|
|
521
|
-
const alias = peripheralAliasMap.get(name) ??
|
|
540
|
+
const alias = peripheralAliasMap.get(name) ?? `SPI${spiMatch[1]}`;
|
|
522
541
|
halInstances.set(name, { className: "SPIBus", fieldValues: new Map([["_bus", alias]]) });
|
|
523
542
|
continue;
|
|
524
543
|
}
|
|
525
|
-
// UART: UART0, UART1, ...
|
|
544
|
+
// UART: UART0, UART1, ... — the FUNCTIONAL thin UART instance, so
|
|
545
|
+
// the board singleton is directly usable (UART0.println(...)) with
|
|
546
|
+
// the same fields a `new UART('UART0')` construction captures
|
|
547
|
+
// (port + the class's baud/ring defaults; variables.ts merges those
|
|
548
|
+
// only at construction, so the registration carries them).
|
|
526
549
|
const uartMatch = name.match(/^UART(\d+)$/);
|
|
527
550
|
if (uartMatch) {
|
|
528
|
-
const alias = peripheralAliasMap.get(name) ??
|
|
529
|
-
halInstances.set(name, {
|
|
551
|
+
const alias = peripheralAliasMap.get(name) ?? `UART${uartMatch[1]}`;
|
|
552
|
+
halInstances.set(name, {
|
|
553
|
+
className: "UART",
|
|
554
|
+
fieldValues: new Map([["_port", alias], ["_bus", alias], ["_baud", "115200"], ["_rxBufferBytes", "64"]]),
|
|
555
|
+
});
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
// USB CDC serial ports: USB0, USB1, ...
|
|
559
|
+
const usbMatch = name.match(/^USB(\d+)$/);
|
|
560
|
+
if (usbMatch) {
|
|
561
|
+
const alias = peripheralAliasMap.get(name) ?? `USB${usbMatch[1]}`;
|
|
562
|
+
halInstances.set(name, { className: "USBConsole", fieldValues: new Map([["_port", alias]]) });
|
|
530
563
|
continue;
|
|
531
564
|
}
|
|
532
565
|
// HAL namespace imports: Pulse, Shift, Random
|
|
@@ -814,20 +847,6 @@ export function buildProgramIR(fileName, sourceText, boardPackage, prebuiltClass
|
|
|
814
847
|
// write/toggle ops, while this file's tracker state is still live (the
|
|
815
848
|
// next file's build resets it, and emit runs after every file is built —
|
|
816
849
|
// multi-file programs would lose the updates otherwise). Then consume the
|
|
817
|
-
// shadow declarations — pins whose reads lowered to the shadow variable
|
|
818
|
-
// form need a file-scope declaration.
|
|
819
|
-
markShadowUpdatingOps(program);
|
|
820
|
-
const shadowDecls = takeShadowDeclarations();
|
|
821
|
-
for (const { pin, initial } of shadowDecls) {
|
|
822
|
-
program.topLevelStatements.unshift({
|
|
823
|
-
kind: "var_decl",
|
|
824
|
-
sourceSpan: { filePath: fileName, startOffset: 0, endOffset: 0, startLine: 0, startColumn: 0, endLine: 0, endColumn: 0 },
|
|
825
|
-
name: pinShadowVarName(pin),
|
|
826
|
-
storage: "var",
|
|
827
|
-
cppType: "bool",
|
|
828
|
-
initializer: { kind: "boolean", value: initial },
|
|
829
|
-
});
|
|
830
|
-
}
|
|
831
850
|
return program;
|
|
832
851
|
});
|
|
833
852
|
}
|
|
@@ -256,6 +256,7 @@ export function classDeclarationToIR(node, fileName, sourceText, diagnostics, fu
|
|
|
256
256
|
visibility: methodVisibility,
|
|
257
257
|
isStatic,
|
|
258
258
|
isAbstract: isMethodAbstract,
|
|
259
|
+
isAsync: member.modifiers?.some(m => m.kind === ts.SyntaxKind.AsyncKeyword) ?? false,
|
|
259
260
|
isOverride,
|
|
260
261
|
...(member.typeParameters && member.typeParameters.length > 0
|
|
261
262
|
? { typeParameters: member.typeParameters.map(tp => tp.name.text) }
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
2
|
import { makeDiagnostic, makeSourceSpan } from "./ast-node-utils.js";
|
|
3
3
|
import { PIN_FACTORY_FUNCTIONS, CONSTANT_FOLD_FUNCTIONS, TYPED_ARRAY_ELEMENT_MAP, activeCArrayVars, activeArrayLiteralVars, activeStringVars, nestedFunctionAliases, nestedClassAliases, hoistedNestedClasses, mutableArrayVars, arrayLiteralSizes, filteredArrayLengthVars, activeNamespaceNames, activeEnumNames, activeStringEnumNames, topLevelClassNames, topLevelInterfaceNames, classTypeNames, topLevelClasses, getActiveExtendsClass, restParamFunctions, getContext, getCurrentBoardConstants } from "./build-ir-state.js";
|
|
4
|
-
import { isPinFoldingEnabled, setPinFoldingEnabled } from "./pin-state-tracking.js";
|
|
5
4
|
import { getCurrentIrTypeScope } from "./symbol-types.js";
|
|
6
5
|
import { renderExprAsText } from "./render-expr.js";
|
|
7
6
|
import { lowerStatement, tryResolveHALExpression } from "./statement-to-ir.js";
|
|
@@ -414,8 +413,8 @@ export function expressionToIR(expr, sourceText, diagnostics, pointerVars = new
|
|
|
414
413
|
return `(sizeof(${safeText}) / sizeof(${safeText}[0]))`;
|
|
415
414
|
}
|
|
416
415
|
if (ts.isCallExpression(receiverNode)) {
|
|
417
|
-
// Case B: a HAL buffer-returning method (
|
|
418
|
-
//
|
|
416
|
+
// Case B: a HAL buffer-returning method (a device target's read
|
|
417
|
+
// verbs) used INLINE as a sub-expression — e.g.
|
|
419
418
|
// `dev.readBytes(0,6).length`. These methods lower to STATEMENTS (a fill
|
|
420
419
|
// loop), not a single C++ expression, so by the time we get here the
|
|
421
420
|
// receiver text is already a leaked `for (...) __buf[__i] = Wire.read()`
|
|
@@ -685,9 +684,9 @@ export function expressionToIR(expr, sourceText, diagnostics, pointerVars = new
|
|
|
685
684
|
// When the cast involves an `enum class` on one side and an integral type
|
|
686
685
|
// on the other, emit a `static_cast<T>(...)` instead of erasing. C++ enum
|
|
687
686
|
// class has NO implicit conversion, so the erased cast produces invalid
|
|
688
|
-
// C++.
|
|
689
|
-
//
|
|
690
|
-
//
|
|
687
|
+
// C++. This is handled for specific sites (relational, index, Map key,
|
|
688
|
+
// storage boundary) but NOT for the general `as` cast — the user's
|
|
689
|
+
// explicit escape hatch (enum stress test Finding C).
|
|
691
690
|
const targetTypeName = expr.type && ts.isTypeReferenceNode(expr.type) && ts.isIdentifier(expr.type.typeName)
|
|
692
691
|
? expr.type.typeName.text : "";
|
|
693
692
|
const isTargetEnum = targetTypeName && activeEnumNames.has(targetTypeName) && !activeStringEnumNames.has(targetTypeName);
|
|
@@ -1103,6 +1102,17 @@ export function expressionToIR(expr, sourceText, diagnostics, pointerVars = new
|
|
|
1103
1102
|
};
|
|
1104
1103
|
}
|
|
1105
1104
|
if (ts.isCallExpression(expr)) {
|
|
1105
|
+
// ---- console.* is not a supported API (value position) ----
|
|
1106
|
+
// Statement-position console calls are rejected in callToStatement; this
|
|
1107
|
+
// covers value-position uses (e.g. `const line = console.readLine()`).
|
|
1108
|
+
// Same rationale: the TypeScript console carry-over is gone — programs
|
|
1109
|
+
// write to a serial console explicitly via the board module.
|
|
1110
|
+
if (ts.isPropertyAccessExpression(expr.expression) &&
|
|
1111
|
+
ts.isIdentifier(expr.expression.expression) &&
|
|
1112
|
+
expr.expression.expression.text === "console") {
|
|
1113
|
+
diagnostics.push(makeDiagnostic(sourceText, expr.pos, `console.${expr.expression.name.text}() is not supported — write to a serial console instead: \`USB0.writeLine(...)\` (USB CDC) or \`UART0.writeLine(...)\` from the board module.`, "error", "console-unsupported"));
|
|
1114
|
+
return { kind: "raw", value: "0 /* console.* is not supported */" };
|
|
1115
|
+
}
|
|
1106
1116
|
// ---- safe.read/safe.write chained with .ok/.fail/.fault/.always ----
|
|
1107
1117
|
// Method chains like `safe.read(pin).ok(r => {...}).fail(r => {...})` cannot
|
|
1108
1118
|
// use the generic method-call builder because it flattens the receiver into
|
|
@@ -1657,7 +1667,7 @@ export function expressionToIR(expr, sourceText, diagnostics, pointerVars = new
|
|
|
1657
1667
|
// with '*' (a class-pointer struct field, e.g. FloorState.monster), the
|
|
1658
1668
|
// method call must use ->. Without this, `dungeon.monster.bounty()`
|
|
1659
1669
|
// emits `.` and fails g++ ("request for member 'bounty' ... pointer
|
|
1660
|
-
// type").
|
|
1670
|
+
// type"). (demo #4 fix.)
|
|
1661
1671
|
isPointer: calleeText.includes("->")
|
|
1662
1672
|
|| (ts.isCallExpression(expr)
|
|
1663
1673
|
&& ts.isPropertyAccessExpression(expr.expression)
|
|
@@ -2199,8 +2209,6 @@ export function expressionToIR(expr, sourceText, diagnostics, pointerVars = new
|
|
|
2199
2209
|
const isBlock = ts.isBlock(body);
|
|
2200
2210
|
// Lambda bodies run at an unmodeled time (callbacks), so pin-state
|
|
2201
2211
|
// constant folding must be off inside them.
|
|
2202
|
-
const prevPinFolding = isPinFoldingEnabled();
|
|
2203
|
-
setPinFoldingEnabled(false);
|
|
2204
2212
|
const bodyStmts = isBlock
|
|
2205
2213
|
? body.statements.map(stmt => {
|
|
2206
2214
|
const lowered = lowerStatement(stmt, "", sourceText, diagnostics, new Map(), new Map(), "<lambda>", new Map(), pointerVars);
|
|
@@ -2212,7 +2220,6 @@ export function expressionToIR(expr, sourceText, diagnostics, pointerVars = new
|
|
|
2212
2220
|
sourceSpan: makeSourceSpan(body, "", sourceText),
|
|
2213
2221
|
value: expressionToIR(body, sourceText, diagnostics, pointerVars),
|
|
2214
2222
|
}];
|
|
2215
|
-
setPinFoldingEnabled(prevPinFolding);
|
|
2216
2223
|
// Infer return type: use explicit annotation, or infer from body. Thread
|
|
2217
2224
|
// the lambda's own param types into the inference so a body like
|
|
2218
2225
|
// `(n) => n.capacity` can resolve `n` and deduce the return type.
|
|
@@ -55,8 +55,6 @@ export declare function resolveHALExprToText(expr: Extract<import("../../api/sha
|
|
|
55
55
|
kind: "hal-expr";
|
|
56
56
|
}>): string | null;
|
|
57
57
|
export declare function registerFloatVariable(name: string): void;
|
|
58
|
-
/** Build snprintf prelude lines from a string_concat expression.
|
|
59
|
-
* Returns { lines, bufferName } or null if the expression can't be formatted. */
|
|
60
58
|
export declare function buildSnprintfFromConcat(expr: Extract<ExpressionIR, {
|
|
61
59
|
kind: "string_concat";
|
|
62
60
|
}>): {
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
-
import { requiredIncludes, registeredCallbacks, activeStringVars, TYPED_ARRAY_ELEMENT_MAP, getContext, floatVariables, halInstances, getCurrentBoardConstants } from "../build-ir-state.js";
|
|
2
|
+
import { requiredIncludes, registeredCallbacks, activeStringVars, TYPED_ARRAY_ELEMENT_MAP, getContext, floatVariables, halInstances, getCurrentBoardConstants, markHalOpResolved } from "../build-ir-state.js";
|
|
3
3
|
import { getCurrentIrTypeScope } from "../symbol-types.js";
|
|
4
4
|
import { renderExprAsText } from "../render-expr.js";
|
|
5
|
-
import { escapeCppKeyword } from "../../utils/strings.js";
|
|
5
|
+
import { escapeCppKeyword, escapeCppStringLiteral } from "../../utils/strings.js";
|
|
6
6
|
import { halClassRegistry, halGlobalFunctions } from "./hal-parser.js";
|
|
7
7
|
import { tryResolveSemanticCall, tryResolveBoardResolveArg, tryResolveCompoundSemanticReturn, resolveConcatPath } from "./hal-plugins.js";
|
|
8
|
-
import { resolveTrackedRead, pinShadowVarName } from "../pin-state-tracking.js";
|
|
9
8
|
import { cppTypeForHalOp } from "../../emit/utils/hal-op-cpp-type.js";
|
|
10
9
|
/** Escape C++ keywords in resolved text, but only when the text looks like a
|
|
11
10
|
* variable reference (not a literal like "false", "true", "42", or a string). */
|
|
@@ -65,16 +64,6 @@ function inlineThisGetterCall(methodName, pin, strategy) {
|
|
|
65
64
|
// lower to the tracked level (constant when statically known, shadow
|
|
66
65
|
// variable otherwise) instead of a hardware read. Reading back a
|
|
67
66
|
// direction-only output is not portable (e.g. Zephyr).
|
|
68
|
-
const pinNum = Number.parseInt(pin, 10);
|
|
69
|
-
if (Number.isFinite(pinNum)) {
|
|
70
|
-
const tracked = resolveTrackedRead(pinNum);
|
|
71
|
-
if (tracked !== null) {
|
|
72
|
-
const levelText = tracked === "shadow"
|
|
73
|
-
? pinShadowVarName(pinNum)
|
|
74
|
-
: (tracked === "high" ? "true" : "false");
|
|
75
|
-
return methodName === "isLow" ? `(!${levelText})` : levelText;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
67
|
if (methodName === "read")
|
|
79
68
|
return strategy?.readDigitalPin?.(pin) ?? `digitalRead(${pin})`;
|
|
80
69
|
if (methodName === "isHigh")
|
|
@@ -150,8 +139,12 @@ export function resolveExpressionText(expr, instance, paramNames, callArgTexts,
|
|
|
150
139
|
}
|
|
151
140
|
if (ts.isNumericLiteral(expr))
|
|
152
141
|
return expr.text;
|
|
142
|
+
// Escape the DECODED text back to a valid C++ literal — expr.text holds
|
|
143
|
+
// real control chars (a "\n" argument decodes to a newline), and a raw
|
|
144
|
+
// newline inside a C string literal is an unterminated literal that
|
|
145
|
+
// corrupts the rest of the file. Same helper every other renderer uses.
|
|
153
146
|
if (ts.isStringLiteral(expr))
|
|
154
|
-
return expr.text
|
|
147
|
+
return `"${escapeCppStringLiteral(expr.text)}"`;
|
|
155
148
|
// Call expression (e.g., digitalRead(this._pin), board("path"))
|
|
156
149
|
if (ts.isCallExpression(expr)) {
|
|
157
150
|
// callback(param) → return the patched placeholder text
|
|
@@ -300,7 +293,7 @@ export function resolveExpressionText(expr, instance, paramNames, callArgTexts,
|
|
|
300
293
|
* ESP-IDF, trips -Werror=attributes when IRAM_ATTR's __COUNTER__ disagrees
|
|
301
294
|
* between forward declaration and definition. */
|
|
302
295
|
const ISR_CALLBACK_SEMANTIC_FNS = new Set([
|
|
303
|
-
"
|
|
296
|
+
"interruptAttachFlags",
|
|
304
297
|
]);
|
|
305
298
|
/** True when a HAL semantic call name wraps a GPIO/hardware ISR callback. */
|
|
306
299
|
export function semanticCallUsesIsrCallback(fnName) {
|
|
@@ -665,10 +658,16 @@ export function resolveHALExprToText(expr) {
|
|
|
665
658
|
if (!strategy?.resolveHALOperation)
|
|
666
659
|
return null;
|
|
667
660
|
const resolved = strategy.resolveHALOperation(expr.operation);
|
|
668
|
-
if (resolved
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
661
|
+
if (resolved) {
|
|
662
|
+
// The op may never exist as an IR node (its text is baked into the
|
|
663
|
+
// calling method's emit lines), so record it for program-analysis's
|
|
664
|
+
// peripheral usage flags.
|
|
665
|
+
markHalOpResolved(expr.operation.operation);
|
|
666
|
+
if (resolved.expression)
|
|
667
|
+
return resolved.expression;
|
|
668
|
+
if (resolved.code)
|
|
669
|
+
return resolved.code.replace(/;\s*$/, "");
|
|
670
|
+
}
|
|
672
671
|
return null;
|
|
673
672
|
}
|
|
674
673
|
export function registerFloatVariable(name) {
|
|
@@ -676,6 +675,20 @@ export function registerFloatVariable(name) {
|
|
|
676
675
|
}
|
|
677
676
|
/** Build snprintf prelude lines from a string_concat expression.
|
|
678
677
|
* Returns { lines, bufferName } or null if the expression can't be formatted. */
|
|
678
|
+
/** True when a binary IR expression touches a known float variable on either
|
|
679
|
+
* side (recursively) — its rendered C++ is double-valued. */
|
|
680
|
+
function binaryTouchesFloatVar(expr) {
|
|
681
|
+
for (const side of [expr.left, expr.right]) {
|
|
682
|
+
if (!side || typeof side !== "object")
|
|
683
|
+
continue;
|
|
684
|
+
const s = side;
|
|
685
|
+
if (s.kind === "identifier" && typeof s.value === "string" && floatVariables.has(s.value))
|
|
686
|
+
return true;
|
|
687
|
+
if (s.kind === "binary" && binaryTouchesFloatVar(s))
|
|
688
|
+
return true;
|
|
689
|
+
}
|
|
690
|
+
return false;
|
|
691
|
+
}
|
|
679
692
|
export function buildSnprintfFromConcat(expr) {
|
|
680
693
|
let formatString = "";
|
|
681
694
|
const args = [];
|
|
@@ -685,18 +698,21 @@ export function buildSnprintfFromConcat(expr) {
|
|
|
685
698
|
for (const part of expr.parts) {
|
|
686
699
|
const text = renderExprAsText(part);
|
|
687
700
|
if (part.kind === "string") {
|
|
688
|
-
|
|
701
|
+
// Escape % → %% first (a bare % in the format string starts a
|
|
702
|
+
// conversion — a literal '%RH' becomes the unknown-conversion 'R'),
|
|
703
|
+
// then the C-literal escapes.
|
|
704
|
+
formatString += text.slice(1, -1).replace(/%/g, "%%").replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
689
705
|
estimatedLength += part.value.length;
|
|
690
706
|
}
|
|
691
707
|
else if (part.kind === "number") {
|
|
692
708
|
const isFloat = part.cppType === "float" || part.cppType === "double" || !Number.isInteger(part.value);
|
|
693
709
|
if (isFloat) {
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
formatString += "%
|
|
699
|
-
args.push(
|
|
710
|
+
// %g formats the double literal directly — portable (Zephyr's
|
|
711
|
+
// cbprintf turns on FP support when it sees a float specifier);
|
|
712
|
+
// dtostrf is AVR-only and fails to compile elsewhere (same reasoning
|
|
713
|
+
// as the float-VARIABLE branch below).
|
|
714
|
+
formatString += "%g";
|
|
715
|
+
args.push(text);
|
|
700
716
|
estimatedLength += 16;
|
|
701
717
|
}
|
|
702
718
|
else {
|
|
@@ -710,15 +726,32 @@ export function buildSnprintfFromConcat(expr) {
|
|
|
710
726
|
const isStringVar = part.kind === "template_string"
|
|
711
727
|
&& part.expression.kind === "identifier"
|
|
712
728
|
&& (activeStringVars.has(part.expression.value) || getCurrentIrTypeScope()?.locals.get(part.expression.value) === "std::string" || getCurrentIrTypeScope()?.globals.get(part.expression.value) === "std::string");
|
|
713
|
-
// Check for float variable reference: template_string wrapping an identifier
|
|
729
|
+
// Check for float variable reference: template_string wrapping an identifier.
|
|
730
|
+
// A var initialized from a double-returning HAL op (sensor.get) records
|
|
731
|
+
// as a float var; one declared `: number` from such an initializer also
|
|
732
|
+
// lands in the IR scope's float types.
|
|
714
733
|
const isFloatVar = part.kind === "template_string"
|
|
715
734
|
&& part.expression.kind === "identifier"
|
|
716
735
|
&& floatVariables.has(part.expression.value);
|
|
736
|
+
// Inline double-returning HAL call (template_string wrapping a call):
|
|
737
|
+
// the lowerings' deterministic shape for a double return is
|
|
738
|
+
// `static_cast<double>(...)` — Time.now()/sensor.get()/millivolt reads.
|
|
739
|
+
// Formatting that with the %d default is a -Wformat warning at best and
|
|
740
|
+
// wrong output at worst; %g matches the float-variable branch.
|
|
741
|
+
const isDoubleCall = part.kind === "template_string"
|
|
742
|
+
&& /^static_cast<double>\(/.test(text);
|
|
717
743
|
if (isStringVar) {
|
|
718
744
|
formatString += "%s";
|
|
719
745
|
const varName = part.expression.value;
|
|
720
746
|
const varType = getCurrentIrTypeScope()?.locals.get(varName) || getCurrentIrTypeScope()?.globals.get(varName) || "";
|
|
721
|
-
|
|
747
|
+
// Normalize through the ACTIVE strategy before the char* check — the
|
|
748
|
+
// IR scope carries the pre-normalization type ("std::string") while
|
|
749
|
+
// the declaration renderer emitted the strategy's mapping of it
|
|
750
|
+
// (Zephyr: std::string → const char*). Without this, a string-literal
|
|
751
|
+
// variable declares as const char* but its snprintf arg gains a
|
|
752
|
+
// .c_str() that const char* does not have.
|
|
753
|
+
const normalizedType = getContext().activeStrategy?.normalizeCppType(varType) ?? varType;
|
|
754
|
+
const cleanType = normalizedType.replace(/\bconst\b\s*/g, "").trim();
|
|
722
755
|
if (cleanType && cleanType !== "char*" && cleanType !== "const char*") {
|
|
723
756
|
args.push(`${text}.c_str()`);
|
|
724
757
|
}
|
|
@@ -728,12 +761,18 @@ export function buildSnprintfFromConcat(expr) {
|
|
|
728
761
|
estimatedLength += 32;
|
|
729
762
|
}
|
|
730
763
|
else if (isFloatVar) {
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
764
|
+
// %g formats the double expression directly — portable (Zephyr's
|
|
765
|
+
// cbprintf turns on FP support when it sees a float specifier);
|
|
766
|
+
// dtostrf is AVR-only and fails to compile elsewhere.
|
|
767
|
+
formatString += "%g";
|
|
768
|
+
args.push(text);
|
|
769
|
+
estimatedLength += 16;
|
|
770
|
+
}
|
|
771
|
+
else if (isDoubleCall) {
|
|
772
|
+
// Inline double-returning HAL call (`${Time.now()}`) — the rendered
|
|
773
|
+
// text IS the double expression; %g, never the %d default.
|
|
774
|
+
formatString += "%g";
|
|
775
|
+
args.push(text);
|
|
737
776
|
estimatedLength += 16;
|
|
738
777
|
}
|
|
739
778
|
else if (part.kind === "template_string" && part.expression.kind === "hal-expr") {
|
|
@@ -751,6 +790,12 @@ export function buildSnprintfFromConcat(expr) {
|
|
|
751
790
|
args.push(`(${argText} ? "true" : "false")`);
|
|
752
791
|
estimatedLength += 5;
|
|
753
792
|
}
|
|
793
|
+
else if (cppType === "float" || cppType === "double") {
|
|
794
|
+
// %g formats the double expression directly — no AVR-only dtostrf.
|
|
795
|
+
formatString += "%g";
|
|
796
|
+
args.push(argText);
|
|
797
|
+
estimatedLength += 12;
|
|
798
|
+
}
|
|
754
799
|
else {
|
|
755
800
|
formatString += "%d";
|
|
756
801
|
args.push(argText);
|
|
@@ -760,15 +805,21 @@ export function buildSnprintfFromConcat(expr) {
|
|
|
760
805
|
else {
|
|
761
806
|
const numVal = Number(text);
|
|
762
807
|
if (!isNaN(numVal) && !Number.isInteger(numVal)) {
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
prelude.push(`dtostrf(${text}, 0, ${precision}, ${floatBuf});`);
|
|
768
|
-
formatString += "%s";
|
|
769
|
-
args.push(floatBuf);
|
|
808
|
+
// A float literal (or float-valued expression) — %g directly; the
|
|
809
|
+
// AVR dtostrf detour fails to compile on every other framework.
|
|
810
|
+
formatString += "%g";
|
|
811
|
+
args.push(text);
|
|
770
812
|
estimatedLength += 16;
|
|
771
813
|
}
|
|
814
|
+
else if (part.kind === "template_string"
|
|
815
|
+
&& part.expression.kind === "binary"
|
|
816
|
+
&& binaryTouchesFloatVar(part.expression)) {
|
|
817
|
+
// Arithmetic on a double var (`tenths / 10`) is double-valued: %g,
|
|
818
|
+
// not %d — the rendered text is already the C++ expression.
|
|
819
|
+
formatString += "%g";
|
|
820
|
+
args.push(text);
|
|
821
|
+
estimatedLength += 12;
|
|
822
|
+
}
|
|
772
823
|
else {
|
|
773
824
|
formatString += "%d";
|
|
774
825
|
args.push(text);
|
|
@@ -16,6 +16,10 @@ export interface HALMethodEntry {
|
|
|
16
16
|
export interface HALClassEntry {
|
|
17
17
|
ctorFieldMap: Map<string, string>;
|
|
18
18
|
ctorDefaults: Map<string, string>;
|
|
19
|
+
/** Class-field initializer literals ("_spiHz" → "1000000") — the defaults
|
|
20
|
+
* a method body reads when construction didn't set the field. Seeded into
|
|
21
|
+
* instance fieldValues so `this._spiHz` in an inlined method resolves. */
|
|
22
|
+
fieldDefaults: Map<string, string>;
|
|
19
23
|
methods: Map<string, HALMethodEntry>;
|
|
20
24
|
}
|
|
21
25
|
export declare const halClassRegistry: Map<string, HALClassEntry>;
|
|
@@ -50,11 +54,7 @@ export declare function extractMethods(cls: ts.ClassDeclaration): Map<string, HA
|
|
|
50
54
|
export declare function loadHALModules(force?: boolean): void;
|
|
51
55
|
/** Get constructor includes for a HAL class. */
|
|
52
56
|
export declare function getCtorIncludes(className: string): string[];
|
|
53
|
-
|
|
54
|
-
export declare function httpFactoryVerb(methodName: string): string | null;
|
|
55
|
-
/** Render an Http factory URL argument as C++ expression text (string
|
|
56
|
-
* literals quoted, identifiers/member accesses verbatim), or null when the
|
|
57
|
-
* argument shape can't be resolved at compile time. */
|
|
57
|
+
export declare function requestCtorFields(ctorArgs: readonly ts.Expression[] | undefined, sourceFile?: ts.SourceFile): Map<string, string> | null;
|
|
58
58
|
export declare function httpUrlArgText(arg: ts.Expression): string | null;
|
|
59
59
|
/** Resolve a call receiver to a tracked HAL instance. */
|
|
60
60
|
export declare function resolveHALReceiver(receiver: ts.Expression): HALInstance | null;
|