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 | 105x 32x 32x 22x 11x 1x 1x 7x 1x 1x 17x 17x | /**
* The C for a constant expression only C can evaluate (#1175): an array
* dimension naming a macro from an included header (`u8[BUF_SIZE + 1]`).
*
* Written from the expression's STRUCTURE, never from its source text. Every
* part that has a value is written as that value, so a C-Next const (which C
* cannot see) never reaches the C by name; operators are C's (`=` is `==`);
* and a negative value is parenthesized, so no two tokens can join into one
* (`1 - -1` must never become `1--1`). The .c and the .h both print a
* dimension here, so they cannot disagree about it.
*/
import ConstantEvaluator from "./ConstantEvaluator";
import invariant from "./invariant";
import type IConstantEnvironment from "./types/IConstantEnvironment";
import type TConstExpr from "../types/TConstExpr";
/** The C-Next operators C spells differently */
const C_OPERATOR: Readonly<Record<string, string>> = { "=": "==" };
class ConstExprPrinter {
static toC(expr: TConstExpr, env: IConstantEnvironment): string {
const result = ConstantEvaluator.evaluate(expr, env);
if (result.kind === "value") return result.value.toString();
switch (expr.kind) {
case "name":
// Only a header's name is left unvalued here, and C spells it as is
return expr.path.join(".");
case "sizeof":
return `sizeof(${env.cTypeName(expr.typeName, expr.at)})`;
case "cast":
return `(${env.cTypeName(expr.typeName, expr.at)})${ConstExprPrinter.operand(expr.operand, env)}`;
case "unary":
return `${expr.op}${ConstExprPrinter.operand(expr.operand, env)}`;
case "binary":
return `${ConstExprPrinter.operand(expr.left, env)} ${C_OPERATOR[expr.op] ?? expr.op} ${ConstExprPrinter.operand(expr.right, env)}`;
case "ternary":
return `(${ConstExprPrinter.toC(expr.condition, env)}) ? ${ConstExprPrinter.operand(expr.whenTrue, env)} : ${ConstExprPrinter.operand(expr.whenFalse, env)}`;
default:
invariant(
false,
`only an expression C can evaluate is printed, not a '${expr.kind}' -- 2.1 rejects one with no value first`,
);
}
}
/** An operand, parenthesized unless it is one token that cannot join another */
private static operand(expr: TConstExpr, env: IConstantEnvironment): string {
const text = ConstExprPrinter.toC(expr, env);
return /^\w+$/.test(text) ? text : `(${text})`;
}
}
export default ConstExprPrinter;
|