scan method
bool
scan(
- RubyExternalScannerState state,
- TreeSitterExternalLexer lexer,
- List<
bool> validSymbols
override
Implementation
@override
bool scan(
RubyExternalScannerState state,
TreeSitterExternalLexer lexer,
List<bool> validSymbols,
) {
state.hasLeadingWhitespace = false;
bool valid(RubyExternalToken token) =>
token.index < validSymbols.length && validSymbols[token.index];
if (!valid(RubyExternalToken.stringStart)) {
if ((valid(RubyExternalToken.stringContent) ||
valid(RubyExternalToken.stringEnd)) &&
state.literalStack.isNotEmpty) {
return _scanLiteralContent(state, lexer);
}
if ((valid(RubyExternalToken.heredocContent) ||
valid(RubyExternalToken.heredocBodyEnd)) &&
state.openHeredocs.isNotEmpty) {
return _scanHeredocContent(state, lexer);
}
}
final whitespaceResult = _scanWhitespace(state, lexer, validSymbols);
if (!whitespaceResult.$1) return false;
if (whitespaceResult.$2 != null) {
return _result(lexer, whitespaceResult.$2!);
}
switch (lexer.lookahead) {
case 0x26: // &
if (valid(RubyExternalToken.blockAmpersand)) {
_advance(lexer);
if (lexer.lookahead != 0x26 &&
lexer.lookahead != 0x2e &&
lexer.lookahead != 0x3d &&
!_isSpace(lexer.lookahead)) {
return _result(lexer, RubyExternalToken.blockAmpersand);
}
return false;
}
case 0x3c: // <
if (valid(RubyExternalToken.singletonClassLeftAngleLeftAngle)) {
_advance(lexer);
if (lexer.lookahead == 0x3c) {
_advance(lexer);
return _result(
lexer,
RubyExternalToken.singletonClassLeftAngleLeftAngle,
);
}
return false;
}
case 0x2a: // *
if (valid(RubyExternalToken.splatStar) ||
valid(RubyExternalToken.binaryStar) ||
valid(RubyExternalToken.hashSplatStarStar) ||
valid(RubyExternalToken.binaryStarStar)) {
_advance(lexer);
if (lexer.lookahead == 0x3d) return false;
if (lexer.lookahead == 0x2a) {
if (!valid(RubyExternalToken.hashSplatStarStar) &&
!valid(RubyExternalToken.binaryStarStar)) {
return false;
}
_advance(lexer);
if (lexer.lookahead == 0x3d) return false;
if (valid(RubyExternalToken.binaryStarStar) &&
!state.hasLeadingWhitespace) {
return _result(lexer, RubyExternalToken.binaryStarStar);
}
if (valid(RubyExternalToken.hashSplatStarStar) &&
!_isSpace(lexer.lookahead)) {
return _result(lexer, RubyExternalToken.hashSplatStarStar);
}
if (valid(RubyExternalToken.binaryStarStar)) {
return _result(lexer, RubyExternalToken.binaryStarStar);
}
return _result(lexer, RubyExternalToken.hashSplatStarStar);
}
if (valid(RubyExternalToken.binaryStar) &&
!state.hasLeadingWhitespace) {
return _result(lexer, RubyExternalToken.binaryStar);
}
if (valid(RubyExternalToken.splatStar) &&
!_isSpace(lexer.lookahead)) {
return _result(lexer, RubyExternalToken.splatStar);
}
if (valid(RubyExternalToken.binaryStar)) {
return _result(lexer, RubyExternalToken.binaryStar);
}
return _result(lexer, RubyExternalToken.splatStar);
}
case 0x2d: // -
if (valid(RubyExternalToken.unaryMinus) ||
valid(RubyExternalToken.unaryMinusNum) ||
valid(RubyExternalToken.binaryMinus)) {
_advance(lexer);
if (lexer.lookahead == 0x3d || lexer.lookahead == 0x3e) {
return false;
}
if (valid(RubyExternalToken.unaryMinusNum) &&
(!valid(RubyExternalToken.binaryStar) ||
state.hasLeadingWhitespace) &&
_isDigit(lexer.lookahead)) {
return _result(lexer, RubyExternalToken.unaryMinusNum);
}
if (valid(RubyExternalToken.unaryMinus) &&
state.hasLeadingWhitespace &&
!_isSpace(lexer.lookahead)) {
return _result(lexer, RubyExternalToken.unaryMinus);
}
if (valid(RubyExternalToken.binaryMinus)) {
return _result(lexer, RubyExternalToken.binaryMinus);
}
return _result(lexer, RubyExternalToken.unaryMinus);
}
case 0x3a: // :
if (valid(RubyExternalToken.symbolStart)) {
_advance(lexer);
if (lexer.lookahead == 0x22 || lexer.lookahead == 0x27) {
final delimiter = lexer.lookahead;
_advance(lexer);
state.literalStack.add(
RubyLiteral(
type: RubyExternalToken.symbolStart,
openDelimiter: delimiter,
closeDelimiter: delimiter,
allowsInterpolation: delimiter == 0x22,
),
);
return _result(lexer, RubyExternalToken.symbolStart);
}
if (_scanSymbolIdentifier(lexer)) {
return _result(lexer, RubyExternalToken.simpleSymbol);
}
return false;
}
case 0x5b: // [
if (valid(RubyExternalToken.elementReferenceBracket) &&
(!state.hasLeadingWhitespace ||
!valid(RubyExternalToken.stringStart))) {
_advance(lexer);
return _result(lexer, RubyExternalToken.elementReferenceBracket);
}
default:
break;
}
final identifierCandidate =
((valid(RubyExternalToken.hashKeySymbol) ||
valid(RubyExternalToken.identifierSuffix)) &&
(_isAlpha(lexer.lookahead) || lexer.lookahead == 0x5f)) ||
(valid(RubyExternalToken.constantSuffix) && _isUpper(lexer.lookahead));
if (identifierCandidate) {
final identifierToken = _isUpper(lexer.lookahead)
? RubyExternalToken.constantSuffix
: RubyExternalToken.identifierSuffix;
while (_isAlphanumeric(lexer.lookahead) || lexer.lookahead == 0x5f) {
_advance(lexer);
}
if (valid(RubyExternalToken.hashKeySymbol) && lexer.lookahead == 0x3a) {
lexer.markEnd();
_advance(lexer);
if (lexer.lookahead != 0x3a) {
return _result(lexer, RubyExternalToken.hashKeySymbol);
}
} else if (valid(identifierToken) && lexer.lookahead == 0x21) {
_advance(lexer);
if (lexer.lookahead != 0x3d) {
return _result(lexer, identifierToken);
}
}
return false;
}
if (valid(RubyExternalToken.stringStart)) {
if (lexer.lookahead == 0x3c) {
_advance(lexer);
if (lexer.lookahead != 0x3c) return false;
_advance(lexer);
final heredoc = RubyHeredoc();
if (lexer.lookahead == 0x2d || lexer.lookahead == 0x7e) {
_advance(lexer);
heredoc.endWordIndentationAllowed = true;
}
_scanHeredocWord(lexer, heredoc);
if (heredoc.word.isEmpty) return false;
state.openHeredocs.add(heredoc);
return _result(lexer, RubyExternalToken.heredocStart);
}
final literal = _scanOpenDelimiter(state, lexer, validSymbols);
if (literal == null) return false;
state.literalStack.add(literal);
return _result(lexer, literal.type);
}
return false;
}