class RawTok {
    private final String stringVal;
    private final TokenKind kind;
    private final int pos;
    private final int endPos;

    RawTok(String stringVal, TokenKind kind, int pos, int endPos) {
      checkElementIndex(pos, endPos, "pos");
      checkArgument(pos < endPos, "expected pos (%s) < endPos (%s)", pos, endPos);
      this.stringVal = stringVal;
      this.kind = kind;
      this.pos = pos;
      this.endPos = endPos;
    }

    /** The token kind, or {@code null} for whitespace and comments. */
    public TokenKind kind() {
      return kind;
    }

    /** The start position. */
    public int pos() {
      return pos;
    }

    /** The end position. */
    public int endPos() {
      return endPos;
    }

    /** The escaped string value of a literal, or {@code null} for other tokens. */
    public String stringVal() {
      return stringVal;
    }
  }

  private static final TokenKind STRINGFRAGMENT =
      stream(TokenKind.values())
          .filter(t -> t.name().contentEquals("STRINGFRAGMENT"))
          .findFirst()
          .orElse(null);

  static boolean isStringFragment(TokenKind kind) {
    return STRINGFRAGMENT != null && Objects.equals(kind, STRINGFRAGMENT);
  }

  private static ImmutableList<Token> readAllTokens(
      String source, Context context, Set<Integer> nonTerminalStringFragments) {<FILL_FUNCTION_BODY>

    if (source == null) {
      return ImmutableList.of();
    }
    ScannerFactory fac = ScannerFactory.instance(context);
    char[] buffer = (source + EOF_COMMENT).toCharArray();
    Scanner scanner =
        new AccessibleScanner(fac, new CommentSavingTokenizer(fac, buffer, buffer.length));
    List<Token> tokens = new ArrayList<>();
    do {
      scanner.nextToken();
      tokens.add(scanner.token());
    } while (scanner.token().kind != TokenKind.EOF);
    for (int i = 0; i < tokens.size(); i++) {
      if (isStringFragment(tokens.get(i).kind)) {
        int start = i;
        while (isStringFragment(tokens.get(i).kind)) {
          i++;
        }
        for (int j = start; j < i - 1; j++) {
          nonTerminalStringFragments.add(tokens.get(j).pos);
        }
      }
    }
    // A string template is tokenized as a series of STRINGFRAGMENT tokens containing the string
    // literal values, followed by the tokens for the template arguments. For the formatter, we
    // want the stream of tokens to appear in order by their start position.
    if (Runtime.version().feature() >= 21) {
      Collections.sort(tokens, Comparator.comparingInt(t -> t.pos));
    }
    return ImmutableList.copyOf(tokens);
  
<no_super_class>