All files / utils LiteralUtils.ts

100% Statements 26/26
97.22% Branches 35/36
100% Functions 3/3
100% Lines 26/26

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                                                        47x     47x 24x       23x 5x       18x 5x       13x 5x       8x 3x                 5x 3x               2x                     24x 5x       19x 19x                                 1070x     1070x 600x       470x 60x       410x 17x     393x          
/**
 * Utility class for analyzing literal values in the parse tree.
 *
 * Extracted from DivisionByZeroAnalyzer and FloatModuloAnalyzer
 * to eliminate duplicate literal checking code.
 */
 
import * as Parser from "../transpiler/logic/parser/grammar/CNextParser";
 
/**
 * Static utility methods for literal analysis
 */
class LiteralUtils {
  /**
   * Check if a literal represents zero.
   *
   * Handles all C-Next literal formats:
   * - Integer: 0
   * - Hex: 0x0, 0X0
   * - Binary: 0b0, 0B0
   * - Suffixed decimal: 0u8, 0i32, etc.
   * - Suffixed hex: 0x0u8, 0x0i32, etc.
   * - Suffixed binary: 0b0u8, 0b0i32, etc.
   *
   * @param ctx - The literal context from the parse tree
   * @returns true if the literal is zero
   */
  static isZero(ctx: Parser.LiteralContext): boolean {
    const text = ctx.getText();
 
    // Integer literal: exactly "0"
    if (ctx.INTEGER_LITERAL()) {
      return text === "0";
    }
 
    // Hex literal: 0x0 or 0X0
    if (ctx.HEX_LITERAL()) {
      return text === "0x0" || text === "0X0";
    }
 
    // Binary literal: 0b0 or 0B0
    if (ctx.BINARY_LITERAL()) {
      return text === "0b0" || text === "0B0";
    }
 
    // Suffixed decimal: 0u8, 0i32, etc.
    if (ctx.SUFFIXED_DECIMAL()) {
      return text.startsWith("0u") || text.startsWith("0i");
    }
 
    // Suffixed hex: 0x0u8, 0x0i32, etc.
    if (ctx.SUFFIXED_HEX()) {
      return (
        text.startsWith("0x0u") ||
        text.startsWith("0x0i") ||
        text.startsWith("0X0u") ||
        text.startsWith("0X0i")
      );
    }
 
    // Suffixed binary: 0b0u8, 0b0i32, etc.
    if (ctx.SUFFIXED_BINARY()) {
      return (
        text.startsWith("0b0u") ||
        text.startsWith("0b0i") ||
        text.startsWith("0B0u") ||
        text.startsWith("0B0i")
      );
    }
 
    return false;
  }
 
  /**
   * Check if a literal is a floating-point number.
   *
   * @param ctx - The literal context from the parse tree
   * @returns true if the literal is a float
   */
  static isFloat(ctx: Parser.LiteralContext): boolean {
    // Check for FLOAT_LITERAL token
    if (ctx.FLOAT_LITERAL()) {
      return true;
    }
 
    // Fallback: check text for decimal point (not in strings)
    const text = ctx.getText();
    return text.includes(".") && !text.startsWith('"');
  }
 
  /**
   * Parse an integer literal string to a numeric value.
   *
   * Handles all C-Next integer formats:
   * - Decimal: 42, -17
   * - Hex: 0x2A, 0X2a
   * - Binary: 0b101010, 0B101010
   *
   * Issue #455: Used for resolving const values in array dimensions.
   *
   * @param text - The literal text to parse
   * @returns The numeric value, or undefined if not a valid integer literal
   */
  static parseIntegerLiteral(text: string): number | undefined {
    const trimmed = text.trim();
 
    // Decimal integer (including negative)
    if (/^-?\d+$/.test(trimmed)) {
      return Number.parseInt(trimmed, 10);
    }
 
    // Hex literal (0x or 0X prefix)
    if (/^0[xX][0-9a-fA-F]+$/.test(trimmed)) {
      return Number.parseInt(trimmed, 16);
    }
 
    // Binary literal (0b or 0B prefix)
    if (/^0[bB][01]+$/.test(trimmed)) {
      return Number.parseInt(trimmed.substring(2), 2);
    }
 
    return undefined;
  }
}
 
export default LiteralUtils;