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 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | 559x 559x 559x 550x 550x 548x 548x 547x 547x 546x 546x 544x 544x 541x 541x 538x 538x 534x 531x 531x 507x 499x 499x 470x 470x 454x 529x 529x 441x 2x 28x 28x 27x 27x 8x 8x 6x 6x 3x 3x 3x 2x | /**
* Expression Unwrapper Utility
*
* Navigates through the C-Next expression tree hierarchy to extract
* inner expressions. The C-Next grammar has a deep expression hierarchy:
*
* expression -> ternary -> or -> and -> equality -> relational ->
* bitwiseOr -> bitwiseXor -> bitwiseAnd -> shift -> additive ->
* multiplicative -> unary -> postfix
*
* This utility extracts inner expressions when they are "simple" (single term
* at each level), returning null if any level has multiple terms (indicating
* a binary operation at that level).
*
* Issue #707: Extracted from CodeGenerator.ts and TypeResolver.ts to
* eliminate code duplication.
*/
import * as Parser from "../../../logic/parser/grammar/CNextParser";
/**
* Utility class for navigating expression tree hierarchy
*/
class ExpressionUnwrapper {
/**
* Navigate from ExpressionContext to ShiftExpressionContext.
* This is the common navigation path shared by getPostfixExpression,
* getUnaryExpression, and getAdditiveExpression.
*
* Returns null if expression has multiple terms at any level above shift.
*/
private static navigateToShift(
ctx: Parser.ExpressionContext,
): Parser.ShiftExpressionContext | null {
const ternary = ctx.ternaryExpression();
const orExprs = ternary.orExpression();
// If it's a ternary (3 orExpressions), we can't get a single expression
if (orExprs.length !== 1) return null;
const or = orExprs[0];
if (or.andExpression().length !== 1) return null;
const and = or.andExpression()[0];
if (and.equalityExpression().length !== 1) return null;
const eq = and.equalityExpression()[0];
if (eq.relationalExpression().length !== 1) return null;
const rel = eq.relationalExpression()[0];
if (rel.bitwiseOrExpression().length !== 1) return null;
const bor = rel.bitwiseOrExpression()[0];
if (bor.bitwiseXorExpression().length !== 1) return null;
const bxor = bor.bitwiseXorExpression()[0];
if (bxor.bitwiseAndExpression().length !== 1) return null;
const band = bxor.bitwiseAndExpression()[0];
if (band.shiftExpression().length !== 1) return null;
return band.shiftExpression()[0];
}
/**
* Navigate from ExpressionContext to UnaryExpressionContext.
* Common helper for getPostfixExpression and getUnaryExpression.
*
* Returns null if expression has multiple terms at any level.
*/
private static navigateToUnary(
ctx: Parser.ExpressionContext,
): Parser.UnaryExpressionContext | null {
const shift = this.navigateToShift(ctx);
if (!shift) return null;
if (shift.additiveExpression().length !== 1) return null;
const add = shift.additiveExpression()[0];
if (add.multiplicativeExpression().length !== 1) return null;
const mult = add.multiplicativeExpression()[0];
if (mult.unaryExpression().length !== 1) return null;
return mult.unaryExpression()[0];
}
/**
* Navigate from ExpressionContext to PostfixExpressionContext.
* Returns null if the expression has multiple terms at any level
* (indicating binary operations).
*
* Use this when you need to access the postfix expression for:
* - Getting the primary expression (identifier, literal)
* - Checking postfix operators (member access, array indexing)
*/
static getPostfixExpression(
ctx: Parser.ExpressionContext,
): Parser.PostfixExpressionContext | null {
const unary = this.navigateToUnary(ctx);
if (!unary?.postfixExpression()) return null;
return unary.postfixExpression()!;
}
/**
* Navigate from ExpressionContext to UnaryExpressionContext.
* Returns null if the expression has multiple terms at any level.
*
* Use this when you need access to unary operators (!, -, ~, etc.)
*/
static getUnaryExpression(
ctx: Parser.ExpressionContext,
): Parser.UnaryExpressionContext | null {
return this.navigateToUnary(ctx);
}
/**
* Navigate from ExpressionContext to AdditiveExpressionContext.
* Returns null if the expression has multiple terms at outer levels.
*
* Use this when you need to check for additive operations (+, -)
*/
static getAdditiveExpression(
ctx: Parser.ExpressionContext,
): Parser.AdditiveExpressionContext | null {
const shift = this.navigateToShift(ctx);
if (!shift) return null;
Iif (shift.additiveExpression().length !== 1) return null;
return shift.additiveExpression()[0];
}
/**
* Extract a simple identifier from an expression.
* Returns the identifier name if the expression is a simple variable
* reference with no postfix operators (member access, indexing).
* Returns null for complex expressions.
*
* Use this for cases like:
* - Checking if an expression is a specific variable
* - Parameter lookup
* - Simple variable references
*/
static getSimpleIdentifier(ctx: Parser.ExpressionContext): string | null {
const postfix = this.getPostfixExpression(ctx);
if (!postfix) return null;
const ops = postfix.postfixOp();
// Must have no postfix operations (no member access, no indexing)
if (ops.length !== 0) return null;
const primary = postfix.primaryExpression();
const id = primary.IDENTIFIER();
return id ? id.getText() : null;
}
/**
* Check if an expression is a simple identifier (variable reference).
* Convenience method for boolean checks.
*/
static isSimpleIdentifier(ctx: Parser.ExpressionContext): boolean {
return this.getSimpleIdentifier(ctx) !== null;
}
}
export default ExpressionUnwrapper;
|