All files / utils ReservedCnxName.ts

100% Statements 6/6
100% Branches 0/0
100% Functions 4/4
100% Lines 6/6

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                                                    93x               93x                   1450x                     19x                   3x                   120x          
/**
 * ReservedCnxName - the single source of truth for names the transpiler invents.
 *
 * ADR-063 part 2 reserves the `cnx_` prefix, compared case-insensitively, for
 * every name that corresponds to no user declaration: temporaries, the strlen
 * cache, overflow helpers, include guards. A user identifier may not begin with
 * it (E0202), which is what makes the transpiler's namespace and the user's
 * disjoint.
 *
 * Before this module each family spelled its own convention — `_tmp<N>`,
 * `_<var>_len`, `_cnx_tmp_<N>`, `cnx_clamp_*`, `<BASENAME>_H` — and three of the
 * five chose shapes a user could declare. Issue #1131 verified the consequence:
 * a user global `_msg_len` was shadowed by the generated strlen cache and every
 * later read silently bound to the wrong storage, with a clean `-Wall -Wextra`
 * compile and exit 0. Route all invented names through here.
 *
 * NOT for qualified user names (`Scope__member`). Those are built by
 * QualifiedCName, and the two must not be confused: `__` asserts "qualified user
 * name, component boundary here", which a temporary has no business claiming.
 */
class ReservedCnxName {
  /**
   * The reserved prefix, in the case used for C identifiers.
   *
   * Rejected in user declarations by E0202 (IdentifierSyntaxAnalyzer).
   */
  static readonly PREFIX = "cnx_";
 
  /**
   * The reserved prefix in the case used for macros.
   *
   * Include guards are uppercase by universal C convention, which is why the
   * E0202 comparison is case-insensitive: one rule covers both spellings.
   */
  static readonly MACRO_PREFIX = "CNX_";
 
  /**
   * Whether an identifier sits in the transpiler's reserved namespace.
   *
   * Prefix-only and case-insensitive, exactly as ADR-063 states. `my_cnx_buffer`
   * is legal — a prefix is all that is needed to keep the namespaces disjoint,
   * so that is all this checks.
   */
  static isReserved(identifierName: string): boolean {
    return identifierName.toLowerCase().startsWith(ReservedCnxName.PREFIX);
  }
 
  /**
   * Name for a generated temporary, e.g. `cnx_tmp3`.
   *
   * Replaces the former `_tmp<N>` (slice-assignment unroll) and `_cnx_tmp_<N>`
   * (argument temporary). Both drew from the same counter, so unifying the
   * spelling cannot make two live temporaries collide.
   */
  static temporary(counter: number): string {
    return `${ReservedCnxName.PREFIX}tmp${counter}`;
  }
 
  /**
   * Name for the cached `strlen` of a string variable, e.g. `cnx_len_message`.
   *
   * The variable name is a suffix rather than an infix (the former shape was
   * `_<var>_len`) so that every generated name reads prefix-first.
   */
  static stringLengthCache(variableName: string): string {
    return `${ReservedCnxName.PREFIX}len_${variableName}`;
  }
 
  /**
   * Name for a clamping overflow helper, e.g. `cnx_clamp_add_u8`.
   *
   * This family already conformed before ADR-063 part 2; it is routed through
   * here so the prefix has exactly one definition.
   */
  static clampHelper(operation: string, cnxType: string): string {
    return `${ReservedCnxName.PREFIX}clamp_${operation}_${cnxType}`;
  }
}
 
export default ReservedCnxName;