diff options
Diffstat (limited to 'crates/ra_syntax/src/string_lexing/parser.rs')
-rw-r--r-- | crates/ra_syntax/src/string_lexing/parser.rs | 92 |
1 files changed, 32 insertions, 60 deletions
diff --git a/crates/ra_syntax/src/string_lexing/parser.rs b/crates/ra_syntax/src/string_lexing/parser.rs index 4a6d5bc93..14c6015c2 100644 --- a/crates/ra_syntax/src/string_lexing/parser.rs +++ b/crates/ra_syntax/src/string_lexing/parser.rs | |||
@@ -1,15 +1,16 @@ | |||
1 | use rowan::{TextRange, TextUnit}; | 1 | use rowan::{TextRange, TextUnit}; |
2 | 2 | ||
3 | use self::CharComponentKind::*; | 3 | use self::StringComponentKind::*; |
4 | 4 | ||
5 | pub struct Parser<'a> { | 5 | pub struct Parser<'a> { |
6 | pub(super) quote: u8, | ||
6 | pub(super) src: &'a str, | 7 | pub(super) src: &'a str, |
7 | pub(super) pos: usize, | 8 | pub(super) pos: usize, |
8 | } | 9 | } |
9 | 10 | ||
10 | impl<'a> Parser<'a> { | 11 | impl<'a> Parser<'a> { |
11 | pub fn new(src: &'a str) -> Parser<'a> { | 12 | pub fn new(src: &'a str, quote: u8) -> Parser<'a> { |
12 | Parser { src, pos: 0 } | 13 | Parser { quote, src, pos: 0 } |
13 | } | 14 | } |
14 | 15 | ||
15 | // Utility methods | 16 | // Utility methods |
@@ -42,7 +43,7 @@ impl<'a> Parser<'a> { | |||
42 | 43 | ||
43 | // Char parsing methods | 44 | // Char parsing methods |
44 | 45 | ||
45 | fn parse_unicode_escape(&mut self, start: TextUnit) -> CharComponent { | 46 | fn parse_unicode_escape(&mut self, start: TextUnit) -> StringComponent { |
46 | match self.peek() { | 47 | match self.peek() { |
47 | Some('{') => { | 48 | Some('{') => { |
48 | self.advance(); | 49 | self.advance(); |
@@ -56,16 +57,16 @@ impl<'a> Parser<'a> { | |||
56 | } | 57 | } |
57 | 58 | ||
58 | let end = self.get_pos(); | 59 | let end = self.get_pos(); |
59 | CharComponent::new(TextRange::from_to(start, end), UnicodeEscape) | 60 | StringComponent::new(TextRange::from_to(start, end), UnicodeEscape) |
60 | } | 61 | } |
61 | Some(_) | None => { | 62 | Some(_) | None => { |
62 | let end = self.get_pos(); | 63 | let end = self.get_pos(); |
63 | CharComponent::new(TextRange::from_to(start, end), UnicodeEscape) | 64 | StringComponent::new(TextRange::from_to(start, end), UnicodeEscape) |
64 | } | 65 | } |
65 | } | 66 | } |
66 | } | 67 | } |
67 | 68 | ||
68 | fn parse_ascii_code_escape(&mut self, start: TextUnit) -> CharComponent { | 69 | fn parse_ascii_code_escape(&mut self, start: TextUnit) -> StringComponent { |
69 | let code_start = self.get_pos(); | 70 | let code_start = self.get_pos(); |
70 | while let Some(next) = self.peek() { | 71 | while let Some(next) = self.peek() { |
71 | if next == '\'' || (self.get_pos() - code_start == 2.into()) { | 72 | if next == '\'' || (self.get_pos() - code_start == 2.into()) { |
@@ -76,12 +77,12 @@ impl<'a> Parser<'a> { | |||
76 | } | 77 | } |
77 | 78 | ||
78 | let end = self.get_pos(); | 79 | let end = self.get_pos(); |
79 | CharComponent::new(TextRange::from_to(start, end), AsciiCodeEscape) | 80 | StringComponent::new(TextRange::from_to(start, end), AsciiCodeEscape) |
80 | } | 81 | } |
81 | 82 | ||
82 | fn parse_escape(&mut self, start: TextUnit) -> CharComponent { | 83 | fn parse_escape(&mut self, start: TextUnit) -> StringComponent { |
83 | if self.peek().is_none() { | 84 | if self.peek().is_none() { |
84 | return CharComponent::new(TextRange::from_to(start, start), AsciiEscape); | 85 | return StringComponent::new(TextRange::from_to(start, start), AsciiEscape); |
85 | } | 86 | } |
86 | 87 | ||
87 | let next = self.advance(); | 88 | let next = self.advance(); |
@@ -90,29 +91,7 @@ impl<'a> Parser<'a> { | |||
90 | match next { | 91 | match next { |
91 | 'x' => self.parse_ascii_code_escape(start), | 92 | 'x' => self.parse_ascii_code_escape(start), |
92 | 'u' => self.parse_unicode_escape(start), | 93 | 'u' => self.parse_unicode_escape(start), |
93 | _ => CharComponent::new(range, AsciiEscape), | 94 | _ => StringComponent::new(range, AsciiEscape), |
94 | } | ||
95 | } | ||
96 | |||
97 | pub fn parse_char_component(&mut self) -> Option<CharComponent> { | ||
98 | let next = self.peek()?; | ||
99 | |||
100 | // Ignore character close | ||
101 | if next == '\'' { | ||
102 | return None; | ||
103 | } | ||
104 | |||
105 | let start = self.get_pos(); | ||
106 | self.advance(); | ||
107 | |||
108 | if next == '\\' { | ||
109 | Some(self.parse_escape(start)) | ||
110 | } else { | ||
111 | let end = self.get_pos(); | ||
112 | Some(CharComponent::new( | ||
113 | TextRange::from_to(start, end), | ||
114 | CodePoint, | ||
115 | )) | ||
116 | } | 95 | } |
117 | } | 96 | } |
118 | 97 | ||
@@ -131,11 +110,11 @@ impl<'a> Parser<'a> { | |||
131 | } | 110 | } |
132 | } | 111 | } |
133 | 112 | ||
134 | pub fn parse_string_component(&mut self) -> Option<StringComponent> { | 113 | pub fn parse_component(&mut self) -> Option<StringComponent> { |
135 | let next = self.peek()?; | 114 | let next = self.peek()?; |
136 | 115 | ||
137 | // Ignore string close | 116 | // Ignore string close |
138 | if next == '"' { | 117 | if next == self.quote as char { |
139 | return None; | 118 | return None; |
140 | } | 119 | } |
141 | 120 | ||
@@ -145,21 +124,31 @@ impl<'a> Parser<'a> { | |||
145 | if next == '\\' { | 124 | if next == '\\' { |
146 | // Strings can use `\` to ignore newlines, so we first try to parse one of those | 125 | // Strings can use `\` to ignore newlines, so we first try to parse one of those |
147 | // before falling back to parsing char escapes | 126 | // before falling back to parsing char escapes |
148 | self.parse_ignore_newline(start).or_else(|| { | 127 | if self.quote == b'"' { |
149 | let char_component = self.parse_escape(start); | 128 | if let Some(component) = self.parse_ignore_newline(start) { |
150 | Some(StringComponent::new( | 129 | return Some(component); |
151 | char_component.range, | 130 | } |
152 | StringComponentKind::Char(char_component.kind), | 131 | } |
153 | )) | 132 | |
154 | }) | 133 | Some(self.parse_escape(start)) |
155 | } else { | 134 | } else { |
156 | let end = self.get_pos(); | 135 | let end = self.get_pos(); |
157 | Some(StringComponent::new( | 136 | Some(StringComponent::new( |
158 | TextRange::from_to(start, end), | 137 | TextRange::from_to(start, end), |
159 | StringComponentKind::Char(CodePoint), | 138 | CodePoint, |
160 | )) | 139 | )) |
161 | } | 140 | } |
162 | } | 141 | } |
142 | |||
143 | pub fn parse_suffix(&mut self) -> Option<TextRange> { | ||
144 | let start = self.get_pos(); | ||
145 | let _ = self.peek()?; | ||
146 | while let Some(_) = self.peek() { | ||
147 | self.advance(); | ||
148 | } | ||
149 | let end = self.get_pos(); | ||
150 | Some(TextRange::from_to(start, end)) | ||
151 | } | ||
163 | } | 152 | } |
164 | 153 | ||
165 | #[derive(Debug, Eq, PartialEq, Clone)] | 154 | #[derive(Debug, Eq, PartialEq, Clone)] |
@@ -177,23 +166,6 @@ impl StringComponent { | |||
177 | #[derive(Debug, Eq, PartialEq, Clone)] | 166 | #[derive(Debug, Eq, PartialEq, Clone)] |
178 | pub enum StringComponentKind { | 167 | pub enum StringComponentKind { |
179 | IgnoreNewline, | 168 | IgnoreNewline, |
180 | Char(CharComponentKind), | ||
181 | } | ||
182 | |||
183 | #[derive(Debug, Eq, PartialEq, Clone)] | ||
184 | pub struct CharComponent { | ||
185 | pub range: TextRange, | ||
186 | pub kind: CharComponentKind, | ||
187 | } | ||
188 | |||
189 | impl CharComponent { | ||
190 | fn new(range: TextRange, kind: CharComponentKind) -> CharComponent { | ||
191 | CharComponent { range, kind } | ||
192 | } | ||
193 | } | ||
194 | |||
195 | #[derive(Debug, Eq, PartialEq, Clone)] | ||
196 | pub enum CharComponentKind { | ||
197 | CodePoint, | 169 | CodePoint, |
198 | AsciiEscape, | 170 | AsciiEscape, |
199 | AsciiCodeEscape, | 171 | AsciiCodeEscape, |