1use crate::xml::xpath::ast::*;
88use crate::xml::xpath::lexer::Token;
89
90#[derive(Debug, Clone, PartialEq)]
92pub struct ParseError {
93 pub message: String,
95 pub pos: usize,
97}
98
99impl std::fmt::Display for ParseError {
100 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101 write!(
102 f,
103 "XPath parse error at position {}: {}",
104 self.pos, self.message
105 )
106 }
107}
108
109#[derive(Debug)]
118pub struct Parser {
119 tokens: Vec<Token>,
120 pos: usize,
121}
122
123impl Parser {
124 pub const fn new(tokens: Vec<Token>) -> Self {
126 Self { tokens, pos: 0 }
127 }
128
129 pub fn parse(&mut self) -> Result<Expr, ParseError> {
131 let expr = self.parse_or_expr()?;
132 if !self.is_eof() {
133 Err(self.error(format!("Unexpected token: {}", self.current())))?;
134 }
135 Ok(expr)
136 }
137
138 fn current(&self) -> Token {
141 if self.pos < self.tokens.len() {
142 self.tokens[self.pos].clone()
143 } else {
144 Token::Eof
145 }
146 }
147
148 fn peek(&self) -> Token {
149 if self.pos + 1 < self.tokens.len() {
150 self.tokens[self.pos + 1].clone()
151 } else {
152 Token::Eof
153 }
154 }
155
156 const fn advance(&mut self) {
157 if self.pos < self.tokens.len() {
158 self.pos += 1;
159 }
160 }
161
162 fn is_eof(&self) -> bool {
163 matches!(self.current(), Token::Eof)
164 }
165
166 const fn error(&self, msg: String) -> ParseError {
167 ParseError {
168 message: msg,
169 pos: self.pos,
170 }
171 }
172
173 fn at(&self, token: &Token) -> bool {
175 std::mem::discriminant(&self.current()) == std::mem::discriminant(token)
176 }
177
178 fn expect(&mut self, expected: &Token) -> Result<(), ParseError> {
180 if self.at(expected) {
181 self.advance();
182 Ok(())
183 } else {
184 Err(self.error(format!("Expected {}, got {}", expected, self.current())))
185 }
186 }
187
188 fn parse_or_expr(&mut self) -> Result<Expr, ParseError> {
192 let mut left = self.parse_and_expr()?;
193 while matches!(self.current(), Token::Or) {
194 self.advance();
195 let right = self.parse_and_expr()?;
196 left = Expr::BinaryOp {
197 op: BinaryOp::Or,
198 left: Box::new(left),
199 right: Box::new(right),
200 };
201 }
202 Ok(left)
203 }
204
205 fn parse_and_expr(&mut self) -> Result<Expr, ParseError> {
207 let mut left = self.parse_equality_expr()?;
208 while matches!(self.current(), Token::And) {
209 self.advance();
210 let right = self.parse_equality_expr()?;
211 left = Expr::BinaryOp {
212 op: BinaryOp::And,
213 left: Box::new(left),
214 right: Box::new(right),
215 };
216 }
217 Ok(left)
218 }
219
220 fn parse_equality_expr(&mut self) -> Result<Expr, ParseError> {
222 let mut left = self.parse_relational_expr()?;
223 loop {
224 let op = match self.current() {
225 Token::Eq => BinaryOp::Eq,
226 Token::Ne => BinaryOp::Ne,
227 _ => break,
228 };
229 self.advance();
230 let right = self.parse_relational_expr()?;
231 left = Expr::BinaryOp {
232 op,
233 left: Box::new(left),
234 right: Box::new(right),
235 };
236 }
237 Ok(left)
238 }
239
240 fn parse_relational_expr(&mut self) -> Result<Expr, ParseError> {
242 let mut left = self.parse_additive_expr()?;
243 loop {
244 let op = match self.current() {
245 Token::Lt => BinaryOp::Lt,
246 Token::Gt => BinaryOp::Gt,
247 Token::Le => BinaryOp::Le,
248 Token::Ge => BinaryOp::Ge,
249 _ => break,
250 };
251 self.advance();
252 let right = self.parse_additive_expr()?;
253 left = Expr::BinaryOp {
254 op,
255 left: Box::new(left),
256 right: Box::new(right),
257 };
258 }
259 Ok(left)
260 }
261
262 fn parse_additive_expr(&mut self) -> Result<Expr, ParseError> {
264 let mut left = self.parse_multiplicative_expr()?;
265 loop {
266 let op = match self.current() {
267 Token::Plus => BinaryOp::Add,
268 Token::Minus => BinaryOp::Sub,
269 _ => break,
270 };
271 self.advance();
272 let right = self.parse_multiplicative_expr()?;
273 left = Expr::BinaryOp {
274 op,
275 left: Box::new(left),
276 right: Box::new(right),
277 };
278 }
279 Ok(left)
280 }
281
282 fn parse_multiplicative_expr(&mut self) -> Result<Expr, ParseError> {
284 let mut left = self.parse_unary_expr()?;
285 loop {
286 let op = match self.current() {
287 Token::Star => BinaryOp::Mul,
289 Token::Div => BinaryOp::Div,
290 Token::Mod => BinaryOp::Mod,
291 _ => break,
292 };
293 self.advance();
294 let right = self.parse_unary_expr()?;
295 left = Expr::BinaryOp {
296 op,
297 left: Box::new(left),
298 right: Box::new(right),
299 };
300 }
301 Ok(left)
302 }
303
304 fn parse_unary_expr(&mut self) -> Result<Expr, ParseError> {
306 let mut minus_count = 0;
307 while matches!(self.current(), Token::Minus) {
308 self.advance();
309 minus_count += 1;
310 }
311 let mut expr = self.parse_union_expr()?;
312 if minus_count % 2 == 1 {
313 expr = Expr::UnaryMinus(Box::new(expr));
314 }
315 Ok(expr)
316 }
317
318 fn parse_union_expr(&mut self) -> Result<Expr, ParseError> {
320 let mut left = self.parse_path_expr()?;
321 while matches!(self.current(), Token::Pipe) {
322 self.advance();
323 let right = self.parse_path_expr()?;
324 left = Expr::Union(Box::new(left), Box::new(right));
325 }
326 Ok(left)
327 }
328
329 fn parse_path_expr(&mut self) -> Result<Expr, ParseError> {
331 if self.is_location_path_start() {
333 return self.parse_location_path();
334 }
335
336 let mut expr = self.parse_filter_expr()?;
338
339 loop {
341 match self.current() {
342 Token::Slash => {
343 self.advance();
344 let step = self.parse_relative_location_path()?;
345 expr = Expr::RelativePath(Box::new(expr), Box::new(step));
346 }
347 Token::DoubleSlash => {
348 self.advance();
349 let step = self.parse_relative_location_path()?;
350 let descendant = Expr::Step(Step {
352 axis: Axis::DescendantOrSelf,
353 node_test: NodeTest::Node,
354 predicates: vec![],
355 });
356 let path = Expr::RelativePath(Box::new(descendant), Box::new(step));
357 expr = Expr::RelativePath(Box::new(expr), Box::new(path));
358 }
359 _ => break,
360 }
361 }
362
363 Ok(expr)
364 }
365
366 fn is_location_path_start(&self) -> bool {
368 match self.current() {
369 Token::Slash | Token::DoubleSlash => true,
370 Token::Dot | Token::DotDot => true,
371 Token::At => true,
372 Token::Star => true,
373 Token::Name(ref n) => {
375 let next = self.peek();
377 if matches!(next, Token::LParen) {
378 !n.contains(':')
387 && matches!(
388 n.as_str(),
389 "node" | "text" | "comment" | "processing-instruction"
390 )
391 } else {
392 true
393 }
394 }
395 Token::Child
397 | Token::Descendant
398 | Token::DescendantOrSelf
399 | Token::Ancestor
400 | Token::AncestorOrSelf
401 | Token::Attribute
402 | Token::Following
403 | Token::FollowingSibling
404 | Token::Namespace
405 | Token::Parent
406 | Token::Preceding
407 | Token::PrecedingSibling
408 | Token::Self_ => true,
409 _ => false,
410 }
411 }
412
413 fn parse_location_path(&mut self) -> Result<Expr, ParseError> {
415 match self.current() {
416 Token::Slash => {
417 self.advance();
418 if self.is_location_path_start() {
419 let path = self.parse_relative_location_path()?;
420 Ok(Expr::AbsolutePath(Box::new(path)))
421 } else {
422 Ok(Expr::Step(Step {
424 axis: Axis::Self_,
425 node_test: NodeTest::Node,
426 predicates: vec![],
427 }))
428 }
429 }
430 Token::DoubleSlash => {
431 self.advance();
432 let path = self.parse_relative_location_path()?;
433 let descendant = Expr::Step(Step {
434 axis: Axis::DescendantOrSelf,
435 node_test: NodeTest::Node,
436 predicates: vec![],
437 });
438 Ok(Expr::AbsolutePath(Box::new(Expr::RelativePath(
439 Box::new(descendant),
440 Box::new(path),
441 ))))
442 }
443 _ => self.parse_relative_location_path(),
444 }
445 }
446
447 fn parse_relative_location_path(&mut self) -> Result<Expr, ParseError> {
449 let mut expr = self.parse_step()?;
450 loop {
451 match self.current() {
452 Token::Slash => {
453 self.advance();
454 let step = self.parse_step()?;
455 expr = Expr::RelativePath(Box::new(expr), Box::new(step));
456 }
457 Token::DoubleSlash => {
458 self.advance();
459 let step = self.parse_step()?;
460 let descendant = Expr::Step(Step {
461 axis: Axis::DescendantOrSelf,
462 node_test: NodeTest::Node,
463 predicates: vec![],
464 });
465 let path = Expr::RelativePath(Box::new(descendant), Box::new(step));
466 expr = Expr::RelativePath(Box::new(expr), Box::new(path));
467 }
468 _ => break,
469 }
470 }
471 Ok(expr)
472 }
473
474 fn parse_step(&mut self) -> Result<Expr, ParseError> {
477 match self.current() {
479 Token::Dot => {
480 self.advance();
481 return Ok(Expr::Step(Step {
482 axis: Axis::Self_,
483 node_test: NodeTest::Node,
484 predicates: vec![],
485 }));
486 }
487 Token::DotDot => {
488 self.advance();
489 return Ok(Expr::Step(Step {
490 axis: Axis::Parent,
491 node_test: NodeTest::Node,
492 predicates: vec![],
493 }));
494 }
495 _ => {}
496 }
497
498 let axis = self.parse_axis_specifier();
500
501 let node_test = self.parse_node_test()?;
503
504 let mut predicates = Vec::new();
506 while matches!(self.current(), Token::LBracket) {
507 self.advance(); let pred = self.parse_or_expr()?;
509 self.expect(&Token::RBracket)?;
510 predicates.push(pred);
511 }
512
513 Ok(Expr::Step(Step {
514 axis,
515 node_test,
516 predicates,
517 }))
518 }
519
520 fn parse_axis_specifier(&mut self) -> Axis {
522 if matches!(self.current(), Token::At) {
524 self.advance();
525 return Axis::Attribute;
526 }
527
528 let is_axis = match self.current() {
532 Token::Ancestor
533 | Token::AncestorOrSelf
534 | Token::Attribute
535 | Token::Child
536 | Token::Descendant
537 | Token::DescendantOrSelf
538 | Token::Following
539 | Token::FollowingSibling
540 | Token::Namespace
541 | Token::Parent
542 | Token::Preceding
543 | Token::PrecedingSibling
544 | Token::Self_ => matches!(self.peek(), Token::DoubleColon),
545 _ => false,
546 };
547
548 if is_axis {
549 let axis = match self.current() {
550 Token::Ancestor => Axis::Ancestor,
551 Token::AncestorOrSelf => Axis::AncestorOrSelf,
552 Token::Attribute => Axis::Attribute,
553 Token::Child => Axis::Child,
554 Token::Descendant => Axis::Descendant,
555 Token::DescendantOrSelf => Axis::DescendantOrSelf,
556 Token::Following => Axis::Following,
557 Token::FollowingSibling => Axis::FollowingSibling,
558 Token::Namespace => Axis::Namespace,
559 Token::Parent => Axis::Parent,
560 Token::Preceding => Axis::Preceding,
561 Token::PrecedingSibling => Axis::PrecedingSibling,
562 Token::Self_ => Axis::Self_,
563 _ => unreachable!(),
564 };
565 self.advance(); self.advance(); return axis;
568 }
569
570 Axis::Child
572 }
573
574 fn token_to_name(&self, token: &Token) -> Option<String> {
576 match token {
577 Token::Name(ref s) => Some(s.clone()),
578 Token::Div => Some("div".to_string()),
579 Token::Mod => Some("mod".to_string()),
580 Token::And => Some("and".to_string()),
581 Token::Or => Some("or".to_string()),
582 Token::Ancestor => Some("ancestor".to_string()),
583 Token::AncestorOrSelf => Some("ancestor-or-self".to_string()),
584 Token::Attribute => Some("attribute".to_string()),
585 Token::Child => Some("child".to_string()),
586 Token::Descendant => Some("descendant".to_string()),
587 Token::DescendantOrSelf => Some("descendant-or-self".to_string()),
588 Token::Following => Some("following".to_string()),
589 Token::FollowingSibling => Some("following-sibling".to_string()),
590 Token::Namespace => Some("namespace".to_string()),
591 Token::Parent => Some("parent".to_string()),
592 Token::Preceding => Some("preceding".to_string()),
593 Token::PrecedingSibling => Some("preceding-sibling".to_string()),
594 Token::Self_ => Some("self".to_string()),
595 _ => None,
596 }
597 }
598
599 fn parse_node_test(&mut self) -> Result<NodeTest, ParseError> {
602 let name_opt = self.token_to_name(&self.current());
604
605 match self.current() {
606 Token::Star => {
607 self.advance();
608 Ok(NodeTest::NameTest(NameTest::Any))
609 }
610 _ if name_opt.is_some() => {
611 let name = name_opt.unwrap();
612
613 if matches!(self.peek(), Token::LParen) {
615 match name.as_str() {
616 "node" => {
617 self.advance();
618 self.advance();
619 self.advance(); Ok(NodeTest::Node)
621 }
622 "text" => {
623 self.advance();
624 self.advance();
625 self.advance();
626 Ok(NodeTest::Text)
627 }
628 "comment" => {
629 self.advance();
630 self.advance();
631 self.advance();
632 Ok(NodeTest::Comment)
633 }
634 "processing-instruction" => {
635 self.advance(); self.advance(); let target = if matches!(self.current(), Token::StringLiteral(_)) {
639 if let Token::StringLiteral(s) = self.current() {
640 self.advance();
641 Some(s)
642 } else {
643 None
644 }
645 } else {
646 None
647 };
648 self.expect(&Token::RParen)?;
649 Ok(NodeTest::ProcessingInstruction(target))
650 }
651 _ => {
652 self.advance(); self.advance(); let mut args = Vec::new();
656 if !matches!(self.current(), Token::RParen) {
657 args.push(self.parse_or_expr()?);
658 while matches!(self.current(), Token::Comma) {
659 self.advance();
660 args.push(self.parse_or_expr()?);
661 }
662 }
663 self.expect(&Token::RParen)?;
664 Ok(NodeTest::NameTest(NameTest::LocalName(name)))
666 }
667 }
668 } else {
669 self.advance();
670 if let Some(rest) = name.strip_suffix(":*") {
672 Ok(NodeTest::NsWildcard(rest.to_string()))
673 } else if let Some((prefix, local)) = name.split_once(':') {
674 Ok(NodeTest::NameTest(NameTest::QName {
675 prefix: prefix.to_string(),
676 local: local.to_string(),
677 }))
678 } else {
679 Ok(NodeTest::NameTest(NameTest::LocalName(name)))
680 }
681 }
682 }
683 _ => Err(self.error(format!("Expected node test, got {}", self.current()))),
684 }
685 }
686
687 fn parse_filter_expr(&mut self) -> Result<Expr, ParseError> {
689 let primary = self.parse_primary_expr()?;
690
691 let mut predicates = Vec::new();
693 while matches!(self.current(), Token::LBracket) {
694 self.advance(); let pred = self.parse_or_expr()?;
696 self.expect(&Token::RBracket)?;
697 predicates.push(pred);
698 }
699
700 if predicates.is_empty() {
701 Ok(primary)
702 } else {
703 Ok(Expr::Filter(Box::new(primary), predicates))
704 }
705 }
706
707 fn parse_primary_expr(&mut self) -> Result<Expr, ParseError> {
709 match self.current() {
710 Token::Dollar => {
711 self.advance();
712 if let Token::Name(name) = self.current() {
713 let name = name.clone();
714 self.advance();
715 Ok(Expr::Variable(name))
716 } else {
717 Err(self.error("Expected variable name after $".to_string()))
718 }
719 }
720 Token::LParen => {
721 self.advance();
722 let expr = self.parse_or_expr()?;
723 self.expect(&Token::RParen)?;
724 Ok(expr)
725 }
726 Token::StringLiteral(ref s) => {
727 let s = s.clone();
728 self.advance();
729 Ok(Expr::StringLiteral(s))
730 }
731 Token::NumberLiteral(n) => {
732 self.advance();
733 Ok(Expr::NumberLiteral(n))
734 }
735 Token::Name(ref name) => {
736 let name = name.clone();
737 if matches!(self.peek(), Token::LParen) {
738 self.advance(); self.advance(); let mut args = Vec::new();
742 if !matches!(self.current(), Token::RParen) {
743 args.push(self.parse_or_expr()?);
744 while matches!(self.current(), Token::Comma) {
745 self.advance();
746 args.push(self.parse_or_expr()?);
747 }
748 }
749 self.expect(&Token::RParen)?;
750 Ok(Expr::FunctionCall { name, args })
751 } else {
752 Err(self.error(format!("Unexpected name '{}' in primary expression", name)))
755 }
756 }
757 _ => Err(self.error(format!(
758 "Expected primary expression, got {}",
759 self.current()
760 ))),
761 }
762 }
763}
764
765pub fn parse_xpath(input: &str) -> Result<Expr, ParseError> {
771 let mut lexer = crate::xml::xpath::lexer::Lexer::new(input);
772 let mut tokens = Vec::new();
773 loop {
774 let tok = lexer.next_token();
775 let is_eof = matches!(tok, Token::Eof);
776 tokens.push(tok);
777 if is_eof {
778 break;
779 }
780 }
781 let starts = lexer.token_starts();
782 let mut parser = Parser::new(tokens);
783 parser.parse().map_err(|e| {
784 let byte_off = starts
790 .get(e.pos)
791 .copied()
792 .unwrap_or(input.len())
793 .min(input.len());
794 ParseError {
795 message: e.message,
796 pos: byte_off,
797 }
798 })
799}
800
801#[cfg(test)]
806mod tests {
807 use super::*;
808
809 #[test]
810 fn test_parse_simple_name() {
811 let expr = parse_xpath("para").unwrap();
812 assert!(matches!(expr, Expr::Step(_)));
813 }
814
815 #[test]
816 fn test_parse_absolute_path() {
817 let expr = parse_xpath("/child::para").unwrap();
818 assert!(matches!(expr, Expr::AbsolutePath(_)));
819 }
820
821 #[test]
822 fn test_parse_attribute() {
823 let expr = parse_xpath("@attr").unwrap();
824 assert!(matches!(expr, Expr::Step(_)));
825 }
826
827 #[test]
828 fn test_parse_predicate() {
829 let expr = parse_xpath("para[1]").unwrap();
830 assert!(matches!(expr, Expr::Step(_)));
831 }
832
833 #[test]
834 fn test_parse_function_call() {
835 let expr = parse_xpath("position()").unwrap();
836 assert!(matches!(expr, Expr::FunctionCall { .. }));
837 }
838
839 #[test]
840 fn test_parse_binary_op() {
841 let expr = parse_xpath("a = b").unwrap();
842 assert!(matches!(
843 expr,
844 Expr::BinaryOp {
845 op: BinaryOp::Eq,
846 ..
847 }
848 ));
849 }
850
851 #[test]
852 fn test_parse_union() {
853 let expr = parse_xpath("a | b").unwrap();
854 assert!(matches!(expr, Expr::Union(_, _)));
855 }
856
857 #[test]
858 fn test_parse_variable() {
859 let expr = parse_xpath("$var").unwrap();
860 assert!(matches!(expr, Expr::Variable(_)));
861 }
862
863 #[test]
864 fn test_parse_string_literal() {
865 let expr = parse_xpath("'hello'").unwrap();
866 assert_eq!(expr, Expr::StringLiteral("hello".to_string()));
867 }
868
869 #[test]
870 fn test_parse_number() {
871 let expr = parse_xpath("42").unwrap();
872 assert_eq!(expr, Expr::NumberLiteral(42.0));
873 }
874
875 #[test]
876 fn test_parse_nested_expression() {
877 let expr = parse_xpath("(1 + 2) * 3").unwrap();
878 assert!(matches!(
879 expr,
880 Expr::BinaryOp {
881 op: BinaryOp::Mul,
882 ..
883 }
884 ));
885 }
886
887 #[test]
888 fn test_parse_chained_path() {
889 let expr = parse_xpath("a/b/c").unwrap();
890 assert!(matches!(expr, Expr::RelativePath(_, _)));
891 }
892
893 #[test]
894 fn test_parse_double_slash() {
895 let expr = parse_xpath("//para").unwrap();
896 assert!(matches!(expr, Expr::AbsolutePath(_)));
897 }
898
899 #[test]
900 fn test_parse_dot() {
901 let expr = parse_xpath(".").unwrap();
902 assert!(matches!(expr, Expr::Step(_)));
903 }
904
905 #[test]
906 fn test_parse_dot_dot() {
907 let expr = parse_xpath("..").unwrap();
908 assert!(matches!(expr, Expr::Step(_)));
909 }
910
911 #[test]
912 fn test_parse_unary_minus() {
913 let expr = parse_xpath("-5").unwrap();
914 assert!(matches!(expr, Expr::UnaryMinus(_)));
915 }
916
917 #[test]
918 fn test_parse_double_unary_minus() {
919 let expr = parse_xpath("--5").unwrap();
920 assert!(!matches!(expr, Expr::UnaryMinus(_)));
922 }
923
924 #[test]
925 fn test_parse_complex_expression() {
926 let expr = parse_xpath("/html/body//div[@class='main']/p[1]").unwrap();
927 assert!(matches!(expr, Expr::AbsolutePath(_)));
928 }
929
930 #[test]
931 fn test_parse_error() {
932 let result = parse_xpath("(");
933 assert!(result.is_err());
934 }
935
936 #[test]
937 fn test_parse_empty() {
938 let result = parse_xpath("");
939 assert!(result.is_err());
940 }
941
942 #[test]
943 fn test_parse_and_or() {
944 let expr = parse_xpath("a = 1 and b = 2 or c = 3").unwrap();
945 assert!(matches!(expr, Expr::BinaryOp { .. }));
946 }
947
948 #[test]
949 fn test_parse_comparison_chain() {
950 let expr = parse_xpath("a < b <= c > d >= e").unwrap();
951 assert!(matches!(
953 expr,
954 Expr::BinaryOp {
955 op: BinaryOp::Ge,
956 ..
957 }
958 ));
959 }
960
961 #[test]
962 fn test_parse_arithmetic() {
963 let expr = parse_xpath("1 + 2 * 3").unwrap();
964 match expr {
966 Expr::BinaryOp {
967 op: BinaryOp::Add,
968 left,
969 right,
970 } => {
971 assert!(matches!(*left, Expr::NumberLiteral(1.0)));
972 assert!(matches!(
973 *right,
974 Expr::BinaryOp {
975 op: BinaryOp::Mul,
976 ..
977 }
978 ));
979 }
980 _ => panic!("Expected Add expression"),
981 }
982 }
983
984 #[test]
985 fn test_parse_filter_path() {
986 let expr = parse_xpath("//div/span").unwrap();
987 assert!(matches!(expr, Expr::AbsolutePath(_)));
988 }
989
990 #[test]
991 fn test_parse_node_test_functions() {
992 let expr = parse_xpath("child::node()").unwrap();
993 assert!(matches!(expr, Expr::Step(_)));
994 if let Expr::Step(step) = expr {
995 assert_eq!(step.node_test, NodeTest::Node);
996 }
997 }
998}