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 135 | 225x 39x 6x 6x 98x 98x 76x 22x 22x 27x 27x 27x 5x 5x 4x 1x 3x 3x 3x 1x 2x 2x 9x 9x 4x 4x 2x 18x 11x 11x 11x 12x 12x 11x 42x 1x 41x 1x 40x 1x | /**
* Pure utility functions for binary expression generation.
* Extracted from BinaryExprGenerator for testability (Issue #419).
*/
import LiteralUtils from "../../../../../utils/LiteralUtils";
class BinaryExprUtils {
/**
* Issue #235: Try to parse a string as a numeric constant.
* Delegates to LiteralUtils.parseIntegerLiteral to avoid duplication.
*/
static tryParseNumericLiteral(code: string): number | undefined {
return LiteralUtils.parseIntegerLiteral(code);
}
/**
* ADR-001: Map C-Next equality operator to C.
* C-Next uses = for equality (mathematical notation), C uses ==.
*/
static mapEqualityOperator(cnextOp: string): string {
return cnextOp === "=" ? "==" : cnextOp;
}
/**
* ADR-045: Generate strcmp comparison code for string equality.
*/
static generateStrcmpCode(
left: string,
right: string,
isNotEqual: boolean,
): string {
const cmpOp = isNotEqual ? "!= 0" : "== 0";
return `strcmp(${left}, ${right}) ${cmpOp}`;
}
/**
* Issue #235: Evaluate a constant arithmetic expression.
* Returns the result if all operands are numeric and evaluation succeeds,
* undefined otherwise (falls back to non-folded code).
*/
static tryFoldConstants(
operandCodes: string[],
operators: string[],
): number | undefined {
const values = operandCodes.map(BinaryExprUtils.tryParseNumericLiteral);
if (values.includes(undefined)) {
return undefined;
}
let result = values[0] as number;
for (let i = 0; i < operators.length; i++) {
const op = operators[i];
const rightValue = values[i + 1] as number;
switch (op) {
case "*":
result = result * rightValue;
break;
case "/":
if (rightValue === 0) {
return undefined;
}
result = Math.trunc(result / rightValue);
break;
case "%":
if (rightValue === 0) {
return undefined;
}
result = result % rightValue;
break;
case "+":
result = result + rightValue;
break;
case "-":
result = result - rightValue;
break;
default:
return undefined;
}
}
return result;
}
/**
* Build a chained binary expression from operands and operators.
* Used by relational, shift, additive, and multiplicative generators.
*/
static buildChainedExpression(
operands: string[],
operators: string[],
defaultOp: string,
): string {
Iif (operands.length === 0) {
return "";
}
let result = operands[0];
for (let i = 1; i < operands.length; i++) {
const op = operators[i - 1] || defaultOp;
result += ` ${op} ${operands[i]}`;
}
return result;
}
/**
* ADR-017: Validate enum type safety for comparisons.
* Throws if comparing different enum types or enum to integer.
*/
static validateEnumComparison(
leftEnumType: string | null,
rightEnumType: string | null,
leftIsInteger: boolean,
rightIsInteger: boolean,
): void {
if (leftEnumType && rightEnumType && leftEnumType !== rightEnumType) {
throw new Error(
`Error: Cannot compare ${leftEnumType} enum to ${rightEnumType} enum`,
);
}
if (leftEnumType && rightIsInteger) {
throw new Error(`Error: Cannot compare ${leftEnumType} enum to integer`);
}
if (rightEnumType && leftIsInteger) {
throw new Error(`Error: Cannot compare integer to ${rightEnumType} enum`);
}
}
}
export default BinaryExprUtils;
|