All files / transpiler/output/headers/generators generateStructHeader.ts

100% Statements 23/23
100% Branches 14/14
100% Functions 2/2
100% Lines 22/22

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                      17x                                   35x     35x 2x     33x 33x   33x     33x   60x       60x 60x   60x               60x 60x 3x 3x   3x 2x   1x     57x       33x   33x        
/**
 * Struct Header Generator
 *
 * Generates C typedef struct declarations from symbol information.
 * Used by HeaderGenerator to emit full struct definitions in headers.
 */
 
import IHeaderTypeInput from "./IHeaderTypeInput";
import typeUtils from "./mapType";
import CppNamespaceUtils from "../../../../utils/CppNamespaceUtils";
 
const { mapType } = typeUtils;
 
/**
 * Generate a C typedef struct declaration for the given struct name.
 *
 * Output format (Issue #296: uses named struct for forward declaration compatibility):
 * ```c
 * typedef struct StructName {
 *     uint32_t field1;
 *     uint8_t buffer[256];
 * } StructName;
 * ```
 *
 * @param name - The struct type name
 * @param input - Symbol information containing struct fields
 * @returns C typedef struct declaration, or forward declaration if data unavailable
 */
function generateStructHeader(name: string, input: IHeaderTypeInput): string {
  const fields = input.structFields.get(name);
 
  // Graceful fallback if struct data not available
  if (!fields || fields.size === 0) {
    return `typedef struct ${name} ${name};`;
  }
 
  const dimensions = input.structFieldDimensions.get(name);
  const lines: string[] = [];
  // Issue #296: Use named struct for forward declaration compatibility
  lines.push(`typedef struct ${name} {`);
 
  // Iterate fields in insertion order (Map preserves order)
  for (const [fieldName, fieldType] of fields) {
    // Issue #502/#522: Convert C++ namespace types from _ to :: format using shared utility
    const convertedType = CppNamespaceUtils.convertToCppNamespace(
      fieldType,
      input.symbolTable,
    );
    const cType = mapType(convertedType);
    const dims = dimensions?.get(fieldName);
    const dimSuffix =
      dims && dims.length > 0 ? dims.map((d) => `[${d}]`).join("") : "";
 
    // Issue #461: Handle string<N> types which map to char[N+1]
    // The embedded dimension must come after array dimensions in C syntax
    // Example: string<64> arr[4] -> char arr[4][65], not char[65] arr[4]
    //
    // Fix: When dims already include the string capacity (from StructCollector),
    // use dimSuffix directly. Only extract embedded dim when no dims provided.
    const embeddedMatch = /^(\w+)\[(\d+)\]$/.exec(cType);
    if (embeddedMatch) {
      const baseType = embeddedMatch[1];
      const embeddedDim = embeddedMatch[2];
      // dims already includes string capacity, so just use dimSuffix
      if (dims && dims.length > 0) {
        lines.push(`    ${baseType} ${fieldName}${dimSuffix};`);
      } else {
        lines.push(`    ${baseType} ${fieldName}[${embeddedDim}];`);
      }
    } else {
      lines.push(`    ${cType} ${fieldName}${dimSuffix};`);
    }
  }
 
  lines.push(`} ${name};`);
 
  return lines.join("\n");
}
 
export default generateStructHeader;