All files / PARSE/3-Declare/cnext/collectors EnumCollector.ts

100% Statements 10/10
100% Branches 2/2
100% Functions 1/1
100% Lines 10/10

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                                                                            388x 388x   388x             388x 388x   388x 863x   863x 863x                                 388x                                        
/**
 * EnumCollector - Extracts enum type declarations from parse trees.
 * ADR-017: Enums provide named integer constants with auto-increment support.
 *
 * Produces TType-based IEnumSymbol with proper IScopeSymbol references.
 */
 
import * as Parser from "../../../2-Parse/grammar/CNextParser";
import ESourceLanguage from "../../../../utils/types/ESourceLanguage";
import IEnumSymbol from "../../../../types/symbols/IEnumSymbol";
import ConstExprLowering from "../../../../utils/ConstExprLowering";
import ScopeUtils from "../../../../utils/ScopeUtils";
import TVisibility from "../../../../types/TVisibility";
import ParserUtils from "../../../../utils/ParserUtils";
import type IEnumMemberSymbol from "../../../../types/symbols/IEnumMemberSymbol";
import MemberSymbolBase from "../utils/MemberSymbolBase";
 
class EnumCollector {
  /**
   * Collect an enum declaration and return an IEnumSymbol.
   *
   * @param ctx The enum declaration context
   * @param sourceFile Source file path
   * @param scopePath The path of the scope this enum belongs to (dotted path, "" at file scope)
   * @param visibility ADR-016 visibility as declared (#1300)
   * @returns The enum symbol with proper scope reference. Each member's value
   *          is recorded as WRITTEN, and its number is left to 1.4 Resolve:
   *          a value may name a const or an earlier member (ADR-017 "Member
   *          Values"), and those settle across the whole program (#1669). A
   *          value 1.4 cannot settle, a negative one, or one outside `i32` is
   *          2.1 Analyze's to report.
   */
  static collect(
    ctx: Parser.EnumDeclarationContext,
    sourceFile: string,
    scopePath: string,
    visibility: TVisibility,
  ): IEnumSymbol {
    const name = ctx.IDENTIFIER().getText();
    const span = ParserUtils.getSpan(ctx);
 
    const members = new Map<string, IEnumMemberSymbol>();
 
    // #1318: a member's identity hangs off the ENUM's source-spelled name, not
    // the enclosing scope's. `identityOf` then yields the identifier codegen
    // already emits -- EColor__RED, and Motor__EMode__HIGH for a scope-declared
    // enum, because fromParts expands the dotted component. Derived here once
    // rather than at each consumer (#1285).
    const identity = ScopeUtils.identityOf({ name, scopePath });
    const enumScopedName = identity.cnxScopedName;
 
    for (const member of ctx.enumMember()) {
      const memberName = member.IDENTIFIER().getText();
 
      const valueExpression = member.expression();
      members.set(memberName, {
        ...MemberSymbolBase.of({
          kind: "enum_member" as const,
          name: memberName,
          parentScopedName: enumScopedName,
          memberCtx: member,
          parentSpan: span,
          sourceFile,
          visibility,
        }),
        valueExpr: valueExpression
          ? ConstExprLowering.lower(valueExpression)
          : null,
        value: null,
      });
    }
 
    return {
      kind: "enum",
      name,
      scopePath,
      // #1285: identity computed once, from the scope chain, not
      // re-derived by every consumer.
      // #1318 review: the same identity the members were keyed by, not a
      // second call with the same arguments -- change one and the members
      // would keep the old parent name while this reported the new one.
      ...identity,
      sourceFile,
      span,
      sourceLanguage: ESourceLanguage.CNext,
      visibility,
      members,
    };
  }
}
 
export default EnumCollector;