mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-29 13:25:09 +00:00
support literal suffixes
This commit is contained in:
parent
73ded3c63c
commit
359e70d1b2
7 changed files with 40 additions and 2 deletions
|
@ -139,6 +139,16 @@ impl<'a> Parser<'a> {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_suffix(&mut self) -> Option<TextRange> {
|
||||||
|
let start = self.get_pos();
|
||||||
|
let _ = self.peek()?;
|
||||||
|
while let Some(_) = self.peek() {
|
||||||
|
self.advance();
|
||||||
|
}
|
||||||
|
let end = self.get_pos();
|
||||||
|
Some(TextRange::from_to(start, end))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
use crate::string_lexing::{
|
use crate::{
|
||||||
|
TextRange,
|
||||||
|
string_lexing::{
|
||||||
parser::Parser,
|
parser::Parser,
|
||||||
StringComponent,
|
StringComponent,
|
||||||
};
|
}};
|
||||||
|
|
||||||
pub fn parse_string_literal(src: &str) -> StringComponentIterator {
|
pub fn parse_string_literal(src: &str) -> StringComponentIterator {
|
||||||
StringComponentIterator {
|
StringComponentIterator {
|
||||||
parser: Parser::new(src, b'"'),
|
parser: Parser::new(src, b'"'),
|
||||||
has_closing_quote: false,
|
has_closing_quote: false,
|
||||||
|
suffix: None,
|
||||||
prefix: None,
|
prefix: None,
|
||||||
quote: b'"',
|
quote: b'"',
|
||||||
}
|
}
|
||||||
|
@ -16,6 +19,7 @@ pub fn parse_byte_string_literal(src: &str) -> StringComponentIterator {
|
||||||
StringComponentIterator {
|
StringComponentIterator {
|
||||||
parser: Parser::new(src, b'"'),
|
parser: Parser::new(src, b'"'),
|
||||||
has_closing_quote: false,
|
has_closing_quote: false,
|
||||||
|
suffix: None,
|
||||||
prefix: Some(b'b'),
|
prefix: Some(b'b'),
|
||||||
quote: b'"',
|
quote: b'"',
|
||||||
}
|
}
|
||||||
|
@ -25,6 +29,7 @@ pub fn parse_char_literal(src: &str) -> StringComponentIterator {
|
||||||
StringComponentIterator {
|
StringComponentIterator {
|
||||||
parser: Parser::new(src, b'\''),
|
parser: Parser::new(src, b'\''),
|
||||||
has_closing_quote: false,
|
has_closing_quote: false,
|
||||||
|
suffix: None,
|
||||||
prefix: None,
|
prefix: None,
|
||||||
quote: b'\'',
|
quote: b'\'',
|
||||||
}
|
}
|
||||||
|
@ -34,6 +39,7 @@ pub fn parse_byte_literal(src: &str) -> StringComponentIterator {
|
||||||
StringComponentIterator {
|
StringComponentIterator {
|
||||||
parser: Parser::new(src, b'\''),
|
parser: Parser::new(src, b'\''),
|
||||||
has_closing_quote: false,
|
has_closing_quote: false,
|
||||||
|
suffix: None,
|
||||||
prefix: Some(b'b'),
|
prefix: Some(b'b'),
|
||||||
quote: b'\'',
|
quote: b'\'',
|
||||||
}
|
}
|
||||||
|
@ -42,6 +48,7 @@ pub fn parse_byte_literal(src: &str) -> StringComponentIterator {
|
||||||
pub struct StringComponentIterator<'a> {
|
pub struct StringComponentIterator<'a> {
|
||||||
parser: Parser<'a>,
|
parser: Parser<'a>,
|
||||||
pub has_closing_quote: bool,
|
pub has_closing_quote: bool,
|
||||||
|
pub suffix: Option<TextRange>,
|
||||||
prefix: Option<u8>,
|
prefix: Option<u8>,
|
||||||
quote: u8,
|
quote: u8,
|
||||||
}
|
}
|
||||||
|
@ -72,6 +79,9 @@ impl<'a> Iterator for StringComponentIterator<'a> {
|
||||||
if self.parser.peek() == Some(self.quote as char) {
|
if self.parser.peek() == Some(self.quote as char) {
|
||||||
self.parser.advance();
|
self.parser.advance();
|
||||||
self.has_closing_quote = true;
|
self.has_closing_quote = true;
|
||||||
|
if let Some(range) = self.parser.parse_suffix() {
|
||||||
|
self.suffix = Some(range);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
|
|
|
@ -27,6 +27,10 @@ pub(super) fn validate_byte_node(node: ast::Byte, errors: &mut Vec<SyntaxError>)
|
||||||
errors.push(SyntaxError::new(UnclosedByte, literal_range));
|
errors.push(SyntaxError::new(UnclosedByte, literal_range));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(range) = components.suffix {
|
||||||
|
errors.push(SyntaxError::new(InvalidSuffix, range));
|
||||||
|
}
|
||||||
|
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
errors.push(SyntaxError::new(EmptyByte, literal_range));
|
errors.push(SyntaxError::new(EmptyByte, literal_range));
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,10 @@ pub(crate) fn validate_byte_string_node(node: ast::ByteString, errors: &mut Vec<
|
||||||
if !components.has_closing_quote {
|
if !components.has_closing_quote {
|
||||||
errors.push(SyntaxError::new(UnclosedString, literal_range));
|
errors.push(SyntaxError::new(UnclosedString, literal_range));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(range) = components.suffix {
|
||||||
|
errors.push(SyntaxError::new(InvalidSuffix, range));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -30,6 +30,10 @@ pub(super) fn validate_char_node(node: ast::Char, errors: &mut Vec<SyntaxError>)
|
||||||
errors.push(SyntaxError::new(UnclosedChar, literal_range));
|
errors.push(SyntaxError::new(UnclosedChar, literal_range));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(range) = components.suffix {
|
||||||
|
errors.push(SyntaxError::new(InvalidSuffix, range));
|
||||||
|
}
|
||||||
|
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
errors.push(SyntaxError::new(EmptyChar, literal_range));
|
errors.push(SyntaxError::new(EmptyChar, literal_range));
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,10 @@ pub(crate) fn validate_string_node(node: ast::String, errors: &mut Vec<SyntaxErr
|
||||||
if !components.has_closing_quote {
|
if !components.has_closing_quote {
|
||||||
errors.push(SyntaxError::new(UnclosedString, literal_range));
|
errors.push(SyntaxError::new(UnclosedString, literal_range));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(range) = components.suffix {
|
||||||
|
errors.push(SyntaxError::new(InvalidSuffix, range));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -93,6 +93,7 @@ pub enum SyntaxErrorKind {
|
||||||
OverlongUnicodeEscape,
|
OverlongUnicodeEscape,
|
||||||
UnicodeEscapeOutOfRange,
|
UnicodeEscapeOutOfRange,
|
||||||
UnclosedString,
|
UnclosedString,
|
||||||
|
InvalidSuffix,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
@ -134,6 +135,7 @@ impl fmt::Display for SyntaxErrorKind {
|
||||||
}
|
}
|
||||||
UnicodeEscapeOutOfRange => write!(f, "Unicode escape code should be at most 0x10FFFF"),
|
UnicodeEscapeOutOfRange => write!(f, "Unicode escape code should be at most 0x10FFFF"),
|
||||||
UnclosedString => write!(f, "Unclosed string literal"),
|
UnclosedString => write!(f, "Unclosed string literal"),
|
||||||
|
InvalidSuffix => write!(f, "Invalid literal suffix"),
|
||||||
ParseError(msg) => write!(f, "{}", msg.0),
|
ParseError(msg) => write!(f, "{}", msg.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue