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

100% Statements 25/25
100% Branches 18/18
100% Functions 3/3
100% Lines 25/25

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                                                  956x 956x     956x 34x 45x                 956x 12x               956x 14x               956x 8x       956x 16x             956x 6x       956x 2x     956x                       71x 61x   10x                     16x 34x   16x 9x            
/**
 * ChildStatementCollector
 *
 * Collects child statements and blocks from control flow statements.
 * This centralizes recursion patterns to prevent missing nested statements.
 *
 * Issue #566: Extracted from CodeGenerator for improved testability.
 */
 
import * as Parser from "../../../logic/parser/grammar/CNextParser.js";
 
/**
 * Result of collecting child statements and blocks from a statement.
 */
interface IChildStatementResult {
  statements: Parser.StatementContext[];
  blocks: Parser.BlockContext[];
}
 
class ChildStatementCollector {
  /**
   * Collect all child statements and blocks from a control flow statement.
   * Handles if, while, for, do-while, switch, critical, and nested blocks.
   */
  static collectAll(stmt: Parser.StatementContext): IChildStatementResult {
    const statements: Parser.StatementContext[] = [];
    const blocks: Parser.BlockContext[] = [];
 
    // if statement: has statement() children (can be blocks or single statements)
    if (stmt.ifStatement()) {
      for (const childStmt of stmt.ifStatement()!.statement()) {
        ChildStatementCollector._classifyChildStatement(
          childStmt,
          statements,
          blocks,
        );
      }
    }
 
    // while statement: single statement() child
    if (stmt.whileStatement()) {
      ChildStatementCollector._classifyChildStatement(
        stmt.whileStatement()!.statement(),
        statements,
        blocks,
      );
    }
 
    // for statement: single statement() child
    if (stmt.forStatement()) {
      ChildStatementCollector._classifyChildStatement(
        stmt.forStatement()!.statement(),
        statements,
        blocks,
      );
    }
 
    // do-while statement: has block() directly
    if (stmt.doWhileStatement()) {
      blocks.push(stmt.doWhileStatement()!.block());
    }
 
    // switch statement: case blocks and optional default block
    if (stmt.switchStatement()) {
      ChildStatementCollector._collectSwitchChildren(
        stmt.switchStatement()!,
        blocks,
      );
    }
 
    // critical statement: has block() directly (ADR-050)
    if (stmt.criticalStatement()) {
      blocks.push(stmt.criticalStatement()!.block());
    }
 
    // Nested block statement
    if (stmt.block()) {
      blocks.push(stmt.block()!);
    }
 
    return { statements, blocks };
  }
 
  /**
   * Classify a child statement as block or single statement.
   * Blocks are pushed to the blocks array, statements to the statements array.
   */
  private static _classifyChildStatement(
    childStmt: Parser.StatementContext,
    statements: Parser.StatementContext[],
    blocks: Parser.BlockContext[],
  ): void {
    if (childStmt.block()) {
      blocks.push(childStmt.block()!);
    } else {
      statements.push(childStmt);
    }
  }
 
  /**
   * Collect blocks from switch statement cases and default.
   */
  private static _collectSwitchChildren(
    switchStmt: Parser.SwitchStatementContext,
    blocks: Parser.BlockContext[],
  ): void {
    for (const caseCtx of switchStmt.switchCase()) {
      blocks.push(caseCtx.block());
    }
    if (switchStmt.defaultCase()) {
      blocks.push(switchStmt.defaultCase()!.block());
    }
  }
}
 
export default ChildStatementCollector;