All files / transpiler/output/codegen/helpers IntegerLiteralValidator.ts

100% Statements 12/12
100% Branches 6/6
100% Functions 3/3
100% Lines 12/12

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                                                                          11x                 17x                                         7x 1x     6x   6x 6x   4x     2x 2x       4x     4x            
/**
 * IntegerLiteralValidator - Validates integer literals and type conversions
 *
 * Issue #696: Extracted from CodeGenerator to reduce cognitive complexity.
 *
 * Handles:
 * - Checking if an expression is an integer literal
 * - Validating literals fit in target type
 * - Validating type conversions for narrowing/sign
 */
 
import LiteralUtils from "../../../../utils/LiteralUtils.js";
 
/**
 * Dependencies for validation operations.
 */
interface IValidatorDeps {
  /** Check if a type name is an integer type */
  isIntegerType: (typeName: string) => boolean;
  /** Validate that a literal value fits in the target type */
  validateLiteralFitsType: (literal: string, typeName: string) => void;
  /** Get the inferred type of an expression */
  getExpressionType: (exprText: string) => string | null;
  /** Validate type conversion for narrowing/sign changes */
  validateTypeConversion: (
    targetType: string,
    sourceType: string | null,
  ) => void;
}
 
/**
 * Validates integer literals and type conversions for variable initialization.
 */
class IntegerLiteralValidator {
  private readonly deps: IValidatorDeps;
 
  constructor(deps: IValidatorDeps) {
    this.deps = deps;
  }
 
  /**
   * Check if the given text is an integer literal.
   *
   * Uses LiteralUtils to check for decimal, hex, and binary formats.
   */
  isIntegerLiteral(text: string): boolean {
    return LiteralUtils.parseIntegerLiteral(text) !== undefined;
  }
 
  /**
   * Validate an expression being assigned to an integer type.
   *
   * If the expression is a literal, validates it fits in the type.
   * Otherwise, validates the type conversion.
   *
   * @param typeName - The target type name
   * @param exprText - The expression text
   * @param line - Source line for error messages
   * @param col - Source column for error messages
   * @throws Error with location if validation fails
   */
  validateIntegerAssignment(
    typeName: string,
    exprText: string,
    line: number,
    col: number,
  ): void {
    if (!this.deps.isIntegerType(typeName)) {
      return;
    }
 
    const trimmedExpr = exprText.trim();
 
    try {
      if (this.isIntegerLiteral(trimmedExpr)) {
        // Direct literal - validate it fits in the target type
        this.deps.validateLiteralFitsType(trimmedExpr, typeName);
      } else {
        // Not a literal - check for narrowing/sign conversions
        const sourceType = this.deps.getExpressionType(exprText);
        this.deps.validateTypeConversion(typeName, sourceType);
      }
    } catch (validationError) {
      const msg =
        validationError instanceof Error
          ? validationError.message
          : String(validationError);
      throw new Error(`${line}:${col} ${msg}`, { cause: validationError });
    }
  }
}
 
export default IntegerLiteralValidator;