scan method

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

Implementation

@override
bool scan(
  BitBakeExternalScannerState state,
  TreeSitterExternalLexer lexer,
  List<bool> validSymbols,
) {
  if (state.indents.isEmpty) state.indents.add(0);
  final errorRecoveryMode =
      _valid(validSymbols, BitBakeExternalToken.stringContent) &&
      _valid(validSymbols, BitBakeExternalToken.indent);
  final withinBrackets =
      _valid(validSymbols, BitBakeExternalToken.closeBrace) ||
      _valid(validSymbols, BitBakeExternalToken.closeParen) ||
      _valid(validSymbols, BitBakeExternalToken.closeBracket);

  if (_valid(validSymbols, BitBakeExternalToken.concat) &&
      !errorRecoveryMode) {
    final c = lexer.lookahead;
    if (c != 0 &&
        !_isWhitespace(c) &&
        c != 0x28 &&
        c != 0x3a &&
        c != 0x5b &&
        c != 0x3d) {
      _emit(lexer, BitBakeExternalToken.concat);
      return true;
    }
  }

  var advancedOnce = false;
  if (_valid(validSymbols, BitBakeExternalToken.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);
        lexer.markEnd();
        _emit(lexer, BitBakeExternalToken.escapeInterpolation);
        return true;
      }
      return false;
    }
  }

  if (_valid(validSymbols, BitBakeExternalToken.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(lexer, BitBakeExternalToken.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;
        }
        if (_isBytes(delimiter)) {
          lexer.markEnd();
          lexer.advance(skip: false);
          if (lexer.lookahead == 0x4e ||
              lexer.lookahead == 0x75 ||
              lexer.lookahead == 0x55) {
            lexer.advance(skip: false);
          } else {
            _emit(lexer, BitBakeExternalToken.stringContent);
            return hasContent;
          }
        } else {
          lexer.markEnd();
          _emit(lexer, BitBakeExternalToken.stringContent);
          return hasContent;
        }
      } else if (lexer.lookahead == endCharacter) {
        if (_isTriple(delimiter)) {
          lexer.markEnd();
          lexer.advance(skip: false);
          if (lexer.lookahead == endCharacter) {
            lexer.advance(skip: false);
            if (lexer.lookahead == endCharacter) {
              if (hasContent) {
                _emit(lexer, BitBakeExternalToken.stringContent);
              } else {
                lexer.advance(skip: false);
                lexer.markEnd();
                state.delimiters.removeLast();
                _emit(lexer, BitBakeExternalToken.stringEnd);
                state.insideFString = false;
              }
              return true;
            }
            lexer.markEnd();
            _emit(lexer, BitBakeExternalToken.stringContent);
            return true;
          }
          lexer.markEnd();
          _emit(lexer, BitBakeExternalToken.stringContent);
          return true;
        }
        if (hasContent) {
          _emit(lexer, BitBakeExternalToken.stringContent);
        } else {
          lexer.advance(skip: false);
          state.delimiters.removeLast();
          _emit(lexer, BitBakeExternalToken.stringEnd);
          state.insideFString = false;
        }
        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.advance(skip: true);
      case 0x0d || 0x0c:
        indentLength = 0;
        lexer.advance(skip: true);
      case 0x09:
        indentLength += 8;
        lexer.advance(skip: true);
      case 0x23:
        if (!foundEndOfLine) return false;
        if (firstCommentIndentLength == -1) {
          firstCommentIndentLength = indentLength;
        }
        while (lexer.lookahead != 0 && lexer.lookahead != 0x0a) {
          lexer.advance(skip: true);
        }
        lexer.advance(skip: true);
        indentLength = 0;
      case 0x5c:
        if (!_valid(validSymbols, BitBakeExternalToken.stringContent)) {
          scanningIndent = false;
          continue;
        }
        lexer.advance(skip: true);
        if (lexer.lookahead == 0x0d) lexer.advance(skip: true);
        if (lexer.lookahead == 0x0a || lexer.isEof) {
          lexer.advance(skip: true);
        } else {
          return false;
        }
      case 0:
        if (lexer.isEof) {
          indentLength = 0;
          foundEndOfLine = true;
        }
        scanningIndent = false;
      default:
        scanningIndent = false;
    }
  }

  if (foundEndOfLine) {
    final currentIndentLength = state.indents.last;
    if (_valid(validSymbols, BitBakeExternalToken.indent) &&
        indentLength > currentIndentLength) {
      state.indents.add(indentLength & 0xffff);
      _emit(lexer, BitBakeExternalToken.indent);
      return true;
    }

    final nextTokenIsStringStart =
        lexer.lookahead == 0x22 ||
        lexer.lookahead == 0x27 ||
        lexer.lookahead == 0x60;
    if ((_valid(validSymbols, BitBakeExternalToken.dedent) ||
            (!_valid(validSymbols, BitBakeExternalToken.newline) &&
                !(_valid(validSymbols, BitBakeExternalToken.stringStart) &&
                    nextTokenIsStringStart) &&
                !withinBrackets)) &&
        indentLength < currentIndentLength &&
        !state.insideFString &&
        firstCommentIndentLength < currentIndentLength) {
      state.indents.removeLast();
      _emit(lexer, BitBakeExternalToken.dedent);
      return true;
    }

    if (_valid(validSymbols, BitBakeExternalToken.newline) &&
        !errorRecoveryMode) {
      _emit(lexer, BitBakeExternalToken.newline);
      return true;
    }
  }

  if (firstCommentIndentLength == -1 &&
      _valid(validSymbols, BitBakeExternalToken.stringStart)) {
    var delimiter = 0;
    var hasFlags = false;
    var scanningFlags = true;
    while (scanningFlags && lexer.lookahead != 0) {
      switch (lexer.lookahead) {
        case 0x66 || 0x46:
          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);
        lexer.markEnd();
      case 0x27:
        delimiter |= _singleQuote;
        lexer.advance(skip: false);
        lexer.markEnd();
        if (lexer.lookahead == 0x27) {
          lexer.advance(skip: false);
          if (lexer.lookahead == 0x27) {
            lexer.advance(skip: false);
            lexer.markEnd();
            delimiter |= _triple;
          }
        }
      case 0x22:
        delimiter |= _doubleQuote;
        lexer.advance(skip: false);
        lexer.markEnd();
        if (lexer.lookahead == 0x22) {
          lexer.advance(skip: false);
          if (lexer.lookahead == 0x22) {
            lexer.advance(skip: false);
            lexer.markEnd();
            delimiter |= _triple;
          }
        }
    }

    if (_endCharacter(delimiter) != 0) {
      state.delimiters.add(delimiter);
      _emit(lexer, BitBakeExternalToken.stringStart);
      state.insideFString = _isFormat(delimiter);
      return true;
    }
    if (hasFlags) return false;
  }

  if (_valid(validSymbols, BitBakeExternalToken.shellContent) &&
      !errorRecoveryMode) {
    while (_isWhitespace(lexer.lookahead)) {
      lexer.advance(skip: true);
      if (lexer.lookahead == 0x0a) {
        lexer.advance(skip: true);
        break;
      }
    }

    var advanceOnce = false;
    var braceDepth = 0;
    while (!lexer.isEof && lexer.lookahead != 0x0a) {
      switch (lexer.lookahead) {
        case 0x24: // $
          lexer.markEnd();
          lexer.advance(skip: false);
          if (lexer.lookahead == 0x7b) {
            lexer.advance(skip: false);
            braceDepth = (braceDepth + 1) & 0xff;
            if (lexer.lookahead == 0x40) {
              lexer.advance(skip: false);
              _emit(lexer, BitBakeExternalToken.shellContent);
              return advanceOnce;
            }
          }
          advanceOnce = true;
        case 0x7b: // {
          lexer.advance(skip: false);
          braceDepth = (braceDepth + 1) & 0xff;
        case 0x7d: // }
          lexer.advance(skip: false);
          braceDepth = (braceDepth - 1) & 0xff;
        case 0x0d || 0x09 || 0x0c || 0x0b || 0x20:
          lexer.advance(skip: false);
        default:
          lexer.advance(skip: false);
          advanceOnce = true;
      }
    }
    lexer.markEnd();
    _emit(lexer, BitBakeExternalToken.shellContent);
    return advanceOnce && braceDepth == 0;
  }

  return false;
}