/src/pest/meta/src/parser.rs
Line | Count | Source |
1 | | // pest. The Elegant Parser |
2 | | // Copyright (c) 2018 DragoČ™ Tiselice |
3 | | // |
4 | | // Licensed under the Apache License, Version 2.0 |
5 | | // <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT |
6 | | // license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
7 | | // option. All files in the project carrying such notice may not be copied, |
8 | | // modified, or distributed except according to those terms. |
9 | | |
10 | | //! Types and helpers for the pest's own grammar parser. |
11 | | |
12 | | use std::char; |
13 | | use std::iter::Peekable; |
14 | | |
15 | | use pest::error::{Error, ErrorVariant}; |
16 | | use pest::iterators::{Pair, Pairs}; |
17 | | use pest::pratt_parser::{Assoc, Op, PrattParser}; |
18 | | use pest::{Parser, Position, Span}; |
19 | | |
20 | | use crate::ast::{Expr, Rule as AstRule, RuleType}; |
21 | | use crate::validator; |
22 | | |
23 | | /// Generated from `grammar.pest` by `cargo bootstrap` (pest_bootstrap). |
24 | | #[allow(missing_docs, unused_qualifications)] |
25 | | mod grammar { |
26 | | include!("grammar.rs"); |
27 | | } |
28 | | |
29 | | /// Import included grammar (`PestParser` class globally for current module). |
30 | | pub use self::grammar::*; |
31 | | |
32 | | /// A helper that will parse using the pest grammar |
33 | | #[allow(clippy::perf)] |
34 | 5.80k | pub fn parse(rule: Rule, data: &str) -> Result<Pairs<'_, Rule>, Error<Rule>> { |
35 | 5.80k | PestParser::parse(rule, data) |
36 | 5.80k | } |
37 | | |
38 | | /// The pest grammar rule |
39 | | #[derive(Clone, Debug, Eq, PartialEq)] |
40 | | pub struct ParserRule<'i> { |
41 | | /// The rule's name |
42 | | pub name: String, |
43 | | /// The rule's span |
44 | | pub span: Span<'i>, |
45 | | /// The rule's type |
46 | | pub ty: RuleType, |
47 | | /// The rule's parser node |
48 | | pub node: ParserNode<'i>, |
49 | | } |
50 | | |
51 | | /// The pest grammar node |
52 | | #[derive(Clone, Debug, Eq, PartialEq)] |
53 | | pub struct ParserNode<'i> { |
54 | | /// The node's expression |
55 | | pub expr: ParserExpr<'i>, |
56 | | /// The node's span |
57 | | pub span: Span<'i>, |
58 | | } |
59 | | |
60 | | impl<'i> ParserNode<'i> { |
61 | | /// will remove nodes that do not match `f` |
62 | 0 | pub fn filter_map_top_down<F, T>(self, mut f: F) -> Vec<T> |
63 | 0 | where |
64 | 0 | F: FnMut(ParserNode<'i>) -> Option<T>, |
65 | | { |
66 | 0 | pub fn filter_internal<'i, F, T>(node: ParserNode<'i>, f: &mut F, result: &mut Vec<T>) |
67 | 0 | where |
68 | 0 | F: FnMut(ParserNode<'i>) -> Option<T>, |
69 | | { |
70 | 0 | if let Some(value) = f(node.clone()) { |
71 | 0 | result.push(value); |
72 | 0 | } |
73 | | |
74 | 0 | match node.expr { |
75 | 0 | ParserExpr::PosPred(node) => { |
76 | 0 | filter_internal(*node, f, result); |
77 | 0 | } |
78 | 0 | ParserExpr::NegPred(node) => { |
79 | 0 | filter_internal(*node, f, result); |
80 | 0 | } |
81 | 0 | ParserExpr::Seq(lhs, rhs) => { |
82 | 0 | filter_internal(*lhs, f, result); |
83 | 0 | filter_internal(*rhs, f, result); |
84 | 0 | } |
85 | 0 | ParserExpr::Choice(lhs, rhs) => { |
86 | 0 | filter_internal(*lhs, f, result); |
87 | 0 | filter_internal(*rhs, f, result); |
88 | 0 | } |
89 | 0 | ParserExpr::Rep(node) => { |
90 | 0 | filter_internal(*node, f, result); |
91 | 0 | } |
92 | 0 | ParserExpr::RepOnce(node) => { |
93 | 0 | filter_internal(*node, f, result); |
94 | 0 | } |
95 | 0 | ParserExpr::RepExact(node, _) => { |
96 | 0 | filter_internal(*node, f, result); |
97 | 0 | } |
98 | 0 | ParserExpr::RepMin(node, _) => { |
99 | 0 | filter_internal(*node, f, result); |
100 | 0 | } |
101 | 0 | ParserExpr::RepMax(node, _) => { |
102 | 0 | filter_internal(*node, f, result); |
103 | 0 | } |
104 | 0 | ParserExpr::RepMinMax(node, ..) => { |
105 | 0 | filter_internal(*node, f, result); |
106 | 0 | } |
107 | 0 | ParserExpr::Opt(node) => { |
108 | 0 | filter_internal(*node, f, result); |
109 | 0 | } |
110 | 0 | ParserExpr::Push(node) => { |
111 | 0 | filter_internal(*node, f, result); |
112 | 0 | } |
113 | 0 | _ => (), |
114 | | } |
115 | 0 | } Unexecuted instantiation: <pest_meta::parser::ParserNode>::filter_map_top_down::filter_internal::<pest_meta::validator::validate_choices::{closure#0}, pest::error::Error<pest_meta::parser::grammar::Rule>>Unexecuted instantiation: <pest_meta::parser::ParserNode>::filter_map_top_down::filter_internal::<pest_meta::validator::validate_repetition::{closure#0}, pest::error::Error<pest_meta::parser::grammar::Rule>> |
116 | | |
117 | 0 | let mut result = vec![]; |
118 | | |
119 | 0 | filter_internal(self, &mut f, &mut result); |
120 | | |
121 | 0 | result |
122 | 0 | } Unexecuted instantiation: <pest_meta::parser::ParserNode>::filter_map_top_down::<pest_meta::validator::validate_choices::{closure#0}, pest::error::Error<pest_meta::parser::grammar::Rule>>Unexecuted instantiation: <pest_meta::parser::ParserNode>::filter_map_top_down::<pest_meta::validator::validate_repetition::{closure#0}, pest::error::Error<pest_meta::parser::grammar::Rule>> |
123 | | } |
124 | | |
125 | | /// All possible parser expressions |
126 | | #[derive(Clone, Debug, Eq, PartialEq)] |
127 | | pub enum ParserExpr<'i> { |
128 | | /// Matches an exact string, e.g. `"a"` |
129 | | Str(String), |
130 | | /// Matches an exact string, case insensitively (ASCII only), e.g. `^"a"` |
131 | | Insens(String), |
132 | | /// Matches one character in the range, e.g. `'a'..'z'` |
133 | | Range(String, String), |
134 | | /// Matches the rule with the given name, e.g. `a` |
135 | | Ident(String), |
136 | | /// Matches a custom part of the stack, e.g. `PEEK[..]` |
137 | | PeekSlice(i32, Option<i32>), |
138 | | /// Positive lookahead; matches expression without making progress, e.g. `&e` |
139 | | PosPred(Box<ParserNode<'i>>), |
140 | | /// Negative lookahead; matches if expression doesn't match, without making progress, e.g. `!e` |
141 | | NegPred(Box<ParserNode<'i>>), |
142 | | /// Matches a sequence of two expressions, e.g. `e1 ~ e2` |
143 | | Seq(Box<ParserNode<'i>>, Box<ParserNode<'i>>), |
144 | | /// Matches either of two expressions, e.g. `e1 | e2` |
145 | | Choice(Box<ParserNode<'i>>, Box<ParserNode<'i>>), |
146 | | /// Optionally matches an expression, e.g. `e?` |
147 | | Opt(Box<ParserNode<'i>>), |
148 | | /// Matches an expression zero or more times, e.g. `e*` |
149 | | Rep(Box<ParserNode<'i>>), |
150 | | /// Matches an expression one or more times, e.g. `e+` |
151 | | RepOnce(Box<ParserNode<'i>>), |
152 | | /// Matches an expression an exact number of times, e.g. `e{n}` |
153 | | RepExact(Box<ParserNode<'i>>, u32), |
154 | | /// Matches an expression at least a number of times, e.g. `e{n,}` |
155 | | RepMin(Box<ParserNode<'i>>, u32), |
156 | | /// Matches an expression at most a number of times, e.g. `e{,n}` |
157 | | RepMax(Box<ParserNode<'i>>, u32), |
158 | | /// Matches an expression a number of times within a range, e.g. `e{m, n}` |
159 | | RepMinMax(Box<ParserNode<'i>>, u32, u32), |
160 | | /// Matches an expression and pushes it to the stack, e.g. `push(e)` |
161 | | Push(Box<ParserNode<'i>>), |
162 | | /// Pushes a literal string to the stack, e.g. `push_literal("a")` |
163 | | #[cfg(feature = "grammar-extras")] |
164 | | PushLiteral(String), |
165 | | /// Matches an expression and assigns a label to it, e.g. #label = exp |
166 | | #[cfg(feature = "grammar-extras")] |
167 | | NodeTag(Box<ParserNode<'i>>, String), |
168 | | } |
169 | | |
170 | 0 | fn convert_rule(rule: ParserRule<'_>) -> AstRule { |
171 | 0 | let ParserRule { name, ty, node, .. } = rule; |
172 | 0 | let expr = convert_node(node); |
173 | 0 | AstRule { name, ty, expr } |
174 | 0 | } |
175 | | |
176 | 0 | fn convert_node(node: ParserNode<'_>) -> Expr { |
177 | 0 | match node.expr { |
178 | 0 | ParserExpr::Str(string) => Expr::Str(string), |
179 | 0 | ParserExpr::Insens(string) => Expr::Insens(string), |
180 | 0 | ParserExpr::Range(start, end) => Expr::Range(start, end), |
181 | 0 | ParserExpr::Ident(ident) => Expr::Ident(ident), |
182 | 0 | ParserExpr::PeekSlice(start, end) => Expr::PeekSlice(start, end), |
183 | 0 | ParserExpr::PosPred(node) => Expr::PosPred(Box::new(convert_node(*node))), |
184 | 0 | ParserExpr::NegPred(node) => Expr::NegPred(Box::new(convert_node(*node))), |
185 | 0 | ParserExpr::Seq(node1, node2) => Expr::Seq( |
186 | 0 | Box::new(convert_node(*node1)), |
187 | 0 | Box::new(convert_node(*node2)), |
188 | 0 | ), |
189 | 0 | ParserExpr::Choice(node1, node2) => Expr::Choice( |
190 | 0 | Box::new(convert_node(*node1)), |
191 | 0 | Box::new(convert_node(*node2)), |
192 | 0 | ), |
193 | 0 | ParserExpr::Opt(node) => Expr::Opt(Box::new(convert_node(*node))), |
194 | 0 | ParserExpr::Rep(node) => Expr::Rep(Box::new(convert_node(*node))), |
195 | 0 | ParserExpr::RepOnce(node) => Expr::RepOnce(Box::new(convert_node(*node))), |
196 | 0 | ParserExpr::RepExact(node, num) => Expr::RepExact(Box::new(convert_node(*node)), num), |
197 | 0 | ParserExpr::RepMin(node, max) => Expr::RepMin(Box::new(convert_node(*node)), max), |
198 | 0 | ParserExpr::RepMax(node, max) => Expr::RepMax(Box::new(convert_node(*node)), max), |
199 | 0 | ParserExpr::RepMinMax(node, min, max) => { |
200 | 0 | Expr::RepMinMax(Box::new(convert_node(*node)), min, max) |
201 | | } |
202 | 0 | ParserExpr::Push(node) => Expr::Push(Box::new(convert_node(*node))), |
203 | | #[cfg(feature = "grammar-extras")] |
204 | | ParserExpr::PushLiteral(string) => Expr::PushLiteral(string), |
205 | | #[cfg(feature = "grammar-extras")] |
206 | | ParserExpr::NodeTag(node, tag) => Expr::NodeTag(Box::new(convert_node(*node)), tag), |
207 | | } |
208 | 0 | } |
209 | | |
210 | | /// Converts a parser's result (`Pairs`) to an AST |
211 | 0 | pub fn consume_rules(pairs: Pairs<'_, Rule>) -> Result<Vec<AstRule>, Vec<Error<Rule>>> { |
212 | 0 | let rules = consume_rules_with_spans(pairs)?; |
213 | 0 | let errors = validator::validate_ast(&rules); |
214 | 0 | if errors.is_empty() { |
215 | 0 | Ok(rules.into_iter().map(convert_rule).collect()) |
216 | | } else { |
217 | 0 | Err(errors) |
218 | | } |
219 | 0 | } |
220 | | |
221 | | /// A helper function to rename verbose rules |
222 | | /// for the sake of better error messages |
223 | | #[inline] |
224 | | pub fn rename_meta_rule(rule: &Rule) -> String { |
225 | | match *rule { |
226 | | Rule::grammar_rule => "rule".to_owned(), |
227 | | Rule::_push => "PUSH".to_owned(), |
228 | | Rule::_push_literal => "PUSH_LITERAL".to_owned(), |
229 | | Rule::assignment_operator => "`=`".to_owned(), |
230 | | Rule::silent_modifier => "`_`".to_owned(), |
231 | | Rule::atomic_modifier => "`@`".to_owned(), |
232 | | Rule::compound_atomic_modifier => "`$`".to_owned(), |
233 | | Rule::non_atomic_modifier => "`!`".to_owned(), |
234 | | Rule::opening_brace => "`{`".to_owned(), |
235 | | Rule::closing_brace => "`}`".to_owned(), |
236 | | Rule::opening_brack => "`[`".to_owned(), |
237 | | Rule::closing_brack => "`]`".to_owned(), |
238 | | Rule::opening_paren => "`(`".to_owned(), |
239 | | Rule::positive_predicate_operator => "`&`".to_owned(), |
240 | | Rule::negative_predicate_operator => "`!`".to_owned(), |
241 | | Rule::sequence_operator => "`&`".to_owned(), |
242 | | Rule::choice_operator => "`|`".to_owned(), |
243 | | Rule::optional_operator => "`?`".to_owned(), |
244 | | Rule::repeat_operator => "`*`".to_owned(), |
245 | | Rule::repeat_once_operator => "`+`".to_owned(), |
246 | | Rule::comma => "`,`".to_owned(), |
247 | | Rule::closing_paren => "`)`".to_owned(), |
248 | | Rule::quote => "`\"`".to_owned(), |
249 | | Rule::insensitive_string => "`^`".to_owned(), |
250 | | Rule::range_operator => "`..`".to_owned(), |
251 | | Rule::single_quote => "`'`".to_owned(), |
252 | | Rule::grammar_doc => "//!".to_owned(), |
253 | | Rule::line_doc => "///".to_owned(), |
254 | | other_rule => format!("{:?}", other_rule), |
255 | | } |
256 | | } |
257 | | |
258 | 0 | fn consume_rules_with_spans( |
259 | 0 | pairs: Pairs<'_, Rule>, |
260 | 0 | ) -> Result<Vec<ParserRule<'_>>, Vec<Error<Rule>>> { |
261 | 0 | let pratt = PrattParser::new() |
262 | 0 | .op(Op::infix(Rule::choice_operator, Assoc::Left)) |
263 | 0 | .op(Op::infix(Rule::sequence_operator, Assoc::Left)); |
264 | | |
265 | 0 | pairs |
266 | 0 | .filter(|pair| pair.as_rule() == Rule::grammar_rule) |
267 | 0 | .filter(|pair| { |
268 | | // To ignore `grammar_rule > line_doc` pairs |
269 | 0 | let mut pairs = pair.clone().into_inner(); |
270 | 0 | let pair = pairs.next().unwrap(); |
271 | | |
272 | 0 | pair.as_rule() != Rule::line_doc |
273 | 0 | }) |
274 | 0 | .map(|pair| { |
275 | 0 | let mut pairs = pair.into_inner().peekable(); |
276 | | |
277 | 0 | let span = pairs.next().unwrap().as_span(); |
278 | 0 | let name = span.as_str().to_owned(); |
279 | | |
280 | 0 | pairs.next().unwrap(); // assignment_operator |
281 | | |
282 | 0 | let ty = if pairs.peek().unwrap().as_rule() != Rule::opening_brace { |
283 | 0 | match pairs.next().unwrap().as_rule() { |
284 | 0 | Rule::silent_modifier => RuleType::Silent, |
285 | 0 | Rule::atomic_modifier => RuleType::Atomic, |
286 | 0 | Rule::compound_atomic_modifier => RuleType::CompoundAtomic, |
287 | 0 | Rule::non_atomic_modifier => RuleType::NonAtomic, |
288 | 0 | _ => unreachable!(), |
289 | | } |
290 | | } else { |
291 | 0 | RuleType::Normal |
292 | | }; |
293 | | |
294 | 0 | pairs.next().unwrap(); // opening_brace |
295 | | |
296 | | // skip initial infix operators |
297 | 0 | let mut inner_nodes = pairs.next().unwrap().into_inner().peekable(); |
298 | 0 | if inner_nodes.peek().unwrap().as_rule() == Rule::choice_operator { |
299 | 0 | inner_nodes.next().unwrap(); |
300 | 0 | } |
301 | | |
302 | 0 | let node = consume_expr(inner_nodes, &pratt)?; |
303 | | |
304 | 0 | Ok(ParserRule { |
305 | 0 | name, |
306 | 0 | span, |
307 | 0 | ty, |
308 | 0 | node, |
309 | 0 | }) |
310 | 0 | }) |
311 | 0 | .collect() |
312 | 0 | } |
313 | | |
314 | 0 | fn get_node_tag<'i>( |
315 | 0 | pairs: &mut Peekable<Pairs<'i, Rule>>, |
316 | 0 | ) -> (Pair<'i, Rule>, Option<(String, Position<'i>)>) { |
317 | 0 | let pair_or_tag = pairs.next().unwrap(); |
318 | 0 | if let Some(next_pair) = pairs.peek() { |
319 | 0 | if next_pair.as_rule() == Rule::assignment_operator { |
320 | 0 | pairs.next().unwrap(); |
321 | 0 | let pair = pairs.next().unwrap(); |
322 | 0 | ( |
323 | 0 | pair, |
324 | 0 | Some(( |
325 | 0 | pair_or_tag.as_str()[1..].to_string(), |
326 | 0 | pair_or_tag.as_span().start_pos(), |
327 | 0 | )), |
328 | 0 | ) |
329 | | } else { |
330 | 0 | (pair_or_tag, None) |
331 | | } |
332 | | } else { |
333 | 0 | (pair_or_tag, None) |
334 | | } |
335 | 0 | } |
336 | | |
337 | 0 | fn consume_expr<'i>( |
338 | 0 | pairs: Peekable<Pairs<'i, Rule>>, |
339 | 0 | pratt: &PrattParser<Rule>, |
340 | 0 | ) -> Result<ParserNode<'i>, Vec<Error<Rule>>> { |
341 | 0 | fn unaries<'i>( |
342 | 0 | mut pairs: Peekable<Pairs<'i, Rule>>, |
343 | 0 | pratt: &PrattParser<Rule>, |
344 | 0 | ) -> Result<ParserNode<'i>, Vec<Error<Rule>>> { |
345 | | #[cfg(feature = "grammar-extras")] |
346 | | let (pair, tag_start) = get_node_tag(&mut pairs); |
347 | | #[cfg(not(feature = "grammar-extras"))] |
348 | 0 | let (pair, _tag_start) = get_node_tag(&mut pairs); |
349 | | |
350 | 0 | let node = match pair.as_rule() { |
351 | | Rule::opening_paren => { |
352 | 0 | let node = unaries(pairs, pratt)?; |
353 | 0 | let end = node.span.end_pos(); |
354 | | |
355 | 0 | ParserNode { |
356 | 0 | expr: node.expr, |
357 | 0 | span: pair.as_span().start_pos().span(&end), |
358 | 0 | } |
359 | | } |
360 | | Rule::positive_predicate_operator => { |
361 | 0 | let node = unaries(pairs, pratt)?; |
362 | 0 | let end = node.span.end_pos(); |
363 | | |
364 | 0 | ParserNode { |
365 | 0 | expr: ParserExpr::PosPred(Box::new(node)), |
366 | 0 | span: pair.as_span().start_pos().span(&end), |
367 | 0 | } |
368 | | } |
369 | | Rule::negative_predicate_operator => { |
370 | 0 | let node = unaries(pairs, pratt)?; |
371 | 0 | let end = node.span.end_pos(); |
372 | | |
373 | 0 | ParserNode { |
374 | 0 | expr: ParserExpr::NegPred(Box::new(node)), |
375 | 0 | span: pair.as_span().start_pos().span(&end), |
376 | 0 | } |
377 | | } |
378 | 0 | other_rule => { |
379 | 0 | let node = match other_rule { |
380 | 0 | Rule::expression => consume_expr(pair.into_inner().peekable(), pratt)?, |
381 | | Rule::_push => { |
382 | 0 | let start = pair.clone().as_span().start_pos(); |
383 | 0 | let mut pairs = pair.into_inner(); |
384 | 0 | pairs.next().unwrap(); // opening_paren |
385 | 0 | let pair = pairs.next().unwrap(); |
386 | | |
387 | 0 | let node = consume_expr(pair.into_inner().peekable(), pratt)?; |
388 | 0 | let end = node.span.end_pos(); |
389 | | |
390 | 0 | ParserNode { |
391 | 0 | expr: ParserExpr::Push(Box::new(node)), |
392 | 0 | span: start.span(&end), |
393 | 0 | } |
394 | | } |
395 | | #[cfg(feature = "grammar-extras")] |
396 | | Rule::_push_literal => { |
397 | | let mut pairs = pair.into_inner(); |
398 | | pairs.next().unwrap(); // opening_paren |
399 | | let contents_pair = pairs.next().unwrap(); |
400 | | let string = |
401 | | unescape(contents_pair.as_str()).expect("incorrect string literal"); |
402 | | ParserNode { |
403 | | expr: ParserExpr::PushLiteral(string[1..string.len() - 1].to_owned()), |
404 | | span: contents_pair.clone().as_span(), |
405 | | } |
406 | | } |
407 | | #[cfg(not(feature = "grammar-extras"))] |
408 | | Rule::_push_literal => { |
409 | 0 | return Err(vec![Error::new_from_span( |
410 | 0 | ErrorVariant::CustomError { |
411 | 0 | message: "PUSH_LITERAL requires feature grammar-extras".to_owned(), |
412 | 0 | }, |
413 | 0 | pair.as_span(), |
414 | 0 | )]); |
415 | | } |
416 | | Rule::peek_slice => { |
417 | 0 | let mut pairs = pair.clone().into_inner(); |
418 | 0 | pairs.next().unwrap(); // opening_brack |
419 | 0 | let pair_start = pairs.next().unwrap(); // .. or integer |
420 | 0 | let start: i32 = match pair_start.as_rule() { |
421 | 0 | Rule::range_operator => 0, |
422 | | Rule::integer => { |
423 | 0 | pairs.next().unwrap(); // .. |
424 | 0 | pair_start.as_str().parse().unwrap() |
425 | | } |
426 | 0 | _ => unreachable!("peek start"), |
427 | | }; |
428 | 0 | let pair_end = pairs.next().unwrap(); // integer or } |
429 | 0 | let end: Option<i32> = match pair_end.as_rule() { |
430 | 0 | Rule::closing_brack => None, |
431 | | Rule::integer => { |
432 | 0 | pairs.next().unwrap(); // } |
433 | 0 | Some(pair_end.as_str().parse().unwrap()) |
434 | | } |
435 | 0 | _ => unreachable!("peek end"), |
436 | | }; |
437 | 0 | ParserNode { |
438 | 0 | expr: ParserExpr::PeekSlice(start, end), |
439 | 0 | span: pair.as_span(), |
440 | 0 | } |
441 | | } |
442 | 0 | Rule::identifier => ParserNode { |
443 | 0 | expr: ParserExpr::Ident(pair.as_str().to_owned()), |
444 | 0 | span: pair.clone().as_span(), |
445 | 0 | }, |
446 | | Rule::string => { |
447 | 0 | let string = unescape(pair.as_str()).expect("incorrect string literal"); |
448 | 0 | ParserNode { |
449 | 0 | expr: ParserExpr::Str(string[1..string.len() - 1].to_owned()), |
450 | 0 | span: pair.clone().as_span(), |
451 | 0 | } |
452 | | } |
453 | | Rule::insensitive_string => { |
454 | 0 | let string = unescape(pair.as_str()).expect("incorrect string literal"); |
455 | 0 | ParserNode { |
456 | 0 | expr: ParserExpr::Insens(string[2..string.len() - 1].to_owned()), |
457 | 0 | span: pair.clone().as_span(), |
458 | 0 | } |
459 | | } |
460 | | Rule::range => { |
461 | 0 | let mut pairs = pair.into_inner(); |
462 | 0 | let pair = pairs.next().unwrap(); |
463 | 0 | let start = unescape(pair.as_str()).expect("incorrect char literal"); |
464 | 0 | let start_pos = pair.clone().as_span().start_pos(); |
465 | 0 | pairs.next(); |
466 | 0 | let pair = pairs.next().unwrap(); |
467 | 0 | let end = unescape(pair.as_str()).expect("incorrect char literal"); |
468 | 0 | let end_pos = pair.clone().as_span().end_pos(); |
469 | | |
470 | 0 | ParserNode { |
471 | 0 | expr: ParserExpr::Range( |
472 | 0 | start[1..start.len() - 1].to_owned(), |
473 | 0 | end[1..end.len() - 1].to_owned(), |
474 | 0 | ), |
475 | 0 | span: start_pos.span(&end_pos), |
476 | 0 | } |
477 | | } |
478 | 0 | x => unreachable!("other rule: {:?}", x), |
479 | | }; |
480 | | |
481 | 0 | pairs.try_fold(node, |node: ParserNode<'i>, pair: Pair<'i, Rule>| { |
482 | 0 | let node = match pair.as_rule() { |
483 | | Rule::optional_operator => { |
484 | 0 | let start = node.span.start_pos(); |
485 | 0 | ParserNode { |
486 | 0 | expr: ParserExpr::Opt(Box::new(node)), |
487 | 0 | span: start.span(&pair.as_span().end_pos()), |
488 | 0 | } |
489 | | } |
490 | | Rule::repeat_operator => { |
491 | 0 | let start = node.span.start_pos(); |
492 | 0 | ParserNode { |
493 | 0 | expr: ParserExpr::Rep(Box::new(node)), |
494 | 0 | span: start.span(&pair.as_span().end_pos()), |
495 | 0 | } |
496 | | } |
497 | | Rule::repeat_once_operator => { |
498 | 0 | let start = node.span.start_pos(); |
499 | 0 | ParserNode { |
500 | 0 | expr: ParserExpr::RepOnce(Box::new(node)), |
501 | 0 | span: start.span(&pair.as_span().end_pos()), |
502 | 0 | } |
503 | | } |
504 | | Rule::repeat_exact => { |
505 | 0 | let mut inner = pair.clone().into_inner(); |
506 | | |
507 | 0 | inner.next().unwrap(); // opening_brace |
508 | | |
509 | 0 | let number = inner.next().unwrap(); |
510 | 0 | let num = if let Ok(num) = number.as_str().parse::<u32>() { |
511 | 0 | num |
512 | | } else { |
513 | 0 | return Err(vec![Error::new_from_span( |
514 | 0 | ErrorVariant::CustomError { |
515 | 0 | message: "number cannot overflow u32".to_owned(), |
516 | 0 | }, |
517 | 0 | number.as_span(), |
518 | 0 | )]); |
519 | | }; |
520 | | |
521 | 0 | if num == 0 { |
522 | 0 | let error: Error<Rule> = Error::new_from_span( |
523 | 0 | ErrorVariant::CustomError { |
524 | 0 | message: "cannot repeat 0 times".to_owned(), |
525 | 0 | }, |
526 | 0 | number.as_span(), |
527 | | ); |
528 | | |
529 | 0 | return Err(vec![error]); |
530 | 0 | } |
531 | | |
532 | 0 | let start = node.span.start_pos(); |
533 | 0 | ParserNode { |
534 | 0 | expr: ParserExpr::RepExact(Box::new(node), num), |
535 | 0 | span: start.span(&pair.as_span().end_pos()), |
536 | 0 | } |
537 | | } |
538 | | Rule::repeat_min => { |
539 | 0 | let mut inner = pair.clone().into_inner(); |
540 | | |
541 | 0 | inner.next().unwrap(); // opening_brace |
542 | | |
543 | 0 | let min_number = inner.next().unwrap(); |
544 | 0 | let min = if let Ok(min) = min_number.as_str().parse::<u32>() { |
545 | 0 | min |
546 | | } else { |
547 | 0 | return Err(vec![Error::new_from_span( |
548 | 0 | ErrorVariant::CustomError { |
549 | 0 | message: "number cannot overflow u32".to_owned(), |
550 | 0 | }, |
551 | 0 | min_number.as_span(), |
552 | 0 | )]); |
553 | | }; |
554 | | |
555 | 0 | let start = node.span.start_pos(); |
556 | 0 | ParserNode { |
557 | 0 | expr: ParserExpr::RepMin(Box::new(node), min), |
558 | 0 | span: start.span(&pair.as_span().end_pos()), |
559 | 0 | } |
560 | | } |
561 | | Rule::repeat_max => { |
562 | 0 | let mut inner = pair.clone().into_inner(); |
563 | | |
564 | 0 | inner.next().unwrap(); // opening_brace |
565 | 0 | inner.next().unwrap(); // comma |
566 | | |
567 | 0 | let max_number = inner.next().unwrap(); |
568 | 0 | let max = if let Ok(max) = max_number.as_str().parse::<u32>() { |
569 | 0 | max |
570 | | } else { |
571 | 0 | return Err(vec![Error::new_from_span( |
572 | 0 | ErrorVariant::CustomError { |
573 | 0 | message: "number cannot overflow u32".to_owned(), |
574 | 0 | }, |
575 | 0 | max_number.as_span(), |
576 | 0 | )]); |
577 | | }; |
578 | | |
579 | 0 | if max == 0 { |
580 | 0 | let error: Error<Rule> = Error::new_from_span( |
581 | 0 | ErrorVariant::CustomError { |
582 | 0 | message: "cannot repeat 0 times".to_owned(), |
583 | 0 | }, |
584 | 0 | max_number.as_span(), |
585 | | ); |
586 | | |
587 | 0 | return Err(vec![error]); |
588 | 0 | } |
589 | | |
590 | 0 | let start = node.span.start_pos(); |
591 | 0 | ParserNode { |
592 | 0 | expr: ParserExpr::RepMax(Box::new(node), max), |
593 | 0 | span: start.span(&pair.as_span().end_pos()), |
594 | 0 | } |
595 | | } |
596 | | Rule::repeat_min_max => { |
597 | 0 | let mut inner = pair.clone().into_inner(); |
598 | | |
599 | 0 | inner.next().unwrap(); // opening_brace |
600 | | |
601 | 0 | let min_number = inner.next().unwrap(); |
602 | 0 | let min = if let Ok(min) = min_number.as_str().parse::<u32>() { |
603 | 0 | min |
604 | | } else { |
605 | 0 | return Err(vec![Error::new_from_span( |
606 | 0 | ErrorVariant::CustomError { |
607 | 0 | message: "number cannot overflow u32".to_owned(), |
608 | 0 | }, |
609 | 0 | min_number.as_span(), |
610 | 0 | )]); |
611 | | }; |
612 | | |
613 | 0 | inner.next().unwrap(); // comma |
614 | | |
615 | 0 | let max_number = inner.next().unwrap(); |
616 | 0 | let max = if let Ok(max) = max_number.as_str().parse::<u32>() { |
617 | 0 | max |
618 | | } else { |
619 | 0 | return Err(vec![Error::new_from_span( |
620 | 0 | ErrorVariant::CustomError { |
621 | 0 | message: "number cannot overflow u32".to_owned(), |
622 | 0 | }, |
623 | 0 | max_number.as_span(), |
624 | 0 | )]); |
625 | | }; |
626 | | |
627 | 0 | if max == 0 { |
628 | 0 | let error: Error<Rule> = Error::new_from_span( |
629 | 0 | ErrorVariant::CustomError { |
630 | 0 | message: "cannot repeat 0 times".to_owned(), |
631 | 0 | }, |
632 | 0 | max_number.as_span(), |
633 | | ); |
634 | | |
635 | 0 | return Err(vec![error]); |
636 | 0 | } |
637 | | |
638 | 0 | let start = node.span.start_pos(); |
639 | 0 | ParserNode { |
640 | 0 | expr: ParserExpr::RepMinMax(Box::new(node), min, max), |
641 | 0 | span: start.span(&pair.as_span().end_pos()), |
642 | 0 | } |
643 | | } |
644 | | Rule::closing_paren => { |
645 | 0 | let start = node.span.start_pos(); |
646 | | |
647 | 0 | ParserNode { |
648 | 0 | expr: node.expr, |
649 | 0 | span: start.span(&pair.as_span().end_pos()), |
650 | 0 | } |
651 | | } |
652 | 0 | rule => unreachable!("node: {:?}", rule), |
653 | | }; |
654 | | |
655 | 0 | Ok(node) |
656 | 0 | })? |
657 | | } |
658 | | }; |
659 | | #[cfg(feature = "grammar-extras")] |
660 | | if let Some((tag, start)) = tag_start { |
661 | | let span = start.span(&node.span.end_pos()); |
662 | | Ok(ParserNode { |
663 | | expr: ParserExpr::NodeTag(Box::new(node), tag), |
664 | | span, |
665 | | }) |
666 | | } else { |
667 | | Ok(node) |
668 | | } |
669 | | #[cfg(not(feature = "grammar-extras"))] |
670 | 0 | Ok(node) |
671 | 0 | } |
672 | | |
673 | 0 | let term = |pair: Pair<'i, Rule>| unaries(pair.into_inner().peekable(), pratt); |
674 | 0 | let infix = |lhs: Result<ParserNode<'i>, Vec<Error<Rule>>>, |
675 | | op: Pair<'i, Rule>, |
676 | 0 | rhs: Result<ParserNode<'i>, Vec<Error<Rule>>>| match op.as_rule() { |
677 | | Rule::sequence_operator => { |
678 | 0 | let lhs = lhs?; |
679 | 0 | let rhs = rhs?; |
680 | | |
681 | 0 | let start = lhs.span.start_pos(); |
682 | 0 | let end = rhs.span.end_pos(); |
683 | | |
684 | 0 | Ok(ParserNode { |
685 | 0 | expr: ParserExpr::Seq(Box::new(lhs), Box::new(rhs)), |
686 | 0 | span: start.span(&end), |
687 | 0 | }) |
688 | | } |
689 | | Rule::choice_operator => { |
690 | 0 | let lhs = lhs?; |
691 | 0 | let rhs = rhs?; |
692 | | |
693 | 0 | let start = lhs.span.start_pos(); |
694 | 0 | let end = rhs.span.end_pos(); |
695 | | |
696 | 0 | Ok(ParserNode { |
697 | 0 | expr: ParserExpr::Choice(Box::new(lhs), Box::new(rhs)), |
698 | 0 | span: start.span(&end), |
699 | 0 | }) |
700 | | } |
701 | 0 | _ => unreachable!("infix"), |
702 | 0 | }; |
703 | | |
704 | 0 | pratt.map_primary(term).map_infix(infix).parse(pairs) |
705 | 0 | } |
706 | | |
707 | 0 | fn unescape(string: &str) -> Option<String> { |
708 | 0 | let mut result = String::new(); |
709 | 0 | let mut chars = string.chars(); |
710 | | |
711 | | loop { |
712 | 0 | match chars.next() { |
713 | 0 | Some('\\') => match chars.next()? { |
714 | 0 | '"' => result.push('"'), |
715 | 0 | '\\' => result.push('\\'), |
716 | 0 | 'r' => result.push('\r'), |
717 | 0 | 'n' => result.push('\n'), |
718 | 0 | 't' => result.push('\t'), |
719 | 0 | '0' => result.push('\0'), |
720 | 0 | '\'' => result.push('\''), |
721 | | 'x' => { |
722 | 0 | let string: String = chars.clone().take(2).collect(); |
723 | | |
724 | 0 | if string.len() != 2 { |
725 | 0 | return None; |
726 | 0 | } |
727 | | |
728 | 0 | for _ in 0..string.len() { |
729 | 0 | chars.next()?; |
730 | | } |
731 | | |
732 | 0 | let value = u8::from_str_radix(&string, 16).ok()?; |
733 | | |
734 | 0 | result.push(char::from(value)); |
735 | | } |
736 | | 'u' => { |
737 | 0 | if chars.next()? != '{' { |
738 | 0 | return None; |
739 | 0 | } |
740 | | |
741 | 0 | let string: String = chars.clone().take_while(|c| *c != '}').collect(); |
742 | | |
743 | 0 | if string.len() < 2 || 6 < string.len() { |
744 | 0 | return None; |
745 | 0 | } |
746 | | |
747 | 0 | for _ in 0..string.len() + 1 { |
748 | 0 | chars.next()?; |
749 | | } |
750 | | |
751 | 0 | let value = u32::from_str_radix(&string, 16).ok()?; |
752 | | |
753 | 0 | result.push(char::from_u32(value)?); |
754 | | } |
755 | 0 | _ => return None, |
756 | | }, |
757 | 0 | Some(c) => result.push(c), |
758 | 0 | None => return Some(result), |
759 | | }; |
760 | | } |
761 | 0 | } |
762 | | |
763 | | #[cfg(test)] |
764 | | mod tests { |
765 | | use std::convert::TryInto; |
766 | | |
767 | | use super::super::unwrap_or_report; |
768 | | use super::*; |
769 | | |
770 | | #[test] |
771 | | fn rules() { |
772 | | parses_to! { |
773 | | parser: PestParser, |
774 | | input: "a = { b } c = { d }", |
775 | | rule: Rule::grammar_rules, |
776 | | tokens: [ |
777 | | grammar_rule(0, 9, [ |
778 | | identifier(0, 1), |
779 | | assignment_operator(2, 3), |
780 | | opening_brace(4, 5), |
781 | | expression(6, 8, [ |
782 | | term(6, 8, [ |
783 | | identifier(6, 7) |
784 | | ]) |
785 | | ]), |
786 | | closing_brace(8, 9) |
787 | | ]), |
788 | | grammar_rule(10, 19, [ |
789 | | identifier(10, 11), |
790 | | assignment_operator(12, 13), |
791 | | opening_brace(14, 15), |
792 | | expression(16, 18, [ |
793 | | term(16, 18, [ |
794 | | identifier(16, 17) |
795 | | ]) |
796 | | ]), |
797 | | closing_brace(18, 19) |
798 | | ]) |
799 | | ] |
800 | | }; |
801 | | } |
802 | | |
803 | | #[test] |
804 | | fn rule() { |
805 | | parses_to! { |
806 | | parser: PestParser, |
807 | | input: "a = ! { b ~ c }", |
808 | | rule: Rule::grammar_rule, |
809 | | tokens: [ |
810 | | grammar_rule(0, 15, [ |
811 | | identifier(0, 1), |
812 | | assignment_operator(2, 3), |
813 | | non_atomic_modifier(4, 5), |
814 | | opening_brace(6, 7), |
815 | | expression(8, 14, [ |
816 | | term(8, 10, [ |
817 | | identifier(8, 9) |
818 | | ]), |
819 | | sequence_operator(10, 11), |
820 | | term(12, 14, [ |
821 | | identifier(12, 13) |
822 | | ]) |
823 | | ]), |
824 | | closing_brace(14, 15) |
825 | | ]) |
826 | | ] |
827 | | }; |
828 | | } |
829 | | |
830 | | #[test] |
831 | | fn expression() { |
832 | | parses_to! { |
833 | | parser: PestParser, |
834 | | input: "_a | 'a'..'b' ~ !^\"abc\" ~ (d | e)*?", |
835 | | rule: Rule::expression, |
836 | | tokens: [ |
837 | | expression(0, 35, [ |
838 | | term(0, 3, [ |
839 | | identifier(0, 2) |
840 | | ]), |
841 | | choice_operator(3, 4), |
842 | | term(5, 14, [ |
843 | | range(5, 13, [ |
844 | | character(5, 8, [ |
845 | | single_quote(5, 6), |
846 | | inner_chr(6, 7), |
847 | | single_quote(7, 8) |
848 | | ]), |
849 | | range_operator(8, 10), |
850 | | character(10, 13, [ |
851 | | single_quote(10, 11), |
852 | | inner_chr(11, 12), |
853 | | single_quote(12, 13) |
854 | | ]) |
855 | | ]) |
856 | | ]), |
857 | | sequence_operator(14, 15), |
858 | | term(16, 24, [ |
859 | | negative_predicate_operator(16, 17), |
860 | | insensitive_string(17, 23, [ |
861 | | string(18, 23, [ |
862 | | quote(18, 19), |
863 | | inner_str(19, 22), |
864 | | quote(22, 23) |
865 | | ]) |
866 | | ]) |
867 | | ]), |
868 | | sequence_operator(24, 25), |
869 | | term(26, 35, [ |
870 | | opening_paren(26, 27), |
871 | | expression(27, 32, [ |
872 | | term(27, 29, [ |
873 | | identifier(27, 28) |
874 | | ]), |
875 | | choice_operator(29, 30), |
876 | | term(31, 32, [ |
877 | | identifier(31, 32) |
878 | | ]) |
879 | | ]), |
880 | | closing_paren(32, 33), |
881 | | repeat_operator(33, 34), |
882 | | optional_operator(34, 35) |
883 | | ]) |
884 | | ]) |
885 | | ] |
886 | | }; |
887 | | } |
888 | | |
889 | | #[test] |
890 | | fn repeat_exact() { |
891 | | parses_to! { |
892 | | parser: PestParser, |
893 | | input: "{1}", |
894 | | rule: Rule::repeat_exact, |
895 | | tokens: [ |
896 | | repeat_exact(0, 3, [ |
897 | | opening_brace(0, 1), |
898 | | number(1, 2), |
899 | | closing_brace(2, 3) |
900 | | ]) |
901 | | ] |
902 | | }; |
903 | | } |
904 | | |
905 | | #[test] |
906 | | fn repeat_min() { |
907 | | parses_to! { |
908 | | parser: PestParser, |
909 | | input: "{2,}", |
910 | | rule: Rule::repeat_min, |
911 | | tokens: [ |
912 | | repeat_min(0, 4, [ |
913 | | opening_brace(0,1), |
914 | | number(1,2), |
915 | | comma(2,3), |
916 | | closing_brace(3,4) |
917 | | ]) |
918 | | ] |
919 | | } |
920 | | } |
921 | | |
922 | | #[test] |
923 | | fn repeat_max() { |
924 | | parses_to! { |
925 | | parser: PestParser, |
926 | | input: "{, 3}", |
927 | | rule: Rule::repeat_max, |
928 | | tokens: [ |
929 | | repeat_max(0, 5, [ |
930 | | opening_brace(0,1), |
931 | | comma(1,2), |
932 | | number(3,4), |
933 | | closing_brace(4,5) |
934 | | ]) |
935 | | ] |
936 | | } |
937 | | } |
938 | | |
939 | | #[test] |
940 | | fn repeat_min_max() { |
941 | | parses_to! { |
942 | | parser: PestParser, |
943 | | input: "{1, 2}", |
944 | | rule: Rule::repeat_min_max, |
945 | | tokens: [ |
946 | | repeat_min_max(0, 6, [ |
947 | | opening_brace(0, 1), |
948 | | number(1, 2), |
949 | | comma(2, 3), |
950 | | number(4, 5), |
951 | | closing_brace(5, 6) |
952 | | ]) |
953 | | ] |
954 | | }; |
955 | | } |
956 | | |
957 | | #[test] |
958 | | fn push() { |
959 | | parses_to! { |
960 | | parser: PestParser, |
961 | | input: "PUSH ( a )", |
962 | | rule: Rule::_push, |
963 | | tokens: [ |
964 | | _push(0, 10, [ |
965 | | opening_paren(5, 6), |
966 | | expression(7, 9, [ |
967 | | term(7, 9, [ |
968 | | identifier(7, 8) |
969 | | ]) |
970 | | ]), |
971 | | closing_paren(9, 10) |
972 | | ]) |
973 | | ] |
974 | | }; |
975 | | } |
976 | | |
977 | | #[test] |
978 | | fn peek_slice_all() { |
979 | | parses_to! { |
980 | | parser: PestParser, |
981 | | input: "PEEK[..]", |
982 | | rule: Rule::peek_slice, |
983 | | tokens: [ |
984 | | peek_slice(0, 8, [ |
985 | | opening_brack(4, 5), |
986 | | range_operator(5, 7), |
987 | | closing_brack(7, 8) |
988 | | ]) |
989 | | ] |
990 | | }; |
991 | | } |
992 | | |
993 | | #[test] |
994 | | fn peek_slice_start() { |
995 | | parses_to! { |
996 | | parser: PestParser, |
997 | | input: "PEEK[1..]", |
998 | | rule: Rule::peek_slice, |
999 | | tokens: [ |
1000 | | peek_slice(0, 9, [ |
1001 | | opening_brack(4, 5), |
1002 | | integer(5, 6), |
1003 | | range_operator(6, 8), |
1004 | | closing_brack(8, 9) |
1005 | | ]) |
1006 | | ] |
1007 | | }; |
1008 | | } |
1009 | | |
1010 | | #[test] |
1011 | | fn peek_slice_end() { |
1012 | | parses_to! { |
1013 | | parser: PestParser, |
1014 | | input: "PEEK[ ..-1]", |
1015 | | rule: Rule::peek_slice, |
1016 | | tokens: [ |
1017 | | peek_slice(0, 11, [ |
1018 | | opening_brack(4, 5), |
1019 | | range_operator(6, 8), |
1020 | | integer(8, 10), |
1021 | | closing_brack(10, 11) |
1022 | | ]) |
1023 | | ] |
1024 | | }; |
1025 | | } |
1026 | | |
1027 | | #[test] |
1028 | | fn peek_slice_start_end() { |
1029 | | parses_to! { |
1030 | | parser: PestParser, |
1031 | | input: "PEEK[-5..10]", |
1032 | | rule: Rule::peek_slice, |
1033 | | tokens: [ |
1034 | | peek_slice(0, 12, [ |
1035 | | opening_brack(4, 5), |
1036 | | integer(5, 7), |
1037 | | range_operator(7, 9), |
1038 | | integer(9, 11), |
1039 | | closing_brack(11, 12) |
1040 | | ]) |
1041 | | ] |
1042 | | }; |
1043 | | } |
1044 | | |
1045 | | #[test] |
1046 | | fn identifier() { |
1047 | | parses_to! { |
1048 | | parser: PestParser, |
1049 | | input: "_a8943", |
1050 | | rule: Rule::identifier, |
1051 | | tokens: [ |
1052 | | identifier(0, 6) |
1053 | | ] |
1054 | | }; |
1055 | | } |
1056 | | |
1057 | | #[test] |
1058 | | fn string() { |
1059 | | parses_to! { |
1060 | | parser: PestParser, |
1061 | | input: "\"aaaaa\\n\\r\\t\\\\\\0\\'\\\"\\x0F\\u{123abC}\\u{12}aaaaa\"", |
1062 | | rule: Rule::string, |
1063 | | tokens: [ |
1064 | | string(0, 46, [ |
1065 | | quote(0, 1), |
1066 | | inner_str(1, 45), |
1067 | | quote(45, 46) |
1068 | | ]) |
1069 | | ] |
1070 | | }; |
1071 | | } |
1072 | | |
1073 | | #[test] |
1074 | | fn insensitive_string() { |
1075 | | parses_to! { |
1076 | | parser: PestParser, |
1077 | | input: "^ \"\\\"hi\"", |
1078 | | rule: Rule::insensitive_string, |
1079 | | tokens: [ |
1080 | | insensitive_string(0, 9, [ |
1081 | | string(3, 9, [ |
1082 | | quote(3, 4), |
1083 | | inner_str(4, 8), |
1084 | | quote(8, 9) |
1085 | | ]) |
1086 | | ]) |
1087 | | ] |
1088 | | }; |
1089 | | } |
1090 | | |
1091 | | #[test] |
1092 | | fn range() { |
1093 | | parses_to! { |
1094 | | parser: PestParser, |
1095 | | input: "'\\n' .. '\\x1a'", |
1096 | | rule: Rule::range, |
1097 | | tokens: [ |
1098 | | range(0, 14, [ |
1099 | | character(0, 4, [ |
1100 | | single_quote(0, 1), |
1101 | | inner_chr(1, 3), |
1102 | | single_quote(3, 4) |
1103 | | ]), |
1104 | | range_operator(5, 7), |
1105 | | character(8, 14, [ |
1106 | | single_quote(8, 9), |
1107 | | inner_chr(9, 13), |
1108 | | single_quote(13, 14) |
1109 | | ]) |
1110 | | ]) |
1111 | | ] |
1112 | | }; |
1113 | | } |
1114 | | |
1115 | | #[test] |
1116 | | fn character() { |
1117 | | parses_to! { |
1118 | | parser: PestParser, |
1119 | | input: "'\\u{123abC}'", |
1120 | | rule: Rule::character, |
1121 | | tokens: [ |
1122 | | character(0, 12, [ |
1123 | | single_quote(0, 1), |
1124 | | inner_chr(1, 11), |
1125 | | single_quote(11, 12) |
1126 | | ]) |
1127 | | ] |
1128 | | }; |
1129 | | } |
1130 | | |
1131 | | #[test] |
1132 | | fn number() { |
1133 | | parses_to! { |
1134 | | parser: PestParser, |
1135 | | input: "0123", |
1136 | | rule: Rule::number, |
1137 | | tokens: [ |
1138 | | number(0, 4) |
1139 | | ] |
1140 | | }; |
1141 | | } |
1142 | | |
1143 | | #[test] |
1144 | | fn comment() { |
1145 | | parses_to! { |
1146 | | parser: PestParser, |
1147 | | input: "a ~ // asda\n b", |
1148 | | rule: Rule::expression, |
1149 | | tokens: [ |
1150 | | expression(0, 17, [ |
1151 | | term(0, 2, [ |
1152 | | identifier(0, 1) |
1153 | | ]), |
1154 | | sequence_operator(2, 3), |
1155 | | term(16, 17, [ |
1156 | | identifier(16, 17) |
1157 | | ]) |
1158 | | ]) |
1159 | | ] |
1160 | | }; |
1161 | | } |
1162 | | |
1163 | | #[test] |
1164 | | fn grammar_doc_and_line_doc() { |
1165 | | let input = "//! hello\n/// world\na = { \"a\" }"; |
1166 | | parses_to! { |
1167 | | parser: PestParser, |
1168 | | input: input, |
1169 | | rule: Rule::grammar_rules, |
1170 | | tokens: [ |
1171 | | grammar_doc(0, 9, [ |
1172 | | inner_doc(4, 9), |
1173 | | ]), |
1174 | | grammar_rule(10, 19, [ |
1175 | | line_doc(10, 19, [ |
1176 | | inner_doc(14, 19), |
1177 | | ]), |
1178 | | ]), |
1179 | | grammar_rule(20, 31, [ |
1180 | | identifier(20, 21), |
1181 | | assignment_operator(22, 23), |
1182 | | opening_brace(24, 25), |
1183 | | expression(26, 30, [ |
1184 | | term(26, 30, [ |
1185 | | string(26, 29, [ |
1186 | | quote(26, 27), |
1187 | | inner_str(27, 28), |
1188 | | quote(28, 29) |
1189 | | ]) |
1190 | | ]) |
1191 | | ]), |
1192 | | closing_brace(30, 31), |
1193 | | ]) |
1194 | | ] |
1195 | | }; |
1196 | | } |
1197 | | |
1198 | | #[test] |
1199 | | fn wrong_identifier() { |
1200 | | fails_with! { |
1201 | | parser: PestParser, |
1202 | | input: "0", |
1203 | | rule: Rule::grammar_rules, |
1204 | | positives: vec![Rule::EOI, Rule::grammar_rule, Rule::grammar_doc], |
1205 | | negatives: vec![], |
1206 | | pos: 0 |
1207 | | }; |
1208 | | } |
1209 | | |
1210 | | #[test] |
1211 | | fn missing_assignment_operator() { |
1212 | | fails_with! { |
1213 | | parser: PestParser, |
1214 | | input: "a {}", |
1215 | | rule: Rule::grammar_rules, |
1216 | | positives: vec![Rule::assignment_operator], |
1217 | | negatives: vec![], |
1218 | | pos: 2 |
1219 | | }; |
1220 | | } |
1221 | | |
1222 | | #[test] |
1223 | | fn wrong_modifier() { |
1224 | | fails_with! { |
1225 | | parser: PestParser, |
1226 | | input: "a = *{}", |
1227 | | rule: Rule::grammar_rules, |
1228 | | positives: vec![ |
1229 | | Rule::opening_brace, |
1230 | | Rule::silent_modifier, |
1231 | | Rule::atomic_modifier, |
1232 | | Rule::compound_atomic_modifier, |
1233 | | Rule::non_atomic_modifier |
1234 | | ], |
1235 | | negatives: vec![], |
1236 | | pos: 4 |
1237 | | }; |
1238 | | } |
1239 | | |
1240 | | #[test] |
1241 | | fn missing_opening_brace() { |
1242 | | fails_with! { |
1243 | | parser: PestParser, |
1244 | | input: "a = _", |
1245 | | rule: Rule::grammar_rules, |
1246 | | positives: vec![Rule::opening_brace], |
1247 | | negatives: vec![], |
1248 | | pos: 5 |
1249 | | }; |
1250 | | } |
1251 | | |
1252 | | #[test] |
1253 | | fn empty_rule() { |
1254 | | fails_with! { |
1255 | | parser: PestParser, |
1256 | | input: "a = {}", |
1257 | | rule: Rule::grammar_rules, |
1258 | | positives: vec![Rule::expression], |
1259 | | negatives: vec![], |
1260 | | pos: 5 |
1261 | | }; |
1262 | | } |
1263 | | |
1264 | | #[test] |
1265 | | fn missing_rhs() { |
1266 | | fails_with! { |
1267 | | parser: PestParser, |
1268 | | input: "a = { b ~ }", |
1269 | | rule: Rule::grammar_rules, |
1270 | | positives: vec![Rule::term], |
1271 | | negatives: vec![], |
1272 | | pos: 10 |
1273 | | }; |
1274 | | } |
1275 | | |
1276 | | #[test] |
1277 | | fn incorrect_prefix() { |
1278 | | fails_with! { |
1279 | | parser: PestParser, |
1280 | | input: "a = { ~ b}", |
1281 | | rule: Rule::grammar_rules, |
1282 | | positives: vec![Rule::expression], |
1283 | | negatives: vec![], |
1284 | | pos: 6 |
1285 | | }; |
1286 | | } |
1287 | | |
1288 | | #[test] |
1289 | | fn wrong_op() { |
1290 | | fails_with! { |
1291 | | parser: PestParser, |
1292 | | input: "a = { b % }", |
1293 | | rule: Rule::grammar_rules, |
1294 | | positives: vec![ |
1295 | | Rule::opening_brace, |
1296 | | Rule::closing_brace, |
1297 | | Rule::sequence_operator, |
1298 | | Rule::choice_operator, |
1299 | | Rule::optional_operator, |
1300 | | Rule::repeat_operator, |
1301 | | Rule::repeat_once_operator |
1302 | | ], |
1303 | | negatives: vec![], |
1304 | | pos: 8 |
1305 | | }; |
1306 | | } |
1307 | | |
1308 | | #[test] |
1309 | | fn missing_closing_paren() { |
1310 | | fails_with! { |
1311 | | parser: PestParser, |
1312 | | input: "a = { (b }", |
1313 | | rule: Rule::grammar_rules, |
1314 | | positives: vec![ |
1315 | | Rule::opening_brace, |
1316 | | Rule::closing_paren, |
1317 | | Rule::sequence_operator, |
1318 | | Rule::choice_operator, |
1319 | | Rule::optional_operator, |
1320 | | Rule::repeat_operator, |
1321 | | Rule::repeat_once_operator |
1322 | | ], |
1323 | | negatives: vec![], |
1324 | | pos: 9 |
1325 | | }; |
1326 | | } |
1327 | | |
1328 | | #[test] |
1329 | | fn missing_term() { |
1330 | | fails_with! { |
1331 | | parser: PestParser, |
1332 | | input: "a = { ! }", |
1333 | | rule: Rule::grammar_rules, |
1334 | | positives: vec![ |
1335 | | Rule::opening_paren, |
1336 | | Rule::positive_predicate_operator, |
1337 | | Rule::negative_predicate_operator, |
1338 | | Rule::_push, |
1339 | | Rule::_push_literal, |
1340 | | Rule::peek_slice, |
1341 | | Rule::identifier, |
1342 | | Rule::insensitive_string, |
1343 | | Rule::quote, |
1344 | | Rule::single_quote |
1345 | | ], |
1346 | | negatives: vec![], |
1347 | | pos: 8 |
1348 | | }; |
1349 | | } |
1350 | | |
1351 | | #[test] |
1352 | | fn string_missing_ending_quote() { |
1353 | | fails_with! { |
1354 | | parser: PestParser, |
1355 | | input: "a = { \" }", |
1356 | | rule: Rule::grammar_rules, |
1357 | | positives: vec![Rule::quote], |
1358 | | negatives: vec![], |
1359 | | pos: 9 |
1360 | | }; |
1361 | | } |
1362 | | |
1363 | | #[test] |
1364 | | fn insensitive_missing_string() { |
1365 | | fails_with! { |
1366 | | parser: PestParser, |
1367 | | input: "a = { ^ }", |
1368 | | rule: Rule::grammar_rules, |
1369 | | positives: vec![Rule::quote], |
1370 | | negatives: vec![], |
1371 | | pos: 8 |
1372 | | }; |
1373 | | } |
1374 | | |
1375 | | #[test] |
1376 | | fn char_missing_ending_single_quote() { |
1377 | | fails_with! { |
1378 | | parser: PestParser, |
1379 | | input: "a = { \' }", |
1380 | | rule: Rule::grammar_rules, |
1381 | | positives: vec![Rule::single_quote], |
1382 | | negatives: vec![], |
1383 | | pos: 8 |
1384 | | }; |
1385 | | } |
1386 | | |
1387 | | #[test] |
1388 | | fn range_missing_range_operator() { |
1389 | | fails_with! { |
1390 | | parser: PestParser, |
1391 | | input: "a = { \'a\' }", |
1392 | | rule: Rule::grammar_rules, |
1393 | | positives: vec![Rule::range_operator], |
1394 | | negatives: vec![], |
1395 | | pos: 10 |
1396 | | }; |
1397 | | } |
1398 | | |
1399 | | #[test] |
1400 | | fn wrong_postfix() { |
1401 | | fails_with! { |
1402 | | parser: PestParser, |
1403 | | input: "a = { a& }", |
1404 | | rule: Rule::grammar_rules, |
1405 | | positives: vec![ |
1406 | | Rule::opening_brace, |
1407 | | Rule::closing_brace, |
1408 | | Rule::sequence_operator, |
1409 | | Rule::choice_operator, |
1410 | | Rule::optional_operator, |
1411 | | Rule::repeat_operator, |
1412 | | Rule::repeat_once_operator |
1413 | | ], |
1414 | | negatives: vec![], |
1415 | | pos: 7 |
1416 | | }; |
1417 | | } |
1418 | | |
1419 | | #[test] |
1420 | | fn node_tag() { |
1421 | | parses_to! { |
1422 | | parser: PestParser, |
1423 | | input: "#a = a", |
1424 | | rule: Rule::expression, |
1425 | | tokens: [ |
1426 | | expression(0, 6, [ |
1427 | | term(0, 6, [ |
1428 | | tag_id(0, 2), |
1429 | | assignment_operator(3, 4), |
1430 | | identifier(5, 6) |
1431 | | ]) |
1432 | | ]) |
1433 | | ] |
1434 | | }; |
1435 | | } |
1436 | | |
1437 | | #[test] |
1438 | | fn incomplete_node_tag() { |
1439 | | fails_with! { |
1440 | | parser: PestParser, |
1441 | | input: "a = { # }", |
1442 | | rule: Rule::grammar_rules, |
1443 | | positives: vec![ |
1444 | | Rule::expression |
1445 | | ], |
1446 | | negatives: vec![], |
1447 | | pos: 6 |
1448 | | }; |
1449 | | } |
1450 | | |
1451 | | #[test] |
1452 | | fn incomplete_node_tag_assignment() { |
1453 | | fails_with! { |
1454 | | parser: PestParser, |
1455 | | input: "a = { #a = }", |
1456 | | rule: Rule::grammar_rules, |
1457 | | positives: vec![ |
1458 | | Rule::opening_paren, |
1459 | | Rule::positive_predicate_operator, |
1460 | | Rule::negative_predicate_operator, |
1461 | | Rule::_push, |
1462 | | Rule::_push_literal, |
1463 | | Rule::peek_slice, |
1464 | | Rule::identifier, |
1465 | | Rule::insensitive_string, |
1466 | | Rule::quote, |
1467 | | Rule::single_quote |
1468 | | ], |
1469 | | negatives: vec![], |
1470 | | pos: 11 |
1471 | | }; |
1472 | | } |
1473 | | |
1474 | | #[test] |
1475 | | fn incomplete_node_tag_pound_key() { |
1476 | | fails_with! { |
1477 | | parser: PestParser, |
1478 | | input: "a = { a = a }", |
1479 | | rule: Rule::grammar_rules, |
1480 | | positives: vec![ |
1481 | | Rule::opening_brace, |
1482 | | Rule::closing_brace, |
1483 | | Rule::sequence_operator, |
1484 | | Rule::choice_operator, |
1485 | | Rule::optional_operator, |
1486 | | Rule::repeat_operator, |
1487 | | Rule::repeat_once_operator |
1488 | | ], |
1489 | | negatives: vec![], |
1490 | | pos: 8 |
1491 | | }; |
1492 | | } |
1493 | | |
1494 | | #[test] |
1495 | | fn ast() { |
1496 | | let input = r#" |
1497 | | /// This is line comment |
1498 | | /// This is rule |
1499 | | rule = _{ a{1} ~ "a"{3,} ~ b{, 2} ~ "b"{1, 2} | !(^"c" | PUSH('d'..'e'))?* } |
1500 | | "#; |
1501 | | |
1502 | | let pairs = PestParser::parse(Rule::grammar_rules, input).unwrap(); |
1503 | | let ast = consume_rules_with_spans(pairs).unwrap(); |
1504 | | let ast: Vec<_> = ast.into_iter().map(convert_rule).collect(); |
1505 | | |
1506 | | assert_eq!( |
1507 | | ast, |
1508 | | vec![AstRule { |
1509 | | name: "rule".to_owned(), |
1510 | | ty: RuleType::Silent, |
1511 | | expr: Expr::Choice( |
1512 | | Box::new(Expr::Seq( |
1513 | | Box::new(Expr::Seq( |
1514 | | Box::new(Expr::Seq( |
1515 | | Box::new(Expr::RepExact(Box::new(Expr::Ident("a".to_owned())), 1)), |
1516 | | Box::new(Expr::RepMin(Box::new(Expr::Str("a".to_owned())), 3)) |
1517 | | )), |
1518 | | Box::new(Expr::RepMax(Box::new(Expr::Ident("b".to_owned())), 2)) |
1519 | | )), |
1520 | | Box::new(Expr::RepMinMax(Box::new(Expr::Str("b".to_owned())), 1, 2)) |
1521 | | )), |
1522 | | Box::new(Expr::NegPred(Box::new(Expr::Rep(Box::new(Expr::Opt( |
1523 | | Box::new(Expr::Choice( |
1524 | | Box::new(Expr::Insens("c".to_owned())), |
1525 | | Box::new(Expr::Push(Box::new(Expr::Range( |
1526 | | "d".to_owned(), |
1527 | | "e".to_owned() |
1528 | | )))) |
1529 | | )) |
1530 | | )))))) |
1531 | | ) |
1532 | | },] |
1533 | | ); |
1534 | | } |
1535 | | |
1536 | | #[cfg(feature = "grammar-extras")] |
1537 | | #[test] |
1538 | | fn ast_push_literal() { |
1539 | | let input = r#"rule = _{ PUSH_LITERAL("a") }"#; |
1540 | | |
1541 | | let pairs = PestParser::parse(Rule::grammar_rules, input).unwrap(); |
1542 | | let ast = consume_rules_with_spans(pairs).unwrap(); |
1543 | | let ast: Vec<_> = ast.into_iter().map(convert_rule).collect(); |
1544 | | |
1545 | | assert_eq!( |
1546 | | ast, |
1547 | | vec![AstRule { |
1548 | | name: "rule".to_owned(), |
1549 | | ty: RuleType::Silent, |
1550 | | expr: Expr::PushLiteral("a".to_string()), |
1551 | | }], |
1552 | | ); |
1553 | | } |
1554 | | |
1555 | | #[test] |
1556 | | #[should_panic(expected = "grammar error |
1557 | | |
1558 | | --> 1:24 |
1559 | | | |
1560 | | 1 | rule = _{ PUSH_LITERAL(a) } |
1561 | | | ^--- |
1562 | | | |
1563 | | = expected quote")] |
1564 | | fn ast_push_literal_bad_input() { |
1565 | | let input = r#"rule = _{ PUSH_LITERAL(a) }"#; |
1566 | | |
1567 | | let pairs_result = PestParser::parse(Rule::grammar_rules, input); |
1568 | | match pairs_result { |
1569 | | Ok(ok) => panic!("expected Err, but found {ok}"), |
1570 | | Err(e) => panic!("grammar error\n\n{e}"), |
1571 | | } |
1572 | | } |
1573 | | |
1574 | | #[test] |
1575 | | fn ast_peek_slice() { |
1576 | | let input = "rule = _{ PEEK[-04..] ~ PEEK[..3] }"; |
1577 | | |
1578 | | let pairs = PestParser::parse(Rule::grammar_rules, input).unwrap(); |
1579 | | let ast = consume_rules_with_spans(pairs).unwrap(); |
1580 | | let ast: Vec<_> = ast.into_iter().map(convert_rule).collect(); |
1581 | | |
1582 | | assert_eq!( |
1583 | | ast, |
1584 | | vec![AstRule { |
1585 | | name: "rule".to_owned(), |
1586 | | ty: RuleType::Silent, |
1587 | | expr: Expr::Seq( |
1588 | | Box::new(Expr::PeekSlice(-4, None)), |
1589 | | Box::new(Expr::PeekSlice(0, Some(3))), |
1590 | | ), |
1591 | | }], |
1592 | | ); |
1593 | | } |
1594 | | |
1595 | | #[test] |
1596 | | #[should_panic(expected = "grammar error |
1597 | | |
1598 | | --> 1:13 |
1599 | | | |
1600 | | 1 | rule = { \"\"{4294967297} } |
1601 | | | ^--------^ |
1602 | | | |
1603 | | = number cannot overflow u32")] |
1604 | | fn repeat_exact_overflow() { |
1605 | | let input = "rule = { \"\"{4294967297} }"; |
1606 | | |
1607 | | let pairs = PestParser::parse(Rule::grammar_rules, input).unwrap(); |
1608 | | unwrap_or_report(consume_rules_with_spans(pairs)); |
1609 | | } |
1610 | | |
1611 | | #[test] |
1612 | | #[should_panic(expected = "grammar error |
1613 | | |
1614 | | --> 1:13 |
1615 | | | |
1616 | | 1 | rule = { \"\"{0} } |
1617 | | | ^ |
1618 | | | |
1619 | | = cannot repeat 0 times")] |
1620 | | fn repeat_exact_zero() { |
1621 | | let input = "rule = { \"\"{0} }"; |
1622 | | |
1623 | | let pairs = PestParser::parse(Rule::grammar_rules, input).unwrap(); |
1624 | | unwrap_or_report(consume_rules_with_spans(pairs)); |
1625 | | } |
1626 | | |
1627 | | #[test] |
1628 | | #[should_panic(expected = "grammar error |
1629 | | |
1630 | | --> 1:13 |
1631 | | | |
1632 | | 1 | rule = { \"\"{4294967297,} } |
1633 | | | ^--------^ |
1634 | | | |
1635 | | = number cannot overflow u32")] |
1636 | | fn repeat_min_overflow() { |
1637 | | let input = "rule = { \"\"{4294967297,} }"; |
1638 | | |
1639 | | let pairs = PestParser::parse(Rule::grammar_rules, input).unwrap(); |
1640 | | unwrap_or_report(consume_rules_with_spans(pairs)); |
1641 | | } |
1642 | | |
1643 | | #[test] |
1644 | | #[should_panic(expected = "grammar error |
1645 | | |
1646 | | --> 1:14 |
1647 | | | |
1648 | | 1 | rule = { \"\"{,4294967297} } |
1649 | | | ^--------^ |
1650 | | | |
1651 | | = number cannot overflow u32")] |
1652 | | fn repeat_max_overflow() { |
1653 | | let input = "rule = { \"\"{,4294967297} }"; |
1654 | | |
1655 | | let pairs = PestParser::parse(Rule::grammar_rules, input).unwrap(); |
1656 | | unwrap_or_report(consume_rules_with_spans(pairs)); |
1657 | | } |
1658 | | |
1659 | | #[test] |
1660 | | #[should_panic(expected = "grammar error |
1661 | | |
1662 | | --> 1:14 |
1663 | | | |
1664 | | 1 | rule = { \"\"{,0} } |
1665 | | | ^ |
1666 | | | |
1667 | | = cannot repeat 0 times")] |
1668 | | fn repeat_max_zero() { |
1669 | | let input = "rule = { \"\"{,0} }"; |
1670 | | |
1671 | | let pairs = PestParser::parse(Rule::grammar_rules, input).unwrap(); |
1672 | | unwrap_or_report(consume_rules_with_spans(pairs)); |
1673 | | } |
1674 | | |
1675 | | #[test] |
1676 | | #[should_panic(expected = "grammar error |
1677 | | |
1678 | | --> 1:13 |
1679 | | | |
1680 | | 1 | rule = { \"\"{4294967297,4294967298} } |
1681 | | | ^--------^ |
1682 | | | |
1683 | | = number cannot overflow u32")] |
1684 | | fn repeat_min_max_overflow() { |
1685 | | let input = "rule = { \"\"{4294967297,4294967298} }"; |
1686 | | |
1687 | | let pairs = PestParser::parse(Rule::grammar_rules, input).unwrap(); |
1688 | | unwrap_or_report(consume_rules_with_spans(pairs)); |
1689 | | } |
1690 | | |
1691 | | #[test] |
1692 | | #[should_panic(expected = "grammar error |
1693 | | |
1694 | | --> 1:15 |
1695 | | | |
1696 | | 1 | rule = { \"\"{0,0} } |
1697 | | | ^ |
1698 | | | |
1699 | | = cannot repeat 0 times")] |
1700 | | fn repeat_min_max_zero() { |
1701 | | let input = "rule = { \"\"{0,0} }"; |
1702 | | |
1703 | | let pairs = PestParser::parse(Rule::grammar_rules, input).unwrap(); |
1704 | | unwrap_or_report(consume_rules_with_spans(pairs)); |
1705 | | } |
1706 | | |
1707 | | #[test] |
1708 | | fn unescape_all() { |
1709 | | let string = r"a\nb\x55c\u{111}d"; |
1710 | | |
1711 | | assert_eq!(unescape(string), Some("a\nb\x55c\u{111}d".to_owned())); |
1712 | | } |
1713 | | |
1714 | | #[test] |
1715 | | fn unescape_empty_escape() { |
1716 | | let string = r"\"; |
1717 | | |
1718 | | assert_eq!(unescape(string), None); |
1719 | | } |
1720 | | |
1721 | | #[test] |
1722 | | fn unescape_wrong_escape() { |
1723 | | let string = r"\w"; |
1724 | | |
1725 | | assert_eq!(unescape(string), None); |
1726 | | } |
1727 | | |
1728 | | #[test] |
1729 | | fn unescape_backslash() { |
1730 | | let string = "\\\\"; |
1731 | | assert_eq!(unescape(string), Some("\\".to_owned())); |
1732 | | } |
1733 | | |
1734 | | #[test] |
1735 | | fn unescape_return() { |
1736 | | let string = "\\r"; |
1737 | | assert_eq!(unescape(string), Some("\r".to_owned())); |
1738 | | } |
1739 | | |
1740 | | #[test] |
1741 | | fn unescape_tab() { |
1742 | | let string = "\\t"; |
1743 | | assert_eq!(unescape(string), Some("\t".to_owned())); |
1744 | | } |
1745 | | |
1746 | | #[test] |
1747 | | fn unescape_null() { |
1748 | | let string = "\\0"; |
1749 | | assert_eq!(unescape(string), Some("\0".to_owned())); |
1750 | | } |
1751 | | |
1752 | | #[test] |
1753 | | fn unescape_single_quote() { |
1754 | | let string = "\\'"; |
1755 | | assert_eq!(unescape(string), Some("\'".to_owned())); |
1756 | | } |
1757 | | |
1758 | | #[test] |
1759 | | fn unescape_wrong_byte() { |
1760 | | let string = r"\xfg"; |
1761 | | |
1762 | | assert_eq!(unescape(string), None); |
1763 | | } |
1764 | | |
1765 | | #[test] |
1766 | | fn unescape_short_byte() { |
1767 | | let string = r"\xf"; |
1768 | | |
1769 | | assert_eq!(unescape(string), None); |
1770 | | } |
1771 | | |
1772 | | #[test] |
1773 | | fn unescape_no_open_brace_unicode() { |
1774 | | let string = r"\u11"; |
1775 | | |
1776 | | assert_eq!(unescape(string), None); |
1777 | | } |
1778 | | |
1779 | | #[test] |
1780 | | fn unescape_no_close_brace_unicode() { |
1781 | | let string = r"\u{11"; |
1782 | | |
1783 | | assert_eq!(unescape(string), None); |
1784 | | } |
1785 | | |
1786 | | #[test] |
1787 | | fn unescape_short_unicode() { |
1788 | | let string = r"\u{1}"; |
1789 | | |
1790 | | assert_eq!(unescape(string), None); |
1791 | | } |
1792 | | |
1793 | | #[test] |
1794 | | fn unescape_long_unicode() { |
1795 | | let string = r"\u{1111111}"; |
1796 | | |
1797 | | assert_eq!(unescape(string), None); |
1798 | | } |
1799 | | |
1800 | | #[test] |
1801 | | fn handles_deep_nesting() { |
1802 | | let sample1 = include_str!(concat!( |
1803 | | env!("CARGO_MANIFEST_DIR"), |
1804 | | "/resources/test/fuzzsample1.grammar" |
1805 | | )); |
1806 | | let sample2 = include_str!(concat!( |
1807 | | env!("CARGO_MANIFEST_DIR"), |
1808 | | "/resources/test/fuzzsample2.grammar" |
1809 | | )); |
1810 | | let sample3 = include_str!(concat!( |
1811 | | env!("CARGO_MANIFEST_DIR"), |
1812 | | "/resources/test/fuzzsample3.grammar" |
1813 | | )); |
1814 | | let sample4 = include_str!(concat!( |
1815 | | env!("CARGO_MANIFEST_DIR"), |
1816 | | "/resources/test/fuzzsample4.grammar" |
1817 | | )); |
1818 | | let sample5 = include_str!(concat!( |
1819 | | env!("CARGO_MANIFEST_DIR"), |
1820 | | "/resources/test/fuzzsample5.grammar" |
1821 | | )); |
1822 | | const ERROR: &str = "call limit reached"; |
1823 | | pest::set_call_limit(Some(5_000usize.try_into().unwrap())); |
1824 | | let s1 = parse(Rule::grammar_rules, sample1); |
1825 | | assert!(s1.is_err()); |
1826 | | assert_eq!(s1.unwrap_err().variant.message(), ERROR); |
1827 | | let s2 = parse(Rule::grammar_rules, sample2); |
1828 | | assert!(s2.is_err()); |
1829 | | assert_eq!(s2.unwrap_err().variant.message(), ERROR); |
1830 | | let s3 = parse(Rule::grammar_rules, sample3); |
1831 | | assert!(s3.is_err()); |
1832 | | assert_eq!(s3.unwrap_err().variant.message(), ERROR); |
1833 | | let s4 = parse(Rule::grammar_rules, sample4); |
1834 | | assert!(s4.is_err()); |
1835 | | assert_eq!(s4.unwrap_err().variant.message(), ERROR); |
1836 | | let s5 = parse(Rule::grammar_rules, sample5); |
1837 | | assert!(s5.is_err()); |
1838 | | assert_eq!(s5.unwrap_err().variant.message(), ERROR); |
1839 | | } |
1840 | | } |