1use crate::ast::{
11 AdditiveOp, Axis, EqualityOp, Expr, FilterExpr, FunctionCall, LocationPath, MultiplicativeOp,
12 NodeTest, PathExpr, PrimaryExpr, QName, RelationalOp, Step,
13};
14use crate::lexer::{Lexer, Token};
15
16#[derive(Debug, Clone, PartialEq)]
19pub struct ParseError {
20 pub position: usize,
21 pub message: String,
22}
23
24impl ParseError {
25 pub(crate) fn new(position: usize, message: impl Into<String>) -> Self {
26 ParseError {
27 position,
28 message: message.into(),
29 }
30 }
31}
32
33impl std::fmt::Display for ParseError {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 write!(f, "parse error at byte {}: {}", self.position, self.message)
36 }
37}
38
39impl std::error::Error for ParseError {}
40
41const NODE_TYPES: [&str; 4] = ["comment", "text", "processing-instruction", "node"];
42
43fn desc_or_self_step() -> Step {
44 Step {
45 axis: Axis::DescendantOrSelf,
46 node_test: NodeTest::Node,
47 predicates: Vec::new(),
48 }
49}
50
51pub fn parse(expr: &str) -> Result<Expr, ParseError> {
53 let tokens = Lexer::tokenize(expr)?;
54 if tokens.is_empty() {
55 return Err(ParseError::new(0, "empty expression"));
56 }
57 let end = expr.len();
58 let mut parser = Parser {
59 tokens,
60 pos: 0,
61 end,
62 };
63 let result = parser.parse_expr()?;
64 if parser.pos != parser.tokens.len() {
65 let p = parser.current_pos();
66 return Err(ParseError::new(p, "unexpected trailing input"));
67 }
68 Ok(result)
69}
70
71struct Parser {
72 tokens: Vec<(Token, usize)>,
73 pos: usize,
74 end: usize,
75}
76
77impl Parser {
78 fn peek(&self) -> Option<&Token> {
79 self.tokens.get(self.pos).map(|(t, _)| t)
80 }
81
82 fn peek_at(&self, offset: usize) -> Option<&Token> {
83 self.tokens.get(self.pos + offset).map(|(t, _)| t)
84 }
85
86 fn current_pos(&self) -> usize {
87 self.tokens
88 .get(self.pos)
89 .map(|(_, p)| *p)
90 .unwrap_or(self.end)
91 }
92
93 fn advance(&mut self) -> Token {
94 let (t, _) = self.tokens[self.pos].clone();
95 self.pos += 1;
96 t
97 }
98
99 fn expect(&mut self, tok: Token, what: &str) -> Result<(), ParseError> {
100 match self.peek() {
101 Some(t) if *t == tok => {
102 self.pos += 1;
103 Ok(())
104 }
105 Some(_) => Err(ParseError::new(
106 self.current_pos(),
107 format!("expected {what}"),
108 )),
109 None => Err(self.eof_error(what)),
110 }
111 }
112
113 fn eof_error(&self, what: &str) -> ParseError {
114 ParseError::new(
115 self.end,
116 format!("unexpected end of input, expected {what}"),
117 )
118 }
119
120 fn parse_expr(&mut self) -> Result<Expr, ParseError> {
123 self.parse_or()
124 }
125
126 fn parse_or(&mut self) -> Result<Expr, ParseError> {
127 let mut lhs = self.parse_and()?;
128 while matches!(self.peek(), Some(Token::Or)) {
129 self.advance();
130 let rhs = self.parse_and()?;
131 lhs = Expr::Or(Box::new(lhs), Box::new(rhs));
132 }
133 Ok(lhs)
134 }
135
136 fn parse_and(&mut self) -> Result<Expr, ParseError> {
137 let mut lhs = self.parse_equality()?;
138 while matches!(self.peek(), Some(Token::And)) {
139 self.advance();
140 let rhs = self.parse_equality()?;
141 lhs = Expr::And(Box::new(lhs), Box::new(rhs));
142 }
143 Ok(lhs)
144 }
145
146 fn parse_equality(&mut self) -> Result<Expr, ParseError> {
147 let mut lhs = self.parse_relational()?;
148 loop {
149 let op = match self.peek() {
150 Some(Token::Eq) => EqualityOp::Eq,
151 Some(Token::Ne) => EqualityOp::Ne,
152 _ => break,
153 };
154 self.advance();
155 let rhs = self.parse_relational()?;
156 lhs = Expr::Equality(Box::new(lhs), op, Box::new(rhs));
157 }
158 Ok(lhs)
159 }
160
161 fn parse_relational(&mut self) -> Result<Expr, ParseError> {
162 let mut lhs = self.parse_additive()?;
163 loop {
164 let op = match self.peek() {
165 Some(Token::Lt) => RelationalOp::Lt,
166 Some(Token::Gt) => RelationalOp::Gt,
167 Some(Token::Le) => RelationalOp::Le,
168 Some(Token::Ge) => RelationalOp::Ge,
169 _ => break,
170 };
171 self.advance();
172 let rhs = self.parse_additive()?;
173 lhs = Expr::Relational(Box::new(lhs), op, Box::new(rhs));
174 }
175 Ok(lhs)
176 }
177
178 fn parse_additive(&mut self) -> Result<Expr, ParseError> {
179 let mut lhs = self.parse_multiplicative()?;
180 loop {
181 let op = match self.peek() {
182 Some(Token::Plus) => AdditiveOp::Add,
183 Some(Token::Minus) => AdditiveOp::Sub,
184 _ => break,
185 };
186 self.advance();
187 let rhs = self.parse_multiplicative()?;
188 lhs = Expr::Additive(Box::new(lhs), op, Box::new(rhs));
189 }
190 Ok(lhs)
191 }
192
193 fn parse_multiplicative(&mut self) -> Result<Expr, ParseError> {
194 let mut lhs = self.parse_unary()?;
195 loop {
196 let op = match self.peek() {
197 Some(Token::Star) => MultiplicativeOp::Mul,
198 Some(Token::Div) => MultiplicativeOp::Div,
199 Some(Token::Mod) => MultiplicativeOp::Mod,
200 _ => break,
201 };
202 self.advance();
203 let rhs = self.parse_unary()?;
204 lhs = Expr::Multiplicative(Box::new(lhs), op, Box::new(rhs));
205 }
206 Ok(lhs)
207 }
208
209 fn parse_unary(&mut self) -> Result<Expr, ParseError> {
210 if matches!(self.peek(), Some(Token::Minus)) {
211 self.advance();
212 let operand = self.parse_unary()?;
213 Ok(Expr::Negate(Box::new(operand)))
214 } else {
215 self.parse_union()
216 }
217 }
218
219 fn parse_union(&mut self) -> Result<Expr, ParseError> {
220 let mut lhs = self.parse_path_expr()?;
221 while matches!(self.peek(), Some(Token::Pipe)) {
222 self.advance();
223 let rhs = self.parse_path_expr()?;
224 lhs = Expr::Union(Box::new(lhs), Box::new(rhs));
225 }
226 Ok(lhs)
227 }
228
229 fn peek_is_node_type_call(&self) -> bool {
232 matches!(self.peek(), Some(Token::Name { prefix: None, local }) if NODE_TYPES.contains(&local.as_str()))
233 && matches!(self.peek_at(1), Some(Token::LParen))
234 }
235
236 fn peek_axis(&self) -> Option<Axis> {
237 if let Some(Token::Name {
238 prefix: None,
239 local,
240 }) = self.peek()
241 && matches!(self.peek_at(1), Some(Token::ColonColon))
242 {
243 return Axis::from_name(local);
244 }
245 None
246 }
247
248 fn starts_location_path(&self) -> bool {
249 match self.peek() {
250 Some(Token::Slash) | Some(Token::SlashSlash) => true,
251 Some(Token::Dot)
252 | Some(Token::DotDot)
253 | Some(Token::At)
254 | Some(Token::Wildcard)
255 | Some(Token::NsWildcard(_)) => true,
256 Some(Token::Name { .. }) => {
257 if self.peek_is_node_type_call() {
258 true
259 } else {
260 !matches!(self.peek_at(1), Some(Token::LParen))
261 }
262 }
263 _ => false,
264 }
265 }
266
267 fn can_start_step(&self) -> bool {
268 matches!(
269 self.peek(),
270 Some(Token::Dot)
271 | Some(Token::DotDot)
272 | Some(Token::At)
273 | Some(Token::Wildcard)
274 | Some(Token::NsWildcard(_))
275 | Some(Token::Name { .. })
276 )
277 }
278
279 fn parse_path_expr(&mut self) -> Result<Expr, ParseError> {
280 if self.starts_location_path() {
281 let loc = self.parse_location_path()?;
282 Ok(Expr::Path(PathExpr::Location(loc)))
283 } else {
284 let filter = self.parse_filter_expr()?;
285 if matches!(self.peek(), Some(Token::Slash)) {
286 self.advance();
287 let steps = self.parse_step_sequence()?;
288 Ok(Expr::Path(PathExpr::FilterLocation(
289 filter,
290 LocationPath {
291 is_absolute: false,
292 steps,
293 },
294 )))
295 } else if matches!(self.peek(), Some(Token::SlashSlash)) {
296 self.advance();
297 let mut steps = vec![desc_or_self_step()];
298 steps.extend(self.parse_step_sequence()?);
299 Ok(Expr::Path(PathExpr::FilterLocation(
300 filter,
301 LocationPath {
302 is_absolute: false,
303 steps,
304 },
305 )))
306 } else {
307 Ok(Expr::Path(PathExpr::Filter(filter)))
308 }
309 }
310 }
311
312 fn parse_location_path(&mut self) -> Result<LocationPath, ParseError> {
313 if matches!(self.peek(), Some(Token::Slash)) {
314 self.advance();
315 if self.can_start_step() {
316 let steps = self.parse_step_sequence()?;
317 Ok(LocationPath {
318 is_absolute: true,
319 steps,
320 })
321 } else {
322 Ok(LocationPath {
323 is_absolute: true,
324 steps: Vec::new(),
325 })
326 }
327 } else if matches!(self.peek(), Some(Token::SlashSlash)) {
328 self.advance();
329 let mut steps = vec![desc_or_self_step()];
330 steps.extend(self.parse_step_sequence()?);
331 Ok(LocationPath {
332 is_absolute: true,
333 steps,
334 })
335 } else {
336 let steps = self.parse_step_sequence()?;
337 Ok(LocationPath {
338 is_absolute: false,
339 steps,
340 })
341 }
342 }
343
344 fn parse_step_sequence(&mut self) -> Result<Vec<Step>, ParseError> {
345 let mut steps = vec![self.parse_step()?];
346 loop {
347 if matches!(self.peek(), Some(Token::Slash)) {
348 self.advance();
349 steps.push(self.parse_step()?);
350 } else if matches!(self.peek(), Some(Token::SlashSlash)) {
351 self.advance();
352 steps.push(desc_or_self_step());
353 steps.push(self.parse_step()?);
354 } else {
355 break;
356 }
357 }
358 Ok(steps)
359 }
360
361 fn parse_step(&mut self) -> Result<Step, ParseError> {
362 match self.peek() {
363 Some(Token::Dot) => {
364 self.advance();
365 return Ok(Step {
366 axis: Axis::SelfAxis,
367 node_test: NodeTest::Node,
368 predicates: Vec::new(),
369 });
370 }
371 Some(Token::DotDot) => {
372 self.advance();
373 return Ok(Step {
374 axis: Axis::Parent,
375 node_test: NodeTest::Node,
376 predicates: Vec::new(),
377 });
378 }
379 _ => {}
380 }
381 let axis = if matches!(self.peek(), Some(Token::At)) {
382 self.advance();
383 Axis::Attribute
384 } else if let Some(axis) = self.peek_axis() {
385 self.advance(); self.advance(); axis
388 } else {
389 Axis::Child
390 };
391 let node_test = self.parse_node_test()?;
392 let mut predicates = Vec::new();
393 while matches!(self.peek(), Some(Token::LBracket)) {
394 self.advance();
395 let e = self.parse_expr()?;
396 self.expect(Token::RBracket, "']'")?;
397 predicates.push(e);
398 }
399 Ok(Step {
400 axis,
401 node_test,
402 predicates,
403 })
404 }
405
406 fn parse_node_test(&mut self) -> Result<NodeTest, ParseError> {
407 match self.peek().cloned() {
408 Some(Token::Wildcard) => {
409 self.advance();
410 Ok(NodeTest::AnyName)
411 }
412 Some(Token::NsWildcard(prefix)) => {
413 self.advance();
414 Ok(NodeTest::NamespaceWildcard(prefix))
415 }
416 Some(Token::Name { prefix, local }) => {
417 if matches!(self.peek_at(1), Some(Token::LParen)) {
418 if prefix.is_none() && NODE_TYPES.contains(&local.as_str()) {
419 self.advance(); self.advance(); let result = match local.as_str() {
422 "node" => {
423 self.expect(Token::RParen, "')'")?;
424 NodeTest::Node
425 }
426 "text" => {
427 self.expect(Token::RParen, "')'")?;
428 NodeTest::Text
429 }
430 "comment" => {
431 self.expect(Token::RParen, "')'")?;
432 NodeTest::Comment
433 }
434 "processing-instruction" => {
435 if let Some(Token::Literal(lit)) = self.peek().cloned() {
436 self.advance();
437 self.expect(Token::RParen, "')'")?;
438 NodeTest::ProcessingInstruction(Some(lit))
439 } else {
440 self.expect(Token::RParen, "')'")?;
441 NodeTest::ProcessingInstruction(None)
442 }
443 }
444 _ => unreachable!("filtered by NODE_TYPES.contains above"),
445 };
446 Ok(result)
447 } else {
448 Err(ParseError::new(
449 self.current_pos(),
450 "function call is not a valid node test",
451 ))
452 }
453 } else {
454 self.advance();
455 Ok(NodeTest::QName(QName { prefix, local }))
456 }
457 }
458 Some(_) => Err(ParseError::new(self.current_pos(), "expected a node test")),
459 None => Err(self.eof_error("a node test")),
460 }
461 }
462
463 fn parse_filter_expr(&mut self) -> Result<FilterExpr, ParseError> {
466 let primary = self.parse_primary_expr()?;
467 let mut predicates = Vec::new();
468 while matches!(self.peek(), Some(Token::LBracket)) {
469 self.advance();
470 let e = self.parse_expr()?;
471 self.expect(Token::RBracket, "']'")?;
472 predicates.push(e);
473 }
474 Ok(FilterExpr {
475 primary,
476 predicates,
477 })
478 }
479
480 fn parse_primary_expr(&mut self) -> Result<PrimaryExpr, ParseError> {
481 match self.peek().cloned() {
482 Some(Token::Variable(qname)) => {
483 self.advance();
484 Ok(PrimaryExpr::Variable(qname))
485 }
486 Some(Token::LParen) => {
487 self.advance();
488 let e = self.parse_expr()?;
489 self.expect(Token::RParen, "')'")?;
490 Ok(PrimaryExpr::Parenthesized(Box::new(e)))
491 }
492 Some(Token::Literal(s)) => {
493 self.advance();
494 Ok(PrimaryExpr::Literal(s))
495 }
496 Some(Token::Number(n)) => {
497 self.advance();
498 Ok(PrimaryExpr::Number(n))
499 }
500 Some(Token::Name { prefix, local })
501 if matches!(self.peek_at(1), Some(Token::LParen)) =>
502 {
503 self.advance(); self.advance(); let args = self.parse_argument_list()?;
506 self.expect(Token::RParen, "')'")?;
507 Ok(PrimaryExpr::Function(FunctionCall {
508 name: QName { prefix, local },
509 args,
510 }))
511 }
512 Some(_) => Err(ParseError::new(
513 self.current_pos(),
514 "expected an expression",
515 )),
516 None => Err(self.eof_error("an expression")),
517 }
518 }
519
520 fn parse_argument_list(&mut self) -> Result<Vec<Expr>, ParseError> {
521 let mut args = Vec::new();
522 if matches!(self.peek(), Some(Token::RParen)) {
523 return Ok(args);
524 }
525 args.push(self.parse_expr()?);
526 while matches!(self.peek(), Some(Token::Comma)) {
527 self.advance();
528 args.push(self.parse_expr()?);
529 }
530 Ok(args)
531 }
532}
533
534#[cfg(test)]
535mod tests {
536 use super::*;
537 use crate::ast::*;
538
539 fn qn(local: &str) -> QName {
540 QName {
541 prefix: None,
542 local: local.to_string(),
543 }
544 }
545
546 fn qn_ns(prefix: &str, local: &str) -> QName {
547 QName {
548 prefix: Some(prefix.to_string()),
549 local: local.to_string(),
550 }
551 }
552
553 fn name_test(local: &str) -> NodeTest {
554 NodeTest::QName(qn(local))
555 }
556
557 fn step(axis: Axis, node_test: NodeTest) -> Step {
558 Step {
559 axis,
560 node_test,
561 predicates: Vec::new(),
562 }
563 }
564
565 fn rel_path(steps: Vec<Step>) -> Expr {
566 Expr::Path(PathExpr::Location(LocationPath {
567 is_absolute: false,
568 steps,
569 }))
570 }
571
572 fn abs_path(steps: Vec<Step>) -> Expr {
573 Expr::Path(PathExpr::Location(LocationPath {
574 is_absolute: true,
575 steps,
576 }))
577 }
578
579 #[test]
582 fn abbreviated_child_axis_matches_full_child_axis() {
583 let abbrev = parse("para").unwrap();
584 let full = parse("child::para").unwrap();
585 let expected = rel_path(vec![step(Axis::Child, name_test("para"))]);
586 assert_eq!(abbrev, expected);
587 assert_eq!(full, expected);
588 }
589
590 #[test]
591 fn abbreviated_attribute_axis_matches_full_attribute_axis() {
592 let abbrev = parse("@name").unwrap();
593 let full = parse("attribute::name").unwrap();
594 let expected = rel_path(vec![step(Axis::Attribute, name_test("name"))]);
595 assert_eq!(abbrev, expected);
596 assert_eq!(full, expected);
597 }
598
599 #[test]
600 fn dot_desugars_to_self_axis_node_test() {
601 assert_eq!(
602 parse(".").unwrap(),
603 rel_path(vec![step(Axis::SelfAxis, NodeTest::Node)])
604 );
605 }
606
607 #[test]
608 fn dot_dot_desugars_to_parent_axis_node_test() {
609 assert_eq!(
610 parse("..").unwrap(),
611 rel_path(vec![step(Axis::Parent, NodeTest::Node)])
612 );
613 }
614
615 #[test]
616 fn double_slash_desugars_to_descendant_or_self_node_step() {
617 assert_eq!(
618 parse("//para").unwrap(),
619 abs_path(vec![
620 step(Axis::DescendantOrSelf, NodeTest::Node),
621 step(Axis::Child, name_test("para")),
622 ])
623 );
624 }
625
626 #[test]
627 fn double_slash_mid_path_inserts_descendant_or_self_step() {
628 assert_eq!(
629 parse("a//b").unwrap(),
630 rel_path(vec![
631 step(Axis::Child, name_test("a")),
632 step(Axis::DescendantOrSelf, NodeTest::Node),
633 step(Axis::Child, name_test("b")),
634 ])
635 );
636 }
637
638 #[test]
639 fn spec_example_absolute_path_with_predicates() {
640 let last_call = Expr::Path(PathExpr::Filter(FilterExpr {
643 primary: PrimaryExpr::Function(FunctionCall {
644 name: qn("last"),
645 args: vec![],
646 }),
647 predicates: vec![],
648 }));
649 let one = Expr::Path(PathExpr::Filter(FilterExpr {
650 primary: PrimaryExpr::Number(1.0),
651 predicates: vec![],
652 }));
653 assert_eq!(
654 parse("/doc/chapter[1]/para[last()]").unwrap(),
655 abs_path(vec![
656 step(Axis::Child, name_test("doc")),
657 Step {
658 axis: Axis::Child,
659 node_test: name_test("chapter"),
660 predicates: vec![one],
661 },
662 Step {
663 axis: Axis::Child,
664 node_test: name_test("para"),
665 predicates: vec![last_call],
666 },
667 ])
668 );
669 }
670
671 #[test]
674 fn all_thirteen_axes_parse_to_their_enum_variant() {
675 let cases = [
676 ("ancestor::a", Axis::Ancestor),
677 ("ancestor-or-self::a", Axis::AncestorOrSelf),
678 ("attribute::a", Axis::Attribute),
679 ("child::a", Axis::Child),
680 ("descendant::a", Axis::Descendant),
681 ("descendant-or-self::a", Axis::DescendantOrSelf),
682 ("following::a", Axis::Following),
683 ("following-sibling::a", Axis::FollowingSibling),
684 ("namespace::a", Axis::Namespace),
685 ("parent::a", Axis::Parent),
686 ("preceding::a", Axis::Preceding),
687 ("preceding-sibling::a", Axis::PrecedingSibling),
688 ("self::a", Axis::SelfAxis),
689 ];
690 for (src, axis) in cases {
691 assert_eq!(
692 parse(src).unwrap(),
693 rel_path(vec![step(axis, name_test("a"))]),
694 "axis expression {src:?}"
695 );
696 }
697 }
698
699 #[test]
702 fn node_type_tests() {
703 assert_eq!(
704 parse("text()").unwrap(),
705 rel_path(vec![step(Axis::Child, NodeTest::Text)])
706 );
707 assert_eq!(
708 parse("comment()").unwrap(),
709 rel_path(vec![step(Axis::Child, NodeTest::Comment)])
710 );
711 assert_eq!(
712 parse("node()").unwrap(),
713 rel_path(vec![step(Axis::Child, NodeTest::Node)])
714 );
715 assert_eq!(
716 parse("processing-instruction()").unwrap(),
717 rel_path(vec![step(
718 Axis::Child,
719 NodeTest::ProcessingInstruction(None)
720 )])
721 );
722 assert_eq!(
723 parse("processing-instruction('foo')").unwrap(),
724 rel_path(vec![step(
725 Axis::Child,
726 NodeTest::ProcessingInstruction(Some("foo".to_string()))
727 )])
728 );
729 }
730
731 #[test]
734 fn chained_predicates() {
735 let a = Step {
736 axis: Axis::Child,
737 node_test: name_test("a"),
738 predicates: vec![
739 rel_path(vec![step(Axis::Child, name_test("b"))]),
740 rel_path(vec![step(Axis::Child, name_test("c"))]),
741 ],
742 };
743 assert_eq!(parse("a[b][c]").unwrap(), rel_path(vec![a]));
744 }
745
746 #[test]
747 fn nested_predicate() {
748 let inner_b = Step {
750 axis: Axis::Child,
751 node_test: name_test("b"),
752 predicates: vec![rel_path(vec![step(Axis::Child, name_test("c"))])],
753 };
754 let a = Step {
755 axis: Axis::Child,
756 node_test: name_test("a"),
757 predicates: vec![rel_path(vec![inner_b])],
758 };
759 assert_eq!(parse("a[b[c]]").unwrap(), rel_path(vec![a]));
760 }
761
762 #[test]
765 fn multiplicative_binds_tighter_than_additive() {
766 let one = Expr::Path(PathExpr::Filter(FilterExpr {
768 primary: PrimaryExpr::Number(1.0),
769 predicates: vec![],
770 }));
771 let two = Expr::Path(PathExpr::Filter(FilterExpr {
772 primary: PrimaryExpr::Number(2.0),
773 predicates: vec![],
774 }));
775 let three = Expr::Path(PathExpr::Filter(FilterExpr {
776 primary: PrimaryExpr::Number(3.0),
777 predicates: vec![],
778 }));
779 let expected = Expr::Additive(
780 Box::new(one),
781 AdditiveOp::Add,
782 Box::new(Expr::Multiplicative(
783 Box::new(two),
784 MultiplicativeOp::Mul,
785 Box::new(three),
786 )),
787 );
788 assert_eq!(parse("1 + 2 * 3").unwrap(), expected);
789 }
790
791 #[test]
792 fn parens_override_precedence() {
793 let one = Expr::Path(PathExpr::Filter(FilterExpr {
795 primary: PrimaryExpr::Number(1.0),
796 predicates: vec![],
797 }));
798 let two = Expr::Path(PathExpr::Filter(FilterExpr {
799 primary: PrimaryExpr::Number(2.0),
800 predicates: vec![],
801 }));
802 let three = Expr::Path(PathExpr::Filter(FilterExpr {
803 primary: PrimaryExpr::Number(3.0),
804 predicates: vec![],
805 }));
806 let sum = Expr::Additive(Box::new(one), AdditiveOp::Add, Box::new(two));
807 let grouped = Expr::Path(PathExpr::Filter(FilterExpr {
808 primary: PrimaryExpr::Parenthesized(Box::new(sum)),
809 predicates: vec![],
810 }));
811 let expected =
812 Expr::Multiplicative(Box::new(grouped), MultiplicativeOp::Mul, Box::new(three));
813 assert_eq!(parse("(1 + 2) * 3").unwrap(), expected);
814 }
815
816 #[test]
817 fn subtraction_is_left_associative() {
818 fn num(n: f64) -> Expr {
820 Expr::Path(PathExpr::Filter(FilterExpr {
821 primary: PrimaryExpr::Number(n),
822 predicates: vec![],
823 }))
824 }
825 let expected = Expr::Additive(
826 Box::new(Expr::Additive(
827 Box::new(num(1.0)),
828 AdditiveOp::Sub,
829 Box::new(num(2.0)),
830 )),
831 AdditiveOp::Sub,
832 Box::new(num(3.0)),
833 );
834 assert_eq!(parse("1 - 2 - 3").unwrap(), expected);
835 }
836
837 #[test]
838 fn unary_minus() {
839 fn num(n: f64) -> Expr {
841 Expr::Path(PathExpr::Filter(FilterExpr {
842 primary: PrimaryExpr::Number(n),
843 predicates: vec![],
844 }))
845 }
846 let expected = Expr::Additive(
847 Box::new(Expr::Negate(Box::new(num(1.0)))),
848 AdditiveOp::Add,
849 Box::new(num(2.0)),
850 );
851 assert_eq!(parse("-1 + 2").unwrap(), expected);
852 }
853
854 #[test]
857 fn div_mod_and_or_as_operators() {
858 fn num(n: f64) -> Expr {
859 Expr::Path(PathExpr::Filter(FilterExpr {
860 primary: PrimaryExpr::Number(n),
861 predicates: vec![],
862 }))
863 }
864 assert_eq!(
865 parse("1 div 2").unwrap(),
866 Expr::Multiplicative(
867 Box::new(num(1.0)),
868 MultiplicativeOp::Div,
869 Box::new(num(2.0))
870 )
871 );
872 assert_eq!(
873 parse("1 mod 2").unwrap(),
874 Expr::Multiplicative(
875 Box::new(num(1.0)),
876 MultiplicativeOp::Mod,
877 Box::new(num(2.0))
878 )
879 );
880 assert_eq!(
881 parse("a and b").unwrap(),
882 Expr::And(
883 Box::new(rel_path(vec![step(Axis::Child, name_test("a"))])),
884 Box::new(rel_path(vec![step(Axis::Child, name_test("b"))])),
885 )
886 );
887 assert_eq!(
888 parse("a or b").unwrap(),
889 Expr::Or(
890 Box::new(rel_path(vec![step(Axis::Child, name_test("a"))])),
891 Box::new(rel_path(vec![step(Axis::Child, name_test("b"))])),
892 )
893 );
894 }
895
896 #[test]
897 fn div_as_ncname_in_non_operator_position() {
898 assert_eq!(
900 parse("child::div").unwrap(),
901 rel_path(vec![step(Axis::Child, name_test("div"))])
902 );
903 assert_eq!(
905 parse("//div").unwrap(),
906 abs_path(vec![
907 step(Axis::DescendantOrSelf, NodeTest::Node),
908 step(Axis::Child, name_test("div")),
909 ])
910 );
911 }
912
913 #[test]
916 fn union_of_three_paths_is_left_associative() {
917 let a = rel_path(vec![step(Axis::Child, name_test("a"))]);
918 let b = rel_path(vec![step(Axis::Child, name_test("b"))]);
919 let c = rel_path(vec![step(Axis::Child, name_test("c"))]);
920 let expected = Expr::Union(Box::new(Expr::Union(Box::new(a), Box::new(b))), Box::new(c));
921 assert_eq!(parse("a | b | c").unwrap(), expected);
922 }
923
924 #[test]
927 fn variable_references() {
928 assert_eq!(
929 parse("$foo").unwrap(),
930 Expr::Path(PathExpr::Filter(FilterExpr {
931 primary: PrimaryExpr::Variable(qn("foo")),
932 predicates: vec![],
933 }))
934 );
935 assert_eq!(
936 parse("$ns:foo").unwrap(),
937 Expr::Path(PathExpr::Filter(FilterExpr {
938 primary: PrimaryExpr::Variable(qn_ns("ns", "foo")),
939 predicates: vec![],
940 }))
941 );
942 }
943
944 #[test]
947 fn literals_both_quote_styles() {
948 assert_eq!(
949 parse("'hello'").unwrap(),
950 Expr::Path(PathExpr::Filter(FilterExpr {
951 primary: PrimaryExpr::Literal("hello".to_string()),
952 predicates: vec![],
953 }))
954 );
955 assert_eq!(
956 parse("\"hello\"").unwrap(),
957 Expr::Path(PathExpr::Filter(FilterExpr {
958 primary: PrimaryExpr::Literal("hello".to_string()),
959 predicates: vec![],
960 }))
961 );
962 }
963
964 #[test]
967 #[allow(clippy::approx_constant)] fn numbers() {
969 fn number(n: f64) -> Expr {
970 Expr::Path(PathExpr::Filter(FilterExpr {
971 primary: PrimaryExpr::Number(n),
972 predicates: vec![],
973 }))
974 }
975 assert_eq!(parse("3").unwrap(), number(3.0));
976 assert_eq!(parse("3.14").unwrap(), number(3.14));
977 assert_eq!(parse(".5").unwrap(), number(0.5));
978 }
979
980 #[test]
983 fn namespace_prefixed_name_tests() {
984 assert_eq!(
985 parse("svg:rect").unwrap(),
986 rel_path(vec![step(
987 Axis::Child,
988 NodeTest::QName(qn_ns("svg", "rect"))
989 )])
990 );
991 assert_eq!(
992 parse("*").unwrap(),
993 rel_path(vec![step(Axis::Child, NodeTest::AnyName)])
994 );
995 assert_eq!(
996 parse("svg:*").unwrap(),
997 rel_path(vec![step(
998 Axis::Child,
999 NodeTest::NamespaceWildcard("svg".to_string())
1000 )])
1001 );
1002 }
1003
1004 #[test]
1007 fn function_call_with_multiple_arguments() {
1008 let call = parse("concat(a, b, c)").unwrap();
1009 let arg = |n: &str| rel_path(vec![step(Axis::Child, name_test(n))]);
1010 assert_eq!(
1011 call,
1012 Expr::Path(PathExpr::Filter(FilterExpr {
1013 primary: PrimaryExpr::Function(FunctionCall {
1014 name: qn("concat"),
1015 args: vec![arg("a"), arg("b"), arg("c")],
1016 }),
1017 predicates: vec![],
1018 }))
1019 );
1020 }
1021
1022 #[test]
1023 fn function_call_with_zero_arguments() {
1024 assert_eq!(
1025 parse("true()").unwrap(),
1026 Expr::Path(PathExpr::Filter(FilterExpr {
1027 primary: PrimaryExpr::Function(FunctionCall {
1028 name: qn("true"),
1029 args: vec![],
1030 }),
1031 predicates: vec![],
1032 }))
1033 );
1034 }
1035
1036 #[test]
1039 fn error_unexpected_end_of_input() {
1040 let err = parse("1 +").unwrap_err();
1041 assert_eq!(err.position, 3);
1042 }
1043
1044 #[test]
1045 fn error_unbalanced_parens() {
1046 let err = parse("(1 + 2").unwrap_err();
1047 assert_eq!(err.position, 6);
1048
1049 let err2 = parse("1 + 2)").unwrap_err();
1050 assert_eq!(err2.position, 5);
1051 }
1052
1053 #[test]
1054 fn error_empty_expression() {
1055 let err = parse("").unwrap_err();
1056 assert_eq!(err.position, 0);
1057 assert_eq!(err.message, "empty expression");
1058 }
1059}