1use nom::branch::alt;
6use nom::bytes::complete::{tag, take_while1};
7use nom::character::complete::{char, digit1, multispace0};
8use nom::combinator::{map, opt, recognize, value};
9use nom::error::{Error as NomError, ErrorKind as NomErrorKind, ParseError as NomParseError};
10use nom::multi::{many0, separated_list0};
11use nom::sequence::{delimited, pair, preceded};
12use nom::{AsChar, Finish, IResult, Input, Parser};
13
14use crate::ast::{
15 Axis, BinaryOperator, CoreFunction, Expression, FilterExpression, KindTest, Literal,
16 LocationStepExpression, NodeTest, PathExpression, PredicateListExpression, QName,
17};
18use crate::{is_valid_continuation, is_valid_start};
19
20pub(crate) fn parse(input: &str) -> Result<Expression, OwnedParserError> {
21 let (_, ast) = expr(input).finish().map_err(OwnedParserError::from)?;
22 Ok(ast)
23}
24
25#[derive(Clone, Debug, PartialEq)]
26pub struct OwnedParserError {
27 pub input: String,
28 pub kind: NomErrorKind,
29}
30
31impl<'a> From<NomError<&'a str>> for OwnedParserError {
32 fn from(err: NomError<&'a str>) -> Self {
33 OwnedParserError {
34 input: err.input.to_string(),
35 kind: err.code,
36 }
37 }
38}
39
40impl std::fmt::Display for OwnedParserError {
41 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
42 write!(f, "error {:?} at: {}", self.kind, self.input)
43 }
44}
45
46impl std::error::Error for OwnedParserError {}
47
48fn expr(input: &str) -> IResult<&str, Expression> {
50 expr_single(input)
51}
52
53fn expr_single(input: &str) -> IResult<&str, Expression> {
55 or_expr(input)
56}
57
58fn or_expr(input: &str) -> IResult<&str, Expression> {
60 let (input, first) = and_expr(input)?;
61 let (input, rest) = many0(preceded(ws(tag("or")), and_expr)).parse(input)?;
62
63 Ok((
64 input,
65 rest.into_iter().fold(first, |acc, expr| {
66 Expression::Binary(Box::new(acc), BinaryOperator::Or, Box::new(expr))
67 }),
68 ))
69}
70
71fn and_expr(input: &str) -> IResult<&str, Expression> {
73 let (input, first) = equality_expr(input)?;
74 let (input, rest) = many0(preceded(ws(tag("and")), equality_expr)).parse(input)?;
75
76 Ok((
77 input,
78 rest.into_iter().fold(first, |acc, expr| {
79 Expression::Binary(Box::new(acc), BinaryOperator::And, Box::new(expr))
80 }),
81 ))
82}
83
84fn equality_expr(input: &str) -> IResult<&str, Expression> {
86 let (input, first) = relational_expr(input)?;
87 let (input, rest) = many0((
88 ws(alt((
89 map(tag("="), |_| BinaryOperator::Equal),
90 map(tag("!="), |_| BinaryOperator::NotEqual),
91 ))),
92 relational_expr,
93 ))
94 .parse(input)?;
95
96 Ok((
97 input,
98 rest.into_iter().fold(first, |acc, (op, expr)| {
99 Expression::Binary(Box::new(acc), op, Box::new(expr))
100 }),
101 ))
102}
103
104fn relational_expr(input: &str) -> IResult<&str, Expression> {
106 let (input, first) = additive_expr(input)?;
107 let (input, rest) = many0((
108 ws(alt((
109 map(tag("<="), |_| BinaryOperator::LessThanOrEqual),
110 map(tag(">="), |_| BinaryOperator::GreaterThanOrEqual),
111 map(tag("<"), |_| BinaryOperator::LessThan),
112 map(tag(">"), |_| BinaryOperator::GreaterThan),
113 ))),
114 additive_expr,
115 ))
116 .parse(input)?;
117
118 Ok((
119 input,
120 rest.into_iter().fold(first, |acc, (op, expr)| {
121 Expression::Binary(Box::new(acc), op, Box::new(expr))
122 }),
123 ))
124}
125
126fn additive_expr(input: &str) -> IResult<&str, Expression> {
128 let (input, first) = multiplicative_expr(input)?;
129 let (input, rest) = many0((
130 ws(alt((
131 map(tag("+"), |_| BinaryOperator::Add),
132 map(tag("-"), |_| BinaryOperator::Subtract),
133 ))),
134 multiplicative_expr,
135 ))
136 .parse(input)?;
137
138 Ok((
139 input,
140 rest.into_iter().fold(first, |acc, (op, expr)| {
141 Expression::Binary(Box::new(acc), op, Box::new(expr))
142 }),
143 ))
144}
145
146fn multiplicative_expr(input: &str) -> IResult<&str, Expression> {
148 let (input, first) = unary_expr(input)?;
149 let (input, rest) = many0((
150 ws(alt((
151 map(tag("*"), |_| BinaryOperator::Multiply),
152 map(tag("div"), |_| BinaryOperator::Divide),
153 map(tag("mod"), |_| BinaryOperator::Modulo),
154 ))),
155 unary_expr,
156 ))
157 .parse(input)?;
158
159 Ok((
160 input,
161 rest.into_iter().fold(first, |acc, (op, expr)| {
162 Expression::Binary(Box::new(acc), op, Box::new(expr))
163 }),
164 ))
165}
166
167fn unary_expr(input: &str) -> IResult<&str, Expression> {
169 let (input, minus_count) = many0(ws(char('-'))).parse(input)?;
170 let (input, expr) = union_expr(input)?;
171
172 Ok((
173 input,
174 (0..minus_count.len()).fold(expr, |acc, _| Expression::Negate(Box::new(acc))),
175 ))
176}
177
178fn union_expr(input: &str) -> IResult<&str, Expression> {
180 let (input, first) = path_expr(input)?;
181 let (input, rest) = many0(preceded(ws(char('|')), path_expr)).parse(input)?;
182
183 Ok((
184 input,
185 rest.into_iter().fold(first, |acc, expr| {
186 Expression::Binary(Box::new(acc), BinaryOperator::Union, Box::new(expr))
187 }),
188 ))
189}
190
191fn path_expr(input: &str) -> IResult<&str, Expression> {
193 ws(alt((
194 map(
196 pair(tag("//"), move |i| relative_path_expr(true, i)),
197 |(_, relative_path)| {
198 Expression::Path(PathExpression {
199 is_absolute: true,
200 has_implicit_descendant_or_self_step: true,
201 steps: relative_path.steps,
202 })
203 },
204 ),
205 map(
207 pair(char('/'), opt(move |i| relative_path_expr(false, i))),
208 |(_, relative_path)| {
209 Expression::Path(PathExpression {
210 is_absolute: true,
211 has_implicit_descendant_or_self_step: false,
212 steps: relative_path.map(|path| path.steps).unwrap_or_default(),
213 })
214 },
215 ),
216 map(
218 move |i| relative_path_expr(false, i),
219 |mut relative_path_expression| {
220 if relative_path_expression.steps.len() == 1 {
221 relative_path_expression.steps.pop().unwrap()
222 } else {
223 Expression::Path(relative_path_expression)
224 }
225 },
226 ),
227 )))
228 .parse(input)
229}
230
231fn relative_path_expr(is_descendant: bool, input: &str) -> IResult<&str, PathExpression> {
232 let (input, first) = step_expr(is_descendant, input)?;
233 let (input, steps) = many0(pair(
234 ws(alt((value(true, tag("//")), value(false, char('/'))))),
235 ws(move |i| step_expr(false, i)),
236 ))
237 .parse(input)?;
238
239 let mut all_steps = vec![first];
240 for (implicit_descendant_or_self, step) in steps {
241 if implicit_descendant_or_self {
242 all_steps.push(Expression::LocationStep(LocationStepExpression {
244 axis: Axis::DescendantOrSelf,
245 node_test: NodeTest::Kind(KindTest::Node),
246 predicate_list: PredicateListExpression { predicates: vec![] },
247 }));
248 }
249 all_steps.push(step);
250 }
251
252 Ok((
253 input,
254 PathExpression {
255 is_absolute: false,
256 has_implicit_descendant_or_self_step: false,
257 steps: all_steps,
258 },
259 ))
260}
261
262fn step_expr(is_descendant: bool, input: &str) -> IResult<&str, Expression> {
263 alt((filter_expr, |i| axis_step(is_descendant, i))).parse(input)
264}
265
266fn axis_step(is_descendant: bool, input: &str) -> IResult<&str, Expression> {
267 let (input, (step, predicates)) = pair(
268 alt((move |i| forward_step(is_descendant, i), reverse_step)),
269 predicate_list,
270 )
271 .parse(input)?;
272
273 let (axis, node_test) = step;
274 Ok((
275 input,
276 Expression::LocationStep(LocationStepExpression {
277 axis,
278 node_test,
279 predicate_list: predicates,
280 }),
281 ))
282}
283
284fn forward_step(is_descendant: bool, input: &str) -> IResult<&str, (Axis, NodeTest)> {
285 alt((pair(forward_axis, node_test), move |i| {
286 abbrev_forward_step(is_descendant, i)
287 }))
288 .parse(input)
289}
290
291fn forward_axis(input: &str) -> IResult<&str, Axis> {
292 let (input, axis) = alt((
293 value(Axis::Child, tag("child::")),
294 value(Axis::Descendant, tag("descendant::")),
295 value(Axis::Attribute, tag("attribute::")),
296 value(Axis::Self_, tag("self::")),
297 value(Axis::DescendantOrSelf, tag("descendant-or-self::")),
298 value(Axis::FollowingSibling, tag("following-sibling::")),
299 value(Axis::Following, tag("following::")),
300 value(Axis::Namespace, tag("namespace::")),
301 ))
302 .parse(input)?;
303
304 Ok((input, axis))
305}
306
307fn abbrev_forward_step(is_descendant: bool, input: &str) -> IResult<&str, (Axis, NodeTest)> {
309 let (input, attr) = opt(char('@')).parse(input)?;
310 let (input, test) = node_test(input)?;
311
312 let axis = if attr.is_some() {
313 Axis::Attribute
314 } else if is_descendant {
315 Axis::DescendantOrSelf
316 } else {
317 Axis::Child
318 };
319 Ok((input, (axis, test)))
320}
321
322fn reverse_step(input: &str) -> IResult<&str, (Axis, NodeTest)> {
323 alt((
324 pair(reverse_axis, node_test),
326 abbrev_reverse_step,
328 ))
329 .parse(input)
330}
331
332fn reverse_axis(input: &str) -> IResult<&str, Axis> {
333 alt((
334 value(Axis::Parent, tag("parent::")),
335 value(Axis::Ancestor, tag("ancestor::")),
336 value(Axis::PrecedingSibling, tag("preceding-sibling::")),
337 value(Axis::Preceding, tag("preceding::")),
338 value(Axis::AncestorOrSelf, tag("ancestor-or-self::")),
339 ))
340 .parse(input)
341}
342
343fn abbrev_reverse_step(input: &str) -> IResult<&str, (Axis, NodeTest)> {
344 map(tag(".."), |_| {
345 (Axis::Parent, NodeTest::Kind(KindTest::Node))
346 })
347 .parse(input)
348}
349
350fn node_test(input: &str) -> IResult<&str, NodeTest> {
352 alt((
353 map(kind_test, NodeTest::Kind),
354 map(name_test, |name| match name {
355 NameTest::Wildcard => NodeTest::Wildcard,
356 NameTest::QName(qname) => NodeTest::Name(qname),
357 }),
358 ))
359 .parse(input)
360}
361
362#[derive(Clone, Debug, PartialEq)]
363enum NameTest {
364 QName(QName),
365 Wildcard,
366}
367
368fn name_test(input: &str) -> IResult<&str, NameTest> {
370 alt((
371 map((ncname, char(':'), char('*')), |(prefix, _, _)| {
373 NameTest::QName(QName {
374 prefix: Some(prefix.to_string()),
375 local_part: "*".to_string(),
376 })
377 }),
378 value(NameTest::Wildcard, char('*')),
380 map(qname, NameTest::QName),
382 ))
383 .parse(input)
384}
385
386fn filter_expr(input: &str) -> IResult<&str, Expression> {
388 let (input, primary) = primary_expr(input)?;
389 let (input, predicate_list) = predicate_list(input)?;
390
391 if predicate_list.predicates.is_empty() {
392 return Ok((input, primary));
393 }
394
395 Ok((
396 input,
397 Expression::Filter(FilterExpression {
398 expression: Box::new(primary),
399 predicates: predicate_list,
400 }),
401 ))
402}
403
404fn predicate_list(input: &str) -> IResult<&str, PredicateListExpression> {
405 let (input, predicates) = many0(predicate).parse(input)?;
406
407 Ok((input, PredicateListExpression { predicates }))
408}
409
410fn predicate(input: &str) -> IResult<&str, Expression> {
412 let (input, expr) = delimited(ws(char('[')), expr, ws(char(']'))).parse(input)?;
413 Ok((input, expr))
414}
415
416fn primary_expr(input: &str) -> IResult<&str, Expression> {
418 alt((
419 literal,
420 var_ref,
421 parenthesized_expr,
422 context_item_expr,
423 function_call,
424 ))
425 .parse(input)
426}
427
428fn literal(input: &str) -> IResult<&str, Expression> {
430 map(alt((numeric_literal, string_literal)), |lit| {
431 Expression::Literal(lit)
432 })
433 .parse(input)
434}
435
436fn numeric_literal(input: &str) -> IResult<&str, Literal> {
438 alt((decimal_literal, integer_literal)).parse(input)
439}
440
441fn var_ref(input: &str) -> IResult<&str, Expression> {
443 let (input, _) = char('$').parse(input)?;
444 let (input, name) = qname(input)?;
445 Ok((input, Expression::Variable(name)))
446}
447
448fn parenthesized_expr(input: &str) -> IResult<&str, Expression> {
449 delimited(ws(char('(')), expr, ws(char(')'))).parse(input)
450}
451
452fn context_item_expr(input: &str) -> IResult<&str, Expression> {
453 map(char('.'), |_| Expression::ContextItem).parse(input)
454}
455
456fn function_call(input: &str) -> IResult<&str, Expression> {
457 let (input, name) = qname(input)?;
458 let (input, args) = delimited(
459 ws(char('(')),
460 separated_list0(ws(char(',')), expr_single),
461 ws(char(')')),
462 )
463 .parse(input)?;
464
465 let arity_error = || nom::Err::Error(NomError::new(input, NomErrorKind::Verify));
467
468 let core_fn = match name.local_part.as_str() {
469 "last" => CoreFunction::Last,
471 "position" => CoreFunction::Position,
472 "count" => CoreFunction::Count(Box::new(args.into_iter().next().ok_or_else(arity_error)?)),
473 "id" => CoreFunction::Id(Box::new(args.into_iter().next().ok_or_else(arity_error)?)),
474 "local-name" => CoreFunction::LocalName(args.into_iter().next().map(Box::new)),
475 "namespace-uri" => CoreFunction::NamespaceUri(args.into_iter().next().map(Box::new)),
476 "name" => CoreFunction::Name(args.into_iter().next().map(Box::new)),
477
478 "string" => CoreFunction::String(args.into_iter().next().map(Box::new)),
480 "concat" => CoreFunction::Concat(args.into_iter().collect()),
481 "starts-with" => {
482 let mut args = args.into_iter();
483 CoreFunction::StartsWith(
484 Box::new(args.next().ok_or_else(arity_error)?),
485 Box::new(args.next().ok_or_else(arity_error)?),
486 )
487 },
488 "contains" => {
489 let mut args = args.into_iter();
490 CoreFunction::Contains(
491 Box::new(args.next().ok_or_else(arity_error)?),
492 Box::new(args.next().ok_or_else(arity_error)?),
493 )
494 },
495 "substring-before" => {
496 let mut args = args.into_iter();
497 CoreFunction::SubstringBefore(
498 Box::new(args.next().ok_or_else(arity_error)?),
499 Box::new(args.next().ok_or_else(arity_error)?),
500 )
501 },
502 "substring-after" => {
503 let mut args = args.into_iter();
504 CoreFunction::SubstringAfter(
505 Box::new(args.next().ok_or_else(arity_error)?),
506 Box::new(args.next().ok_or_else(arity_error)?),
507 )
508 },
509 "substring" => {
510 let mut args = args.into_iter();
511 CoreFunction::Substring(
512 Box::new(args.next().ok_or_else(arity_error)?),
513 Box::new(args.next().ok_or_else(arity_error)?),
514 args.next().map(Box::new),
515 )
516 },
517 "string-length" => CoreFunction::StringLength(args.into_iter().next().map(Box::new)),
518 "normalize-space" => CoreFunction::NormalizeSpace(args.into_iter().next().map(Box::new)),
519 "translate" => {
520 let mut args = args.into_iter();
521 CoreFunction::Translate(
522 Box::new(args.next().ok_or_else(arity_error)?),
523 Box::new(args.next().ok_or_else(arity_error)?),
524 Box::new(args.next().ok_or_else(arity_error)?),
525 )
526 },
527
528 "number" => CoreFunction::Number(args.into_iter().next().map(Box::new)),
530 "sum" => CoreFunction::Sum(Box::new(args.into_iter().next().ok_or_else(arity_error)?)),
531 "floor" => CoreFunction::Floor(Box::new(args.into_iter().next().ok_or_else(arity_error)?)),
532 "ceiling" => {
533 CoreFunction::Ceiling(Box::new(args.into_iter().next().ok_or_else(arity_error)?))
534 },
535 "round" => CoreFunction::Round(Box::new(args.into_iter().next().ok_or_else(arity_error)?)),
536
537 "boolean" => {
539 CoreFunction::Boolean(Box::new(args.into_iter().next().ok_or_else(arity_error)?))
540 },
541 "not" => CoreFunction::Not(Box::new(args.into_iter().next().ok_or_else(arity_error)?)),
542 "true" => CoreFunction::True,
543 "false" => CoreFunction::False,
544 "lang" => CoreFunction::Lang(Box::new(args.into_iter().next().ok_or_else(arity_error)?)),
545
546 _ => return Err(nom::Err::Error(NomError::new(input, NomErrorKind::Verify))),
548 };
549
550 Ok((input, Expression::Function(core_fn)))
551}
552
553fn kind_test(input: &str) -> IResult<&str, KindTest> {
554 alt((pi_test, comment_test, text_test, any_kind_test)).parse(input)
555}
556
557fn any_kind_test(input: &str) -> IResult<&str, KindTest> {
558 map((tag("node"), ws(char('(')), ws(char(')'))), |_| {
559 KindTest::Node
560 })
561 .parse(input)
562}
563
564fn text_test(input: &str) -> IResult<&str, KindTest> {
565 map((tag("text"), ws(char('(')), ws(char(')'))), |_| {
566 KindTest::Text
567 })
568 .parse(input)
569}
570
571fn comment_test(input: &str) -> IResult<&str, KindTest> {
572 map((tag("comment"), ws(char('(')), ws(char(')'))), |_| {
573 KindTest::Comment
574 })
575 .parse(input)
576}
577
578fn pi_test(input: &str) -> IResult<&str, KindTest> {
579 map(
580 (
581 tag("processing-instruction"),
582 ws(char('(')),
583 opt(ws(string_literal)),
584 ws(char(')')),
585 ),
586 |(_, _, literal, _)| {
587 KindTest::PI(literal.map(|l| match l {
588 Literal::String(s) => s,
589 _ => unreachable!(),
590 }))
591 },
592 )
593 .parse(input)
594}
595
596fn ws<'a, F, O, E>(inner: F) -> impl Parser<&'a str, Output = O, Error = E>
597where
598 E: NomParseError<&'a str>,
599 F: Parser<&'a str, Output = O, Error = E>,
600{
601 delimited(multispace0, inner, multispace0)
602}
603
604fn integer_literal(input: &str) -> IResult<&str, Literal> {
605 map(recognize((opt(char('-')), digit1)), |s: &str| {
606 Literal::Integer(s.parse().unwrap())
607 })
608 .parse(input)
609}
610
611fn decimal_literal(input: &str) -> IResult<&str, Literal> {
612 map(
613 recognize((opt(char('-')), opt(digit1), char('.'), digit1)),
614 |s: &str| Literal::Decimal(s.parse().unwrap()),
615 )
616 .parse(input)
617}
618
619fn string_literal(input: &str) -> IResult<&str, Literal> {
620 alt((
621 delimited(
622 char('"'),
623 map(take_while1(|c| c != '"'), |s: &str| {
624 Literal::String(s.to_string())
625 }),
626 char('"'),
627 ),
628 delimited(
629 char('\''),
630 map(take_while1(|c| c != '\''), |s: &str| {
631 Literal::String(s.to_string())
632 }),
633 char('\''),
634 ),
635 ))
636 .parse(input)
637}
638
639fn qname(input: &str) -> IResult<&str, QName> {
641 let (input, prefix) = opt((ncname, char(':'))).parse(input)?;
642 let (input, local) = ncname(input)?;
643
644 Ok((
645 input,
646 QName {
647 prefix: prefix.map(|(p, _)| p.to_string()),
648 local_part: local.to_string(),
649 },
650 ))
651}
652
653fn ncname(input: &str) -> IResult<&str, &str> {
655 fn name_start_character<T, E: NomParseError<T>>(input: T) -> IResult<T, T, E>
656 where
657 T: Input,
658 <T as Input>::Item: AsChar,
659 {
660 input.split_at_position1_complete(
661 |character| !is_valid_start(character.as_char()) || character.as_char() == ':',
662 NomErrorKind::OneOf,
663 )
664 }
665
666 fn name_character<T, E: NomParseError<T>>(input: T) -> IResult<T, T, E>
667 where
668 T: Input,
669 <T as Input>::Item: AsChar,
670 {
671 input.split_at_position1_complete(
672 |character| !is_valid_continuation(character.as_char()) || character.as_char() == ':',
673 NomErrorKind::OneOf,
674 )
675 }
676
677 recognize(pair(name_start_character, many0(name_character))).parse(input)
678}
679
680#[cfg(test)]
682mod tests {
683 use super::*;
684
685 #[test]
686 fn test_node_tests() {
687 let cases = vec![
688 ("node()", NodeTest::Kind(KindTest::Node)),
689 ("text()", NodeTest::Kind(KindTest::Text)),
690 ("comment()", NodeTest::Kind(KindTest::Comment)),
691 (
692 "processing-instruction()",
693 NodeTest::Kind(KindTest::PI(None)),
694 ),
695 (
696 "processing-instruction('test')",
697 NodeTest::Kind(KindTest::PI(Some("test".to_string()))),
698 ),
699 ("*", NodeTest::Wildcard),
700 (
701 "prefix:*",
702 NodeTest::Name(QName {
703 prefix: Some("prefix".to_string()),
704 local_part: "*".to_string(),
705 }),
706 ),
707 (
708 "div",
709 NodeTest::Name(QName {
710 prefix: None,
711 local_part: "div".to_string(),
712 }),
713 ),
714 (
715 "ns:div",
716 NodeTest::Name(QName {
717 prefix: Some("ns".to_string()),
718 local_part: "div".to_string(),
719 }),
720 ),
721 ];
722
723 for (input, expected) in cases {
724 match node_test(input) {
725 Ok((remaining, result)) => {
726 assert!(remaining.is_empty(), "Parser didn't consume all input");
727 assert_eq!(result, expected, "{:?} was parsed incorrectly", input);
728 },
729 Err(e) => panic!("Failed to parse '{}': {:?}", input, e),
730 }
731 }
732 }
733
734 #[test]
735 fn test_filter_expr() {
736 let cases = vec![
737 (
738 "processing-instruction('test')[2]",
739 Expression::LocationStep(LocationStepExpression {
740 axis: Axis::Child,
741 node_test: NodeTest::Kind(KindTest::PI(Some("test".to_string()))),
742 predicate_list: PredicateListExpression {
743 predicates: vec![Expression::Literal(Literal::Integer(2))],
744 },
745 }),
746 ),
747 (
748 "concat('hello', ' ', 'world')",
749 Expression::Function(CoreFunction::Concat(vec![
750 Expression::Literal(Literal::String("hello".to_string())),
751 Expression::Literal(Literal::String(" ".to_string())),
752 Expression::Literal(Literal::String("world".to_string())),
753 ])),
754 ),
755 ];
756
757 for (input, expected) in cases {
758 match parse(input) {
759 Ok(result) => {
760 assert_eq!(result, expected, "{:?} was parsed incorrectly", input);
761 },
762 Err(e) => panic!("Failed to parse '{}': {:?}", input, e),
763 }
764 }
765 }
766
767 #[test]
768 fn test_complex_paths() {
769 let cases = vec![
770 (
771 "//*[contains(@class, 'test')]",
772 Expression::Path(PathExpression {
773 is_absolute: true,
774 has_implicit_descendant_or_self_step: true,
775 steps: vec![Expression::LocationStep(LocationStepExpression {
776 axis: Axis::DescendantOrSelf,
777 node_test: NodeTest::Wildcard,
778 predicate_list: PredicateListExpression {
779 predicates: vec![Expression::Function(CoreFunction::Contains(
780 Box::new(Expression::LocationStep(LocationStepExpression {
781 axis: Axis::Attribute,
782 node_test: NodeTest::Name(QName {
783 prefix: None,
784 local_part: "class".to_owned(),
785 }),
786 predicate_list: PredicateListExpression { predicates: vec![] },
787 })),
788 Box::new(Expression::Literal(Literal::String("test".to_owned()))),
789 ))],
790 },
791 })],
792 }),
793 ),
794 (
795 "//div[position() > 1]/*[last()]",
796 Expression::Path(PathExpression {
797 is_absolute: true,
798 has_implicit_descendant_or_self_step: true,
799 steps: vec![
800 Expression::LocationStep(LocationStepExpression {
801 axis: Axis::DescendantOrSelf,
802 node_test: NodeTest::Name(QName {
803 prefix: None,
804 local_part: "div".to_owned(),
805 }),
806 predicate_list: PredicateListExpression {
807 predicates: vec![Expression::Binary(
808 Box::new(Expression::Function(CoreFunction::Position)),
809 BinaryOperator::GreaterThan,
810 Box::new(Expression::Literal(Literal::Integer(1))),
811 )],
812 },
813 }),
814 Expression::LocationStep(LocationStepExpression {
815 axis: Axis::Child,
816 node_test: NodeTest::Wildcard,
817 predicate_list: PredicateListExpression {
818 predicates: vec![Expression::Function(CoreFunction::Last)],
819 },
820 }),
821 ],
822 }),
823 ),
824 (
825 "//mu[@xml:id=\"id1\"]//rho[@title][@xml:lang=\"en-GB\"]",
826 Expression::Path(PathExpression {
827 is_absolute: true,
828 has_implicit_descendant_or_self_step: true,
829 steps: vec![
830 Expression::LocationStep(LocationStepExpression {
831 axis: Axis::DescendantOrSelf,
832 node_test: NodeTest::Name(QName {
833 prefix: None,
834 local_part: "mu".to_owned(),
835 }),
836 predicate_list: PredicateListExpression {
837 predicates: vec![Expression::Binary(
838 Box::new(Expression::LocationStep(LocationStepExpression {
839 axis: Axis::Attribute,
840 node_test: NodeTest::Name(QName {
841 prefix: Some("xml".to_owned()),
842 local_part: "id".to_owned(),
843 }),
844 predicate_list: PredicateListExpression {
845 predicates: vec![],
846 },
847 })),
848 BinaryOperator::Equal,
849 Box::new(Expression::Literal(Literal::String(
850 "id1".to_owned(),
851 ))),
852 )],
853 },
854 }),
855 Expression::LocationStep(LocationStepExpression {
856 axis: Axis::DescendantOrSelf,
857 node_test: NodeTest::Kind(KindTest::Node),
858 predicate_list: PredicateListExpression { predicates: vec![] },
859 }),
860 Expression::LocationStep(LocationStepExpression {
861 axis: Axis::Child,
862 node_test: NodeTest::Name(QName {
863 prefix: None,
864 local_part: "rho".to_owned(),
865 }),
866 predicate_list: PredicateListExpression {
867 predicates: vec![
868 Expression::LocationStep(LocationStepExpression {
869 axis: Axis::Attribute,
870 node_test: NodeTest::Name(QName {
871 prefix: None,
872 local_part: "title".to_owned(),
873 }),
874 predicate_list: PredicateListExpression {
875 predicates: vec![],
876 },
877 }),
878 Expression::Binary(
879 Box::new(Expression::LocationStep(
880 LocationStepExpression {
881 axis: Axis::Attribute,
882 node_test: NodeTest::Name(QName {
883 prefix: Some("xml".to_owned()),
884 local_part: "lang".to_owned(),
885 }),
886 predicate_list: PredicateListExpression {
887 predicates: vec![],
888 },
889 },
890 )),
891 BinaryOperator::Equal,
892 Box::new(Expression::Literal(Literal::String(
893 "en-GB".to_owned(),
894 ))),
895 ),
896 ],
897 },
898 }),
899 ],
900 }),
901 ),
902 ];
903
904 for (input, expected) in cases {
905 match parse(input) {
906 Ok(result) => {
907 assert_eq!(result, expected, "{:?} was parsed incorrectly", input);
908 },
909 Err(e) => panic!("Failed to parse '{}': {:?}", input, e),
910 }
911 }
912 }
913}