@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
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
// UI-specific behaviour that still happens here:
|
|
9
9
|
// - signal.set(value) → assign (already in callToStatement)
|
|
10
10
|
// - signal() → identifier (already in expressionToIR)
|
|
11
|
-
// - console.* → platform transform (already at emit via StatementRenderer)
|
|
12
11
|
// - CSS color string literals → rgb int (resolveColorIR walk on the IR)
|
|
13
12
|
// - canvas ctx.* → ui_display_* (ambient canvas ctx + rewriteCanvasCall)
|
|
14
13
|
// ---------------------------------------------------------------------------
|
|
@@ -246,15 +245,7 @@ export function renameIdentifiersInStatements(statements, from, to) {
|
|
|
246
245
|
return statements.map(renameStmt);
|
|
247
246
|
}
|
|
248
247
|
// ── Console-in-callback tracking (legacy string-bake leftover) ─────────────
|
|
249
|
-
let _loweredConsoleInCallback = false;
|
|
250
|
-
export function noteConsoleInCallback() {
|
|
251
|
-
_loweredConsoleInCallback = true;
|
|
252
|
-
}
|
|
253
|
-
export function loweredConsoleInCallback() {
|
|
254
|
-
return _loweredConsoleInCallback;
|
|
255
|
-
}
|
|
256
248
|
export function resetCallbackLoweringState() {
|
|
257
|
-
_loweredConsoleInCallback = false;
|
|
258
249
|
endCanvasAmbient();
|
|
259
250
|
}
|
|
260
251
|
// ── Ambient canvas context ─────────────────────────────────────────────────
|
|
@@ -304,21 +295,6 @@ function callbackTypeMaps() {
|
|
|
304
295
|
* go through lowerStatementList instead.
|
|
305
296
|
*/
|
|
306
297
|
export function lowerCallbackExpr(expr, sourceText, diagnostics) {
|
|
307
|
-
if (ts.isCallExpression(expr) &&
|
|
308
|
-
ts.isPropertyAccessExpression(expr.expression) &&
|
|
309
|
-
ts.isIdentifier(expr.expression.expression) &&
|
|
310
|
-
expr.expression.expression.text === "console") {
|
|
311
|
-
const method = expr.expression.name.text;
|
|
312
|
-
const renderedArgs = expr.arguments
|
|
313
|
-
.map((arg) => renderExprAsText(expressionToIR(arg, sourceText, diagnostics)))
|
|
314
|
-
.join(" << ");
|
|
315
|
-
_loweredConsoleInCallback = true;
|
|
316
|
-
const strategy = getContext().activeStrategy;
|
|
317
|
-
if (strategy) {
|
|
318
|
-
return strategy.transformConsoleCall(method, renderedArgs, false).replace(/;$/, "");
|
|
319
|
-
}
|
|
320
|
-
return `std::cout << ${renderedArgs} << std::endl`;
|
|
321
|
-
}
|
|
322
298
|
if (ts.isCallExpression(expr) &&
|
|
323
299
|
ts.isPropertyAccessExpression(expr.expression) &&
|
|
324
300
|
expr.expression.name.text === "set" &&
|
|
@@ -8,18 +8,13 @@ import { renderExprAsText } from "../render-expr.js";
|
|
|
8
8
|
import { expressionToIR } from "../expression-to-ir.js";
|
|
9
9
|
import { buildInlineForLoop } from "./array-methods.js";
|
|
10
10
|
import { isKnownHALClass, getCtorIncludes, getHALCtorFieldMap, registerFloatVariable, resolveHALReceiver, isHALSingleton, } from "../hal-resolver.js";
|
|
11
|
-
import {
|
|
11
|
+
import { requestCtorFields, halClassRegistry } from "../hal/hal-parser.js";
|
|
12
12
|
import { resolveHALCallForVarInit } from "./hal-call-resolver.js";
|
|
13
13
|
import { recordSignal } from "./ui-call-resolver.js";
|
|
14
14
|
import { hasSafetyHook, requireSafetyHook } from "../../safety-hook.js";
|
|
15
|
-
function replaceHalReadBufferPlaceholder(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
if (op.operation === "spi.read_buffer" && op.buffer === "__HAL_READ_BUF__") {
|
|
20
|
-
return { ...op, buffer: varName };
|
|
21
|
-
}
|
|
22
|
-
return op;
|
|
15
|
+
function replaceHalReadBufferPlaceholder(_op, _varName) {
|
|
16
|
+
// i2c/spi read_buffer ops were removed with the legacy Wire/SPI surfaces.
|
|
17
|
+
return _op;
|
|
23
18
|
}
|
|
24
19
|
export function assignmentOperatorToString(kind) {
|
|
25
20
|
switch (kind) {
|
|
@@ -445,10 +440,8 @@ export function variableStatementToIR(statement, fileName, sourceText, diagnosti
|
|
|
445
440
|
fieldValues.set("_bus", arg.text);
|
|
446
441
|
else if (className === "SPIBus")
|
|
447
442
|
fieldValues.set("_bus", arg.text);
|
|
448
|
-
else if (className === "
|
|
443
|
+
else if (className === "UART")
|
|
449
444
|
fieldValues.set("_port", arg.text);
|
|
450
|
-
else if (className === "EEPROMClass")
|
|
451
|
-
fieldValues.set("_name", arg.text);
|
|
452
445
|
}
|
|
453
446
|
else if (ts.isNumericLiteral(arg)) {
|
|
454
447
|
if (className === "Pin")
|
|
@@ -460,15 +453,273 @@ export function variableStatementToIR(statement, fileName, sourceText, diagnosti
|
|
|
460
453
|
}
|
|
461
454
|
}
|
|
462
455
|
}
|
|
463
|
-
// new
|
|
464
|
-
//
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
const
|
|
470
|
-
if (
|
|
471
|
-
fieldValues.set("
|
|
456
|
+
// new Sensor(SENSOR.<part>, I2C1.device(0x44)) — the generic
|
|
457
|
+
// DT-bound peripheral. The part token is kept as text (property
|
|
458
|
+
// access text like 'SENSOR.sensirion_sht3xd'); the bus + address
|
|
459
|
+
// come from the I2CTarget the second arg resolves to. The lowering
|
|
460
|
+
// resolves the token against the generated catalog.
|
|
461
|
+
if (className === "Sensor" && ctorArgs && ctorArgs.length >= 2) {
|
|
462
|
+
const dev = resolveSensorDeviceArg(ctorArgs[1]);
|
|
463
|
+
if (dev) {
|
|
464
|
+
fieldValues.set("_part", ctorArgs[0].getText());
|
|
465
|
+
fieldValues.set("_bus", dev.bus);
|
|
466
|
+
fieldValues.set("_kind", dev.kind);
|
|
467
|
+
fieldValues.set("_port", dev.port);
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
diagnostics.push(makeDiagnostic(sourceText, declaration.pos, `new Sensor(...) second argument must be an I2C device (e.g. I2C1.device(0x44), possibly via a const) — got '${ctorArgs[1].getText()}'.`, "error", "HAL_SENSOR_CTOR"));
|
|
471
|
+
}
|
|
472
|
+
// opts object literal: numeric properties pass through, pin
|
|
473
|
+
// identifiers resolve to their number (alert?: PA5). Absent
|
|
474
|
+
// properties fall back to the class-field initializer defaults
|
|
475
|
+
// (_spiHz = 1000000 etc.) so `this._spiHz` in an inlined method
|
|
476
|
+
// body always resolves.
|
|
477
|
+
const sensorDefaults = halClassRegistry.get("Sensor")?.fieldDefaults;
|
|
478
|
+
if (sensorDefaults) {
|
|
479
|
+
for (const [name, val] of sensorDefaults) {
|
|
480
|
+
if (!fieldValues.has(name))
|
|
481
|
+
fieldValues.set(name, val);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
if (ctorArgs.length >= 3 && ts.isObjectLiteralExpression(ctorArgs[2])) {
|
|
485
|
+
for (const prop of ctorArgs[2].properties) {
|
|
486
|
+
if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name))
|
|
487
|
+
continue;
|
|
488
|
+
const name = prop.name.text;
|
|
489
|
+
if (ts.isNumericLiteral(prop.initializer)) {
|
|
490
|
+
fieldValues.set(`_${name}`, prop.initializer.text);
|
|
491
|
+
}
|
|
492
|
+
else if (ts.isIdentifier(prop.initializer)) {
|
|
493
|
+
const inst = halInstances.get(prop.initializer.text);
|
|
494
|
+
fieldValues.set(`_${name}`, inst?.fieldValues.get("_pin") ?? inst?.fieldValues.get("pin") ?? prop.initializer.text);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
// new Request(method, url, opts?) — shared capture (also serves
|
|
500
|
+
// bare `new Request(...).send()` receivers via resolveHALReceiver).
|
|
501
|
+
if (className === "Request") {
|
|
502
|
+
const reqFields = requestCtorFields(ctorArgs, ctorArgs?.[0]?.getSourceFile());
|
|
503
|
+
if (reqFields)
|
|
504
|
+
for (const [k, v] of reqFields)
|
|
505
|
+
fieldValues.set(k, v);
|
|
506
|
+
}
|
|
507
|
+
// Thin Zephyr-shaped peripherals (GPIO/PWM/ADC/DAC/
|
|
508
|
+
// Watchdog/Counter — hal/gpio-pin.ts and siblings). Same discipline
|
|
509
|
+
// as Sensor: construction facts become instance fields. Pin args
|
|
510
|
+
// keep their identifier/text form (resolved to numbers later);
|
|
511
|
+
// flag/gain token EXPRESSIONS keep their source text — the lowering
|
|
512
|
+
// maps token names to C macros; numeric opts props pass through as
|
|
513
|
+
// numbers (numeric separators stripped for C++).
|
|
514
|
+
const thinPinFirst = { GPIO: true, PWM: true, ADC: true, DAC: true };
|
|
515
|
+
if (thinPinFirst[className] && ctorArgs && ctorArgs.length >= 1) {
|
|
516
|
+
const pinArg = ctorArgs[0];
|
|
517
|
+
if (ts.isIdentifier(pinArg)) {
|
|
518
|
+
// resolveHALReceiver seeds board-module pin constants (LED,
|
|
519
|
+
// BUTTON, datasheet names) into halInstances on first lookup —
|
|
520
|
+
// a plain halInstances.get() would miss them.
|
|
521
|
+
const inst = halInstances.get(pinArg.text) ?? resolveHALReceiver(pinArg);
|
|
522
|
+
fieldValues.set("_pin", inst?.fieldValues.get("_pin") ?? inst?.fieldValues.get("pin") ?? pinArg.text);
|
|
523
|
+
}
|
|
524
|
+
else {
|
|
525
|
+
fieldValues.set("_pin", pinArg.getText());
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
if (className === "GPIO" && ctorArgs && ctorArgs.length >= 2) {
|
|
529
|
+
// "GPIO.OUTPUT | GPIO.PULL_UP" — the token text is the IR carrier.
|
|
530
|
+
fieldValues.set("_flags", ctorArgs[1].getText());
|
|
531
|
+
}
|
|
532
|
+
const thinOptsCtor = { PWM: true, ADC: true, DAC: true, Counter: true };
|
|
533
|
+
if (thinOptsCtor[className] && ctorArgs && ctorArgs.length >= 2 && ts.isObjectLiteralExpression(ctorArgs[1])) {
|
|
534
|
+
for (const prop of ctorArgs[1].properties) {
|
|
535
|
+
if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name))
|
|
536
|
+
continue;
|
|
537
|
+
const name = prop.name.text;
|
|
538
|
+
if (ts.isNumericLiteral(prop.initializer)) {
|
|
539
|
+
fieldValues.set(`_${name}`, prop.initializer.text.replace(/_/g, ""));
|
|
540
|
+
}
|
|
541
|
+
else {
|
|
542
|
+
// Token (ADC.GAIN_1_4) or runtime expression text.
|
|
543
|
+
fieldValues.set(`_${name}`, prop.initializer.getText());
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
if (className === "Watchdog" && ctorArgs && ctorArgs.length >= 1 && ts.isNumericLiteral(ctorArgs[0])) {
|
|
548
|
+
fieldValues.set("_timeoutMs", ctorArgs[0].text.replace(/_/g, ""));
|
|
549
|
+
}
|
|
550
|
+
// Thin File/Mqtt: the path / broker-uri + client-id facts.
|
|
551
|
+
if (className === "File" && ctorArgs && ctorArgs.length >= 1 && ts.isStringLiteral(ctorArgs[0])) {
|
|
552
|
+
fieldValues.set("_path", ctorArgs[0].text);
|
|
553
|
+
}
|
|
554
|
+
if (className === "Mqtt" && ctorArgs && ctorArgs.length >= 1 && ts.isStringLiteral(ctorArgs[0])) {
|
|
555
|
+
fieldValues.set("_uri", ctorArgs[0].text);
|
|
556
|
+
const mopts = ctorArgs[1];
|
|
557
|
+
if (mopts && ts.isObjectLiteralExpression(mopts)) {
|
|
558
|
+
for (const prop of mopts.properties) {
|
|
559
|
+
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)
|
|
560
|
+
&& prop.name.text === "clientId" && ts.isStringLiteral(prop.initializer)) {
|
|
561
|
+
fieldValues.set("_clientId", prop.initializer.text);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
// Thin Store: the namespace is the construction fact (plain text —
|
|
567
|
+
// the plugin case quotes it when composing the settings key).
|
|
568
|
+
if (className === "Store" && ctorArgs && ctorArgs.length >= 1 && ts.isStringLiteral(ctorArgs[0])) {
|
|
569
|
+
fieldValues.set("_ns", ctorArgs[0].text);
|
|
570
|
+
}
|
|
571
|
+
// Thin BLE: the advertised name is the construction fact.
|
|
572
|
+
if (className === "BLE" && ctorArgs && ctorArgs.length >= 1 && ts.isStringLiteral(ctorArgs[0])) {
|
|
573
|
+
fieldValues.set("_name", JSON.stringify(ctorArgs[0].text));
|
|
574
|
+
}
|
|
575
|
+
if (className === "Counter" && ctorArgs && ctorArgs.length >= 1 && ts.isNumericLiteral(ctorArgs[0])) {
|
|
576
|
+
fieldValues.set("_instance", ctorArgs[0].text.replace(/_/g, ""));
|
|
577
|
+
}
|
|
578
|
+
// Thin WiFi station: first arg is the ssid literal; the opts carry
|
|
579
|
+
// the link facts. Nested ipv4 facts flatten to _ipAddr/_gateway/
|
|
580
|
+
// _netmask. Computed defaults (security ternary, timeoutMs ??) are
|
|
581
|
+
// applied by the wifiJoin plugin case, not here.
|
|
582
|
+
if (className === "WiFi" && ctorArgs && ctorArgs.length >= 1) {
|
|
583
|
+
if (ts.isStringLiteral(ctorArgs[0])) {
|
|
584
|
+
fieldValues.set("_ssid", JSON.stringify(ctorArgs[0].text));
|
|
585
|
+
}
|
|
586
|
+
else {
|
|
587
|
+
fieldValues.set("_ssid", ctorArgs[0].getText());
|
|
588
|
+
}
|
|
589
|
+
const wopts = ctorArgs[1];
|
|
590
|
+
if (wopts && ts.isObjectLiteralExpression(wopts)) {
|
|
591
|
+
for (const prop of wopts.properties) {
|
|
592
|
+
if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name))
|
|
593
|
+
continue;
|
|
594
|
+
const name = prop.name.text;
|
|
595
|
+
if (name === "ipv4" && ts.isObjectLiteralExpression(prop.initializer)) {
|
|
596
|
+
for (const ip of prop.initializer.properties) {
|
|
597
|
+
if (!ts.isPropertyAssignment(ip) || !ts.isIdentifier(ip.name))
|
|
598
|
+
continue;
|
|
599
|
+
const ipName = ip.name.text;
|
|
600
|
+
const key = ipName === "addr" ? "_ipAddr" : `_${ipName}`;
|
|
601
|
+
if (ts.isStringLiteral(ip.initializer)) {
|
|
602
|
+
fieldValues.set(key, JSON.stringify(ip.initializer.text));
|
|
603
|
+
}
|
|
604
|
+
else {
|
|
605
|
+
fieldValues.set(key, ip.initializer.getText());
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
else if (name !== "powerSave") {
|
|
610
|
+
if (ts.isStringLiteral(prop.initializer)) {
|
|
611
|
+
fieldValues.set(`_${name}`, JSON.stringify(prop.initializer.text));
|
|
612
|
+
}
|
|
613
|
+
else if (ts.isNumericLiteral(prop.initializer)) {
|
|
614
|
+
fieldValues.set(`_${name}`, prop.initializer.text.replace(/_/g, ""));
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
fieldValues.set(`_${name}`, prop.initializer.getText());
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
else {
|
|
621
|
+
// powerSave: WiFi.PS_OFF token → ps=1 flag (0 = default on).
|
|
622
|
+
const txt = prop.initializer.getText();
|
|
623
|
+
fieldValues.set("_ps", txt.includes("PS_OFF") ? "1" : "0");
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
if (className === "Thread" && ctorArgs && ctorArgs.length >= 1 && ts.isNumericLiteral(ctorArgs[0])) {
|
|
629
|
+
fieldValues.set("_index", ctorArgs[0].text.replace(/_/g, ""));
|
|
630
|
+
// stackKb → bytes here (the class-body arithmetic is erased).
|
|
631
|
+
const kbArg = ctorArgs.length >= 2 && ts.isObjectLiteralExpression(ctorArgs[1])
|
|
632
|
+
? ctorArgs[1].properties.find((p) => ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) && p.name.text === "stackKb")
|
|
633
|
+
: undefined;
|
|
634
|
+
const kb = kbArg && ts.isPropertyAssignment(kbArg) && ts.isNumericLiteral(kbArg.initializer)
|
|
635
|
+
? parseInt(kbArg.initializer.text.replace(/_/g, ""), 10) : 2;
|
|
636
|
+
fieldValues.set("_stackBytes", String((isNaN(kb) ? 2 : kb) * 1024));
|
|
637
|
+
}
|
|
638
|
+
// Tier-2 thin buses. The first arg is the board's bus/port instance
|
|
639
|
+
// export (I2C0/SPI0/UART1) — kept as text, which the lowerings'
|
|
640
|
+
// parseControllerIndex reads; SPITarget adds the cs pin (identifier
|
|
641
|
+
// or property access, resolved later like every pin arg); opts carry
|
|
642
|
+
// the wire facts (hz/mode/baud).
|
|
643
|
+
const thinBusFirst = { I2CTarget: true, SPITarget: true, UART: true };
|
|
644
|
+
if (thinBusFirst[className] && ctorArgs && ctorArgs.length >= 1) {
|
|
645
|
+
const busArg = ctorArgs[0];
|
|
646
|
+
if (ts.isIdentifier(busArg)) {
|
|
647
|
+
const inst = halInstances.get(busArg.text);
|
|
648
|
+
fieldValues.set("_bus", inst?.fieldValues.get("_bus") ?? busArg.text);
|
|
649
|
+
fieldValues.set("_port", inst?.fieldValues.get("_port") ?? inst?.fieldValues.get("_bus") ?? busArg.text);
|
|
650
|
+
}
|
|
651
|
+
else if (ts.isStringLiteral(busArg)) {
|
|
652
|
+
fieldValues.set("_bus", busArg.text);
|
|
653
|
+
fieldValues.set("_port", busArg.text);
|
|
654
|
+
}
|
|
655
|
+
else {
|
|
656
|
+
fieldValues.set("_bus", busArg.getText());
|
|
657
|
+
fieldValues.set("_port", busArg.getText());
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
if (className === "SPITarget" && ctorArgs && ctorArgs.length >= 2) {
|
|
661
|
+
const csArg = ctorArgs[1];
|
|
662
|
+
if (ts.isIdentifier(csArg)) {
|
|
663
|
+
const inst = halInstances.get(csArg.text);
|
|
664
|
+
fieldValues.set("_cs", inst?.fieldValues.get("_pin") ?? inst?.fieldValues.get("pin") ?? csArg.text);
|
|
665
|
+
}
|
|
666
|
+
else {
|
|
667
|
+
fieldValues.set("_cs", csArg.getText());
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
if (className === "I2CTarget" && ctorArgs && ctorArgs.length >= 2 && ts.isNumericLiteral(ctorArgs[1])) {
|
|
671
|
+
fieldValues.set("_address", ctorArgs[1].text);
|
|
672
|
+
}
|
|
673
|
+
const thinBusOpts = { I2CTarget: true, SPITarget: true, UART: true, Thread: true };
|
|
674
|
+
if (thinBusOpts[className] && ctorArgs && ctorArgs.length >= 2) {
|
|
675
|
+
// I2CTarget/UART: (bus, opts?); SPITarget: (bus, cs, opts?).
|
|
676
|
+
const optsArg = ctorArgs.length === 2 ? ctorArgs[1] : ctorArgs[2];
|
|
677
|
+
if (optsArg && ts.isObjectLiteralExpression(optsArg)) {
|
|
678
|
+
for (const prop of optsArg.properties) {
|
|
679
|
+
if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name))
|
|
680
|
+
continue;
|
|
681
|
+
const name = prop.name.text;
|
|
682
|
+
if (ts.isNumericLiteral(prop.initializer)) {
|
|
683
|
+
fieldValues.set(`_${name}`, prop.initializer.text.replace(/_/g, ""));
|
|
684
|
+
}
|
|
685
|
+
else {
|
|
686
|
+
fieldValues.set(`_${name}`, prop.initializer.getText());
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
// Thin-class field DEFAULTS (the singleton __default_fields channel
|
|
692
|
+
// does not reach constructed instances). Fill only absent fields —
|
|
693
|
+
// an omitted opts object must resolve to these sentinels, not leak
|
|
694
|
+
// `this->_gain` text into the ops (string args pass through raw).
|
|
695
|
+
const thinFieldDefaults = {
|
|
696
|
+
ADC: { _gain: "", _reference: "" },
|
|
697
|
+
I2CTarget: { _hz: "0" },
|
|
698
|
+
SPITarget: { _hz: "1000000", _mode: "0" },
|
|
699
|
+
UART: { _baud: "115200", _rxBufferBytes: "64" },
|
|
700
|
+
DAC: { _resolution: "0" },
|
|
701
|
+
};
|
|
702
|
+
// WiFi absent-fact sentinels: fields whose class initializer is
|
|
703
|
+
// `opts.x?.y` render as raw `this->_x` when the fact was omitted.
|
|
704
|
+
// "undefined" is what dropUndefined() strips at the plugin case,
|
|
705
|
+
// so the op omits the fact entirely.
|
|
706
|
+
if (className === "WiFi") {
|
|
707
|
+
const wifiDefaults = {
|
|
708
|
+
_psk: "undefined", _ipAddr: "undefined", _gateway: "undefined",
|
|
709
|
+
_netmask: "undefined", _timeoutMs: "15000", _channel: "0",
|
|
710
|
+
_band: "0", _ps: "0",
|
|
711
|
+
};
|
|
712
|
+
for (const [k, v] of Object.entries(wifiDefaults)) {
|
|
713
|
+
if (!fieldValues.has(k))
|
|
714
|
+
fieldValues.set(k, v);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
const thinDefs = thinFieldDefaults[className];
|
|
718
|
+
if (thinDefs) {
|
|
719
|
+
for (const [k, v] of Object.entries(thinDefs)) {
|
|
720
|
+
if (!fieldValues.has(k))
|
|
721
|
+
fieldValues.set(k, v);
|
|
722
|
+
}
|
|
472
723
|
}
|
|
473
724
|
if (ctorArgs) {
|
|
474
725
|
// Resolve a Pin-identifier ctor arg to its _pin number, for any HAL
|
|
@@ -503,8 +754,8 @@ export function variableStatementToIR(statement, fileName, sourceText, diagnosti
|
|
|
503
754
|
if (result && (!isOwnershipMethod || isSingletonReceiver)) {
|
|
504
755
|
const isHalOpReturn = result.returnValue === "__hal_op_return__";
|
|
505
756
|
// A __TYPED_ARRAY__ return comes ONLY from a HAL method body
|
|
506
|
-
// (`return new Uint8Array(count)` in
|
|
507
|
-
//
|
|
757
|
+
// (`return new Uint8Array(count)` in buffer-returning device
|
|
758
|
+
// methods). The method's side-effect HAL ops (the
|
|
508
759
|
// i2c.read_buffer / spi.read_buffer fill loops) write INTO this buffer
|
|
509
760
|
// via the __HAL_READ_BUF__ placeholder (rewritten to `varName`). So the
|
|
510
761
|
// buffer var_decl MUST precede the fill ops in emitted order — at top
|
|
@@ -568,9 +819,16 @@ export function variableStatementToIR(statement, fileName, sourceText, diagnosti
|
|
|
568
819
|
const instance = resolveHALReceiver(receiver);
|
|
569
820
|
const fieldValues = new Map(instance?.fieldValues || []);
|
|
570
821
|
// For device() factory calls, copy the address/cs from the call arg
|
|
571
|
-
// so
|
|
572
|
-
if (result.returnClassName === "
|
|
573
|
-
const
|
|
822
|
+
// so I2CTarget/SPITarget methods can resolve this._address / this._cs.
|
|
823
|
+
if (result.returnClassName === "I2CTarget" || result.returnClassName === "SPITarget") {
|
|
824
|
+
const isSpiTarget = result.returnClassName === "SPITarget";
|
|
825
|
+
const fieldName = isSpiTarget ? "_cs" : "_address";
|
|
826
|
+
// The targets' __default_fields channel does not reach factory
|
|
827
|
+
// results; carry the wire defaults so this._hz / this._mode
|
|
828
|
+
// resolve in the inlined method bodies.
|
|
829
|
+
fieldValues.set("_hz", isSpiTarget ? "1000000" : "0");
|
|
830
|
+
if (isSpiTarget)
|
|
831
|
+
fieldValues.set("_mode", "0");
|
|
574
832
|
const firstArg = init.arguments?.[0];
|
|
575
833
|
if (firstArg) {
|
|
576
834
|
if (ts.isNumericLiteral(firstArg))
|
|
@@ -585,19 +843,6 @@ export function variableStatementToIR(statement, fileName, sourceText, diagnosti
|
|
|
585
843
|
}
|
|
586
844
|
}
|
|
587
845
|
}
|
|
588
|
-
// For Http factory calls (const req = Http.get(url)), record the
|
|
589
|
-
// HTTP verb + URL so req.send() can resolve this._method/this._url.
|
|
590
|
-
if (result.returnClassName === "HttpRequest") {
|
|
591
|
-
const verb = httpFactoryVerb(init.expression.name.text);
|
|
592
|
-
if (verb)
|
|
593
|
-
fieldValues.set("_method", verb);
|
|
594
|
-
const urlArg = init.arguments?.[0];
|
|
595
|
-
if (urlArg) {
|
|
596
|
-
const urlText = httpUrlArgText(urlArg);
|
|
597
|
-
if (urlText)
|
|
598
|
-
fieldValues.set("_url", urlText);
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
846
|
halInstances.set(varName, {
|
|
602
847
|
className: result.returnClassName,
|
|
603
848
|
fieldValues,
|
|
@@ -634,11 +879,16 @@ export function variableStatementToIR(statement, fileName, sourceText, diagnosti
|
|
|
634
879
|
}
|
|
635
880
|
}
|
|
636
881
|
if (result.returnValue && result.returnValue !== "this") {
|
|
882
|
+
const lastOp = result.halOps[result.halOps.length - 1];
|
|
883
|
+
// A double-returning HAL op makes the captured var floating
|
|
884
|
+
// (sensor.get → val1 + val2/1e6): the snprintf specifier picker
|
|
885
|
+
// reads floatVariables and must pick %g, not %d.
|
|
886
|
+
if (lastOp && lastOp.operation === "sensor.get")
|
|
887
|
+
registerFloatVariable(varName);
|
|
637
888
|
if (isHalOpReturn) {
|
|
638
|
-
const lastOp = result.halOps[result.halOps.length - 1];
|
|
639
889
|
lowered.push({
|
|
640
890
|
kind: "var_decl",
|
|
641
|
-
sourceSpan: makeSourceSpan(declaration, fileName, sourceText),
|
|
891
|
+
sourceSpan: makeSourceSpan(declaration.initializer, fileName, sourceText),
|
|
642
892
|
leadingComments: commentsAssigned ? [] : statementComments.leadingComments,
|
|
643
893
|
trailingComments: [],
|
|
644
894
|
name: varName,
|
|
@@ -703,11 +953,20 @@ export function variableStatementToIR(statement, fileName, sourceText, diagnosti
|
|
|
703
953
|
}
|
|
704
954
|
}
|
|
705
955
|
}
|
|
956
|
+
// A typed-array buffer declared `const` stays writable storage: HAL fills
|
|
957
|
+
// write through it (e.g. spi.transceive's rx buffer), so the emitted C
|
|
958
|
+
// array must not be const — mirroring the __TYPED_ARRAY__ return branch.
|
|
959
|
+
// Keeping the source storage would split the definition (`uint8_t id[]`,
|
|
960
|
+
// the array renderer drops the qualifier) from the split-mode extern
|
|
961
|
+
// (`extern const uint8_t id[]`) — a conflicting declaration.
|
|
962
|
+
let effectiveStorage = storage;
|
|
706
963
|
if (actualInitializer && ts.isNewExpression(actualInitializer)) {
|
|
707
964
|
const ctorText = actualInitializer.expression && ts.isIdentifier(actualInitializer.expression)
|
|
708
965
|
? actualInitializer.expression.text : "";
|
|
709
966
|
if (TYPED_ARRAY_ELEMENT_MAP[ctorText] && ts.isIdentifier(declaration.name)) {
|
|
710
967
|
activeCArrayVars.add(declaration.name.text);
|
|
968
|
+
if (effectiveStorage === "const")
|
|
969
|
+
effectiveStorage = "let";
|
|
711
970
|
}
|
|
712
971
|
}
|
|
713
972
|
let lambdaInitializer;
|
|
@@ -742,7 +1001,7 @@ export function variableStatementToIR(statement, fileName, sourceText, diagnosti
|
|
|
742
1001
|
leadingComments: commentsAssigned ? [] : statementComments.leadingComments,
|
|
743
1002
|
trailingComments: commentsAssigned ? [] : statementComments.trailingComments,
|
|
744
1003
|
name: declaration.name.text,
|
|
745
|
-
storage,
|
|
1004
|
+
storage: effectiveStorage,
|
|
746
1005
|
cppType: "auto",
|
|
747
1006
|
isVolatile,
|
|
748
1007
|
initializer: lambdaInitializer ?? (actualInitializer
|
|
@@ -1161,3 +1420,40 @@ export function collectPointerVars(statements) {
|
|
|
1161
1420
|
}
|
|
1162
1421
|
return pointerVars;
|
|
1163
1422
|
}
|
|
1423
|
+
/**
|
|
1424
|
+
* Resolve the second `new Sensor(part, <dev>)` argument to an I2C bus name +
|
|
1425
|
+
* 7-bit address. Accepts the inline factory form `I2C1.device(0x44)` and an
|
|
1426
|
+
* identifier previously bound to one (`const dev = I2C1.device(0x44)`). The
|
|
1427
|
+
* general receiver resolution carries the bus fields through `device()`'s
|
|
1428
|
+
* I2CTarget return type; the inline form's address is taken from the call's
|
|
1429
|
+
* numeric argument (the general path does not extract call args).
|
|
1430
|
+
*/
|
|
1431
|
+
function resolveSensorDeviceArg(arg) {
|
|
1432
|
+
const inst = resolveHALReceiver(arg);
|
|
1433
|
+
const portField = inst?.className === "SPITarget" ? "_cs" : "_address";
|
|
1434
|
+
if (inst && (inst.className === "I2CTarget" || inst.className === "SPITarget") && inst.fieldValues.has("_bus") && inst.fieldValues.has(portField)) {
|
|
1435
|
+
return { bus: inst.fieldValues.get("_bus"), port: inst.fieldValues.get(portField), kind: inst.className === "SPITarget" ? "spi" : "i2c" };
|
|
1436
|
+
}
|
|
1437
|
+
// Inline bus.device(<port>) call: the general receiver path carries the bus
|
|
1438
|
+
// fields through device()'s return type but drops the argument — take the
|
|
1439
|
+
// port from the call's numeric literal.
|
|
1440
|
+
if (ts.isCallExpression(arg) && ts.isPropertyAccessExpression(arg.expression) && arg.expression.name.text === "device") {
|
|
1441
|
+
const args = arg.arguments ?? [];
|
|
1442
|
+
const numericArg = args.find((a) => ts.isNumericLiteral(a));
|
|
1443
|
+
// SPI CS arrives as a pin identifier (SPI0.device(PA4)) — resolve it to
|
|
1444
|
+
// its number the same way the device() chain path does.
|
|
1445
|
+
const pinArg = args.find((a) => ts.isIdentifier(a));
|
|
1446
|
+
const pinInst = pinArg && ts.isIdentifier(pinArg) ? halInstances.get(pinArg.text) : undefined;
|
|
1447
|
+
const portText = numericArg && ts.isNumericLiteral(numericArg)
|
|
1448
|
+
? numericArg.text
|
|
1449
|
+
: (pinInst?.fieldValues.get("_pin") ?? pinInst?.fieldValues.get("pin"));
|
|
1450
|
+
if (inst && inst.fieldValues.has("_bus") && portText !== undefined) {
|
|
1451
|
+
// The bus kind follows the receiver's resolved class when it round-
|
|
1452
|
+
// tripped; otherwise infer from the bus alias (SPI/SPI<n> vs Wire).
|
|
1453
|
+
const busName = inst.fieldValues.get("_bus");
|
|
1454
|
+
const kind = inst.className === "SPITarget" || /^SPI/.test(busName) ? "spi" : "i2c";
|
|
1455
|
+
return { bus: busName, port: portText, kind };
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
return null;
|
|
1459
|
+
}
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
//
|
|
4
4
|
// Validates that try/catch and throw statements are not used on architectures
|
|
5
5
|
// that do not support C++ exceptions. The platform strategy determines which
|
|
6
|
-
// architectures have exceptions disabled (e.g.
|
|
6
|
+
// architectures have exceptions disabled (e.g. Zephyr with
|
|
7
|
+
// CONFIG_CPP_EXCEPTIONS=n).
|
|
7
8
|
// ---------------------------------------------------------------------------
|
|
8
9
|
/**
|
|
9
10
|
* Validate that try/catch and throw statements are not used on
|
|
@@ -34,7 +35,7 @@ export function validateTryCatch(program, boardConstants, strategy) {
|
|
|
34
35
|
severity: 'error',
|
|
35
36
|
code: 'try-catch-unsupported',
|
|
36
37
|
message: `try/catch is not supported on ${arch.toUpperCase()} targets. ` +
|
|
37
|
-
`
|
|
38
|
+
`C++ exceptions are disabled (-fno-exceptions) on this target and the generated ` +
|
|
38
39
|
`code will not compile. Use return-code error checking instead.`,
|
|
39
40
|
hint: `function readSensor(): number | null {\n const data = sensor.read();\n if (!data) return null; // error path\n return data.value; // success path\n}`,
|
|
40
41
|
line: stmt.sourceSpan?.startLine,
|
|
@@ -53,7 +54,7 @@ export function validateTryCatch(program, boardConstants, strategy) {
|
|
|
53
54
|
severity: 'error',
|
|
54
55
|
code: 'try-catch-unsupported',
|
|
55
56
|
message: `throw is not supported on ${arch.toUpperCase()} targets. ` +
|
|
56
|
-
`
|
|
57
|
+
`C++ exceptions are disabled (-fno-exceptions) on this target. ` +
|
|
57
58
|
`Use return codes or error flags instead.`,
|
|
58
59
|
hint: `return null; // or return an error code`,
|
|
59
60
|
line: stmt.sourceSpan?.startLine,
|
|
@@ -38,7 +38,7 @@ const BUS_INTERFACE_TYPE_NAMES = new Set([
|
|
|
38
38
|
"I2CAddress", "SPITransferOptions",
|
|
39
39
|
]);
|
|
40
40
|
const STRATEGY_TYPE_NAMES = new Set([
|
|
41
|
-
"NativeStrategy", "
|
|
41
|
+
"NativeStrategy", "ZephyrStrategy", "BoardStrategy",
|
|
42
42
|
"RuntimePolyfillIR", "PeripheralUsage",
|
|
43
43
|
]);
|
|
44
44
|
const BOARD_CONSTANT_TYPE_NAMES = new Set([
|
|
@@ -50,7 +50,8 @@ const OWNERSHIP_WRAPPER_TYPE_NAMES = new Set([
|
|
|
50
50
|
]);
|
|
51
51
|
/** Safety wrapper types: like ownership wrappers (phantom TS types that carry
|
|
52
52
|
* a type parameter), but instead of stripping the wrapper, the C++ keeps it
|
|
53
|
-
* as a template instantiation: SafeVariable<number> → SafeVariable<
|
|
53
|
+
* as a template instantiation: SafeVariable<number> → SafeVariable<double>,
|
|
54
|
+
* SafeInt<number> → SafeInt<int32_t> (integer-only by contract).
|
|
54
55
|
* The C++ template definition is provided by the safety polyfill. */
|
|
55
56
|
const SAFE_WRAPPER_TYPE_NAMES = new Set([
|
|
56
57
|
"SafeVariable",
|
|
@@ -158,10 +159,20 @@ export function typeNodeToCppType(node, typeAliases, typeParametersInScope) {
|
|
|
158
159
|
// SafeVariable<T> is a safety wrapper: unlike ownership wrappers (which
|
|
159
160
|
// strip the wrapper name entirely), SafeVariable keeps the wrapper name
|
|
160
161
|
// in the C++ type because the polyfill provides a template definition.
|
|
161
|
-
// SafeVariable<number> → SafeVariable<
|
|
162
|
-
// the
|
|
162
|
+
// SafeVariable<number> → SafeVariable<double> (the keyword's general
|
|
163
|
+
// mapping; the polyfill ships float/double specializations).
|
|
163
164
|
if (SAFE_WRAPPER_TYPE_NAMES.has(wrapperName)) {
|
|
164
165
|
const innerTypeNode = node.typeArguments?.[0];
|
|
166
|
+
// SafeInt is signed-integer-only by contract — its polyfill carries a
|
|
167
|
+
// static_assert rejecting floating-point T. The TS `number` keyword
|
|
168
|
+
// (and SafeInt's implicit `T = number` default) therefore resolves to
|
|
169
|
+
// int32_t, NOT the general number→double mapping. An explicit float /
|
|
170
|
+
// double annotation still passes through so the static_assert fires as
|
|
171
|
+
// designed.
|
|
172
|
+
if (wrapperName === "SafeInt" &&
|
|
173
|
+
(innerTypeNode === undefined || innerTypeNode.kind === ts.SyntaxKind.NumberKeyword)) {
|
|
174
|
+
return "SafeInt<int32_t>";
|
|
175
|
+
}
|
|
165
176
|
const innerCppType = typeNodeToCppType(innerTypeNode, typeAliases, typeParametersInScope);
|
|
166
177
|
return `${wrapperName}<${innerCppType}>`;
|
|
167
178
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { resolveStrategy } from "../platform/registry.js";
|
|
2
2
|
import { hasLoadedFramework, getLoadedFramework } from "../framework-registry.js";
|
|
3
3
|
import { analyzeInterruptSafety, inferVolatileForIsrSharedVars, detectReentrancyRisk } from "./interrupt-analysis.js";
|
|
4
|
-
import { analyzeWorkerIsolation } from "./worker-analysis.js";
|
|
5
4
|
import { validateADCRange } from "./adc-range-validation.js";
|
|
6
5
|
import { createEmptyPeripheralUsage } from "./peripheral-usage.js";
|
|
7
6
|
import { validatePeripherals } from "./peripheral-validation.js";
|
|
@@ -11,8 +10,6 @@ import { validatePinAliasConflicts } from "./pin-alias-conflict.js";
|
|
|
11
10
|
import { validatePinModeConfig } from "./pin-mode-validation.js";
|
|
12
11
|
import { validateUnsafePins } from "./pin-safety.js";
|
|
13
12
|
import { validatePulldownSupport } from "./pulldown-validation.js";
|
|
14
|
-
import { validatePWMTimerSharing } from "./pwm-timer-sharing.js";
|
|
15
|
-
import { validateTimer0PWMTimingConflict } from "./timer0-pwm-timing-conflict.js";
|
|
16
13
|
import { validateTryCatch } from "./try-catch-validation.js";
|
|
17
14
|
import { validateMemoryBudget } from "./memory-budget-validation.js";
|
|
18
15
|
import { validateBlockingDelayInLoop } from "./timing-validation.js";
|
|
@@ -29,16 +26,10 @@ export function runProgramValidations(program, strategy) {
|
|
|
29
26
|
diagnostics.push(...validateUnsafePins(peripheralUsage, program.boardConstants, program.fileName));
|
|
30
27
|
diagnostics.push(...analyzeResources(program, resolvedStrategy));
|
|
31
28
|
diagnostics.push(...validatePinAliasConflicts(peripheralUsage, program.boardConstants, program.fileName));
|
|
32
|
-
diagnostics.push(...validatePWMTimerSharing(peripheralUsage, program.boardConstants, program.fileName));
|
|
33
|
-
diagnostics.push(...validateTimer0PWMTimingConflict(peripheralUsage, program.boardConstants, program.fileName));
|
|
34
29
|
diagnostics.push(...validatePulldownSupport(peripheralUsage, program.boardConstants, program.fileName));
|
|
35
30
|
diagnostics.push(...analyzeInterruptSafety(program, peripheralUsage, resolvedStrategy.isrUnsafeOperations?.()));
|
|
36
31
|
inferVolatileForIsrSharedVars(program, diagnostics);
|
|
37
32
|
detectReentrancyRisk(program, diagnostics);
|
|
38
|
-
// Worker isolation: bus access in workers is a hard error; worker-shared
|
|
39
|
-
// globals get volatile promotion (info) or a data-race warning. Only fires
|
|
40
|
-
// when worker.submit ops are present, so non-worker programs are unaffected.
|
|
41
|
-
analyzeWorkerIsolation(program, diagnostics);
|
|
42
33
|
diagnostics.push(...validateADCRange(program, program.boardConstants));
|
|
43
34
|
diagnostics.push(...validateUnitSuspicion(program));
|
|
44
35
|
diagnostics.push(...validatePinModeConfig(program));
|
|
@@ -32,12 +32,3 @@ export declare function generateDeclsForDirectory(dir: string, recursive?: boole
|
|
|
32
32
|
* a later step for the directory-scan path.
|
|
33
33
|
*/
|
|
34
34
|
export declare function generateDecl(filePath: string, outputPath?: string): string | null;
|
|
35
|
-
import { type ComponentScanRoots } from "./component-discovery.js";
|
|
36
|
-
/**
|
|
37
|
-
* Generate .d.ts declarations for every declared component's headers,
|
|
38
|
-
* picking the C or C++ emitter per header based on whether it declares classes.
|
|
39
|
-
*
|
|
40
|
-
* Returns the list of created/updated .d.ts paths (headers that produced no
|
|
41
|
-
* declarations are skipped).
|
|
42
|
-
*/
|
|
43
|
-
export declare function generateComponentDeclsForProject(projectDir: string, roots: ComponentScanRoots): string[];
|