]> git.lizzy.rs Git - rust.git/commitdiff
dedupe literal parsers
authorAleksey Kladov <aleksey.kladov@gmail.com>
Thu, 27 Dec 2018 11:42:46 +0000 (14:42 +0300)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Thu, 27 Dec 2018 11:42:46 +0000 (14:42 +0300)
crates/ra_syntax/src/string_lexing.rs
crates/ra_syntax/src/string_lexing/byte.rs [deleted file]
crates/ra_syntax/src/string_lexing/byte_string.rs [deleted file]
crates/ra_syntax/src/string_lexing/char.rs [deleted file]
crates/ra_syntax/src/string_lexing/parser.rs
crates/ra_syntax/src/string_lexing/string.rs
crates/ra_syntax/src/validation/byte.rs
crates/ra_syntax/src/validation/byte_string.rs
crates/ra_syntax/src/validation/char.rs
crates/ra_syntax/src/validation/string.rs

index 94853331f2e89417b4767bbfddaec0b104cd01cf..349733f3fbf8eac7c7aebf24c7cca6c49122ca84 100644 (file)
@@ -1,13 +1,7 @@
 mod parser;
-mod byte;
-mod byte_string;
-mod char;
 mod string;
 
 pub use self::{
-    byte::parse_byte_literal,
-    byte_string::parse_byte_string_literal,
-    char::parse_char_literal,
-    parser::{CharComponent, CharComponentKind, StringComponent, StringComponentKind},
-    string::parse_string_literal,
+    parser::{StringComponent, StringComponentKind},
+    string::{parse_string_literal, parse_char_literal, parse_byte_literal, parse_byte_string_literal},
 };
diff --git a/crates/ra_syntax/src/string_lexing/byte.rs b/crates/ra_syntax/src/string_lexing/byte.rs
deleted file mode 100644 (file)
index b3228d6..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-use super::parser::Parser;
-use super::CharComponent;
-
-pub fn parse_byte_literal(src: &str) -> ByteComponentIterator {
-    ByteComponentIterator {
-        parser: Parser::new(src),
-        has_closing_quote: false,
-    }
-}
-
-pub struct ByteComponentIterator<'a> {
-    parser: Parser<'a>,
-    pub has_closing_quote: bool,
-}
-
-impl<'a> Iterator for ByteComponentIterator<'a> {
-    type Item = CharComponent;
-    fn next(&mut self) -> Option<CharComponent> {
-        if self.parser.pos == 0 {
-            assert!(
-                self.parser.advance() == 'b',
-                "Byte literal should start with a `b`"
-            );
-
-            assert!(
-                self.parser.advance() == '\'',
-                "Byte literal should start with a `b`, followed by a quote"
-            );
-        }
-
-        if let Some(component) = self.parser.parse_char_component() {
-            return Some(component);
-        }
-
-        // We get here when there are no char components left to parse
-        if self.parser.peek() == Some('\'') {
-            self.parser.advance();
-            self.has_closing_quote = true;
-        }
-
-        assert!(
-            self.parser.peek() == None,
-            "byte literal should leave no unparsed input: src = {:?}, pos = {}, length = {}",
-            self.parser.src,
-            self.parser.pos,
-            self.parser.src.len()
-        );
-
-        None
-    }
-}
diff --git a/crates/ra_syntax/src/string_lexing/byte_string.rs b/crates/ra_syntax/src/string_lexing/byte_string.rs
deleted file mode 100644 (file)
index a605615..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-use super::parser::Parser;
-use super::StringComponent;
-
-pub fn parse_byte_string_literal(src: &str) -> ByteStringComponentIterator {
-    ByteStringComponentIterator {
-        parser: Parser::new(src),
-        has_closing_quote: false,
-    }
-}
-
-pub struct ByteStringComponentIterator<'a> {
-    parser: Parser<'a>,
-    pub has_closing_quote: bool,
-}
-
-impl<'a> Iterator for ByteStringComponentIterator<'a> {
-    type Item = StringComponent;
-    fn next(&mut self) -> Option<StringComponent> {
-        if self.parser.pos == 0 {
-            assert!(
-                self.parser.advance() == 'b',
-                "byte string literal should start with a `b`"
-            );
-
-            assert!(
-                self.parser.advance() == '"',
-                "byte string literal should start with a `b`, followed by double quotes"
-            );
-        }
-
-        if let Some(component) = self.parser.parse_string_component() {
-            return Some(component);
-        }
-
-        // We get here when there are no char components left to parse
-        if self.parser.peek() == Some('"') {
-            self.parser.advance();
-            self.has_closing_quote = true;
-        }
-
-        assert!(
-            self.parser.peek() == None,
-            "byte string literal should leave no unparsed input: src = {:?}, pos = {}, length = {}",
-            self.parser.src,
-            self.parser.pos,
-            self.parser.src.len()
-        );
-
-        None
-    }
-}
diff --git a/crates/ra_syntax/src/string_lexing/char.rs b/crates/ra_syntax/src/string_lexing/char.rs
deleted file mode 100644 (file)
index e018131..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-use super::parser::Parser;
-use super::CharComponent;
-
-pub fn parse_char_literal(src: &str) -> CharComponentIterator {
-    CharComponentIterator {
-        parser: Parser::new(src),
-        has_closing_quote: false,
-    }
-}
-
-pub struct CharComponentIterator<'a> {
-    parser: Parser<'a>,
-    pub has_closing_quote: bool,
-}
-
-impl<'a> Iterator for CharComponentIterator<'a> {
-    type Item = CharComponent;
-    fn next(&mut self) -> Option<CharComponent> {
-        if self.parser.pos == 0 {
-            assert!(
-                self.parser.advance() == '\'',
-                "char literal should start with a quote"
-            );
-        }
-
-        if let Some(component) = self.parser.parse_char_component() {
-            return Some(component);
-        }
-
-        // We get here when there are no char components left to parse
-        if self.parser.peek() == Some('\'') {
-            self.parser.advance();
-            self.has_closing_quote = true;
-        }
-
-        assert!(
-            self.parser.peek() == None,
-            "char literal should leave no unparsed input: src = {:?}, pos = {}, length = {}",
-            self.parser.src,
-            self.parser.pos,
-            self.parser.src.len()
-        );
-
-        None
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use rowan::TextRange;
-    use crate::string_lexing::{
-        CharComponent,
-        CharComponentKind::*,
-};
-
-    fn parse(src: &str) -> (bool, Vec<CharComponent>) {
-        let component_iterator = &mut super::parse_char_literal(src);
-        let components: Vec<_> = component_iterator.collect();
-        (component_iterator.has_closing_quote, components)
-    }
-
-    fn unclosed_char_component(src: &str) -> CharComponent {
-        let (has_closing_quote, components) = parse(src);
-        assert!(!has_closing_quote, "char should not have closing quote");
-        assert!(components.len() == 1);
-        components[0].clone()
-    }
-
-    fn closed_char_component(src: &str) -> CharComponent {
-        let (has_closing_quote, components) = parse(src);
-        assert!(has_closing_quote, "char should have closing quote");
-        assert!(
-            components.len() == 1,
-            "Literal: {}\nComponents: {:#?}",
-            src,
-            components
-        );
-        components[0].clone()
-    }
-
-    fn closed_char_components(src: &str) -> Vec<CharComponent> {
-        let (has_closing_quote, components) = parse(src);
-        assert!(has_closing_quote, "char should have closing quote");
-        components
-    }
-
-    fn range_closed(src: &str) -> TextRange {
-        TextRange::from_to(1.into(), (src.len() as u32 - 1).into())
-    }
-
-    fn range_unclosed(src: &str) -> TextRange {
-        TextRange::from_to(1.into(), (src.len() as u32).into())
-    }
-
-    #[test]
-    fn test_unicode_escapes() {
-        let unicode_escapes = &[r"{DEAD}", "{BEEF}", "{FF}", "{}", ""];
-        for escape in unicode_escapes {
-            let escape_sequence = format!(r"'\u{}'", escape);
-            let component = closed_char_component(&escape_sequence);
-            let expected_range = range_closed(&escape_sequence);
-            assert_eq!(component.kind, UnicodeEscape);
-            assert_eq!(component.range, expected_range);
-        }
-    }
-
-    #[test]
-    fn test_unicode_escapes_unclosed() {
-        let unicode_escapes = &["{DEAD", "{BEEF", "{FF"];
-        for escape in unicode_escapes {
-            let escape_sequence = format!(r"'\u{}'", escape);
-            let component = unclosed_char_component(&escape_sequence);
-            let expected_range = range_unclosed(&escape_sequence);
-            assert_eq!(component.kind, UnicodeEscape);
-            assert_eq!(component.range, expected_range);
-        }
-    }
-
-    #[test]
-    fn test_empty_char() {
-        let (has_closing_quote, components) = parse("''");
-        assert!(has_closing_quote, "char should have closing quote");
-        assert!(components.len() == 0);
-    }
-
-    #[test]
-    fn test_unclosed_char() {
-        let component = unclosed_char_component("'a");
-        assert!(component.kind == CodePoint);
-        assert!(component.range == TextRange::from_to(1.into(), 2.into()));
-    }
-
-    #[test]
-    fn test_digit_escapes() {
-        let literals = &[r"", r"5", r"55"];
-
-        for literal in literals {
-            let lit_text = format!(r"'\x{}'", literal);
-            let component = closed_char_component(&lit_text);
-            assert!(component.kind == AsciiCodeEscape);
-            assert!(component.range == range_closed(&lit_text));
-        }
-
-        // More than 2 digits starts a new codepoint
-        let components = closed_char_components(r"'\x555'");
-        assert!(components.len() == 2);
-        assert!(components[1].kind == CodePoint);
-    }
-
-    #[test]
-    fn test_ascii_escapes() {
-        let literals = &[
-            r"\'", "\\\"", // equivalent to \"
-            r"\n", r"\r", r"\t", r"\\", r"\0",
-        ];
-
-        for literal in literals {
-            let lit_text = format!("'{}'", literal);
-            let component = closed_char_component(&lit_text);
-            assert!(component.kind == AsciiEscape);
-            assert!(component.range == range_closed(&lit_text));
-        }
-    }
-
-    #[test]
-    fn test_no_escapes() {
-        let literals = &['"', 'n', 'r', 't', '0', 'x', 'u'];
-
-        for &literal in literals {
-            let lit_text = format!("'{}'", literal);
-            let component = closed_char_component(&lit_text);
-            assert!(component.kind == CodePoint);
-            assert!(component.range == range_closed(&lit_text));
-        }
-    }
-}
index 4a6d5bc935233ac96c479b6d4d748fbba930e2ed..13f3db8899b79d7cbd817bfd4b41d9547cf7909f 100644 (file)
@@ -1,15 +1,16 @@
 use rowan::{TextRange, TextUnit};
 
-use self::CharComponentKind::*;
+use self::StringComponentKind::*;
 
 pub struct Parser<'a> {
+    pub(super) quote: u8,
     pub(super) src: &'a str,
     pub(super) pos: usize,
 }
 
 impl<'a> Parser<'a> {
-    pub fn new(src: &'a str) -> Parser<'a> {
-        Parser { src, pos: 0 }
+    pub fn new(src: &'a str, quote: u8) -> Parser<'a> {
+        Parser { quote, src, pos: 0 }
     }
 
     // Utility methods
@@ -42,7 +43,7 @@ pub fn get_pos(&self) -> TextUnit {
 
     // Char parsing methods
 
-    fn parse_unicode_escape(&mut self, start: TextUnit) -> CharComponent {
+    fn parse_unicode_escape(&mut self, start: TextUnit) -> StringComponent {
         match self.peek() {
             Some('{') => {
                 self.advance();
@@ -56,16 +57,16 @@ fn parse_unicode_escape(&mut self, start: TextUnit) -> CharComponent {
                 }
 
                 let end = self.get_pos();
-                CharComponent::new(TextRange::from_to(start, end), UnicodeEscape)
+                StringComponent::new(TextRange::from_to(start, end), UnicodeEscape)
             }
             Some(_) | None => {
                 let end = self.get_pos();
-                CharComponent::new(TextRange::from_to(start, end), UnicodeEscape)
+                StringComponent::new(TextRange::from_to(start, end), UnicodeEscape)
             }
         }
     }
 
-    fn parse_ascii_code_escape(&mut self, start: TextUnit) -> CharComponent {
+    fn parse_ascii_code_escape(&mut self, start: TextUnit) -> StringComponent {
         let code_start = self.get_pos();
         while let Some(next) = self.peek() {
             if next == '\'' || (self.get_pos() - code_start == 2.into()) {
@@ -76,12 +77,12 @@ fn parse_ascii_code_escape(&mut self, start: TextUnit) -> CharComponent {
         }
 
         let end = self.get_pos();
-        CharComponent::new(TextRange::from_to(start, end), AsciiCodeEscape)
+        StringComponent::new(TextRange::from_to(start, end), AsciiCodeEscape)
     }
 
-    fn parse_escape(&mut self, start: TextUnit) -> CharComponent {
+    fn parse_escape(&mut self, start: TextUnit) -> StringComponent {
         if self.peek().is_none() {
-            return CharComponent::new(TextRange::from_to(start, start), AsciiEscape);
+            return StringComponent::new(TextRange::from_to(start, start), AsciiEscape);
         }
 
         let next = self.advance();
@@ -90,29 +91,7 @@ fn parse_escape(&mut self, start: TextUnit) -> CharComponent {
         match next {
             'x' => self.parse_ascii_code_escape(start),
             'u' => self.parse_unicode_escape(start),
-            _ => CharComponent::new(range, AsciiEscape),
-        }
-    }
-
-    pub fn parse_char_component(&mut self) -> Option<CharComponent> {
-        let next = self.peek()?;
-
-        // Ignore character close
-        if next == '\'' {
-            return None;
-        }
-
-        let start = self.get_pos();
-        self.advance();
-
-        if next == '\\' {
-            Some(self.parse_escape(start))
-        } else {
-            let end = self.get_pos();
-            Some(CharComponent::new(
-                TextRange::from_to(start, end),
-                CodePoint,
-            ))
+            _ => StringComponent::new(range, AsciiEscape),
         }
     }
 
@@ -131,11 +110,11 @@ pub fn parse_ignore_newline(&mut self, start: TextUnit) -> Option<StringComponen
         }
     }
 
-    pub fn parse_string_component(&mut self) -> Option<StringComponent> {
+    pub fn parse_component(&mut self) -> Option<StringComponent> {
         let next = self.peek()?;
 
         // Ignore string close
-        if next == '"' {
+        if next == self.quote as char {
             return None;
         }
 
@@ -145,18 +124,18 @@ pub fn parse_string_component(&mut self) -> Option<StringComponent> {
         if next == '\\' {
             // Strings can use `\` to ignore newlines, so we first try to parse one of those
             // before falling back to parsing char escapes
-            self.parse_ignore_newline(start).or_else(|| {
-                let char_component = self.parse_escape(start);
-                Some(StringComponent::new(
-                    char_component.range,
-                    StringComponentKind::Char(char_component.kind),
-                ))
-            })
+            if self.quote == b'"' {
+                if let Some(component) = self.parse_ignore_newline(start) {
+                    return Some(component);
+                }
+            }
+
+            Some(self.parse_escape(start))
         } else {
             let end = self.get_pos();
             Some(StringComponent::new(
                 TextRange::from_to(start, end),
-                StringComponentKind::Char(CodePoint),
+                CodePoint,
             ))
         }
     }
@@ -177,23 +156,6 @@ fn new(range: TextRange, kind: StringComponentKind) -> StringComponent {
 #[derive(Debug, Eq, PartialEq, Clone)]
 pub enum StringComponentKind {
     IgnoreNewline,
-    Char(CharComponentKind),
-}
-
-#[derive(Debug, Eq, PartialEq, Clone)]
-pub struct CharComponent {
-    pub range: TextRange,
-    pub kind: CharComponentKind,
-}
-
-impl CharComponent {
-    fn new(range: TextRange, kind: CharComponentKind) -> CharComponent {
-        CharComponent { range, kind }
-    }
-}
-
-#[derive(Debug, Eq, PartialEq, Clone)]
-pub enum CharComponentKind {
     CodePoint,
     AsciiEscape,
     AsciiCodeEscape,
index d8351e9af7ab76992829679804d7856b688496d8..7476fea13ca3e759d821f1ae489c04b17a0e6f7d 100644 (file)
@@ -1,41 +1,82 @@
-use super::parser::Parser;
-use super::StringComponent;
+use crate::string_lexing::{
+    parser::Parser,
+    StringComponent,
+};
 
 pub fn parse_string_literal(src: &str) -> StringComponentIterator {
     StringComponentIterator {
-        parser: Parser::new(src),
+        parser: Parser::new(src, b'"'),
         has_closing_quote: false,
+        prefix: None,
+        quote: b'"',
+    }
+}
+
+pub fn parse_byte_string_literal(src: &str) -> StringComponentIterator {
+    StringComponentIterator {
+        parser: Parser::new(src, b'"'),
+        has_closing_quote: false,
+        prefix: Some(b'b'),
+        quote: b'"',
+    }
+}
+
+pub fn parse_char_literal(src: &str) -> StringComponentIterator {
+    StringComponentIterator {
+        parser: Parser::new(src, b'\''),
+        has_closing_quote: false,
+        prefix: None,
+        quote: b'\'',
+    }
+}
+
+pub fn parse_byte_literal(src: &str) -> StringComponentIterator {
+    StringComponentIterator {
+        parser: Parser::new(src, b'\''),
+        has_closing_quote: false,
+        prefix: Some(b'b'),
+        quote: b'\'',
     }
 }
 
 pub struct StringComponentIterator<'a> {
     parser: Parser<'a>,
     pub has_closing_quote: bool,
+    prefix: Option<u8>,
+    quote: u8,
 }
 
 impl<'a> Iterator for StringComponentIterator<'a> {
     type Item = StringComponent;
     fn next(&mut self) -> Option<StringComponent> {
         if self.parser.pos == 0 {
+            if let Some(prefix) = self.prefix {
+                assert!(
+                    self.parser.advance() == prefix as char,
+                    "literal should start with a {:?}",
+                    prefix as char,
+                );
+            }
             assert!(
-                self.parser.advance() == '"',
-                "string literal should start with double quotes"
+                self.parser.advance() == self.quote as char,
+                "literal should start with a {:?}",
+                self.quote as char,
             );
         }
 
-        if let Some(component) = self.parser.parse_string_component() {
+        if let Some(component) = self.parser.parse_component() {
             return Some(component);
         }
 
         // We get here when there are no char components left to parse
-        if self.parser.peek() == Some('"') {
+        if self.parser.peek() == Some(self.quote as char) {
             self.parser.advance();
             self.has_closing_quote = true;
         }
 
         assert!(
             self.parser.peek() == None,
-            "string literal should leave no unparsed input: src = {:?}, pos = {}, length = {}",
+            "literal should leave no unparsed input: src = {:?}, pos = {}, length = {}",
             self.parser.src,
             self.parser.pos,
             self.parser.src.len()
@@ -44,3 +85,133 @@ fn next(&mut self) -> Option<StringComponent> {
         None
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use rowan::TextRange;
+    use crate::string_lexing::{
+        StringComponent,
+        StringComponentKind::*,
+};
+
+    fn parse(src: &str) -> (bool, Vec<StringComponent>) {
+        let component_iterator = &mut super::parse_char_literal(src);
+        let components: Vec<_> = component_iterator.collect();
+        (component_iterator.has_closing_quote, components)
+    }
+
+    fn unclosed_char_component(src: &str) -> StringComponent {
+        let (has_closing_quote, components) = parse(src);
+        assert!(!has_closing_quote, "char should not have closing quote");
+        assert!(components.len() == 1);
+        components[0].clone()
+    }
+
+    fn closed_char_component(src: &str) -> StringComponent {
+        let (has_closing_quote, components) = parse(src);
+        assert!(has_closing_quote, "char should have closing quote");
+        assert!(
+            components.len() == 1,
+            "Literal: {}\nComponents: {:#?}",
+            src,
+            components
+        );
+        components[0].clone()
+    }
+
+    fn closed_char_components(src: &str) -> Vec<StringComponent> {
+        let (has_closing_quote, components) = parse(src);
+        assert!(has_closing_quote, "char should have closing quote");
+        components
+    }
+
+    fn range_closed(src: &str) -> TextRange {
+        TextRange::from_to(1.into(), (src.len() as u32 - 1).into())
+    }
+
+    fn range_unclosed(src: &str) -> TextRange {
+        TextRange::from_to(1.into(), (src.len() as u32).into())
+    }
+
+    #[test]
+    fn test_unicode_escapes() {
+        let unicode_escapes = &[r"{DEAD}", "{BEEF}", "{FF}", "{}", ""];
+        for escape in unicode_escapes {
+            let escape_sequence = format!(r"'\u{}'", escape);
+            let component = closed_char_component(&escape_sequence);
+            let expected_range = range_closed(&escape_sequence);
+            assert_eq!(component.kind, UnicodeEscape);
+            assert_eq!(component.range, expected_range);
+        }
+    }
+
+    #[test]
+    fn test_unicode_escapes_unclosed() {
+        let unicode_escapes = &["{DEAD", "{BEEF", "{FF"];
+        for escape in unicode_escapes {
+            let escape_sequence = format!(r"'\u{}'", escape);
+            let component = unclosed_char_component(&escape_sequence);
+            let expected_range = range_unclosed(&escape_sequence);
+            assert_eq!(component.kind, UnicodeEscape);
+            assert_eq!(component.range, expected_range);
+        }
+    }
+
+    #[test]
+    fn test_empty_char() {
+        let (has_closing_quote, components) = parse("''");
+        assert!(has_closing_quote, "char should have closing quote");
+        assert!(components.len() == 0);
+    }
+
+    #[test]
+    fn test_unclosed_char() {
+        let component = unclosed_char_component("'a");
+        assert!(component.kind == CodePoint);
+        assert!(component.range == TextRange::from_to(1.into(), 2.into()));
+    }
+
+    #[test]
+    fn test_digit_escapes() {
+        let literals = &[r"", r"5", r"55"];
+
+        for literal in literals {
+            let lit_text = format!(r"'\x{}'", literal);
+            let component = closed_char_component(&lit_text);
+            assert!(component.kind == AsciiCodeEscape);
+            assert!(component.range == range_closed(&lit_text));
+        }
+
+        // More than 2 digits starts a new codepoint
+        let components = closed_char_components(r"'\x555'");
+        assert!(components.len() == 2);
+        assert!(components[1].kind == CodePoint);
+    }
+
+    #[test]
+    fn test_ascii_escapes() {
+        let literals = &[
+            r"\'", "\\\"", // equivalent to \"
+            r"\n", r"\r", r"\t", r"\\", r"\0",
+        ];
+
+        for literal in literals {
+            let lit_text = format!("'{}'", literal);
+            let component = closed_char_component(&lit_text);
+            assert!(component.kind == AsciiEscape);
+            assert!(component.range == range_closed(&lit_text));
+        }
+    }
+
+    #[test]
+    fn test_no_escapes() {
+        let literals = &['"', 'n', 'r', 't', '0', 'x', 'u'];
+
+        for &literal in literals {
+            let lit_text = format!("'{}'", literal);
+            let component = closed_char_component(&lit_text);
+            assert!(component.kind == CodePoint);
+            assert!(component.range == range_closed(&lit_text));
+        }
+    }
+}
index 43c0d7edda55b91e09b87a769c78e6f8dd64fbef..e3603e7616ef6d3b13406f68e71820b42a698ef0 100644 (file)
@@ -2,7 +2,7 @@
 
 use crate::{
     ast::{self, AstNode},
-    string_lexing::{self, CharComponentKind},
+    string_lexing::{self, StringComponentKind},
     TextRange,
     validation::char,
     yellow::{
@@ -38,11 +38,11 @@ pub(super) fn validate_byte_node(node: ast::Byte, errors: &mut Vec<SyntaxError>)
 
 pub(super) fn validate_byte_component(
     text: &str,
-    kind: CharComponentKind,
+    kind: StringComponentKind,
     range: TextRange,
     errors: &mut Vec<SyntaxError>,
 ) {
-    use self::CharComponentKind::*;
+    use self::StringComponentKind::*;
     match kind {
         AsciiEscape => validate_byte_escape(text, range, errors),
         AsciiCodeEscape => validate_byte_code_escape(text, range, errors),
@@ -63,6 +63,7 @@ pub(super) fn validate_byte_component(
                 errors.push(SyntaxError::new(ByteOutOfRange, range));
             }
         }
+        IgnoreNewline => { /* always valid */ }
     }
 }
 
index 7b830e97cde1945fb42624b8524f096efab807b4..2f98472f47d92eb781a20ba339c74351d5c38e11 100644 (file)
@@ -17,15 +17,15 @@ pub(crate) fn validate_byte_string_node(node: ast::ByteString, errors: &mut Vec<
         let range = component.range + literal_range.start();
 
         match component.kind {
-            StringComponentKind::Char(kind) => {
+            StringComponentKind::IgnoreNewline => { /* always valid */ }
+            _ => {
                 // Chars must escape \t, \n and \r codepoints, but strings don't
                 let text = &literal_text[component.range];
                 match text {
                     "\t" | "\n" | "\r" => { /* always valid */ }
-                    _ => byte::validate_byte_component(text, kind, range, errors),
+                    _ => byte::validate_byte_component(text, component.kind, range, errors),
                 }
             }
-            StringComponentKind::IgnoreNewline => { /* always valid */ }
         }
     }
 
index 4728c85e6fd1f5a12b91bbceeda6a054a6758772..deb5b0a9e1ce2c2fffd76d8b8474052cbae57fce 100644 (file)
@@ -6,7 +6,7 @@
 
 use crate::{
     ast::{self, AstNode},
-    string_lexing::{self, CharComponentKind},
+    string_lexing::{self, StringComponentKind},
     TextRange,
     yellow::{
         SyntaxError,
@@ -41,12 +41,12 @@ pub(super) fn validate_char_node(node: ast::Char, errors: &mut Vec<SyntaxError>)
 
 pub(super) fn validate_char_component(
     text: &str,
-    kind: CharComponentKind,
+    kind: StringComponentKind,
     range: TextRange,
     errors: &mut Vec<SyntaxError>,
 ) {
     // Validate escapes
-    use self::CharComponentKind::*;
+    use self::StringComponentKind::*;
     match kind {
         AsciiEscape => validate_ascii_escape(text, range, errors),
         AsciiCodeEscape => validate_ascii_code_escape(text, range, errors),
@@ -57,6 +57,7 @@ pub(super) fn validate_char_component(
                 errors.push(SyntaxError::new(UnescapedCodepoint, range));
             }
         }
+        StringComponentKind::IgnoreNewline => { /* always valid */ }
     }
 }
 
index 089879d1530748b2e412ae6ad1c235c9ec54c24a..456180ab66eba71b3c28afb8477cc69943a0c401 100644 (file)
@@ -1,6 +1,6 @@
 use crate::{
     ast::{self, AstNode},
-    string_lexing::{self, StringComponentKind},
+    string_lexing,
     yellow::{
         SyntaxError,
         SyntaxErrorKind::*,
@@ -16,16 +16,11 @@ pub(crate) fn validate_string_node(node: ast::String, errors: &mut Vec<SyntaxErr
     for component in &mut components {
         let range = component.range + literal_range.start();
 
-        match component.kind {
-            StringComponentKind::Char(kind) => {
-                // Chars must escape \t, \n and \r codepoints, but strings don't
-                let text = &literal_text[component.range];
-                match text {
-                    "\t" | "\n" | "\r" => { /* always valid */ }
-                    _ => char::validate_char_component(text, kind, range, errors),
-                }
-            }
-            StringComponentKind::IgnoreNewline => { /* always valid */ }
+        // Chars must escape \t, \n and \r codepoints, but strings don't
+        let text = &literal_text[component.range];
+        match text {
+            "\t" | "\n" | "\r" => { /* always valid */ }
+            _ => char::validate_char_component(text, component.kind, range, errors),
         }
     }