All files / transpiler/logic/symbols/cnext/utils TypeUtils.ts

87.5% Statements 28/32
82.14% Branches 23/28
100% Functions 5/5
90% Lines 27/30

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                                                48x 48x                             2809x 9x 9x         2800x 7x       2793x 7x 14x       2786x 306x       2480x 1325x       1155x 48x     1107x                                 2809x       2809x 105x 105x 105x                 2704x 2704x 1597x       1107x                   85x          
/**
 * TypeUtils - Utilities for extracting and converting C-Next types.
 */
 
import * as Parser from "../../../parser/grammar/CNextParser";
import CNEXT_TO_C_TYPE_MAP from "../../../../../utils/constants/TypeMappings";
 
/**
 * Common interface for type contexts that share the same type accessors.
 * Both TypeContext and ArrayTypeContext have these methods.
 */
interface ITypeAccessors {
  primitiveType(): Parser.PrimitiveTypeContext | null;
  userType(): Parser.UserTypeContext | null;
  stringType(): Parser.StringTypeContext | null;
  scopedType(): Parser.ScopedTypeContext | null;
  qualifiedType(): Parser.QualifiedTypeContext | null;
  globalType(): Parser.GlobalTypeContext | null;
}
 
/**
 * Resolve string type with optional capacity.
 */
function resolveStringType(stringCtx: Parser.StringTypeContext): string {
  const intLiteral = stringCtx.INTEGER_LITERAL();
  return intLiteral ? `string<${intLiteral.getText()}>` : "string";
}
 
/**
 * Dispatch type resolution for contexts that share common type accessors.
 * Handles scoped, qualified, global, primitive, string, and user types.
 * Used by both bare type contexts and array element type contexts.
 *
 * @returns The resolved type name, or null if no matching type accessor found
 */
function dispatchTypeResolution(
  accessors: ITypeAccessors,
  scopeName?: string,
): string | null {
  // Handle this.Type for scoped types (e.g., this.State -> Motor_State)
  if (accessors.scopedType()) {
    const typeName = accessors.scopedType()!.IDENTIFIER().getText();
    return scopeName ? `${scopeName}_${typeName}` : typeName;
  }
 
  // Handle global.Type for global types inside scope
  // global.ECategory -> ECategory (just the type name, no scope prefix)
  if (accessors.globalType()) {
    return accessors.globalType()!.IDENTIFIER().getText();
  }
 
  // Handle Scope.Type from outside scope (e.g., Motor.State -> Motor_State)
  if (accessors.qualifiedType()) {
    const identifiers = accessors.qualifiedType()!.IDENTIFIER();
    return identifiers.map((id) => id.getText()).join("_");
  }
 
  // Handle user-defined types
  if (accessors.userType()) {
    return accessors.userType()!.getText();
  }
 
  // Handle primitive types
  if (accessors.primitiveType()) {
    return accessors.primitiveType()!.getText();
  }
 
  // Handle string types - preserve capacity for validation (Issue #139)
  if (accessors.stringType()) {
    return resolveStringType(accessors.stringType()!);
  }
 
  return null;
}
 
class TypeUtils {
  /**
   * Extract the type name from a type context.
   * Handles scoped types (this.Type), qualified types (Scope.Type),
   * and simple types.
   *
   * @param ctx The type context (may be null)
   * @param scopeName Optional current scope for this.Type resolution
   * @returns The resolved type name
   */
  static getTypeName(
    ctx: Parser.TypeContext | null,
    scopeName?: string,
  ): string {
    Iif (!ctx) return "void";
 
    // Handle arrayType: Type[size] - extract the inner type without dimension
    // The dimension is tracked separately in arrayDimensions
    if (ctx.arrayType()) {
      const result = dispatchTypeResolution(ctx.arrayType()!, scopeName);
      Eif (result !== null) {
        return result;
      }
      // Fallback for unrecognized array types - strip the dimension part
      const text = ctx.arrayType()!.getText();
      const bracketIdx = text.indexOf("[");
      return bracketIdx > 0 ? text.substring(0, bracketIdx) : text;
    }
 
    // Non-array types - dispatch directly
    const result = dispatchTypeResolution(ctx, scopeName);
    if (result !== null) {
      return result;
    }
 
    // Fallback
    return ctx.getText();
  }
 
  /**
   * Convert a C-Next type name to its C equivalent.
   *
   * @param typeName The C-Next type name
   * @returns The C type name
   */
  static cnextTypeToCType(typeName: string): string {
    return CNEXT_TO_C_TYPE_MAP[typeName] ?? typeName;
  }
}
 
export default TypeUtils;