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

100% Statements 24/24
80.76% Branches 21/26
100% Functions 7/7
100% Lines 24/24

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                                        2x 1x   1x               5x 5x                 11x 3x                               3x 1x   2x             9x                           8x 3x               5x   5x 8x     8x 8x     8x   8x 8x   8x                                 11x 11x                      
/**
 * Helper utilities for generating array access code.
 * Extracted from CodeGenerator to improve testability.
 */
import IArrayAccessInfo from "../types/IArrayAccessInfo";
import IArrayAccessDeps from "../types/IArrayAccessDeps";
import BitRangeHelper from "./BitRangeHelper";
import CodeGenErrors from "./CodeGenErrors";
 
/**
 * Helper class for array access code generation.
 * Works with an intermediate representation (IArrayAccessInfo)
 * instead of ANTLR parser contexts for testability.
 */
class ArrayAccessHelper {
  /**
   * Generate the complete array access expression.
   * Routes to single-index or bit-range based on accessType.
   */
  static generate(info: IArrayAccessInfo, deps: IArrayAccessDeps): string {
    if (info.accessType === "single-index") {
      return ArrayAccessHelper.generateSingleIndex(info);
    }
    return ArrayAccessHelper.generateBitRange(info, deps);
  }
 
  /**
   * Generate single-index access: array[i]
   * Validates that bitmap types don't use bracket notation.
   */
  static generateSingleIndex(info: IArrayAccessInfo): string {
    ArrayAccessHelper.validateNotBitmap(info);
    return `${info.resolvedName}[${info.indexExpr}]`;
  }
 
  /**
   * Validate bitmap access is not using bracket notation.
   * Bitmaps must use named field access (e.g., flags.FIELD_NAME).
   * @throws Error if attempting bracket indexing on a bitmap type
   */
  static validateNotBitmap(info: IArrayAccessInfo): void {
    if (info.typeInfo?.isBitmap && info.typeInfo.bitmapTypeName) {
      throw CodeGenErrors.bitmapBracketIndexing(
        info.line,
        info.typeInfo.bitmapTypeName,
        info.rawName,
      );
    }
  }
 
  /**
   * Generate bit range access: value[start, width]
   * Handles both integer and float types.
   */
  static generateBitRange(
    info: IArrayAccessInfo,
    deps: IArrayAccessDeps,
  ): string {
    if (ArrayAccessHelper.isFloatBitRange(info.typeInfo)) {
      return ArrayAccessHelper.generateFloatBitRange(info, deps);
    }
    return ArrayAccessHelper.generateIntegerBitRange(info, deps);
  }
 
  /**
   * Determine if this is a float bit range (needs shadow variable).
   */
  static isFloatBitRange(typeInfo: { baseType?: string } | undefined): boolean {
    return typeInfo?.baseType === "f32" || typeInfo?.baseType === "f64";
  }
 
  /**
   * Generate float bit range read with union-based type punning.
   * Uses union { float f; uint32_t u; } for MISRA 21.15 compliance.
   *
   * NOTE: This helper is not used in production (PostfixExpressionGenerator
   * handles float bit access directly). It exists for testing and completeness.
   */
  static generateFloatBitRange(
    info: IArrayAccessInfo,
    deps: IArrayAccessDeps,
  ): string {
    if (!deps.isInFunctionBody()) {
      throw CodeGenErrors.floatBitIndexingAtGlobalScope(
        info.rawName,
        info.startExpr ?? "0",
        info.widthExpr ?? "0",
      );
    }
 
    // No string.h needed - uses union-based type punning
    deps.requireInclude("float_static_assert");
 
    const isF64 = info.typeInfo?.baseType === "f64";
    const shadowType = BitRangeHelper.getShadowType(
      info.typeInfo?.baseType ?? "f32",
    );
    const shadowName = BitRangeHelper.getShadowVarName(info.rawName);
    const mask = deps.generateBitMask(info.widthExpr ?? "0", isF64);
 
    // Register shadow variable if not already declared
    deps.registerFloatShadow(shadowName, shadowType);
 
    const shadowIsCurrent = deps.isShadowCurrent(shadowName);
    deps.markShadowCurrent(shadowName);
 
    return BitRangeHelper.buildFloatBitReadExpr({
      shadowName,
      varName: info.resolvedName,
      start: info.startExpr ?? "0",
      mask,
      shadowIsCurrent,
    });
  }
 
  /**
   * Generate integer bit range read: ((value >> start) & mask)
   * Passes sourceType and targetType to BitRangeHelper for MISRA 10.3 casts.
   */
  static generateIntegerBitRange(
    info: IArrayAccessInfo,
    deps: IArrayAccessDeps,
  ): string {
    const mask = deps.generateBitMask(info.widthExpr ?? "0");
    return BitRangeHelper.buildIntegerBitReadExpr({
      varName: info.resolvedName,
      start: info.startExpr ?? "0",
      mask,
      sourceType: info.typeInfo?.baseType,
      targetType: info.targetType,
    });
  }
}
 
export default ArrayAccessHelper;