Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | 73x 73x 2x 71x 71x 49x 22x 77x 5x 72x 48x 24x | /**
* Issue #579 / Issue #1100: Shared subscript classifier for array vs bit access
*
* This utility unifies the classification logic used by:
* - AssignmentClassifier (assignment path)
* - CodeGenerator._generatePostfixExpr (expression path)
*
* The classification rule is:
* 1. If isArray or isString -> array access
* 2. Otherwise -> bit manipulation
*
* This rule is identical for parameters and local variables. ADR-006 requires
* array parameters to use explicit array syntax (`u8[8] buf`), which sets
* isArray on the parameter's type info exactly like a local array declaration
* does. A scalar-typed parameter (no array brackets) is therefore classified
* the same way a scalar local variable is: bit manipulation (ADR-007 — "Any
* integer type can be indexed to access individual bits", with no carve-out
* for parameters).
*
* Issue #1100: A prior version of this classifier treated ANY function
* parameter without explicit array syntax as array access (`isParameter &&
* !isArray -> array`), added in #579 to support buffer-style parameters
* declared without brackets (e.g. `void fillBuffer(u8 buf)`). That blanket
* rule was a divergent decision path from local-variable classification: it
* silently broke ADR-007 bit-indexing for scalar parameters (`u32 v; ...
* v[4]` inside a function became `v[4]` array-subscript C code on a pointer
* instead of a shift-and-mask bit read), producing invalid/incorrect C
* for the extremely common embedded pattern of reading a bit out of a
* hardware-register-shaped scalar parameter. Buffer-style parameters must now
* use explicit array syntax (`u8[N] buf`), which was already the ADR-006
* documented and supported spelling — see tests/params/param-array-indexing.test.cnx.
*/
import TSubscriptKind from "./TSubscriptKind";
import TTypeInfo from "../types/TTypeInfo";
/**
* Context needed for subscript classification
*/
interface ISubscriptContext {
/** Type information for the variable being subscripted, null if unknown */
typeInfo: TTypeInfo | null;
/** Number of subscript expressions (1 for single index, 2 for range/slice) */
subscriptCount: number;
/** Whether this is a register access (registers always use bit manipulation) */
isRegisterAccess?: boolean;
}
/**
* Classifies subscript operations as array or bit access.
*
* This class provides a single source of truth for determining whether
* a subscript operation like `x[i]` or `x[a, b]` should be treated as
* array element access or bit manipulation.
*/
class SubscriptClassifier {
/**
* Classify a subscript operation.
*
* @param ctx - Classification context with type info and subscript count
* @returns The kind of subscript operation (array or bit access)
*/
static classify(ctx: ISubscriptContext): TSubscriptKind {
const { typeInfo, subscriptCount, isRegisterAccess } = ctx;
// Registers always use bit manipulation
if (isRegisterAccess) {
return subscriptCount === 2 ? "bit_range" : "bit_single";
}
// Check if this should be array access
const isArrayAccess = SubscriptClassifier.isArrayAccess(typeInfo);
if (isArrayAccess) {
// Slice vs element access
return subscriptCount === 2 ? "array_slice" : "array_element";
}
// Default: bit manipulation
return subscriptCount === 2 ? "bit_range" : "bit_single";
}
/**
* Determine if a type should use array access semantics.
*
* Array access is used when:
* - Type is explicitly an array (isArray: true) — including array
* parameters declared with explicit syntax, e.g. `u8[8] buf` (ADR-006)
* - Type is a string (strings are char arrays)
*
* Parameters are NOT special-cased here (Issue #1100): whether a subscript
* is array access or bit access depends solely on the declared type, the
* same rule used for local variables. A scalar parameter without array
* syntax is bit-indexable exactly like a scalar local variable (ADR-007).
*
* @param typeInfo - Type information, or null if unknown
* @returns true if subscript should be treated as array access
*/
static isArrayAccess(typeInfo: TTypeInfo | null): boolean {
if (!typeInfo) {
// Unknown type - default to array access for safety
// This matches the expression path's fallback behavior
return true;
}
// Explicit array or string -> array access
if (typeInfo.isArray || typeInfo.isString) {
return true;
}
// Otherwise it's a scalar - use bit access
return false;
}
}
export default SubscriptClassifier;
|