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

Method lex_string

crates/ruff_python_parser/src/lexer.rs:915–1026  ·  view source on GitHub ↗

Lex a string literal.

(&mut self, quote: char)

Source from the content-addressed store, hash-verified

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