scan method

  1. @override
bool scan(
  1. FsharpExternalScannerState state,
  2. TreeSitterExternalLexer lexer,
  3. List<bool> validSymbols
)
override

Implementation

@override
bool scan(
  FsharpExternalScannerState state,
  TreeSitterExternalLexer lexer,
  List<bool> validSymbols,
) {
  bool valid(FsharpExternalToken token) =>
      token.index < validSymbols.length && validSymbols[token.index];
  void emit(FsharpExternalToken token) =>
      lexer.setResultSymbol(symbols[token.index]);

  if (valid(FsharpExternalToken.virtualOpenSection) &&
      valid(FsharpExternalToken.virtualEndSection) &&
      valid(FsharpExternalToken.virtualEndDeclaration)) {
    return false;
  }

  if (state.runback.isNotEmpty &&
      state.runback.last == 0 &&
      valid(FsharpExternalToken.virtualEndDeclaration)) {
    state.runback.removeLast();
    emit(FsharpExternalToken.virtualEndDeclaration);
    return true;
  }
  if (state.runback.isNotEmpty &&
      state.runback.last == 1 &&
      valid(FsharpExternalToken.virtualEndSection)) {
    state.runback.removeLast();
    emit(FsharpExternalToken.virtualEndSection);
    return true;
  }
  state.runback.clear();

  var hasNewline = false;
  lexer.markEnd();
  while (true) {
    if (lexer.lookahead == 0x20) {
      _skip(lexer);
    } else if (lexer.lookahead == 0x0a) {
      _skip(lexer);
      hasNewline = true;
      while (true) {
        if (lexer.lookahead == 0x20) {
          _skip(lexer);
        } else {
          state.indentLength = lexer.column;
          break;
        }
      }
    } else if (lexer.lookahead == 0x0d) {
      _skip(lexer);
    } else if (valid(FsharpExternalToken.virtualEndDeclaration) &&
        lexer.lookahead == 0x3b) {
      _advance(lexer);
      lexer.markEnd();
      emit(FsharpExternalToken.virtualEndDeclaration);
      return true;
    } else if (valid(FsharpExternalToken.virtualEndSection) &&
        (lexer.lookahead == 0x29 ||
            lexer.lookahead == 0x5d ||
            lexer.lookahead == 0x7d)) {
      emit(FsharpExternalToken.virtualEndSection);
      state.indentLengthStack.removeLast();
      return true;
    } else if (valid(FsharpExternalToken.virtualEndSection) &&
        lexer.lookahead == 0x7c) {
      _skip(lexer);
      if (lexer.lookahead == 0x7d || lexer.lookahead == 0x5d) {
        emit(FsharpExternalToken.virtualEndSection);
        state.indentLengthStack.removeLast();
        return true;
      }
    } else if (lexer.isEof) {
      if (valid(FsharpExternalToken.virtualEndSection)) {
        emit(FsharpExternalToken.virtualEndSection);
        return true;
      }
      if (valid(FsharpExternalToken.virtualEndDeclaration)) {
        emit(FsharpExternalToken.virtualEndDeclaration);
        return true;
      }
      break;
    } else {
      break;
    }
  }

  final closing =
      lexer.lookahead == 0x5d ||
      lexer.lookahead == 0x29 ||
      lexer.lookahead == 0x7d;

  if (valid(FsharpExternalToken.virtualOpenSection) && !lexer.isEof) {
    // Preserve the pinned scanner's mutation order: it pushes before
    // rejecting a closing delimiter or a `|}`/`|]` sequence.
    state.indentLengthStack.add(lexer.column);
    if (closing) return false;
    if (lexer.lookahead == 0x7c) {
      _skip(lexer);
      if (lexer.lookahead == 0x7d || lexer.lookahead == 0x5d) return false;
    }
    emit(FsharpExternalToken.virtualOpenSection);
    return true;
  } else if (valid(FsharpExternalToken.blockCommentContent)) {
    // `can_call_mark_end` is permanently true in the pinned C++ source.
    lexer.markEnd();
    while (true) {
      if (lexer.lookahead == 0) {
        break;
      } else if (lexer.lookahead != 0x28 && lexer.lookahead != 0x2a) {
        _advance(lexer);
      } else if (lexer.lookahead == 0x2a) {
        lexer.markEnd();
        _advance(lexer);
        if (lexer.lookahead == 0x29) break;
      } else if (_scanBlockComment(lexer)) {
        lexer.markEnd();
        _advance(lexer);
        if (lexer.lookahead == 0x2a) break;
      }
    }
    emit(FsharpExternalToken.blockCommentContent);
    return true;
  } else if (hasNewline) {
    state.runback.clear();
    while (state.indentLength <= state.indentLengthStack.last) {
      if (state.indentLength == state.indentLengthStack.last) {
        // Equal indentation before either comment form does not end a
        // declaration in the pinned scanner.
        if (lexer.lookahead == 0x2f) {
          _skip(lexer);
          if (lexer.lookahead == 0x2f) break;
        }
        if (lexer.lookahead == 0x28) {
          _skip(lexer);
          if (lexer.lookahead == 0x2a) break;
        }
        state.runback.add(0);
        break;
      } else if (state.indentLength < state.indentLengthStack.last) {
        state.indentLengthStack.removeLast();
        state.runback.add(1);
      }
    }

    state.runback.setAll(0, state.runback.reversed.toList());
    if (state.runback.isNotEmpty &&
        state.runback.last == 0 &&
        valid(FsharpExternalToken.virtualEndDeclaration)) {
      state.runback.removeLast();
      emit(FsharpExternalToken.virtualEndDeclaration);
      return true;
    }
    if (state.runback.isNotEmpty &&
        state.runback.last == 1 &&
        valid(FsharpExternalToken.virtualEndSection)) {
      state.runback.removeLast();
      emit(FsharpExternalToken.virtualEndSection);
      return true;
    } else if (lexer.isEof && valid(FsharpExternalToken.virtualEndSection)) {
      emit(FsharpExternalToken.virtualEndSection);
      return true;
    }
  }

  return false;
}