@typecad/cuttlefish 1.0.0-alpha.6 → 1.0.0-alpha.8
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/dist/api/config.d.ts +32 -0
- package/dist/api/index.d.ts +1 -1
- package/dist/api/schema/types.d.ts +15 -0
- package/dist/api/shared/async-runtime-static.d.ts +12 -1
- package/dist/api/shared/async-runtime-static.js +69 -24
- package/dist/api/shared/async-symbol-detector.d.ts +11 -0
- package/dist/api/shared/async-symbol-detector.js +140 -0
- package/dist/api/shared/async-types.d.ts +24 -0
- package/dist/api/shared/coop-scheduler.d.ts +60 -0
- package/dist/api/shared/coop-scheduler.js +149 -0
- package/dist/api/shared/display-adapter.d.ts +4 -3
- package/dist/api/shared/display-adapter.js +15 -118
- package/dist/api/shared/display-adapters/sdl.js +38 -31
- package/dist/api/shared/display-profile.d.ts +47 -25
- package/dist/api/shared/display-profile.js +31 -164
- package/dist/api/shared/framework-manifest-registry.d.ts +9 -0
- package/dist/api/shared/framework-manifest-registry.js +27 -0
- package/dist/api/shared/framework-manifest.d.ts +581 -0
- package/dist/api/shared/framework-manifest.js +182 -0
- package/dist/api/shared/glcdfont.d.ts +12 -0
- package/dist/api/shared/glcdfont.js +124 -0
- package/dist/api/shared/graphics-strategy.d.ts +37 -0
- package/dist/api/shared/hal-op-ir.d.ts +755 -1
- package/dist/api/shared/hal-op-ir.js +129 -1
- package/dist/api/shared/index.d.ts +20 -2
- package/dist/api/shared/index.js +25 -1
- package/dist/api/shared/ir-core.d.ts +4 -0
- package/dist/api/shared/ir-declarations.d.ts +6 -0
- package/dist/api/shared/native-display-op-resolver.d.ts +10 -0
- package/dist/api/shared/native-display-op-resolver.js +64 -0
- package/dist/api/shared/platform-strategy.d.ts +113 -2
- package/dist/api/shared/polyfill-helper-registry.js +18 -1
- package/dist/api/shared/promise-runtime.d.ts +1 -1
- package/dist/api/shared/promise-runtime.js +95 -13
- package/dist/api/shared/toolchain-types.d.ts +17 -0
- package/dist/api/shared/validate-framework-manifest.d.ts +28 -0
- package/dist/api/shared/validate-framework-manifest.js +494 -0
- package/dist/api/shared/worker-runtime-polyfill.d.ts +22 -0
- package/dist/api/shared/worker-runtime-polyfill.js +34 -0
- package/dist/api/shared/worker-runtime.d.ts +69 -0
- package/dist/api/shared/worker-runtime.js +163 -0
- package/dist/cli.js +186 -82
- package/dist/config-loader.d.ts +7 -2
- package/dist/config-loader.js +23 -3
- package/dist/config-schema.d.ts +112 -70
- package/dist/config-schema.js +14 -0
- package/dist/contract/board-generator.d.ts +17 -0
- package/dist/contract/board-generator.js +57 -0
- package/dist/contract/contract-parser.d.ts +217 -0
- package/dist/contract/contract-parser.js +224 -0
- package/dist/contract/index.d.ts +22 -0
- package/dist/contract/index.js +68 -0
- package/dist/create/board-codegen.js +4 -4
- package/dist/create/board-generators.js +4 -5
- package/dist/create/board-spec.d.ts +72 -75
- package/dist/create/board-spec.js +0 -1
- package/dist/create/init-scaffold.d.ts +9 -2
- package/dist/create/init-scaffold.js +0 -14
- package/dist/create/init-templates.d.ts +2 -0
- package/dist/create/init-templates.js +74 -8
- package/dist/create/init-wizard.js +31 -7
- package/dist/debug/preprocessor.js +178 -39
- package/dist/debug/types.d.ts +23 -0
- package/dist/diagnostics/mermaid-builder.d.ts +1 -1
- package/dist/diagnostics/mermaid-builder.js +34 -24
- package/dist/emit/compliance/arxml-writer.d.ts +11 -0
- package/dist/emit/compliance/arxml-writer.js +34 -0
- package/dist/emit/compliance/compliance-context.d.ts +57 -0
- package/dist/emit/compliance/compliance-context.js +113 -0
- package/dist/emit/compliance/deviation-ledger.d.ts +27 -0
- package/dist/emit/compliance/deviation-ledger.js +47 -0
- package/dist/emit/compliance/deviation-writer.d.ts +30 -0
- package/dist/emit/compliance/deviation-writer.js +37 -0
- package/dist/emit/compliance/index.d.ts +7 -0
- package/dist/emit/compliance/index.js +6 -0
- package/dist/emit/compliance/rule-engine.d.ts +13 -0
- package/dist/emit/compliance/rule-engine.js +101 -0
- package/dist/emit/compliance/rules.d.ts +16 -0
- package/dist/emit/compliance/rules.js +191 -0
- package/dist/emit/compliance/types.d.ts +59 -0
- package/dist/emit/compliance/types.js +8 -0
- package/dist/emit/cpp-emitter.js +4 -3
- package/dist/emit/emitters/class-emitter.js +6 -1
- package/dist/emit/emitters/emitter-context.d.ts +28 -1
- package/dist/emit/emitters/function-emitter-impl.js +153 -53
- package/dist/emit/emitters/line-appender.js +19 -0
- package/dist/emit/emitters/line-marker.d.ts +38 -0
- package/dist/emit/emitters/line-marker.js +39 -0
- package/dist/emit/emitters/output-finalizer.d.ts +6 -0
- package/dist/emit/emitters/output-finalizer.js +101 -12
- package/dist/emit/emitters/setup.d.ts +17 -0
- package/dist/emit/emitters/setup.js +257 -36
- package/dist/emit/emitters/top-level-prep.js +8 -0
- package/dist/emit/emitters/type-decl-emitter.js +28 -3
- package/dist/emit/emitters/ui-emitter.js +33 -9
- package/dist/emit/expression-renderer.d.ts +1 -1
- package/dist/emit/expression-renderer.js +91 -6
- package/dist/emit/route-hal-op.js +18 -5
- package/dist/emit/snprintf-helpers.js +15 -4
- package/dist/emit/statement-renderer.d.ts +10 -0
- package/dist/emit/statement-renderer.js +34 -5
- package/dist/emit/utils/async-state-machine.js +221 -125
- package/dist/emit/utils/hal-op-cpp-type.d.ts +6 -0
- package/dist/emit/utils/hal-op-cpp-type.js +40 -0
- package/dist/framework-package.js +2 -0
- package/dist/framework-registry.d.ts +17 -0
- package/dist/ir/adc-range-validation.js +14 -1
- package/dist/ir/build-ir-state.d.ts +1 -0
- package/dist/ir/build-ir-state.js +14 -0
- package/dist/ir/build-ir.js +9 -5
- package/dist/ir/call-graph.js +16 -0
- package/dist/ir/expression-to-ir.js +164 -0
- package/dist/ir/feature-registry.js +7 -25
- package/dist/ir/function-builder.js +22 -0
- package/dist/ir/hal/hal-emitter.d.ts +5 -2
- package/dist/ir/hal/hal-emitter.js +50 -18
- package/dist/ir/hal/hal-parser.d.ts +6 -0
- package/dist/ir/hal/hal-parser.js +81 -0
- package/dist/ir/hal/hal-plugins.js +723 -1
- package/dist/ir/identifier-collector.js +35 -0
- package/dist/ir/interrupt-analysis.d.ts +5 -1
- package/dist/ir/interrupt-analysis.js +8 -16
- package/dist/ir/network-validation.d.ts +4 -0
- package/dist/ir/network-validation.js +184 -0
- package/dist/ir/ownership-analysis.js +20 -1
- package/dist/ir/pin-capability-validation.js +37 -0
- package/dist/ir/pin-mode-validation.d.ts +2 -2
- package/dist/ir/pin-mode-validation.js +49 -18
- package/dist/ir/program-analysis.d.ts +65 -0
- package/dist/ir/program-analysis.js +318 -2
- package/dist/ir/render-expr.js +11 -0
- package/dist/ir/timing-validation.d.ts +6 -1
- package/dist/ir/timing-validation.js +60 -13
- package/dist/ir/transformers/call-statement.js +105 -0
- package/dist/ir/transformers/expressions.js +62 -0
- package/dist/ir/transformers/hal-call-resolver.js +21 -0
- package/dist/ir/transformers/hal-emit-helpers.js +1 -1
- package/dist/ir/transformers/namespace-methods.js +17 -12
- package/dist/ir/transformers/ui-reactive.js +2 -2
- package/dist/ir/transformers/variables.js +92 -3
- package/dist/ir/type-resolution.js +18 -0
- package/dist/ir/ui-element-auto-wire.js +7 -5
- package/dist/ir/utils/map-statements.d.ts +4 -0
- package/dist/ir/utils/map-statements.js +79 -0
- package/dist/ir/validation-orchestrator.js +9 -2
- package/dist/ir/worker-analysis.d.ts +10 -0
- package/dist/ir/worker-analysis.js +261 -0
- package/dist/libdef/c-to-decl.d.ts +27 -0
- package/dist/libdef/c-to-decl.js +397 -0
- package/dist/libdef/component-decls.d.ts +2 -0
- package/dist/libdef/component-decls.js +6 -0
- package/dist/libdef/component-discovery.d.ts +43 -0
- package/dist/libdef/component-discovery.js +83 -0
- package/dist/libdef/cpp-to-decl.d.ts +9 -0
- package/dist/libdef/cpp-to-decl.js +72 -0
- package/dist/libdef/registry.js +5 -2
- package/dist/lint-cache.d.ts +59 -0
- package/dist/lint-cache.js +257 -0
- package/dist/orchestrator/graph-builder.js +14 -9
- package/dist/platform/coop-scheduler-runtime.d.ts +19 -0
- package/dist/platform/coop-scheduler-runtime.js +41 -0
- package/dist/platform/generic-strategy.d.ts +15 -3
- package/dist/platform/generic-strategy.js +49 -4
- package/dist/safety/safety-bridge.d.ts +11 -0
- package/dist/safety/safety-bridge.js +48 -0
- package/dist/safety/sidecar-bridge.d.ts +5 -0
- package/dist/safety/sidecar-bridge.js +22 -0
- package/dist/safety-hook.d.ts +79 -0
- package/dist/safety-hook.js +35 -0
- package/dist/testing.d.ts +7 -1
- package/dist/testing.js +8 -1
- package/dist/transpile.d.ts +3 -0
- package/dist/transpile.js +175 -41
- package/dist/types.d.ts +13 -2
- package/dist/ui-hook.d.ts +17 -3
- package/dist/utils/cli.js +78 -4
- package/dist/utils/fs.d.ts +13 -0
- package/dist/utils/fs.js +50 -0
- package/package.json +24 -5
- package/dist/api/shared/display-adapters/eink-mono.d.ts +0 -2
- package/dist/api/shared/display-adapters/eink-mono.js +0 -53
- package/dist/api/shared/display-adapters/ssd1309.d.ts +0 -2
- package/dist/api/shared/display-adapters/ssd1309.js +0 -136
- package/dist/api/shared/display-adapters/st7796.d.ts +0 -2
- package/dist/api/shared/display-adapters/st7796.js +0 -132
- package/dist/licenses.d.ts +0 -185
- package/dist/licenses.js +0 -963
|
@@ -10,6 +10,7 @@ import { accessorGetterName } from "./utils/cpp-helpers.js";
|
|
|
10
10
|
import { INTEGRAL_CPP_TYPE_RE } from "./utils/cpp-helpers.js";
|
|
11
11
|
import { renderPeripheralProperty } from "../mapping/peripheral-names.js";
|
|
12
12
|
import { parseCppType, renderCppType, bareType, parsedIsPointer, parsedIsVector, needsCStrForStringLike } from "../api/shared/cpp-type-ir.js";
|
|
13
|
+
import { cppTypeForHalOp } from "./utils/hal-op-cpp-type.js";
|
|
13
14
|
/**
|
|
14
15
|
* Renders ExpressionIR nodes to C++ code strings.
|
|
15
16
|
*/
|
|
@@ -79,6 +80,18 @@ export class ExpressionRenderer {
|
|
|
79
80
|
if (!expr || typeof expr !== 'object' || !expr.kind) {
|
|
80
81
|
return "/* invalid expression */";
|
|
81
82
|
}
|
|
83
|
+
// When a per-scope knownVariableTypes is passed (e.g. a function's child
|
|
84
|
+
// emission scope carrying its parameters), install it on the instance for
|
|
85
|
+
// the duration of this render so every recursive render() call and
|
|
86
|
+
// renderIdentifier() reads the merged scope (globals + params). Without
|
|
87
|
+
// this, recursive paths that don't forward knownVariableTypes (ternary
|
|
88
|
+
// branches, call args, array elements, …) would resolve identifiers
|
|
89
|
+
// against only the top-level scope, missing function parameters — which
|
|
90
|
+
// breaks reserved-name escaping for params like `min`/`max` on Arduino.
|
|
91
|
+
const prevKnownVariableTypes = this.knownVariableTypes;
|
|
92
|
+
if (knownVariableTypes) {
|
|
93
|
+
this.knownVariableTypes = knownVariableTypes;
|
|
94
|
+
}
|
|
82
95
|
let rendered;
|
|
83
96
|
switch (expr.kind) {
|
|
84
97
|
case "number": {
|
|
@@ -99,7 +112,7 @@ export class ExpressionRenderer {
|
|
|
99
112
|
rendered = expr.value ? "true" : "false";
|
|
100
113
|
break;
|
|
101
114
|
case "identifier":
|
|
102
|
-
rendered = this.renderIdentifier(expr.value);
|
|
115
|
+
rendered = this.renderIdentifier(expr.value, knownVariableTypes);
|
|
103
116
|
break;
|
|
104
117
|
case "raw":
|
|
105
118
|
rendered = this.renderRaw(expr.value, exprTransformer);
|
|
@@ -149,6 +162,18 @@ export class ExpressionRenderer {
|
|
|
149
162
|
case "method-call":
|
|
150
163
|
rendered = this.renderMethodCall(expr, exprTransformer);
|
|
151
164
|
break;
|
|
165
|
+
case "call": {
|
|
166
|
+
// Bare call expression: `Name(args)` with no receiver (e.g. a
|
|
167
|
+
// constructor call `SafeInt(x)` written inline, or a free function).
|
|
168
|
+
// Method-on-receiver calls lower as "method-call"; this arm is for the
|
|
169
|
+
// receiverless form. The callee is escaped against C++ reserved names;
|
|
170
|
+
// when a target type is in scope, renderValueForTarget (the caller)
|
|
171
|
+
// wraps this with template args (SafeInt(x) -> SafeInt<int32_t>(x)).
|
|
172
|
+
const callArgs = expr.args.map(a => this.render(a, exprTransformer)).join(", ");
|
|
173
|
+
const callCallee = escapeCppKeyword(exprTransformer ? exprTransformer(expr.callee) : expr.callee, this.strategy.reservedNames());
|
|
174
|
+
rendered = `${callCallee}(${callArgs})`;
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
152
177
|
case "element-access":
|
|
153
178
|
rendered = this.renderElementAccess(expr, exprTransformer, knownVariableTypes);
|
|
154
179
|
break;
|
|
@@ -191,9 +216,10 @@ export class ExpressionRenderer {
|
|
|
191
216
|
`This is a transpiler bug; the renderer is missing a case for this kind.`);
|
|
192
217
|
}
|
|
193
218
|
}
|
|
219
|
+
this.knownVariableTypes = prevKnownVariableTypes;
|
|
194
220
|
return normalizeRawExpression(rendered, this.strategy, this.classNameMap);
|
|
195
221
|
}
|
|
196
|
-
renderIdentifier(value) {
|
|
222
|
+
renderIdentifier(value, scopeKnownVariableTypes) {
|
|
197
223
|
const nullVal = this.strategy.nullValue();
|
|
198
224
|
// expression-to-ir lowers the TS `null` literal to the identifier sentinel
|
|
199
225
|
// "nullptr" and `undefined` to "CUTTLEFISH_UNDEFINED". Both must route
|
|
@@ -209,7 +235,27 @@ export class ExpressionRenderer {
|
|
|
209
235
|
if (this.strategy.passthroughMacroNames().has(value)) {
|
|
210
236
|
return value;
|
|
211
237
|
}
|
|
212
|
-
|
|
238
|
+
// Platform-reserved names (e.g. Arduino `Serial`, or the `min`/`max` math
|
|
239
|
+
// macros) are globals/macros provided by the framework headers. Escaping
|
|
240
|
+
// them would break references to those globals — UNLESS the name is a
|
|
241
|
+
// user-declared variable/parameter that shadows and would collide. Check
|
|
242
|
+
// both the instance field (globals/locals seen so far) AND the per-scope
|
|
243
|
+
// map passed by the caller (function parameters, which live in the child
|
|
244
|
+
// emission scope and aren't on the instance field). Declaration sites
|
|
245
|
+
// already escape user vars (renderParameters → renderTypedName), so the
|
|
246
|
+
// body references must escape to match.
|
|
247
|
+
const reservedNames = this.strategy.reservedNames();
|
|
248
|
+
if (reservedNames.has(value)) {
|
|
249
|
+
const isUserVar = (this.knownVariableTypes !== undefined && this.knownVariableTypes.has(value)) ||
|
|
250
|
+
(scopeKnownVariableTypes !== undefined && scopeKnownVariableTypes.has(value)) ||
|
|
251
|
+
(this.pointerVarTypes !== undefined && this.pointerVarTypes.has(value)) ||
|
|
252
|
+
(this.globalPointerVarTypes !== undefined && this.globalPointerVarTypes.has(value)) ||
|
|
253
|
+
(this.stringVarNames !== undefined && this.stringVarNames.has(value));
|
|
254
|
+
if (!isUserVar) {
|
|
255
|
+
return value;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return escapeCppKeyword(value, reservedNames);
|
|
213
259
|
}
|
|
214
260
|
renderRaw(value, exprTransformer) {
|
|
215
261
|
const effectiveClassNameMap = this.classNameMap;
|
|
@@ -403,6 +449,8 @@ export class ExpressionRenderer {
|
|
|
403
449
|
}
|
|
404
450
|
case "unary":
|
|
405
451
|
return expr.operator === "!" ? "bool" : this.inferExpressionCppType(expr.operand, knownVariableTypes);
|
|
452
|
+
case "hal-expr":
|
|
453
|
+
return cppTypeForHalOp(expr.operation.operation);
|
|
406
454
|
default:
|
|
407
455
|
return undefined;
|
|
408
456
|
}
|
|
@@ -714,10 +762,16 @@ export class ExpressionRenderer {
|
|
|
714
762
|
}
|
|
715
763
|
case "hal-expr": {
|
|
716
764
|
const rendered = this.render(expr, exprTransformer);
|
|
717
|
-
// HAL expressions that resolve to string-like outputs use %s
|
|
718
765
|
if (rendered.startsWith('"') || this.stringVarNames?.has(rendered)) {
|
|
719
766
|
return { format: "%s", arg: rendered, estimatedLength: 32 };
|
|
720
767
|
}
|
|
768
|
+
const cppType = cppTypeForHalOp(expr.operation.operation);
|
|
769
|
+
if (cppType && this.isStringLikeCppType(cppType)) {
|
|
770
|
+
return { format: "%s", arg: rendered, estimatedLength: 32 };
|
|
771
|
+
}
|
|
772
|
+
if (cppType === "bool") {
|
|
773
|
+
return { format: "%s", arg: `(${rendered} ? "true" : "false")`, estimatedLength: 5 };
|
|
774
|
+
}
|
|
721
775
|
return { format: "%d", arg: rendered, estimatedLength: 12 };
|
|
722
776
|
}
|
|
723
777
|
case "method-call":
|
|
@@ -878,10 +932,27 @@ export class ExpressionRenderer {
|
|
|
878
932
|
* (safer than a wrong cast).
|
|
879
933
|
*/
|
|
880
934
|
renderValueForTarget(expr, targetType, knownVariableTypes, exprTransformer) {
|
|
881
|
-
const rendered = this.render(expr, exprTransformer, knownVariableTypes);
|
|
882
935
|
if (!targetType)
|
|
883
|
-
return
|
|
936
|
+
return this.render(expr, exprTransformer, knownVariableTypes);
|
|
884
937
|
const normalizedTarget = targetType.trim();
|
|
938
|
+
// Inject template args for constructor calls on pre-C++17 toolchains
|
|
939
|
+
// (e.g. AVR without CTAD). SafeVariable(0) → SafeVariable<int32_t>(0).
|
|
940
|
+
// Handles both `method-call` (when the constructor appears as a standalone
|
|
941
|
+
// initializer) and `call` (when it appears on the RHS of an assignment,
|
|
942
|
+
// which lowers as `T x = {}; x = T(args);`). The callee must match the
|
|
943
|
+
// template name and the target must be a `Name<...>` instantiation, so a
|
|
944
|
+
// regular function call assigned to a non-templated type never matches.
|
|
945
|
+
const tmplMatch = normalizedTarget.match(/^([A-Za-z_]\w*)<(.+)>/);
|
|
946
|
+
const exprAny = expr;
|
|
947
|
+
const isCtorCall = tmplMatch != null
|
|
948
|
+
&& (exprAny.kind === "method-call" || exprAny.kind === "call")
|
|
949
|
+
&& exprAny.callee === tmplMatch[1]
|
|
950
|
+
&& exprAny.callee != null && !exprAny.callee.includes("<");
|
|
951
|
+
if (isCtorCall && exprAny.args) {
|
|
952
|
+
const argsText = exprAny.args.map(a => this.render(a, exprTransformer, knownVariableTypes)).join(", ");
|
|
953
|
+
return `${tmplMatch[1]}<${tmplMatch[2]}>(${argsText})`;
|
|
954
|
+
}
|
|
955
|
+
const rendered = this.render(expr, exprTransformer, knownVariableTypes);
|
|
885
956
|
// Never cast into string-like storage — enums that lower to const char*
|
|
886
957
|
// (string enums) already match, and a string target is never an enum boundary.
|
|
887
958
|
if (this.isStringLikeCppType(normalizedTarget))
|
|
@@ -1350,6 +1421,8 @@ export class ExpressionRenderer {
|
|
|
1350
1421
|
renderMethodCall(expr, exprTransformer) {
|
|
1351
1422
|
const argsText = expr.args.map(a => this.render(a, exprTransformer)).join(", ");
|
|
1352
1423
|
let callee = exprTransformer ? exprTransformer(expr.callee) : expr.callee;
|
|
1424
|
+
const rExpr = expr.receiverExpr;
|
|
1425
|
+
const mName = expr.methodName;
|
|
1353
1426
|
// Convert . to :: for static or namespace method calls if the IR flagged them.
|
|
1354
1427
|
if (expr.isStatic || expr.isNamespace) {
|
|
1355
1428
|
callee = callee.replace(/\./g, "::");
|
|
@@ -1380,6 +1453,18 @@ export class ExpressionRenderer {
|
|
|
1380
1453
|
return callee;
|
|
1381
1454
|
}
|
|
1382
1455
|
callee = this.escapeFinalMemberName(callee);
|
|
1456
|
+
// Structured-receiver path: when the method-call IR carries a receiverExpr
|
|
1457
|
+
// (the safe.read().ok().fail() chain builder sets this), render the receiver
|
|
1458
|
+
// via the full renderer so nested lambda args survive (the flat callee string
|
|
1459
|
+
// would have destroyed them as /* __lambda__ */ placeholders). The methodName
|
|
1460
|
+
// is escaped against reserved names (e.g. div -> div_).
|
|
1461
|
+
const receiverExpr = expr.receiverExpr;
|
|
1462
|
+
const methodName = expr.methodName;
|
|
1463
|
+
if (receiverExpr !== undefined && methodName !== undefined) {
|
|
1464
|
+
const receiverText = this.render(receiverExpr, exprTransformer);
|
|
1465
|
+
const escapedMethod = escapeCppKeyword(methodName, this.strategy.reservedNames());
|
|
1466
|
+
return `${receiverText}.${escapedMethod}(${argsText})`;
|
|
1467
|
+
}
|
|
1383
1468
|
return `${callee}(${argsText})`;
|
|
1384
1469
|
}
|
|
1385
1470
|
escapeFinalMemberName(callee) {
|
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
2
|
// Op routing — dispatch a HALOpIR to the right strategy resolver.
|
|
3
3
|
//
|
|
4
|
-
// display.* ops go to resolveDisplayOp (graphics-specific)
|
|
5
|
-
//
|
|
6
|
-
//
|
|
4
|
+
// display.* ops go to resolveDisplayOp (graphics-specific).
|
|
5
|
+
// safety.* ops go to the safety hook's resolveSafetyOp (when @typecad/safety
|
|
6
|
+
// is loaded) — NEVER to a per-target strategy, because the safety
|
|
7
|
+
// package is MCU-agnostic by construction.
|
|
8
|
+
// everything else goes to resolveHALOperation (the existing generic seam).
|
|
9
|
+
// Keeps the consumer sites (expression-renderer, statement-renderer,
|
|
10
|
+
// render-expr) DRY.
|
|
7
11
|
// ---------------------------------------------------------------------------
|
|
12
|
+
import { getSafetyHook } from "../safety-hook.js";
|
|
8
13
|
export function routeHALOp(op, strategy) {
|
|
9
|
-
if (typeof op.operation === "string"
|
|
10
|
-
|
|
14
|
+
if (typeof op.operation === "string") {
|
|
15
|
+
if (op.operation.startsWith("display.")) {
|
|
16
|
+
return strategy.resolveDisplayOp?.(op);
|
|
17
|
+
}
|
|
18
|
+
if (op.operation.startsWith("safety.")) {
|
|
19
|
+
// Safety ops are resolved by the @typecad/safety package via hook.
|
|
20
|
+
// Returns undefined if the package is not loaded (caller emits an
|
|
21
|
+
// unhandled-op warning).
|
|
22
|
+
return getSafetyHook()?.resolveSafetyOp?.(op);
|
|
23
|
+
}
|
|
11
24
|
}
|
|
12
25
|
return strategy.resolveHALOperation?.(op);
|
|
13
26
|
}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
// Types are imported from @typecad/cuttlefish/api/shared.
|
|
9
9
|
// ---------------------------------------------------------------------------
|
|
10
10
|
import { escapeCppStringLiteral, escapeSnprintfFormatFragment } from "../utils/strings.js";
|
|
11
|
+
import { cppTypeForHalOp } from "./utils/hal-op-cpp-type.js";
|
|
11
12
|
import { parsedElementString, parsedIsStringLike } from "../api/shared/cpp-type-ir.js";
|
|
12
13
|
// ---------------------------------------------------------------------------
|
|
13
14
|
// Scope state management
|
|
@@ -235,11 +236,14 @@ export function inferSnprintfArg(expr, strategy, scopeState, renderExpression, p
|
|
|
235
236
|
return { format: "%d", arg: renderExpression(expr), estimatedLength: 12, preludeLines: [] };
|
|
236
237
|
}
|
|
237
238
|
}
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
239
|
+
const halIntFunctions = new Set([
|
|
240
|
+
...(strategy?.halCallNames?.() ?? new Set()),
|
|
241
|
+
// pulseIn/pulseInLong and the Wire_available/Serial_available forms
|
|
242
|
+
// are framework-specific suffix conventions; frameworks may add them
|
|
243
|
+
// to halCallNames. Kept as a fallback here until all frameworks do.
|
|
244
|
+
"pulseIn", "pulseInLong", "Wire_available", "Serial_available",
|
|
241
245
|
]);
|
|
242
|
-
if (
|
|
246
|
+
if (halIntFunctions.has(funcName)) {
|
|
243
247
|
return { format: "%d", arg: renderExpression(expr), estimatedLength: 12, preludeLines: [] };
|
|
244
248
|
}
|
|
245
249
|
}
|
|
@@ -369,6 +373,13 @@ export function inferSnprintfArg(expr, strategy, scopeState, renderExpression, p
|
|
|
369
373
|
if (rendered.startsWith('"') || stringVarNames?.has(rendered)) {
|
|
370
374
|
return { format: "%s", arg: rendered, estimatedLength: 32, preludeLines: [] };
|
|
371
375
|
}
|
|
376
|
+
const cppType = cppTypeForHalOp(expr.operation.operation);
|
|
377
|
+
if (cppType && strategy.isStringLikeType(cppType)) {
|
|
378
|
+
return { format: "%s", arg: rendered, estimatedLength: 32, preludeLines: [] };
|
|
379
|
+
}
|
|
380
|
+
if (cppType === "bool") {
|
|
381
|
+
return { format: "%s", arg: `(${rendered} ? "true" : "false")`, estimatedLength: 5, preludeLines: [] };
|
|
382
|
+
}
|
|
372
383
|
return { format: "%d", arg: rendered, estimatedLength: 12, preludeLines: [] };
|
|
373
384
|
}
|
|
374
385
|
default:
|
|
@@ -63,6 +63,14 @@ interface StatementRendererContext {
|
|
|
63
63
|
* list. Optional so ad-hoc/test constructions still work.
|
|
64
64
|
*/
|
|
65
65
|
diagnostics?: Diagnostic[];
|
|
66
|
+
/**
|
|
67
|
+
* Optional compliance context for A3-9-1 (fixed-width integer default).
|
|
68
|
+
* When provided and A3-9-1 is enforced, defaultNumericType() returns a
|
|
69
|
+
* fixed-width type instead of the legacy 'int'.
|
|
70
|
+
*/
|
|
71
|
+
compliance?: {
|
|
72
|
+
isBanned(ruleId: string): boolean;
|
|
73
|
+
};
|
|
66
74
|
}
|
|
67
75
|
/**
|
|
68
76
|
* Renders StatementIR nodes to C++ code strings.
|
|
@@ -83,6 +91,8 @@ export declare class StatementRenderer {
|
|
|
83
91
|
private readonly interfaceFieldTypes;
|
|
84
92
|
/** Shared emit-time diagnostics sink (see StatementRendererContext.diagnostics). */
|
|
85
93
|
private readonly _diagnostics;
|
|
94
|
+
/** Compliance context for A3-9-1 fixed-width integer default. */
|
|
95
|
+
private readonly _compliance?;
|
|
86
96
|
constructor(context: StatementRendererContext);
|
|
87
97
|
/**
|
|
88
98
|
* Gets the underlying expression renderer for direct use.
|
|
@@ -116,6 +116,7 @@ export class StatementRenderer {
|
|
|
116
116
|
this.namespaceNames = context.namespaceNames ?? new Set();
|
|
117
117
|
this.interfaceFieldTypes = context.interfaceFieldTypes ?? new Map();
|
|
118
118
|
this._diagnostics = context.diagnostics ?? [];
|
|
119
|
+
this._compliance = context.compliance;
|
|
119
120
|
// Create expression renderer with shared context
|
|
120
121
|
this.expressionRenderer = new ExpressionRenderer({
|
|
121
122
|
strategy: context.strategy,
|
|
@@ -324,7 +325,7 @@ export class StatementRenderer {
|
|
|
324
325
|
this.expressionRenderer.pushPrelude([
|
|
325
326
|
`const char* ${idxVar}_keys[] = { ${keysArr} };`,
|
|
326
327
|
]);
|
|
327
|
-
return `for (${this.strategy.defaultNumericType()} ${idxVar} = 0; ${idxVar} < ${statement.keys.length}; ${idxVar}++)`;
|
|
328
|
+
return `for (${this.strategy.defaultNumericType(this._compliance)} ${idxVar} = 0; ${idxVar} < ${statement.keys.length}; ${idxVar}++)`;
|
|
328
329
|
}
|
|
329
330
|
const varDecl = statement.variable;
|
|
330
331
|
if (varDecl.kind === "var_decl") {
|
|
@@ -485,6 +486,28 @@ export class StatementRenderer {
|
|
|
485
486
|
const rawStmt = statement.callee.slice('__RAW_STMT__'.length);
|
|
486
487
|
return forHeader ? rawStmt : `${rawStmt.endsWith(';') ? rawStmt : rawStmt + ';'}`;
|
|
487
488
|
}
|
|
489
|
+
// Handle expression statements whose IR must render at EMIT time (not the
|
|
490
|
+
// build-time renderExprAsText). The safe.read().ok().fail() chain uses this:
|
|
491
|
+
// its lambda args can only render via the emit-time renderLambda (which
|
|
492
|
+
// produces [&](){...}), so the structured chain IR is carried as args[0]
|
|
493
|
+
// and rendered here via the expression renderer.
|
|
494
|
+
if (statement.callee === '__EXPR_STMT__' && statement.args.length >= 1) {
|
|
495
|
+
const exprText = this.expressionRenderer.render(statement.args[0], undefined, knownVariableTypes);
|
|
496
|
+
return forHeader ? exprText : `${exprText};`;
|
|
497
|
+
}
|
|
498
|
+
// Awaited network markers (__WIFI_WAIT__/__HTTP_WAIT__) reaching the
|
|
499
|
+
// plain renderer means the await sits outside an async state machine
|
|
500
|
+
// (top-level await, or a position the state-machine splitter doesn't
|
|
501
|
+
// support). Fall back to the blocking form of the op they carry.
|
|
502
|
+
if ((statement.callee === "__WIFI_WAIT__" || statement.callee === "__HTTP_WAIT__" || statement.callee === "__BLE_WAIT__" || statement.callee === "__HAL_WAIT__")
|
|
503
|
+
&& statement.args[0]?.kind === "hal-expr") {
|
|
504
|
+
const resolved = routeHALOp(statement.args[0].operation, this.strategy);
|
|
505
|
+
const code = resolved?.code ?? (resolved?.expression ? `${resolved.expression};` : undefined);
|
|
506
|
+
if (code) {
|
|
507
|
+
return forHeader ? code.replace(/;$/, "") : code;
|
|
508
|
+
}
|
|
509
|
+
return `/* unhandled awaited hal-op: ${statement.args[0].operation.operation} */`;
|
|
510
|
+
}
|
|
488
511
|
// Handle emit() — compile-time C++ injection
|
|
489
512
|
if (statement.callee === "__EMIT__") {
|
|
490
513
|
const rawText = statement.args.map(arg => this.renderEmitArg(arg)).join("");
|
|
@@ -645,13 +668,13 @@ export class StatementRenderer {
|
|
|
645
668
|
// that don't support std::vector → emit as a plain C-style array.
|
|
646
669
|
// Mutable arrays (.push/.pop/.indexOf) are rewritten to StaticArray<int> in
|
|
647
670
|
// the IR builder (via mutableArrayVars) and never reach this branch.
|
|
648
|
-
const elementType = parsedElementString(rawType) ?? this.strategy.defaultNumericType();
|
|
671
|
+
const elementType = parsedElementString(rawType) ?? this.strategy.defaultNumericType(this._compliance);
|
|
649
672
|
return forHeader
|
|
650
673
|
? `${elementType} ${safeArrName}[] = { ${elements} }`
|
|
651
674
|
: `${elementType} ${safeArrName}[] = { ${elements} };`;
|
|
652
675
|
}
|
|
653
676
|
// Use "int" for "auto" element type since C arrays need explicit types
|
|
654
|
-
const arrayType = statement.initializer.elementType === "auto" ? this.strategy.defaultNumericType() : statement.initializer.elementType;
|
|
677
|
+
const arrayType = statement.initializer.elementType === "auto" ? this.strategy.defaultNumericType(this._compliance) : statement.initializer.elementType;
|
|
655
678
|
return forHeader
|
|
656
679
|
? `${arrayType} ${safeArrName}[] = { ${elements} }`
|
|
657
680
|
: `${arrayType} ${safeArrName}[] = { ${elements} };`;
|
|
@@ -726,7 +749,7 @@ export class StatementRenderer {
|
|
|
726
749
|
}
|
|
727
750
|
// Handle spread array initializers
|
|
728
751
|
if (statement.initializer.kind === "spread_array") {
|
|
729
|
-
let arrayType = statement.initializer.elementType === "auto" ? this.strategy.defaultNumericType() : statement.initializer.elementType;
|
|
752
|
+
let arrayType = statement.initializer.elementType === "auto" ? this.strategy.defaultNumericType(this._compliance) : statement.initializer.elementType;
|
|
730
753
|
const spreadName = this.expressionRenderer.render(statement.initializer.spreadExpr, calleeTransformer, knownVariableTypes);
|
|
731
754
|
if (statement.initializer.elementType === "auto" && knownVariableTypes && statement.initializer.spreadExpr.kind === "identifier") {
|
|
732
755
|
const srcInfo = knownVariableTypes.get(statement.initializer.spreadExpr.value);
|
|
@@ -879,11 +902,17 @@ export class StatementRenderer {
|
|
|
879
902
|
if (this.stringEnumNames.has(typeName)) {
|
|
880
903
|
return this.strategy.normalizeCppType("const char*");
|
|
881
904
|
}
|
|
905
|
+
// A3-9-1: under autosar, substitute the platform's default numeric type
|
|
906
|
+
// for the legacy "int" spelling. The IR layer hardcodes "int" for number
|
|
907
|
+
// literals, so we catch it here at the renderer boundary.
|
|
908
|
+
if (typeName === "int" && this._compliance?.isBanned("A3-9-1")) {
|
|
909
|
+
return this.strategy.defaultNumericType(this._compliance);
|
|
910
|
+
}
|
|
882
911
|
return this.strategy.normalizeCppType(typeName);
|
|
883
912
|
}
|
|
884
913
|
inferFieldType(value, parentName, fieldName) {
|
|
885
914
|
return inferObjectFieldType(value, this.pointerVarTypes, this.knownFunctionReturnTypes, undefined, undefined, undefined, // largeEnumNames - would need to pass through
|
|
886
|
-
parentName, fieldName, this.strategy.defaultNumericType(), (o, n) => this.strategy.resolvePinType?.(o, n));
|
|
915
|
+
parentName, fieldName, this.strategy.defaultNumericType(this._compliance), (o, n) => this.strategy.resolvePinType?.(o, n));
|
|
887
916
|
}
|
|
888
917
|
/**
|
|
889
918
|
* Transform console.log/error/warn calls based on target platform.
|