support literal suffixes

This commit is contained in:
Aleksey Kladov 2018-12-27 15:03:18 +03:00
parent 73ded3c63c
commit 359e70d1b2
7 changed files with 40 additions and 2 deletions

View file

@ -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)]

View file

@ -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!(

View file

@ -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));
} }

View file

@ -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)]

View file

@ -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));
} }

View file

@ -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)]

View file

@ -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),
} }
} }