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

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

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                                                                72x 72x 72x   72x 92x 80x             80x   12x           87x     67x                         80x 80x 80x                     12x   10x 10x     2x   1x 1x 1x       1x          
/**
 * Postfix Chain Builder
 *
 * Processes postfix operations (member access, array subscript, bit range)
 * in assignment target chains.
 *
 * Extracted from CodeGenerator.doGenerateAssignmentTarget to reduce
 * cognitive complexity.
 */
 
import IPostfixChainDeps from "../types/IPostfixChainDeps";
import IPostfixOperation from "../types/IPostfixOperation";
 
/**
 * Static utility for building postfix operation chains
 */
class PostfixChainBuilder {
  /**
   * Process a chain of postfix operations and build the result string
   *
   * @param baseResult The starting string (base identifier)
   * @param firstId The first identifier in the chain (for register detection)
   * @param operations Array of postfix operations to process
   * @param deps Dependencies for expression generation and separator resolution
   * @returns The complete result string with all postfix operations applied
   */
  static build(
    baseResult: string,
    firstId: string,
    operations: IPostfixOperation[],
    deps: IPostfixChainDeps,
  ): string {
    let result = baseResult;
    const identifierChain: string[] = [firstId];
    let isFirstOp = true;
 
    for (const op of operations) {
      if (op.memberName) {
        result = PostfixChainBuilder.processMemberAccess(
          result,
          op.memberName,
          identifierChain,
          isFirstOp,
          deps,
        );
        identifierChain.push(op.memberName);
      } else {
        result = PostfixChainBuilder.processSubscript(
          result,
          op.expressions,
          deps,
        );
      }
      isFirstOp = false;
    }
 
    return result;
  }
 
  /**
   * Process a member access operation (.identifier)
   */
  private static processMemberAccess(
    result: string,
    memberName: string,
    identifierChain: string[],
    isFirstOp: boolean,
    deps: IPostfixChainDeps,
  ): string {
    const chainWithMember = [...identifierChain, memberName];
    const separator = deps.getSeparator(isFirstOp, chainWithMember, memberName);
    return `${result}${separator}${memberName}`;
  }
 
  /**
   * Process a subscript operation ([expr] or [expr, expr])
   */
  private static processSubscript(
    result: string,
    expressions: unknown[],
    deps: IPostfixChainDeps,
  ): string {
    if (expressions.length === 1) {
      // Single subscript: array access or single bit
      const indexExpr = deps.generateExpression(expressions[0]);
      return `${result}[${indexExpr}]`;
    }
 
    if (expressions.length === 2) {
      // Bit range: [start, width]
      const start = deps.generateExpression(expressions[0]);
      const width = deps.generateExpression(expressions[1]);
      return `${result}[${start}, ${width}]`;
    }
 
    // No expressions - shouldn't happen, but handle gracefully
    return result;
  }
}
 
export default PostfixChainBuilder;