1 | use super::{ |
2 | comment, |
3 | errors::{ErrorKind, ParserError}, |
4 | slice::Slice, |
5 | }; |
6 | use crate::ast; |
7 | |
8 | pub type Result<T> = std::result::Result<T, ParserError>; |
9 | |
10 | pub struct Parser<S> { |
11 | pub(super) source: S, |
12 | pub(super) ptr: usize, |
13 | pub(super) length: usize, |
14 | } |
15 | |
16 | impl<'s, S> Parser<S> |
17 | where |
18 | S: Slice<'s>, |
19 | { |
20 | pub fn new(source: S) -> Self { |
21 | let length = source.as_ref().as_bytes().len(); |
22 | Self { |
23 | source, |
24 | ptr: 0, |
25 | length, |
26 | } |
27 | } |
28 | |
29 | pub fn parse( |
30 | mut self, |
31 | ) -> std::result::Result<ast::Resource<S>, (ast::Resource<S>, Vec<ParserError>)> { |
32 | let mut errors = vec![]; |
33 | |
34 | let mut body = vec![]; |
35 | |
36 | self.skip_blank_block(); |
37 | let mut last_comment = None; |
38 | let mut last_blank_count = 0; |
39 | |
40 | while self.ptr < self.length { |
41 | let entry_start = self.ptr; |
42 | let mut entry = self.get_entry(entry_start); |
43 | |
44 | if let Some(comment) = last_comment.take() { |
45 | match entry { |
46 | Ok(ast::Entry::Message(ref mut msg)) if last_blank_count < 2 => { |
47 | msg.comment = Some(comment); |
48 | } |
49 | Ok(ast::Entry::Term(ref mut term)) if last_blank_count < 2 => { |
50 | term.comment = Some(comment); |
51 | } |
52 | _ => { |
53 | body.push(ast::Entry::Comment(comment)); |
54 | } |
55 | } |
56 | } |
57 | |
58 | match entry { |
59 | Ok(ast::Entry::Comment(comment)) => { |
60 | last_comment = Some(comment); |
61 | } |
62 | Ok(entry) => { |
63 | body.push(entry); |
64 | } |
65 | Err(mut err) => { |
66 | self.skip_to_next_entry_start(); |
67 | err.slice = Some(entry_start..self.ptr); |
68 | errors.push(err); |
69 | let content = self.source.slice(entry_start..self.ptr); |
70 | body.push(ast::Entry::Junk { content }); |
71 | } |
72 | } |
73 | last_blank_count = self.skip_blank_block(); |
74 | } |
75 | |
76 | if let Some(last_comment) = last_comment.take() { |
77 | body.push(ast::Entry::Comment(last_comment)); |
78 | } |
79 | if errors.is_empty() { |
80 | Ok(ast::Resource { body }) |
81 | } else { |
82 | Err((ast::Resource { body }, errors)) |
83 | } |
84 | } |
85 | |
86 | fn get_entry(&mut self, entry_start: usize) -> Result<ast::Entry<S>> { |
87 | let entry = match get_current_byte!(self) { |
88 | Some(b'#' ) => { |
89 | let (comment, level) = self.get_comment()?; |
90 | match level { |
91 | comment::Level::Regular => ast::Entry::Comment(comment), |
92 | comment::Level::Group => ast::Entry::GroupComment(comment), |
93 | comment::Level::Resource => ast::Entry::ResourceComment(comment), |
94 | comment::Level::None => unreachable!(), |
95 | } |
96 | } |
97 | Some(b'-' ) => ast::Entry::Term(self.get_term(entry_start)?), |
98 | _ => ast::Entry::Message(self.get_message(entry_start)?), |
99 | }; |
100 | Ok(entry) |
101 | } |
102 | |
103 | pub fn get_message(&mut self, entry_start: usize) -> Result<ast::Message<S>> { |
104 | let id = self.get_identifier()?; |
105 | self.skip_blank_inline(); |
106 | self.expect_byte(b'=' )?; |
107 | let pattern = self.get_pattern()?; |
108 | |
109 | self.skip_blank_block(); |
110 | |
111 | let attributes = self.get_attributes(); |
112 | |
113 | if pattern.is_none() && attributes.is_empty() { |
114 | let entry_id = id.name.as_ref().to_owned(); |
115 | return error!( |
116 | ErrorKind::ExpectedMessageField { entry_id }, |
117 | entry_start, self.ptr |
118 | ); |
119 | } |
120 | |
121 | Ok(ast::Message { |
122 | id, |
123 | value: pattern, |
124 | attributes, |
125 | comment: None, |
126 | }) |
127 | } |
128 | |
129 | pub fn get_term(&mut self, entry_start: usize) -> Result<ast::Term<S>> { |
130 | self.expect_byte(b'-' )?; |
131 | let id = self.get_identifier()?; |
132 | self.skip_blank_inline(); |
133 | self.expect_byte(b'=' )?; |
134 | self.skip_blank_inline(); |
135 | |
136 | let value = self.get_pattern()?; |
137 | |
138 | self.skip_blank_block(); |
139 | |
140 | let attributes = self.get_attributes(); |
141 | |
142 | if let Some(value) = value { |
143 | Ok(ast::Term { |
144 | id, |
145 | value, |
146 | attributes, |
147 | comment: None, |
148 | }) |
149 | } else { |
150 | error!( |
151 | ErrorKind::ExpectedTermField { |
152 | entry_id: id.name.as_ref().to_owned() |
153 | }, |
154 | entry_start, self.ptr |
155 | ) |
156 | } |
157 | } |
158 | |
159 | fn get_attributes(&mut self) -> Vec<ast::Attribute<S>> { |
160 | let mut attributes = vec![]; |
161 | |
162 | loop { |
163 | let line_start = self.ptr; |
164 | self.skip_blank_inline(); |
165 | if !self.take_byte_if(b'.' ) { |
166 | self.ptr = line_start; |
167 | break; |
168 | } |
169 | |
170 | if let Ok(attr) = self.get_attribute() { |
171 | attributes.push(attr); |
172 | } else { |
173 | self.ptr = line_start; |
174 | break; |
175 | } |
176 | } |
177 | attributes |
178 | } |
179 | |
180 | fn get_attribute(&mut self) -> Result<ast::Attribute<S>> { |
181 | let id = self.get_identifier()?; |
182 | self.skip_blank_inline(); |
183 | self.expect_byte(b'=' )?; |
184 | let pattern = self.get_pattern()?; |
185 | |
186 | match pattern { |
187 | Some(pattern) => Ok(ast::Attribute { id, value: pattern }), |
188 | None => error!(ErrorKind::MissingValue, self.ptr), |
189 | } |
190 | } |
191 | |
192 | pub(super) fn get_identifier_unchecked(&mut self) -> ast::Identifier<S> { |
193 | let mut ptr = self.ptr; |
194 | |
195 | while matches!(get_byte!(self, ptr), Some(b) if b.is_ascii_alphanumeric() || *b == b'-' || *b == b'_' ) |
196 | { |
197 | ptr += 1; |
198 | } |
199 | |
200 | let name = self.source.slice(self.ptr - 1..ptr); |
201 | self.ptr = ptr; |
202 | |
203 | ast::Identifier { name } |
204 | } |
205 | |
206 | pub(super) fn get_identifier(&mut self) -> Result<ast::Identifier<S>> { |
207 | if !self.is_identifier_start() { |
208 | return error!( |
209 | ErrorKind::ExpectedCharRange { |
210 | range: "a-zA-Z" .to_string() |
211 | }, |
212 | self.ptr |
213 | ); |
214 | } |
215 | self.ptr += 1; |
216 | Ok(self.get_identifier_unchecked()) |
217 | } |
218 | |
219 | pub(super) fn get_attribute_accessor(&mut self) -> Result<Option<ast::Identifier<S>>> { |
220 | if self.take_byte_if(b'.' ) { |
221 | let ident = self.get_identifier()?; |
222 | Ok(Some(ident)) |
223 | } else { |
224 | Ok(None) |
225 | } |
226 | } |
227 | |
228 | fn get_variant_key(&mut self) -> Result<ast::VariantKey<S>> { |
229 | self.skip_blank(); |
230 | |
231 | let key = if self.is_number_start() { |
232 | ast::VariantKey::NumberLiteral { |
233 | value: self.get_number_literal()?, |
234 | } |
235 | } else { |
236 | ast::VariantKey::Identifier { |
237 | name: self.get_identifier()?.name, |
238 | } |
239 | }; |
240 | |
241 | self.skip_blank(); |
242 | |
243 | self.expect_byte(b']' )?; |
244 | |
245 | Ok(key) |
246 | } |
247 | |
248 | pub(super) fn get_variants(&mut self) -> Result<Vec<ast::Variant<S>>> { |
249 | let mut variants = Vec::with_capacity(2); |
250 | let mut has_default = false; |
251 | |
252 | loop { |
253 | let default = self.take_byte_if(b'*' ); |
254 | if default { |
255 | if has_default { |
256 | return error!(ErrorKind::MultipleDefaultVariants, self.ptr); |
257 | } else { |
258 | has_default = true; |
259 | } |
260 | } |
261 | |
262 | if !self.take_byte_if(b'[' ) { |
263 | break; |
264 | } |
265 | |
266 | let key = self.get_variant_key()?; |
267 | |
268 | let value = self.get_pattern()?; |
269 | |
270 | if let Some(value) = value { |
271 | variants.push(ast::Variant { |
272 | key, |
273 | value, |
274 | default, |
275 | }); |
276 | self.skip_blank(); |
277 | } else { |
278 | return error!(ErrorKind::MissingValue, self.ptr); |
279 | } |
280 | } |
281 | |
282 | if has_default { |
283 | Ok(variants) |
284 | } else { |
285 | error!(ErrorKind::MissingDefaultVariant, self.ptr) |
286 | } |
287 | } |
288 | |
289 | pub(super) fn get_placeable(&mut self) -> Result<ast::Expression<S>> { |
290 | self.skip_blank(); |
291 | let exp = self.get_expression()?; |
292 | self.skip_blank_inline(); |
293 | self.expect_byte(b'}' )?; |
294 | |
295 | let invalid_expression_found = match &exp { |
296 | ast::Expression::Inline(ast::InlineExpression::TermReference { |
297 | ref attribute, .. |
298 | }) => attribute.is_some(), |
299 | _ => false, |
300 | }; |
301 | if invalid_expression_found { |
302 | return error!(ErrorKind::TermAttributeAsPlaceable, self.ptr); |
303 | } |
304 | |
305 | Ok(exp) |
306 | } |
307 | } |
308 | |