scan method

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

Implementation

@override
bool scan(
  PythonExternalScannerState state,
  TreeSitterExternalLexer lexer,
  List<bool> validSymbols,
) {
  if (state.indents.isEmpty) state.indents.add(0);
  bool valid(PythonExternalToken token) =>
      token.index < validSymbols.length && validSymbols[token.index];
  void emit(PythonExternalToken token) =>
      lexer.setResultSymbol(symbols[token.index]);

  final errorRecoveryMode =
      valid(PythonExternalToken.stringContent) &&
      valid(PythonExternalToken.indent);
  final withinBrackets =
      valid(PythonExternalToken.closeBrace) ||
      valid(PythonExternalToken.closeParen) ||
      valid(PythonExternalToken.closeBracket);

  var advancedOnce = false;
  if (valid(PythonExternalToken.escapeInterpolation) &&
      state.delimiters.isNotEmpty &&
      (lexer.lookahead == 0x7b || lexer.lookahead == 0x7d) &&
      !errorRecoveryMode) {
    final delimiter = state.delimiters.last;
    if (_isFormat(delimiter)) {
      lexer.markEnd();
      final isLeftBrace = lexer.lookahead == 0x7b;
      lexer.advance(skip: false);
      advancedOnce = true;
      if ((lexer.lookahead == 0x7b && isLeftBrace) ||
          (lexer.lookahead == 0x7d && !isLeftBrace)) {
        lexer
          ..advance(skip: false)
          ..markEnd();
        emit(PythonExternalToken.escapeInterpolation);
        return true;
      }
      return false;
    }
  }

  if (valid(PythonExternalToken.stringContent) &&
      state.delimiters.isNotEmpty &&
      !errorRecoveryMode) {
    final delimiter = state.delimiters.last;
    final endCharacter = _endCharacter(delimiter);
    var hasContent = advancedOnce;
    while (lexer.lookahead != 0) {
      if ((advancedOnce ||
              lexer.lookahead == 0x7b ||
              lexer.lookahead == 0x7d) &&
          _isFormat(delimiter)) {
        lexer.markEnd();
        emit(PythonExternalToken.stringContent);
        return hasContent;
      }
      if (lexer.lookahead == 0x5c) {
        if (_isRaw(delimiter)) {
          lexer.advance(skip: false);
          if (lexer.lookahead == endCharacter || lexer.lookahead == 0x5c) {
            lexer.advance(skip: false);
          }
          if (lexer.lookahead == 0x0d) {
            lexer.advance(skip: false);
            if (lexer.lookahead == 0x0a) lexer.advance(skip: false);
          } else if (lexer.lookahead == 0x0a) {
            lexer.advance(skip: false);
          }
          continue;
        }
        lexer.markEnd();
        if (_isBytes(delimiter)) {
          lexer.advance(skip: false);
          if (lexer.lookahead == 0x4e ||
              lexer.lookahead == 0x75 ||
              lexer.lookahead == 0x55) {
            lexer.advance(skip: false);
          } else {
            emit(PythonExternalToken.stringContent);
            return hasContent;
          }
        } else {
          emit(PythonExternalToken.stringContent);
          return hasContent;
        }
      } else if (lexer.lookahead == endCharacter) {
        if (_isTriple(delimiter)) {
          lexer
            ..markEnd()
            ..advance(skip: false);
          if (lexer.lookahead == endCharacter) {
            lexer.advance(skip: false);
            if (lexer.lookahead == endCharacter) {
              if (hasContent) {
                emit(PythonExternalToken.stringContent);
              } else {
                lexer
                  ..advance(skip: false)
                  ..markEnd();
                state.delimiters.removeLast();
                emit(PythonExternalToken.stringEnd);
              }
              return true;
            }
          }
          lexer.markEnd();
          emit(PythonExternalToken.stringContent);
          return true;
        }
        if (hasContent) {
          emit(PythonExternalToken.stringContent);
        } else {
          lexer.advance(skip: false);
          state.delimiters.removeLast();
          emit(PythonExternalToken.stringEnd);
        }
        lexer.markEnd();
        return true;
      } else if (lexer.lookahead == 0x0a &&
          hasContent &&
          !_isTriple(delimiter)) {
        return false;
      }
      lexer.advance(skip: false);
      hasContent = true;
    }
  }

  lexer.markEnd();
  var foundEndOfLine = false;
  var indentLength = 0;
  var firstCommentIndentLength = -1;
  var scanningIndent = true;
  while (scanningIndent) {
    switch (lexer.lookahead) {
      case 0x0a:
        foundEndOfLine = true;
        indentLength = 0;
        lexer.advance(skip: true);
      case 0x20:
        indentLength += lexer.advanceSpaces(skip: true);
      case 0x0d || 0x0c:
        indentLength = 0;
        lexer.advance(skip: true);
      case 0x09:
        indentLength += 8;
        lexer.advance(skip: true);
      case 0x23:
        if (valid(PythonExternalToken.indent) ||
            valid(PythonExternalToken.dedent) ||
            valid(PythonExternalToken.newline) ||
            valid(PythonExternalToken.exceptKeyword)) {
          if (!foundEndOfLine) return false;
          if (firstCommentIndentLength == -1) {
            firstCommentIndentLength = indentLength;
          }
          lexer
            ..advanceUntilNewline(skip: true)
            ..advance(skip: true);
          indentLength = 0;
        } else {
          scanningIndent = false;
        }
      case 0x5c:
        lexer.advance(skip: true);
        if (lexer.lookahead == 0x0d) lexer.advance(skip: true);
        if (lexer.lookahead == 0x0a || lexer.lookahead == 0) {
          lexer.advance(skip: true);
        } else {
          return false;
        }
      case 0:
        indentLength = 0;
        foundEndOfLine = true;
        scanningIndent = false;
      default:
        scanningIndent = false;
    }
  }

  if (foundEndOfLine) {
    final currentIndent = state.indents.last;
    if (valid(PythonExternalToken.indent) && indentLength > currentIndent) {
      state.indents.add(indentLength);
      emit(PythonExternalToken.indent);
      return true;
    }
    final nextIsString =
        lexer.lookahead == 0x22 ||
        lexer.lookahead == 0x27 ||
        lexer.lookahead == 0x60;
    if ((valid(PythonExternalToken.dedent) ||
            (!valid(PythonExternalToken.newline) &&
                !(valid(PythonExternalToken.stringStart) && nextIsString) &&
                !withinBrackets)) &&
        indentLength < currentIndent &&
        !state.insideInterpolatedString &&
        firstCommentIndentLength < currentIndent) {
      state.indents.removeLast();
      emit(PythonExternalToken.dedent);
      return true;
    }
    if (valid(PythonExternalToken.newline) && !errorRecoveryMode) {
      emit(PythonExternalToken.newline);
      return true;
    }
  }

  if (firstCommentIndentLength == -1 &&
      valid(PythonExternalToken.stringStart)) {
    var delimiter = 0;
    var hasFlags = false;
    var scanningFlags = true;
    while (scanningFlags && lexer.lookahead != 0) {
      switch (lexer.lookahead) {
        case 0x66 || 0x46 || 0x74 || 0x54:
          delimiter |= _format;
        case 0x72 || 0x52:
          delimiter |= _raw;
        case 0x62 || 0x42:
          delimiter |= _bytes;
        case 0x75 || 0x55:
          break;
        default:
          scanningFlags = false;
          continue;
      }
      hasFlags = true;
      lexer.advance(skip: false);
    }
    switch (lexer.lookahead) {
      case 0x60:
        delimiter |= _backQuote;
        lexer
          ..advance(skip: false)
          ..markEnd();
      case 0x27:
        delimiter |= _singleQuote;
        lexer
          ..advance(skip: false)
          ..markEnd();
        if (lexer.lookahead == 0x27) {
          lexer.advance(skip: false);
          if (lexer.lookahead == 0x27) {
            lexer
              ..advance(skip: false)
              ..markEnd();
            delimiter |= _triple;
          }
        }
      case 0x22:
        delimiter |= _doubleQuote;
        lexer
          ..advance(skip: false)
          ..markEnd();
        if (lexer.lookahead == 0x22) {
          lexer.advance(skip: false);
          if (lexer.lookahead == 0x22) {
            lexer
              ..advance(skip: false)
              ..markEnd();
            delimiter |= _triple;
          }
        }
    }
    if (_endCharacter(delimiter) != 0) {
      state.delimiters.add(delimiter);
      emit(PythonExternalToken.stringStart);
      return true;
    }
    if (hasFlags) return false;
  }
  return false;
}