All files / transpiler/logic/symbols SymbolUtils.ts

100% Statements 21/21
100% Branches 8/8
100% Functions 5/5
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 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 137 138 139 140 141 142 143 144 145 146                        19x                             74x     74x   74x 14x 19x   19x 19x   18x     1x         74x                     36x                                                                         36x                   94x             1x                               2x                 19x 19x 19x 19x 19x        
/**
 * Shared utilities for C and C++ symbol collectors.
 * Used by the C collectors in logic/symbols/c/ and C++ collectors in logic/symbols/cpp/.
 */
 
/**
 * Reserved field names that conflict with C-Next built-in properties.
 * These should not be used as struct field names.
 *
 * Note: "length" was removed from this list (ADR-058) since .length is now deprecated.
 * Structs can have fields named "length" without conflict.
 */
const RESERVED_FIELD_NAMES = new Set<string>([]);
 
/**
 * Parse array dimensions from declarator text using regex.
 * Extracts both numeric values and macro names from square bracket notation.
 *
 * Issue #981: Support macro-sized array dimensions like [BUF_SIZE].
 * Without this, struct fields with macro-sized arrays are incorrectly treated
 * as non-arrays, causing bit extraction instead of array access.
 *
 * @param text - The declarator text containing array notation
 * @returns Array of dimension sizes (numbers) or macro names (strings),
 *          e.g., [8] returns [8], [BUF_SIZE] returns ["BUF_SIZE"], [2][N] returns [2, "N"]
 */
function parseArrayDimensions(text: string): (number | string)[] {
  const dimensions: (number | string)[] = [];
  // Match any bracket content: digits, identifiers, or expressions
  // Captures: [8], [BUF_SIZE], [N], [SIZE + 1], etc.
  const arrayMatches = text.match(/\[([^\]]+)\]/g);
 
  if (arrayMatches) {
    for (const match of arrayMatches) {
      const content = match.slice(1, -1).trim();
      // Try to parse as numeric first
      const numericValue = Number.parseInt(content, 10);
      if (!Number.isNaN(numericValue) && String(numericValue) === content) {
        // Pure numeric dimension
        dimensions.push(numericValue);
      } else {
        // Macro name or expression - store as string
        dimensions.push(content);
      }
    }
  }
 
  return dimensions;
}
 
/**
 * Map C/C++ type names to their bit widths.
 * Supports stdint.h types and standard C types commonly used as enum backing types.
 *
 * @param typeName - The C/C++ type name (e.g., "uint8_t", "int", "unsigned long")
 * @returns Bit width (8, 16, 32, 64) or 0 if unknown
 */
function getTypeWidth(typeName: string): number {
  const typeWidths: Record<string, number> = {
    // stdint.h types
    uint8_t: 8,
    int8_t: 8,
    uint16_t: 16,
    int16_t: 16,
    uint32_t: 32,
    int32_t: 32,
    uint64_t: 64,
    int64_t: 64,
    // Standard C types (common sizes)
    char: 8,
    "signed char": 8,
    "unsigned char": 8,
    short: 16,
    "short int": 16,
    "signed short": 16,
    "signed short int": 16,
    "unsigned short": 16,
    "unsigned short int": 16,
    int: 32,
    "signed int": 32,
    unsigned: 32,
    "unsigned int": 32,
    long: 32,
    "long int": 32,
    "signed long": 32,
    "signed long int": 32,
    "unsigned long": 32,
    "unsigned long int": 32,
    "long long": 64,
    "long long int": 64,
    "signed long long": 64,
    "signed long long int": 64,
    "unsigned long long": 64,
    "unsigned long long int": 64,
  };
  return typeWidths[typeName] ?? 0;
}
 
/**
 * Check if a field name is reserved in C-Next.
 *
 * @param fieldName - The field name to check
 * @returns true if the field name conflicts with C-Next built-in properties
 */
function isReservedFieldName(fieldName: string): boolean {
  return RESERVED_FIELD_NAMES.has(fieldName);
}
 
/**
 * Get the list of reserved field names for error messages.
 */
function getReservedFieldNames(): string[] {
  return Array.from(RESERVED_FIELD_NAMES);
}
 
/**
 * Generate a warning message for a reserved field name.
 *
 * @param language - "C" or "C++"
 * @param structName - Name of the struct containing the field
 * @param fieldName - The reserved field name
 * @returns Warning message string
 */
function getReservedFieldWarning(
  language: "C" | "C++",
  structName: string,
  fieldName: string,
): string {
  return (
    `Warning: ${language} header struct '${structName}' has field '${fieldName}' ` +
    `which conflicts with C-Next's .${fieldName} property. ` +
    `Consider renaming the field or be aware that '${structName}.${fieldName}' ` +
    `may not work as expected in C-Next code.`
  );
}
 
class SymbolUtils {
  static readonly parseArrayDimensions = parseArrayDimensions;
  static readonly getTypeWidth = getTypeWidth;
  static readonly isReservedFieldName = isReservedFieldName;
  static readonly getReservedFieldNames = getReservedFieldNames;
  static readonly getReservedFieldWarning = getReservedFieldWarning;
}
 
export default SymbolUtils;