All files / transpiler/logic/symbols/cnext/collectors RegisterCollector.ts

100% Statements 18/18
83.33% Branches 5/6
100% Functions 1/1
100% Lines 18/18

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                                                                        32x 32x           32x     32x   32x 61x 61x 61x     61x 61x       61x   61x 4x 57x 17x     61x             61x     32x                                    
/**
 * RegisterCollector - Extracts register block declarations from parse trees.
 * Registers provide typed access to memory-mapped I/O locations.
 *
 * Produces TType-based IRegisterSymbol with proper IScopeSymbol references.
 */
 
import * as Parser from "../../../parser/grammar/CNextParser";
import ESourceLanguage from "../../../../../utils/types/ESourceLanguage";
import IRegisterSymbol from "../../../../types/symbols/IRegisterSymbol";
import IRegisterMemberInfo from "../../../../types/symbols/IRegisterMemberInfo";
import IScopeSymbol from "../../../../types/symbols/IScopeSymbol";
import TypeUtils from "../utils/TypeUtils";
import ScopeUtils from "../../../../../utils/ScopeUtils";
 
/** Access mode type for register members */
type TAccessMode = "rw" | "ro" | "wo" | "w1c" | "w1s";
 
class RegisterCollector {
  /**
   * Collect a register declaration and return an IRegisterSymbol.
   *
   * @param ctx The register declaration context
   * @param sourceFile Source file path
   * @param knownBitmaps Set of known bitmap type names for reference resolution
   * @param scope The scope this register belongs to (IScopeSymbol)
   * @param isScopeType ADR-057 predicate: is this *qualified* name a scope type?
   * @returns The register symbol with proper scope reference
   */
  static collect(
    ctx: Parser.RegisterDeclarationContext,
    sourceFile: string,
    knownBitmaps: Set<string>,
    scope: IScopeSymbol,
    isScopeType?: (qualifiedName: string) => boolean,
  ): IRegisterSymbol {
    const name = ctx.IDENTIFIER().getText();
    const line = ctx.start?.line ?? 0;
    // #1285: the scope REFERENCE flows on from here. Flattening it to its
    // leaf name was the choke point that made every downstream qualification
    // one level deep, whatever the chain actually was.
 
    // Get base address
    const baseAddress = ctx.expression().getText();
 
    // Collect register members
    const members = new Map<string, IRegisterMemberInfo>();
 
    for (const member of ctx.registerMember()) {
      const memberName = member.IDENTIFIER().getText();
      const offset = member.expression().getText();
      const accessMod = member.accessModifier().getText() as TAccessMode;
 
      // Get member type and convert to C type
      const typeName = TypeUtils.getTypeName(member.type(), scope, isScopeType);
      const cType = TypeUtils.cnextTypeToCType(typeName);
 
      // Check if member type is a bitmap
      // Try both scoped name and plain name for bitmap lookup
      const scopedTypeName = ScopeUtils.qualifyInScope(typeName, scope);
      let bitmapType: string | undefined;
      if (knownBitmaps.has(scopedTypeName)) {
        bitmapType = scopedTypeName;
      } else if (knownBitmaps.has(typeName)) {
        bitmapType = typeName;
      }
 
      const memberInfo: IRegisterMemberInfo = {
        offset,
        cType,
        access: accessMod,
        bitmapType,
      };
 
      members.set(memberName, memberInfo);
    }
 
    return {
      kind: "register",
      name,
      scope,
      // #1285: identity computed once, from the scope chain, not
      // re-derived by every consumer.
      ...ScopeUtils.identityOf({ name, scope }),
      sourceFile,
      sourceLine: line,
      sourceLanguage: ESourceLanguage.CNext,
      isExported: true,
      baseAddress,
      members,
    };
  }
}
 
export default RegisterCollector;