All files / src/abap/1_lexer/tokens abstract_token.ts

93.93% Statements 62/66
94.11% Branches 16/17
100% Functions 6/6
93.93% Lines 62/66

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 671x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1984358x 1984358x 462x 462x 1983896x 1984358x 1963673x 1963673x 1984358x     1984358x 1984358x 1984358x 1984358x 1x 1x 1x 1x 1x 1x 1x 1x 1x 992179x 992179x 992179x 992179x 418x 418x 992179x 1x 1x 1x     1x 1x 11681406x 11681406x 1x 1x 7466675x 7466675x 1x 1x 397754x 397754x 1x 1x 113245x 113245x 1x  
import {Position} from "../../../position";
import {VirtualPosition} from "../../../virtual_position";
 
// token strings repeat a lot across files (keywords, common names, upper cased copies), share them.
// Longer strings are typically comments or text literals, not worth sharing
const INTERN_MAX_LENGTH = 30;
// bound the table, it lives for the lifetime of the process
const INTERN_MAX_ENTRIES = 100000;
// V8 represents substrings of this length or longer as slices that reference the full source,
// these are flattened before being stored, so the table does not keep removed files alive
const SLICED_MIN_LENGTH = 13;
let interned = new Map<string, string>();
 
function intern(str: string): string {
  if (str.length > INTERN_MAX_LENGTH) {
    return str;
  }
  const found = interned.get(str);
  if (found !== undefined) {
    return found;
  }
  if (interned.size >= INTERN_MAX_ENTRIES) {
    interned = new Map<string, string>();
  }
  const copy = str.length >= SLICED_MIN_LENGTH ? str.split("").join("") : str;
  interned.set(copy, copy);
  return copy;
}
 
// the token is its own start position, saves a separate Position object per token
export abstract class AbstractToken extends Position {
  private readonly str: string;
  private readonly strUpper: string;
  // only assigned for tokens from macro expansion, so other tokens don't pay for the field
  private readonly virtual?: VirtualPosition;
 
  public constructor(start: Position, str: string) {
    super(start.getRow(), start.getCol());
    this.str = intern(str);
    this.strUpper = intern(str.toUpperCase());
    if (start instanceof VirtualPosition) {
      this.virtual = start;
    }
  }
 
  // special function, for debugging purposes, see https://github.com/abaplint/abaplint/pull/3137
  public [Symbol.for("debug.description")](){
    return `${this.constructor.name} ${this.str}`;
  }
 
  public getStr(): string {
    return this.str;
  }
 
  public getUpperStr(): string {
    return this.strUpper;
  }
 
  public getStart(): Position {
    return this.virtual ?? this;
  }
 
  public getEnd(): Position {
    return new Position(this.getRow(), this.getCol() + this.str.length);
  }
}