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

100% Statements 16/16
100% Branches 12/12
100% Functions 5/5
100% Lines 16/16

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                                                                            10x     10x       10x 4x       6x 6x                     19x     19x 9x   10x       19x 6x     13x             8x             9x                   2x          
/**
 * Helper utilities for generating bit range access code.
 * Extracted from CodeGenerator to improve testability.
 */
 
import NarrowingCastHelper from "./NarrowingCastHelper.js";
 
/**
 * Options for generating float bit read expressions.
 */
interface IFloatBitReadOptions {
  shadowName: string;
  varName: string;
  start: string;
  mask: string;
  shadowIsCurrent: boolean;
}
 
/**
 * Options for generating integer bit read expressions.
 */
interface IIntegerBitReadOptions {
  varName: string;
  start: string;
  mask: string;
  sourceType?: string; // Optional: source variable type for cast detection
  targetType?: string; // Optional: target variable type for cast
}
 
/**
 * Helper class for bit range access code generation.
 */
class BitRangeHelper {
  /**
   * Build the bit read expression for floats.
   * Uses memcpy pattern to safely reinterpret float bits.
   */
  static buildFloatBitReadExpr(options: IFloatBitReadOptions): string {
    const { shadowName, varName, start, mask, shadowIsCurrent } = options;
 
    const shiftedRead =
      start === "0"
        ? `(${shadowName} & ${mask})`
        : `((${shadowName} >> ${start}) & ${mask})`;
 
    if (shadowIsCurrent) {
      return shiftedRead;
    }
 
    // Need memcpy to update shadow
    const memcpyPrefix = `memcpy(&${shadowName}, &${varName}, sizeof(${varName}))`;
    return `(${memcpyPrefix}, ${shiftedRead})`;
  }
 
  /**
   * Generate integer bit range read: ((value >> start) & mask)
   * Optimizes away the shift when start is 0.
   *
   * When sourceType and targetType are provided, wraps the expression
   * with MISRA 10.3 compliant cast if needed.
   */
  static buildIntegerBitReadExpr(options: IIntegerBitReadOptions): string {
    const { varName, start, mask, sourceType, targetType } = options;
 
    let expr: string;
    if (start === "0") {
      expr = `((${varName}) & ${mask})`;
    } else {
      expr = `((${varName} >> ${start}) & ${mask})`;
    }
 
    // If target type provided, wrap with MISRA cast if needed
    if (sourceType && targetType) {
      return NarrowingCastHelper.wrap(expr, sourceType, targetType);
    }
 
    return expr;
  }
 
  /**
   * Generate the shadow variable name for float bit access.
   */
  static getShadowVarName(rawName: string): string {
    return `__bits_${rawName}`;
  }
 
  /**
   * Get the shadow type for a float type.
   */
  static getShadowType(baseType: string): string {
    return baseType === "f64" ? "uint64_t" : "uint32_t";
  }
 
  /**
   * Generate a shadow variable declaration.
   */
  static buildShadowDeclaration(
    shadowName: string,
    shadowType: string,
  ): string {
    return `${shadowType} ${shadowName};`;
  }
}
 
export default BitRangeHelper;