All files / utils BareIdentifier.ts

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

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                                                                  50x           407x          
/**
 * BareIdentifier - is this rendered text one identifier, or an expression?
 *
 * Codegen and the analyzers both work with text that has already been rendered
 * or lifted out of the parse tree, and both repeatedly need the same thing
 * before they can treat it as a name: proof that it IS a name. `person.name`,
 * `a + b`, `"literal"` and `f()` all arrive as strings in the same slot as
 * `count`, and only the last one can be handed to a symbol lookup.
 *
 * The test was written out five times -- `CodeGenerator` and `EnumTypeResolver`
 * inline, `NullCheckAnalyzer` inline in pass 2.1, and `StringOperationsHelper`
 * and `ArrayDimensionParser` each as a private constant under a DIFFERENT name
 * (`IDENTIFIER_REGEX`, `IDENTIFIER_RE`). Two independent namings of one
 * predicate is the tell that it kept being re-derived rather than found.
 *
 * It lives in `utils/` because it has to: `output/` may not import
 * `1-Analyze` -- depcruise makes that edge an error, transitively -- and three
 * of the five sites sit on opposite sides of that line. `CompositeType`, the
 * one composite typing both passes read, lives here for the same reason.
 *
 * NOT a validity check for a name a user may declare. `ReservedCnxName` owns
 * that, and it rejects names this accepts (`cnx_tmp0` matches here and is
 * E0202 there). This answers only "is this text shaped like a single
 * identifier", which is what a caller needs before asking anyone about it.
 */
class BareIdentifier {
  /**
   * The C identifier shape: a letter or underscore, then word characters.
   *
   * Deliberately not anchored to the grammar's IDENTIFIER token at runtime --
   * every caller holds text, not a token, and the point is to reject text that
   * was never one identifier to begin with.
   */
  private static readonly SHAPE = /^[a-zA-Z_]\w*$/;
 
  /**
   * True when `text` is exactly one identifier, with nothing else in it.
   */
  static matches(text: string): boolean {
    return BareIdentifier.SHAPE.test(text);
  }
}
 
export default BareIdentifier;