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