MCPcopy Create free account
hub / github.com/astral-sh/ruff / lex_string

Method lex_string

crates/ruff_python_parser/src/lexer.rs:918–1029  ·  view source on GitHub ↗

Lex a string literal.

(&mut self, quote: char)

Source from the content-addressed store, hash-verified

916
917 /// Lex a string literal.
918 fn lex_string(&mut self, quote: char) -> TokenKind {
919 #[cfg(debug_assertions)]
920 debug_assert_eq!(self.cursor.previous(), quote);
921
922 if quote == '"' {
923 self.current_flags |= TokenFlags::DOUBLE_QUOTES;
924 }
925
926 // If the next two characters are also the quote character, then we have a triple-quoted
927 // string; consume those two characters and ensure that we require a triple-quote to close
928 if self.cursor.eat_char2(quote, quote) {
929 self.current_flags |= TokenFlags::TRIPLE_QUOTED_STRING;
930 }
931
932 let quote_byte = u8::try_from(quote).expect("char that fits in u8");
933 if self.current_flags.is_triple_quoted() {
934 // For triple-quoted strings, scan until we find the closing quote (ignoring escaped
935 // quotes) or the end of the file.
936 loop {
937 let Some(index) = memchr::memchr(quote_byte, self.cursor.rest().as_bytes()) else {
938 self.cursor.skip_to_end();
939
940 self.current_flags |= TokenFlags::UNCLOSED_STRING;
941 self.push_error(LexicalError::new(
942 LexicalErrorType::UnclosedStringError,
943 self.token_range(),
944 ));
945 break;
946 };
947
948 // Rare case: if there are an odd number of backslashes before the quote, then
949 // the quote is escaped and we should continue scanning.
950 let num_backslashes = self.cursor.rest().as_bytes()[..index]
951 .iter()
952 .rev()
953 .take_while(|&&c| c == b'\\')
954 .count();
955
956 // Advance the cursor past the quote and continue scanning.
957 self.cursor.skip_bytes(index + 1);
958
959 // If the character is escaped, continue scanning.
960 if num_backslashes % 2 == 1 {
961 continue;
962 }
963
964 // Otherwise, if it's followed by two more quotes, then we're done.
965 if self.cursor.eat_char2(quote, quote) {
966 break;
967 }
968 }
969 } else {
970 // For non-triple-quoted strings, scan until we find the closing quote, but end early
971 // if we encounter a newline or the end of the file.
972 loop {
973 let Some(index) =
974 memchr::memchr3(quote_byte, b'\r', b'\n', self.cursor.rest().as_bytes())
975 else {

Callers 2

lex_identifierMethod · 0.80

Calls 14

expectMethod · 0.80
restMethod · 0.80
skip_to_endMethod · 0.80
push_errorMethod · 0.80
eat_char2Method · 0.45
is_triple_quotedMethod · 0.45
as_bytesMethod · 0.45
token_rangeMethod · 0.45
countMethod · 0.45
iterMethod · 0.45
skip_bytesMethod · 0.45
firstMethod · 0.45

Tested by

no test coverage detected