@typecad/cuttlefish 0.1.0-alpha.2 → 1.0.0-alpha.10
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 +10 -10
- package/dist/api/board-types.d.ts +1 -1
- 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 +595 -0
- package/dist/api/shared/framework-manifest.js +193 -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 +764 -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 +119 -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/types.d.ts +8 -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-utils.d.ts +1 -0
- package/dist/cli-utils.js +3 -1
- package/dist/cli.js +249 -32
- 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/framework-catalog.d.ts +64 -0
- package/dist/create/framework-catalog.js +136 -0
- package/dist/create/index.d.ts +5 -1
- package/dist/create/index.js +3 -1
- package/dist/create/init-scaffold.d.ts +12 -3
- package/dist/create/init-scaffold.js +49 -14
- package/dist/create/init-templates.d.ts +4 -0
- package/dist/create/init-templates.js +263 -17
- package/dist/create/init-wizard.js +41 -27
- package/dist/create/install-deps.d.ts +32 -0
- package/dist/create/install-deps.js +46 -0
- 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 +372 -30
- 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/install/framework-catalog.d.ts +53 -0
- package/dist/install/framework-catalog.js +107 -0
- package/dist/install/handle-install.d.ts +35 -0
- package/dist/install/handle-install.js +177 -0
- package/dist/install/index.d.ts +4 -0
- package/dist/install/index.js +3 -0
- package/dist/ir/adc-range-validation.js +40 -26
- 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 +207 -6
- 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 +733 -1
- package/dist/ir/identifier-collector.js +35 -0
- package/dist/ir/interrupt-analysis.d.ts +5 -1
- package/dist/ir/interrupt-analysis.js +16 -19
- package/dist/ir/memory-budget-validation.js +1 -0
- package/dist/ir/network-validation.d.ts +4 -0
- package/dist/ir/network-validation.js +184 -0
- package/dist/ir/ownership-analysis.js +39 -1
- package/dist/ir/peripheral-ownership.js +5 -0
- package/dist/ir/peripheral-validation.d.ts +1 -1
- package/dist/ir/peripheral-validation.js +6 -3
- package/dist/ir/pin-alias-conflict.d.ts +1 -1
- package/dist/ir/pin-alias-conflict.js +2 -1
- package/dist/ir/pin-capability-validation.js +71 -32
- package/dist/ir/pin-mode-validation.d.ts +2 -2
- package/dist/ir/pin-mode-validation.js +54 -18
- package/dist/ir/pin-safety.d.ts +1 -1
- package/dist/ir/pin-safety.js +2 -1
- package/dist/ir/program-analysis.d.ts +81 -0
- package/dist/ir/program-analysis.js +429 -0
- package/dist/ir/pulldown-validation.d.ts +1 -1
- package/dist/ir/pulldown-validation.js +2 -1
- package/dist/ir/pwm-timer-sharing.d.ts +1 -1
- package/dist/ir/pwm-timer-sharing.js +2 -1
- package/dist/ir/render-expr.js +11 -0
- package/dist/ir/resource-analysis.js +2 -0
- package/dist/ir/timer0-pwm-timing-conflict.d.ts +1 -1
- package/dist/ir/timer0-pwm-timing-conflict.js +2 -1
- package/dist/ir/timing-validation.d.ts +6 -1
- package/dist/ir/timing-validation.js +61 -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 +137 -19
- package/dist/ir/try-catch-validation.js +2 -0
- package/dist/ir/type-resolution.js +20 -2
- package/dist/ir/ui-element-auto-wire.js +7 -5
- package/dist/ir/unit-suspicion-validation.js +9 -7
- 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 +15 -8
- 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 +8 -2
- package/dist/testing.js +9 -2
- package/dist/transpile.d.ts +3 -0
- package/dist/transpile.js +191 -49
- package/dist/types.d.ts +22 -3
- package/dist/ui-hook.d.ts +17 -3
- package/dist/utils/cli.js +122 -2
- package/dist/utils/fs.d.ts +13 -0
- package/dist/utils/fs.js +50 -0
- package/dist/utils/ui.js +3 -1
- package/package.json +23 -3
- 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/ir/heap-array-validation.d.ts +0 -24
- package/dist/ir/heap-array-validation.js +0 -29
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { findBoardPinByName } from './board-pin-utils.js';
|
|
2
|
-
export function validatePinAliasConflicts(usage, boardConstants) {
|
|
2
|
+
export function validatePinAliasConflicts(usage, boardConstants, filePath) {
|
|
3
3
|
if (!boardConstants || usage.pinsUsed.size === 0) {
|
|
4
4
|
return [];
|
|
5
5
|
}
|
|
@@ -26,6 +26,7 @@ export function validatePinAliasConflicts(usage, boardConstants) {
|
|
|
26
26
|
diagnostics.push({
|
|
27
27
|
severity: 'warning',
|
|
28
28
|
code: 'pin-alias-conflict',
|
|
29
|
+
filePath,
|
|
29
30
|
source: 'pin-alias-conflict',
|
|
30
31
|
message: `Pin '${canonicalPinName}' is referenced through multiple names${boardLabel}: ${orderedNames.join(', ')}. These names refer to the same physical pin. Pick one name to keep pin usage and diagnostics unambiguous.`,
|
|
31
32
|
});
|
|
@@ -77,10 +77,39 @@ function findPinsWithCapability(capability, boardConstants) {
|
|
|
77
77
|
}
|
|
78
78
|
return result;
|
|
79
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Does the board declare ANY per-pin `type:'pwm'` function entry anywhere?
|
|
82
|
+
*
|
|
83
|
+
* AVR-family boards (atmega328p, etc.) hardwire PWM to specific timer-output
|
|
84
|
+
* pins, so their MCU descriptors list `{ type:'pwm', ... }` per pin and the
|
|
85
|
+
* capability check correctly rejects PWM on non-timer pins. ESP32-family
|
|
86
|
+
* boards route LEDC to ANY output GPIO via the GPIO matrix, so their MCU
|
|
87
|
+
* descriptors carry zero `type:'pwm'` entries — PWM is a board-wide property
|
|
88
|
+
* (the `pins.pwm` collection), not a per-pin function. On such boards the
|
|
89
|
+
* per-pin capability check would false-positive on every pin, so the caller
|
|
90
|
+
* skips it when this returns false. This distinguishes the two families
|
|
91
|
+
* cleanly (AVR has entries, ESP32 has none) without special-casing arch names.
|
|
92
|
+
*/
|
|
93
|
+
function boardHasAnyPwmFunctionEntries(boardConstants) {
|
|
94
|
+
if (!boardConstants)
|
|
95
|
+
return false;
|
|
96
|
+
for (let i = 0; i < 100; i++) {
|
|
97
|
+
if (boardConstants.get(`pins.all.${i}.name`) === undefined)
|
|
98
|
+
continue;
|
|
99
|
+
for (let j = 0; j < 10; j++) {
|
|
100
|
+
const type = boardConstants.get(`pins.all.${i}.functions.${j}.type`);
|
|
101
|
+
if (type === undefined)
|
|
102
|
+
break;
|
|
103
|
+
if (String(type) === 'pwm')
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
80
109
|
// ---------------------------------------------------------------------------
|
|
81
110
|
// Capability check for a single HAL operation
|
|
82
111
|
// ---------------------------------------------------------------------------
|
|
83
|
-
function checkCapability(operation, sourceLine, sourceCol, boardConstants, diagnostics) {
|
|
112
|
+
function checkCapability(operation, sourceLine, sourceCol, filePath, boardConstants, diagnostics) {
|
|
84
113
|
// Only operations with a pin field are capability-checked.
|
|
85
114
|
const op = operation.operation;
|
|
86
115
|
if (!('pin' in operation))
|
|
@@ -88,6 +117,13 @@ function checkCapability(operation, sourceLine, sourceCol, boardConstants, diagn
|
|
|
88
117
|
const capability = operationToCapability(op);
|
|
89
118
|
if (!capability)
|
|
90
119
|
return; // GPIO/timing — always available.
|
|
120
|
+
// ESP32-family boards route PWM (LEDC) to any output GPIO via the GPIO
|
|
121
|
+
// matrix, so they carry zero per-pin `type:'pwm'` entries (unlike AVR,
|
|
122
|
+
// which hardwires PWM to timer-output pins). On such boards the per-pin PWM
|
|
123
|
+
// capability check would reject every pin; skip it and let the framework's
|
|
124
|
+
// LEDC driver handle routing. This does NOT weaken AVR, which has entries.
|
|
125
|
+
if (capability === 'pwm' && !boardHasAnyPwmFunctionEntries(boardConstants))
|
|
126
|
+
return;
|
|
91
127
|
const pin = operation.pin;
|
|
92
128
|
if (typeof pin !== 'number' || pin < 0)
|
|
93
129
|
return;
|
|
@@ -145,48 +181,49 @@ function checkCapability(operation, sourceLine, sourceCol, boardConstants, diagn
|
|
|
145
181
|
hint,
|
|
146
182
|
line: sourceLine,
|
|
147
183
|
column: sourceCol,
|
|
184
|
+
filePath,
|
|
148
185
|
source: 'pin-capability-validation',
|
|
149
186
|
});
|
|
150
187
|
}
|
|
151
188
|
// ---------------------------------------------------------------------------
|
|
152
189
|
// IR tree scanner
|
|
153
190
|
// ---------------------------------------------------------------------------
|
|
154
|
-
function scanExpression(expr, boardConstants, parentLine, parentCol, diagnostics) {
|
|
191
|
+
function scanExpression(expr, boardConstants, parentLine, parentCol, parentFilePath, diagnostics) {
|
|
155
192
|
if (!expr || typeof expr !== 'object')
|
|
156
193
|
return;
|
|
157
194
|
switch (expr.kind) {
|
|
158
195
|
case 'binary': {
|
|
159
|
-
scanExpression(expr.left, boardConstants, parentLine, parentCol, diagnostics);
|
|
160
|
-
scanExpression(expr.right, boardConstants, parentLine, parentCol, diagnostics);
|
|
196
|
+
scanExpression(expr.left, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
197
|
+
scanExpression(expr.right, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
161
198
|
break;
|
|
162
199
|
}
|
|
163
200
|
case 'ternary': {
|
|
164
|
-
scanExpression(expr.condition, boardConstants, parentLine, parentCol, diagnostics);
|
|
165
|
-
scanExpression(expr.whenTrue, boardConstants, parentLine, parentCol, diagnostics);
|
|
166
|
-
scanExpression(expr.whenFalse, boardConstants, parentLine, parentCol, diagnostics);
|
|
201
|
+
scanExpression(expr.condition, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
202
|
+
scanExpression(expr.whenTrue, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
203
|
+
scanExpression(expr.whenFalse, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
167
204
|
break;
|
|
168
205
|
}
|
|
169
206
|
case 'property-access': {
|
|
170
|
-
scanExpression(expr.object, boardConstants, parentLine, parentCol, diagnostics);
|
|
207
|
+
scanExpression(expr.object, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
171
208
|
break;
|
|
172
209
|
}
|
|
173
210
|
case 'unary': {
|
|
174
|
-
scanExpression(expr.operand, boardConstants, parentLine, parentCol, diagnostics);
|
|
211
|
+
scanExpression(expr.operand, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
175
212
|
break;
|
|
176
213
|
}
|
|
177
214
|
case 'paren': {
|
|
178
|
-
scanExpression(expr.inner, boardConstants, parentLine, parentCol, diagnostics);
|
|
215
|
+
scanExpression(expr.inner, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
179
216
|
break;
|
|
180
217
|
}
|
|
181
218
|
case 'array': {
|
|
182
219
|
for (const el of expr.elements) {
|
|
183
|
-
scanExpression(el, boardConstants, parentLine, parentCol, diagnostics);
|
|
220
|
+
scanExpression(el, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
184
221
|
}
|
|
185
222
|
break;
|
|
186
223
|
}
|
|
187
224
|
case 'object': {
|
|
188
225
|
for (const field of expr.fields) {
|
|
189
|
-
scanExpression(field.value, boardConstants, parentLine, parentCol, diagnostics);
|
|
226
|
+
scanExpression(field.value, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
190
227
|
}
|
|
191
228
|
break;
|
|
192
229
|
}
|
|
@@ -204,43 +241,43 @@ function scanExpression(expr, boardConstants, parentLine, parentCol, diagnostics
|
|
|
204
241
|
}
|
|
205
242
|
case 'method-call': {
|
|
206
243
|
for (const arg of expr.args) {
|
|
207
|
-
scanExpression(arg, boardConstants, parentLine, parentCol, diagnostics);
|
|
244
|
+
scanExpression(arg, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
208
245
|
}
|
|
209
246
|
break;
|
|
210
247
|
}
|
|
211
248
|
case 'element-access': {
|
|
212
|
-
scanExpression(expr.object, boardConstants, parentLine, parentCol, diagnostics);
|
|
213
|
-
scanExpression(expr.index, boardConstants, parentLine, parentCol, diagnostics);
|
|
249
|
+
scanExpression(expr.object, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
250
|
+
scanExpression(expr.index, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
214
251
|
break;
|
|
215
252
|
}
|
|
216
253
|
case 'string_concat': {
|
|
217
254
|
for (const part of expr.parts) {
|
|
218
|
-
scanExpression(part, boardConstants, parentLine, parentCol, diagnostics);
|
|
255
|
+
scanExpression(part, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
219
256
|
}
|
|
220
257
|
break;
|
|
221
258
|
}
|
|
222
259
|
case 'template_string': {
|
|
223
|
-
scanExpression(expr.expression, boardConstants, parentLine, parentCol, diagnostics);
|
|
260
|
+
scanExpression(expr.expression, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
224
261
|
break;
|
|
225
262
|
}
|
|
226
263
|
case 'spread_array': {
|
|
227
|
-
scanExpression(expr.spreadExpr, boardConstants, parentLine, parentCol, diagnostics);
|
|
264
|
+
scanExpression(expr.spreadExpr, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
228
265
|
for (const el of expr.additionalElements) {
|
|
229
|
-
scanExpression(el, boardConstants, parentLine, parentCol, diagnostics);
|
|
266
|
+
scanExpression(el, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
230
267
|
}
|
|
231
268
|
break;
|
|
232
269
|
}
|
|
233
270
|
case 'instanceof': {
|
|
234
|
-
scanExpression(expr.object, boardConstants, parentLine, parentCol, diagnostics);
|
|
271
|
+
scanExpression(expr.object, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
235
272
|
break;
|
|
236
273
|
}
|
|
237
274
|
case 'await': {
|
|
238
|
-
scanExpression(expr.value, boardConstants, parentLine, parentCol, diagnostics);
|
|
275
|
+
scanExpression(expr.value, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
239
276
|
break;
|
|
240
277
|
}
|
|
241
278
|
case 'hal-expr': {
|
|
242
279
|
// Expression-form HAL operation (e.g. adc.read used as a value).
|
|
243
|
-
checkCapability(expr.operation, parentLine, parentCol, boardConstants, diagnostics);
|
|
280
|
+
checkCapability(expr.operation, parentLine, parentCol, parentFilePath, boardConstants, diagnostics);
|
|
244
281
|
break;
|
|
245
282
|
}
|
|
246
283
|
case 'number':
|
|
@@ -249,6 +286,7 @@ function scanExpression(expr, boardConstants, parentLine, parentCol, diagnostics
|
|
|
249
286
|
case 'identifier':
|
|
250
287
|
case 'raw':
|
|
251
288
|
case 'tuple-access':
|
|
289
|
+
case 'call':
|
|
252
290
|
break;
|
|
253
291
|
default:
|
|
254
292
|
assertNever(expr);
|
|
@@ -259,20 +297,21 @@ function scanStatement(stmt, boardConstants, diagnostics) {
|
|
|
259
297
|
return;
|
|
260
298
|
const line = stmt.sourceSpan?.startLine;
|
|
261
299
|
const col = stmt.sourceSpan?.startColumn;
|
|
300
|
+
const filePath = stmt.sourceSpan?.filePath;
|
|
262
301
|
switch (stmt.kind) {
|
|
263
302
|
case 'var_decl': {
|
|
264
303
|
if (stmt.initializer)
|
|
265
|
-
scanExpression(stmt.initializer, boardConstants, line, col, diagnostics);
|
|
304
|
+
scanExpression(stmt.initializer, boardConstants, line, col, filePath, diagnostics);
|
|
266
305
|
break;
|
|
267
306
|
}
|
|
268
307
|
case 'assign': {
|
|
269
308
|
if (stmt.value)
|
|
270
|
-
scanExpression(stmt.value, boardConstants, line, col, diagnostics);
|
|
309
|
+
scanExpression(stmt.value, boardConstants, line, col, filePath, diagnostics);
|
|
271
310
|
break;
|
|
272
311
|
}
|
|
273
312
|
case 'if': {
|
|
274
313
|
if (stmt.condition)
|
|
275
|
-
scanExpression(stmt.condition, boardConstants, line, col, diagnostics);
|
|
314
|
+
scanExpression(stmt.condition, boardConstants, line, col, filePath, diagnostics);
|
|
276
315
|
for (const s of stmt.thenBranch)
|
|
277
316
|
scanStatement(s, boardConstants, diagnostics);
|
|
278
317
|
if (stmt.elseBranch)
|
|
@@ -283,14 +322,14 @@ function scanStatement(stmt, boardConstants, diagnostics) {
|
|
|
283
322
|
case 'while':
|
|
284
323
|
case 'do_while': {
|
|
285
324
|
if (stmt.condition)
|
|
286
|
-
scanExpression(stmt.condition, boardConstants, line, col, diagnostics);
|
|
325
|
+
scanExpression(stmt.condition, boardConstants, line, col, filePath, diagnostics);
|
|
287
326
|
for (const s of stmt.body)
|
|
288
327
|
scanStatement(s, boardConstants, diagnostics);
|
|
289
328
|
break;
|
|
290
329
|
}
|
|
291
330
|
case 'for': {
|
|
292
331
|
if (stmt.condition)
|
|
293
|
-
scanExpression(stmt.condition, boardConstants, line, col, diagnostics);
|
|
332
|
+
scanExpression(stmt.condition, boardConstants, line, col, filePath, diagnostics);
|
|
294
333
|
if (stmt.initializer)
|
|
295
334
|
scanStatement(stmt.initializer, boardConstants, diagnostics);
|
|
296
335
|
if (stmt.increment)
|
|
@@ -309,23 +348,23 @@ function scanStatement(stmt, boardConstants, diagnostics) {
|
|
|
309
348
|
}
|
|
310
349
|
case 'return': {
|
|
311
350
|
if (stmt.value)
|
|
312
|
-
scanExpression(stmt.value, boardConstants, line, col, diagnostics);
|
|
351
|
+
scanExpression(stmt.value, boardConstants, line, col, filePath, diagnostics);
|
|
313
352
|
break;
|
|
314
353
|
}
|
|
315
354
|
case 'call': {
|
|
316
355
|
for (const arg of stmt.args) {
|
|
317
|
-
scanExpression(arg, boardConstants, line, col, diagnostics);
|
|
356
|
+
scanExpression(arg, boardConstants, line, col, filePath, diagnostics);
|
|
318
357
|
}
|
|
319
358
|
break;
|
|
320
359
|
}
|
|
321
360
|
case 'hal-op': {
|
|
322
361
|
// Statement-form HAL operation — the primary capability check target.
|
|
323
|
-
checkCapability(stmt.operation, line, col, boardConstants, diagnostics);
|
|
362
|
+
checkCapability(stmt.operation, line, col, filePath, boardConstants, diagnostics);
|
|
324
363
|
break;
|
|
325
364
|
}
|
|
326
365
|
case 'switch': {
|
|
327
366
|
if (stmt.expression)
|
|
328
|
-
scanExpression(stmt.expression, boardConstants, line, col, diagnostics);
|
|
367
|
+
scanExpression(stmt.expression, boardConstants, line, col, filePath, diagnostics);
|
|
329
368
|
for (const c of stmt.cases) {
|
|
330
369
|
for (const s of c.body)
|
|
331
370
|
scanStatement(s, boardConstants, diagnostics);
|
|
@@ -355,7 +394,7 @@ function scanStatement(stmt, boardConstants, diagnostics) {
|
|
|
355
394
|
}
|
|
356
395
|
case 'throw': {
|
|
357
396
|
if (stmt.value)
|
|
358
|
-
scanExpression(stmt.value, boardConstants, line, col, diagnostics);
|
|
397
|
+
scanExpression(stmt.value, boardConstants, line, col, filePath, diagnostics);
|
|
359
398
|
break;
|
|
360
399
|
}
|
|
361
400
|
case 'update':
|
|
@@ -4,7 +4,7 @@ import type { Diagnostic } from '../types.js';
|
|
|
4
4
|
* Validate that GPIO I/O operations are preceded by mode configuration.
|
|
5
5
|
*
|
|
6
6
|
* - Read without prior mode → **warning** (undefined behavior on floating pin)
|
|
7
|
-
* - Write without prior mode → **info** (
|
|
8
|
-
* explicit configuration is recommended)
|
|
7
|
+
* - Write without prior mode → **info** (Wiring-derived frameworks implicitly
|
|
8
|
+
* set OUTPUT, but explicit configuration is recommended)
|
|
9
9
|
*/
|
|
10
10
|
export declare function validatePinModeConfig(program: ProgramIR): Diagnostic[];
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// configuration. Generates warnings for reads and info for writes.
|
|
6
6
|
// ---------------------------------------------------------------------------
|
|
7
7
|
import { scanNestedStatements } from './interrupt-analysis.js';
|
|
8
|
+
import { hasLoadedFramework, getLoadedFramework } from '../framework-registry.js';
|
|
8
9
|
/** Methods that configure pin mode. */
|
|
9
10
|
const MODE_SET_METHODS = new Set([
|
|
10
11
|
'inputPullUp', 'inputPullDown', 'outputOpenDrain',
|
|
@@ -14,7 +15,7 @@ const MODE_SET_METHODS = new Set([
|
|
|
14
15
|
const READ_METHODS = new Set([
|
|
15
16
|
'read', 'isHigh', 'isLow', 'readAnalog', 'readVoltage',
|
|
16
17
|
]);
|
|
17
|
-
/** Write operations that implicitly set OUTPUT mode on
|
|
18
|
+
/** Write operations that implicitly set OUTPUT mode on Wiring-derived frameworks. */
|
|
18
19
|
const WRITE_METHODS = new Set([
|
|
19
20
|
'write', 'high', 'low', 'toggle', 'pulse', 'pwm', 'tone',
|
|
20
21
|
]);
|
|
@@ -26,8 +27,8 @@ const PIN_RECEIVER_KINDS = new Set([
|
|
|
26
27
|
* Validate that GPIO I/O operations are preceded by mode configuration.
|
|
27
28
|
*
|
|
28
29
|
* - Read without prior mode → **warning** (undefined behavior on floating pin)
|
|
29
|
-
* - Write without prior mode → **info** (
|
|
30
|
-
* explicit configuration is recommended)
|
|
30
|
+
* - Write without prior mode → **info** (Wiring-derived frameworks implicitly
|
|
31
|
+
* set OUTPUT, but explicit configuration is recommended)
|
|
31
32
|
*/
|
|
32
33
|
export function validatePinModeConfig(program) {
|
|
33
34
|
const diagnostics = [];
|
|
@@ -43,6 +44,7 @@ export function validatePinModeConfig(program) {
|
|
|
43
44
|
message: `Analog pin '${receiver}' used as digital output. ` +
|
|
44
45
|
`Analog input capability (ADC) is lost while pin is in OUTPUT mode. ` +
|
|
45
46
|
`Call ${receiver}.asInput() to restore analog reading.`,
|
|
47
|
+
filePath: program.fileName,
|
|
46
48
|
code: 'analog-pin-as-output',
|
|
47
49
|
source: 'pin-mode-validation',
|
|
48
50
|
});
|
|
@@ -55,6 +57,7 @@ export function validatePinModeConfig(program) {
|
|
|
55
57
|
severity: 'warning',
|
|
56
58
|
message: `Pin '${receiver}' read via '${method}()' without prior mode configuration. ` +
|
|
57
59
|
`Call ${receiver}.asInput() or ${receiver}.inputPullUp() first.`,
|
|
60
|
+
filePath: program.fileName,
|
|
58
61
|
code: 'pin-mode-not-set',
|
|
59
62
|
source: 'pin-mode-validation',
|
|
60
63
|
});
|
|
@@ -63,7 +66,8 @@ export function validatePinModeConfig(program) {
|
|
|
63
66
|
diagnostics.push({
|
|
64
67
|
severity: 'info',
|
|
65
68
|
message: `Pin '${receiver}' written via '${method}()' without explicit mode configuration. ` +
|
|
66
|
-
`
|
|
69
|
+
`The target framework implicitly sets OUTPUT, but explicit ${receiver}.asOutput() is recommended.`,
|
|
70
|
+
filePath: program.fileName,
|
|
67
71
|
code: 'pin-mode-not-set',
|
|
68
72
|
source: 'pin-mode-validation',
|
|
69
73
|
});
|
|
@@ -100,6 +104,7 @@ export function validatePinModeConfig(program) {
|
|
|
100
104
|
severity: 'warning',
|
|
101
105
|
message: `Pin ${op.pin} read without prior mode configuration. ` +
|
|
102
106
|
`Call asInput() or inputPullUp() first — reading a floating pin is undefined behavior.`,
|
|
107
|
+
filePath: program.fileName,
|
|
103
108
|
code: 'pin-mode-not-set',
|
|
104
109
|
source: 'pin-mode-validation',
|
|
105
110
|
});
|
|
@@ -108,7 +113,8 @@ export function validatePinModeConfig(program) {
|
|
|
108
113
|
diagnostics.push({
|
|
109
114
|
severity: 'info',
|
|
110
115
|
message: `Pin ${op.pin} written without explicit mode configuration. ` +
|
|
111
|
-
`
|
|
116
|
+
`The target framework implicitly sets OUTPUT, but explicit asOutput() is recommended.`,
|
|
117
|
+
filePath: program.fileName,
|
|
112
118
|
code: 'pin-mode-not-set',
|
|
113
119
|
source: 'pin-mode-validation',
|
|
114
120
|
});
|
|
@@ -143,21 +149,51 @@ export function validatePinModeConfig(program) {
|
|
|
143
149
|
// Raw nodes: after full HAL resolution, some pin ops land as their C++ text
|
|
144
150
|
// (e.g. `digitalRead(2)`, `digitalWrite(2, 1)`) rather than structured
|
|
145
151
|
// hal-expr nodes. Extract the pin number and apply the same mode check.
|
|
146
|
-
//
|
|
152
|
+
// Detect GPIO ops in lowered raw C++ text. Build the read/write name
|
|
153
|
+
// patterns from the loaded framework's HAL vocabulary (halCallNames),
|
|
154
|
+
// classifying names containing "Read" as reads and "Write" as writes (the
|
|
155
|
+
// Wiring-derived convention). Seed with digitalRead/digitalWrite as the
|
|
156
|
+
// canonical Wiring forms so the validator works even when no framework is
|
|
157
|
+
// loaded. Non-Wiring frameworks that emit other call forms register them
|
|
158
|
+
// via halCallNames; this loop picks them up.
|
|
147
159
|
if (e.kind === 'raw' && typeof e.value === 'string') {
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
+
const frameworkHalNames = hasLoadedFramework()
|
|
161
|
+
? getLoadedFramework().strategy.halCallNames?.()
|
|
162
|
+
: undefined;
|
|
163
|
+
const halNames = frameworkHalNames ?? new Set(['digitalRead', 'digitalWrite']);
|
|
164
|
+
const readNames = [...halNames].filter(n => /read/i.test(n));
|
|
165
|
+
const writeNames = [...halNames].filter(n => /write/i.test(n));
|
|
166
|
+
let pin = null;
|
|
167
|
+
let op = null;
|
|
168
|
+
for (const rn of readNames) {
|
|
169
|
+
const esc = rn.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
170
|
+
const m = e.value.match(new RegExp(`${esc}\\((\\d+)\\)`));
|
|
171
|
+
if (m) {
|
|
172
|
+
pin = parseInt(m[1], 10);
|
|
173
|
+
op = { operation: 'gpio.read', pin };
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (!op) {
|
|
178
|
+
for (const wn of writeNames) {
|
|
179
|
+
const esc = wn.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
180
|
+
const m = e.value.match(new RegExp(`${esc}\\((\\d+)`));
|
|
181
|
+
if (m) {
|
|
182
|
+
pin = parseInt(m[1], 10);
|
|
183
|
+
op = { operation: 'gpio.write', pin };
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// toggle: a write call whose second arg is a read call on the same pin.
|
|
189
|
+
if (!op) {
|
|
190
|
+
const tm = e.value.match(/\((\d+),\s*\w*[Rr]ead/);
|
|
191
|
+
if (tm) {
|
|
192
|
+
op = { operation: 'gpio.toggle', pin: parseInt(tm[1], 10) };
|
|
193
|
+
}
|
|
160
194
|
}
|
|
195
|
+
if (op)
|
|
196
|
+
checkGpioHalOp(op);
|
|
161
197
|
}
|
|
162
198
|
// Recurse into nested expressions
|
|
163
199
|
if (e.args && Array.isArray(e.args)) {
|
package/dist/ir/pin-safety.d.ts
CHANGED
|
@@ -8,4 +8,4 @@ import type { Diagnostic } from '../types.js';
|
|
|
8
8
|
* @param boardConstants - Board constants containing pins.unsafe array
|
|
9
9
|
* @returns Array of diagnostic warnings for unsafe pin usage
|
|
10
10
|
*/
|
|
11
|
-
export declare function validateUnsafePins(usage: PeripheralUsage, boardConstants: BoardConstants | undefined): Diagnostic[];
|
|
11
|
+
export declare function validateUnsafePins(usage: PeripheralUsage, boardConstants: BoardConstants | undefined, filePath: string): Diagnostic[];
|
package/dist/ir/pin-safety.js
CHANGED
|
@@ -30,7 +30,7 @@ function buildUnsafePinMessage(pinName, boardConstants) {
|
|
|
30
30
|
* @param boardConstants - Board constants containing pins.unsafe array
|
|
31
31
|
* @returns Array of diagnostic warnings for unsafe pin usage
|
|
32
32
|
*/
|
|
33
|
-
export function validateUnsafePins(usage, boardConstants) {
|
|
33
|
+
export function validateUnsafePins(usage, boardConstants, filePath) {
|
|
34
34
|
const diagnostics = [];
|
|
35
35
|
if (!boardConstants)
|
|
36
36
|
return diagnostics;
|
|
@@ -50,6 +50,7 @@ export function validateUnsafePins(usage, boardConstants) {
|
|
|
50
50
|
severity: 'warning',
|
|
51
51
|
message: buildUnsafePinMessage(pinName, boardConstants),
|
|
52
52
|
code: 'unsafe-pin-usage',
|
|
53
|
+
filePath,
|
|
53
54
|
source: 'pin-safety',
|
|
54
55
|
});
|
|
55
56
|
}
|
|
@@ -29,6 +29,22 @@ export interface ProgramAnalysisResult {
|
|
|
29
29
|
usesTiming: boolean;
|
|
30
30
|
usesWDT: boolean;
|
|
31
31
|
usesStrPtr: boolean;
|
|
32
|
+
usesUart: boolean;
|
|
33
|
+
usesSPI: boolean;
|
|
34
|
+
usesI2C: boolean;
|
|
35
|
+
usesEEPROM: boolean;
|
|
36
|
+
usesTone: boolean;
|
|
37
|
+
/** map()/constrain() Arduino-API calls. framework-avr gates its native
|
|
38
|
+
* _native_map/_native_constrain helpers on these (they're dead code
|
|
39
|
+
* otherwise — no other internal caller references them). */
|
|
40
|
+
usesMap: boolean;
|
|
41
|
+
usesConstrain: boolean;
|
|
42
|
+
/** Comprehensive timing gate for the native millis() Timer0 ISR on AVR.
|
|
43
|
+
* True when the program directly uses millis/delay/micros, OR has hidden
|
|
44
|
+
* consumers of the soft clock: setInterval/setTimeout (timerCallCount),
|
|
45
|
+
* async functions (the runtime polls millis), or a mounted UI (per-frame
|
|
46
|
+
* tick injected by the emitter, not present in user source). */
|
|
47
|
+
usesNativeTiming: boolean;
|
|
32
48
|
hasSerialBegin: boolean;
|
|
33
49
|
hasGenerators: boolean;
|
|
34
50
|
usesStdMap: boolean;
|
|
@@ -36,6 +52,71 @@ export interface ProgramAnalysisResult {
|
|
|
36
52
|
* __tc_TimerRuntime::MAX_TIMERS to the observed count (floor 1) rather than
|
|
37
53
|
* a blind constant, so a one-timer program links one slot, not eight. */
|
|
38
54
|
timerCallCount: number;
|
|
55
|
+
/** ESP32 peripheral usage — framework-esp32 gates its IDF driver blocks and
|
|
56
|
+
* forced includes on these. Detected from HAL-op operation names, the same
|
|
57
|
+
* way usesUart/usesSPI/usesI2C are. Other frameworks have no CUTTLEFISH_*
|
|
58
|
+
* blocks with these marker names so the setup.ts filters are no-ops there. */
|
|
59
|
+
usesGPIO: boolean;
|
|
60
|
+
usesPWM: boolean;
|
|
61
|
+
usesRmt: boolean;
|
|
62
|
+
usesADC: boolean;
|
|
63
|
+
usesDAC: boolean;
|
|
64
|
+
usesPower: boolean;
|
|
65
|
+
usesWdt: boolean;
|
|
66
|
+
usesInterrupts: boolean;
|
|
67
|
+
usesPulse: boolean;
|
|
68
|
+
usesShift: boolean;
|
|
69
|
+
/** WiFi / HTTP / BLE usage — framework-esp32 gates the __tc_wifi/__tc_http/
|
|
70
|
+
* __tc_ble runtime shims and their esp_wifi/esp_http_client/nimble includes
|
|
71
|
+
* on these. Detected from wifi.* / http.* / ble.* HAL-op operation names. */
|
|
72
|
+
usesWifi: boolean;
|
|
73
|
+
/** Fine-grained WiFi sub-feature tracking — gates individual shim sub-blocks
|
|
74
|
+
* so that unused static helper functions don't trigger -Wunused-function. */
|
|
75
|
+
usesWifiConnect: boolean;
|
|
76
|
+
usesWifiConnectBlocking: boolean;
|
|
77
|
+
usesWifiQuery: boolean;
|
|
78
|
+
usesWifiScan: boolean;
|
|
79
|
+
usesWifiConfig: boolean;
|
|
80
|
+
usesHttp: boolean;
|
|
81
|
+
usesBle: boolean;
|
|
82
|
+
/** Preferences (NVS) usage — framework-esp32 gates the __tc_prefs runtime shim
|
|
83
|
+
* and its nvs_flash/nvs includes on this. Detected from preferences.* ops. */
|
|
84
|
+
usesPreferences: boolean;
|
|
85
|
+
/** Random usage — frameworks gate their PRNG runtime/include on this
|
|
86
|
+
* (e.g. framework-esp32 includes <esp_random.h>). Detected from random.* ops. */
|
|
87
|
+
usesRandom: boolean;
|
|
88
|
+
/** FS (filesystem) usage — frameworks gate their VFS/SD runtime shim on this.
|
|
89
|
+
* Detected from fs.* ops. */
|
|
90
|
+
usesFS: boolean;
|
|
91
|
+
/** mDNS usage — frameworks gate the esp_mdns runtime/include on this. */
|
|
92
|
+
usesMdns: boolean;
|
|
93
|
+
/** MQTT usage — frameworks gate the esp_mqtt runtime/include on this. */
|
|
94
|
+
usesMqtt: boolean;
|
|
95
|
+
/** OTA usage — frameworks gate the esp_https_ota runtime/include on this. */
|
|
96
|
+
usesOta: boolean;
|
|
97
|
+
/** Temperature (die temp) usage. Detected from temp.* ops. */
|
|
98
|
+
usesTemp: boolean;
|
|
99
|
+
/** Hardware timer (GPTimer) usage. Detected from hwtimer.* ops. */
|
|
100
|
+
usesHwtimer: boolean;
|
|
101
|
+
/** Capacitive touch pins usage. Detected from capacitive.* ops. */
|
|
102
|
+
usesCapacitive: boolean;
|
|
103
|
+
/** Worker offload usage. Detected from worker.* ops. Frameworks gate the
|
|
104
|
+
* worker_runtime polyfill (and its per-framework backing) on this. */
|
|
105
|
+
usesWorker: boolean;
|
|
106
|
+
/** Native/desktop: std::chrono / steady_clock usage (gates <chrono>). */
|
|
107
|
+
usesChrono: boolean;
|
|
108
|
+
/** Native/desktop: std::set usage (gates <set>). */
|
|
109
|
+
usesSet: boolean;
|
|
110
|
+
/** Native/desktop: std::algorithm usage (std::sort/find/transform etc., gates <algorithm>). */
|
|
111
|
+
usesAlgorithm: boolean;
|
|
112
|
+
/** Native/desktop: cstdio usage (printf/fprintf/snprintf, gates <cstdio>). */
|
|
113
|
+
usesCstdio: boolean;
|
|
114
|
+
/** digitalRead() in lowered raw text or gpio.read hal-op (gates the native digitalRead shim). */
|
|
115
|
+
usesDigitalRead: boolean;
|
|
116
|
+
/** display.* hal-op present, or a UI is mounted (replaces ad-hoc programUsesDisplay walks). */
|
|
117
|
+
usesDisplay: boolean;
|
|
118
|
+
/** cuttlefish_halt() in lowered raw text (gates the cuttlefish_halt macro polyfill). */
|
|
119
|
+
usesHalt: boolean;
|
|
39
120
|
}
|
|
40
121
|
/**
|
|
41
122
|
* Analyze a program IR in a single pass to detect all features.
|