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 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 36x 36x 36x 25x 4x 21x 21x 29x 29x 8x 21x 21x 19x 19x 17x | /**
* ArrayInitializerUtils - Shared utilities for analyzing array initializers.
* Issue #636: Used by both VariableCollector (headers) and CodeGenerator (.c files)
* to ensure consistent array size inference from initializers.
*/
import * as Parser from "../../../2-Parse/grammar/CNextParser";
import StringUtils from "../../../../utils/StringUtils";
class ArrayInitializerUtils {
/**
* Find an ArrayInitializerContext from an expression.
* Traverses the parse tree: Expression → Ternary → Or → And → ... → Primary → ArrayInitializer
*
* @param expr The expression context to search
* @returns The array initializer context, or null if not found
*/
static findArrayInitializer(
expr: Parser.ExpressionContext,
): Parser.ArrayInitializerContext | null {
// Expression → TernaryExpression
const ternary = expr.ternaryExpression();
Iif (!ternary) return null;
// TernaryExpression → OrExpression (when not a ternary)
const orExpr = ternary.orExpression();
Iif (!orExpr || orExpr.length === 0) return null;
// OrExpression → AndExpression
const andExpr = orExpr[0].andExpression();
Iif (!andExpr || andExpr.length === 0) return null;
// AndExpression → EqualityExpression
const equality = andExpr[0].equalityExpression();
Iif (!equality || equality.length === 0) return null;
// EqualityExpression → RelationalExpression
const relational = equality[0].relationalExpression();
Iif (!relational || relational.length === 0) return null;
// RelationalExpression → BitwiseOrExpression
const bitwiseOr = relational[0].bitwiseOrExpression();
Iif (!bitwiseOr || bitwiseOr.length === 0) return null;
// BitwiseOrExpression → BitwiseXorExpression
const bitwiseXor = bitwiseOr[0].bitwiseXorExpression();
Iif (!bitwiseXor || bitwiseXor.length === 0) return null;
// BitwiseXorExpression → BitwiseAndExpression
const bitwiseAnd = bitwiseXor[0].bitwiseAndExpression();
Iif (!bitwiseAnd || bitwiseAnd.length === 0) return null;
// BitwiseAndExpression → ShiftExpression
const shift = bitwiseAnd[0].shiftExpression();
Iif (!shift || shift.length === 0) return null;
// ShiftExpression → AdditiveExpression
const additive = shift[0].additiveExpression();
Iif (!additive || additive.length === 0) return null;
// AdditiveExpression → MultiplicativeExpression
const multiplicative = additive[0].multiplicativeExpression();
Iif (!multiplicative || multiplicative.length === 0) return null;
// MultiplicativeExpression → UnaryExpression
const unaryArr = multiplicative[0].unaryExpression();
Iif (!unaryArr || unaryArr.length === 0) return null;
const unary = unaryArr[0];
// UnaryExpression → PostfixExpression
const postfix = unary.postfixExpression();
if (!postfix) return null;
// PostfixExpression → PrimaryExpression
const primary = postfix.primaryExpression();
Iif (!primary) return null;
// PrimaryExpression → ArrayInitializer
return primary.arrayInitializer();
}
/**
* Count the number of elements in an array initializer.
* Handles both list syntax [1, 2, 3] and fill-all syntax [0*].
*
* @param arrayInit The array initializer context
* @returns Object with count (for list) or isFillAll (for fill-all syntax)
*/
static countElements(arrayInit: Parser.ArrayInitializerContext): {
count: number;
isFillAll: boolean;
} {
// Check for fill-all syntax: [expr*]
// Fill-all has expression() directly on the arrayInitializer, not wrapped in elements
if (arrayInit.expression()) {
return { count: 0, isFillAll: true };
}
// List syntax: [elem1, elem2, ...]
const elements = arrayInit.arrayInitializerElement();
return { count: elements.length, isFillAll: false };
}
/**
* Get the inferred array size from an expression containing an array initializer.
* Returns the element count if the expression is a list-style array initializer,
* or undefined if no array initializer found or if it uses fill-all syntax.
*
* ADR-035: a string literal initializes a `u8` array with its bytes and the
* terminator (`u8[] message <- "Hello"` is `u8[6]`). Uncounted, the `.h`
* stated a scalar against the `.c`'s `uint8_t message[] = "Hello"` (#1824
* review); whether the element type allows a literal is E0866's.
*
* @param expr The expression context
* @returns The inferred size, or undefined
*/
static getInferredSize(expr: Parser.ExpressionContext): number | undefined {
const text = expr.getText();
if (text.length >= 2 && text.startsWith('"') && text.endsWith('"')) {
return StringUtils.literalLength(text) + 1;
}
const arrayInit = this.findArrayInitializer(expr);
if (!arrayInit) return undefined;
const { count, isFillAll } = this.countElements(arrayInit);
if (isFillAll) return undefined; // Fill-all requires explicit size
return count > 0 ? count : undefined;
}
}
export default ArrayInitializerUtils;
|