All files / utils CExpression.ts

95% Statements 19/20
95% Branches 19/20
100% Functions 2/2
100% Lines 17/17

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                                162x                 162x 162x 162x 1417x 1417x 18x 7x 1399x 7x 1392x 81x 1311x 81x 1230x 10x     152x          
/**
 * Generated C, read as text: whether an expression is one operand as it
 * stands, or needs parentheses to be one where it meets a tighter operator.
 *
 * The one home for that decision (#1760 second review). A C cast and a
 * bit write's mask each spliced an expression beside an operator: the cast
 * as `(float)x << 1`, which shifted a float, and the mask as `a | b & mask`,
 * which wrote bits outside the range. Each had or needed its own check.
 */
class CExpression {
  /**
   * `expr` as one operand: parenthesized when it has an operator outside
   * brackets and literals, as it stands otherwise, so an operand that is
   * already one (a name, a call, a literal) is not wrapped
   */
  static operand(expr: string): string {
    return CExpression.hasOperator(expr) ? `(${expr})` : expr;
  }
 
  /**
   * Whether generated C has an operator outside brackets and literals. The
   * generator spaces every binary and ternary operator, and nothing else at
   * that depth, so such a space is one.
   */
  private static hasOperator(expr: string): boolean {
    let depth = 0;
    let quote: string | null = null;
    for (let i = 0; i < expr.length; i++) {
      const ch = expr[i];
      if (quote !== null) {
        Iif (ch === "\\") i++;
        else if (ch === quote) quote = null;
      } else if (ch === '"' || ch === "'") {
        quote = ch;
      } else if ("([{".includes(ch)) {
        depth++;
      } else if (")]}".includes(ch)) {
        depth--;
      } else if (depth === 0 && /\s/.test(ch)) {
        return true;
      }
    }
    return false;
  }
}
 
export default CExpression;