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 | 290x 46x 6x 6x 130x 130x 110x 20x 20x 25x 25x 25x 5x 5x 4x 1x 3x 3x 3x 1x 2x 2x 6x 6x 5x 5x 2x 16x 11x 11x 11x 12x 12x 11x 49x 1x 48x 1x 47x 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;
|