scan method
bool
scan(
- PythonExternalScannerState state,
- TreeSitterExternalLexer lexer,
- 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;
}