1use markup5ever::{LocalName, Namespace, Prefix, QualName};
6
7use crate::NamespaceResolver;
8use crate::ast::{
9    Axis, BinaryOperator, CoreFunction, Expression, FilterExpression, KindTest, Literal,
10    LocationStepExpression, NodeTest, PathExpression, PredicateListExpression,
11};
12use crate::tokenizer::{Error as TokenizerError, LiteralToken, OperatorToken, Token, tokenize};
13
14#[derive(Clone, Debug)]
15pub enum Error {
16    Tokenization(TokenizerError),
17    UnknownFunction,
18    ExpectedSeperatorBetweenFunctionArguments,
19    TooFewFunctionArguments,
20    TooManyFunctionArguments,
21    ExpectedClosingParenthesis,
22    ExpectedClosingBracket,
23    CannotUseVariables,
24    UnknownAxis,
25    TrailingInput,
26    UnknownNodeTest,
27    ExpectedNodeTest,
28    UnexpectedEndOfInput,
29    FailedToResolveNamespacePrefix,
30}
31
32impl From<TokenizerError> for Error {
33    fn from(value: TokenizerError) -> Self {
34        Self::Tokenization(value)
35    }
36}
37
38pub fn parse<N>(
40    input: &str,
41    namespace_resolver: Option<N>,
42    is_in_html_document: bool,
43) -> Result<Expression, Error>
44where
45    N: NamespaceResolver,
46{
47    let mut parser = Parser::new(input, namespace_resolver, is_in_html_document)?;
48    let root_expression = parser.parse_expression()?;
49    if !parser.remaining().is_empty() {
50        log::debug!(
51            "Found trailing tokens after expression: {:?}",
52            parser.remaining()
53        );
54        return Err(Error::TrailingInput);
55    }
56
57    log::debug!("Parsed XPath expression: {root_expression:?}");
58    Ok(root_expression)
59}
60
61pub(crate) struct Parser<'a, N>
62where
63    N: NamespaceResolver,
64{
65    tokens: Vec<Token<'a>>,
66    position: usize,
67    namespace_resolver: Option<N>,
68    is_in_html_document: bool,
69}
70
71impl<'a, N> Parser<'a, N>
72where
73    N: NamespaceResolver,
74{
75    pub(crate) fn new(
76        input: &'a str,
77        namespace_resolver: Option<N>,
78        is_in_html_document: bool,
79    ) -> Result<Self, TokenizerError> {
80        let parser = Self {
81            tokens: tokenize(input)?,
82            position: 0,
83            namespace_resolver,
84            is_in_html_document,
85        };
86        Ok(parser)
87    }
88
89    fn expect_current_token(&self) -> Result<Token<'a>, Error> {
90        self.tokens
91            .get(self.position)
92            .copied()
93            .ok_or(Error::UnexpectedEndOfInput)
94    }
95
96    fn peek(&self, n: usize) -> Option<Token<'a>> {
97        self.tokens.get(self.position + n).copied()
98    }
99
100    fn advance(&mut self, advance_by: usize) {
101        self.position += advance_by;
102    }
103
104    pub(crate) fn remaining(&self) -> &[Token<'a>] {
105        &self.tokens[self.position..]
106    }
107
108    fn resolve_qualified_name(&self, prefix: &str) -> Result<Namespace, Error> {
109        let Some(namespace_resolver) = self.namespace_resolver.as_ref() else {
110            return Err(Error::FailedToResolveNamespacePrefix);
111        };
112
113        log::debug!("Resolving namespace prefix: {:?}", prefix);
114        namespace_resolver
115            .resolve_namespace_prefix(prefix)
116            .map(Namespace::from)
117            .ok_or(Error::FailedToResolveNamespacePrefix)
118    }
119
120    fn advance_if_current_token_equals(&mut self, wanted: Token<'a>) -> bool {
121        if self.peek(0).is_some_and(|token| token == wanted) {
122            self.position += 1;
123            true
124        } else {
125            false
126        }
127    }
128
129    pub(crate) fn parse_expression(&mut self) -> Result<Expression, Error> {
130        let mut result;
131
132        let mut expression_stack: Vec<(Expression, OperatorToken)> = vec![];
133        loop {
134            let mut negations = 0;
135            while self.advance_if_current_token_equals(Token::Operator(OperatorToken::Subtract)) {
136                negations += 1;
137            }
138
139            result = self.parse_union_expression()?;
140
141            if negations > 1 {
142                if negations % 2 == 0 {
143                    result = Expression::Function(CoreFunction::Number(Some(Box::new(result))))
144                } else {
145                    result = Expression::Negate(Box::new(result))
146                }
147            }
148
149            let Some(next_token) = self.peek(0) else {
151                break;
152            };
153            let Token::Operator(current_operator) = next_token else {
154                break;
155            };
156            self.advance(1);
157
158            while let Some((lhs, operator)) = expression_stack
160                .pop_if(|(_, operator)| current_operator.precedence() <= operator.precedence())
161            {
162                result = create_binary_expression(Box::new(lhs), operator, Box::new(result));
163            }
164
165            expression_stack.push((result, current_operator));
166        }
167
168        for (lhs, operator) in expression_stack.into_iter().rev() {
170            result = create_binary_expression(Box::new(lhs), operator, Box::new(result))
171        }
172
173        Ok(result)
174    }
175
176    fn parse_union_expression(&mut self) -> Result<Expression, Error> {
178        let mut result = self.parse_path_expression()?;
179
180        while self.advance_if_current_token_equals(Token::Union) {
181            let rhs = self.parse_path_expression()?;
182            result = Expression::Binary(Box::new(result), BinaryOperator::Union, Box::new(rhs));
183        }
184
185        Ok(result)
186    }
187
188    fn parse_path_expression(&mut self) -> Result<Expression, Error> {
190        let current_token = self.expect_current_token()?;
191
192        let is_absolute = matches!(current_token, Token::Parent | Token::Ancestor);
193        let has_implicit_descendant_or_self_step = current_token == Token::Ancestor;
194
195        if is_absolute {
196            self.advance(1);
197
198            if !self
199                .peek(0)
200                .is_some_and(|token| token.is_start_of_location_step())
201            {
202                return Ok(Expression::Path(PathExpression {
203                    is_absolute,
204                    has_implicit_descendant_or_self_step,
205                    steps: vec![],
206                }));
207            }
208        }
209
210        let first_expression = if !is_absolute {
211            let expression = self.parse_filter_or_step_expression()?;
212
213            if !self
215                .peek(0)
216                .is_some_and(|token| matches!(token, Token::Parent | Token::Ancestor))
217            {
218                return Ok(expression);
219            }
220
221            expression
222        } else {
223            self.parse_step_expression()?
224        };
225
226        let mut path_expression = PathExpression {
227            is_absolute,
228            has_implicit_descendant_or_self_step,
229            steps: vec![first_expression],
230        };
231
232        while let Some(current_token) = self.peek(0) {
233            match current_token {
234                Token::Ancestor => {
235                    self.advance(1);
236
237                    path_expression
239                        .steps
240                        .push(Expression::LocationStep(LocationStepExpression {
241                            axis: Axis::DescendantOrSelf,
242                            node_test: NodeTest::Kind(KindTest::Node),
243                            predicate_list: PredicateListExpression { predicates: vec![] },
244                        }));
245                    true
246                },
247                Token::Parent => {
248                    self.advance(1);
249                    false
250                },
251                _ => {
252                    return Ok(Expression::Path(path_expression));
254                },
255            };
256
257            let step_expression = self.parse_step_expression()?;
258            path_expression.steps.push(step_expression);
259        }
260
261        Ok(Expression::Path(path_expression))
262    }
263
264    fn parse_filter_or_step_expression(&mut self) -> Result<Expression, Error> {
268        let mut expression = match self.expect_current_token()? {
269            Token::FunctionCall(name) => {
270                self.advance(1);
271                self.parse_function_call(name)?
272            },
273            Token::OpeningParenthesis => {
274                self.advance(1);
275                let expression = self.parse_expression()?;
276                if !self.advance_if_current_token_equals(Token::ClosingParenthesis) {
277                    log::debug!("{:?}", self.expect_current_token()?);
278                    return Err(Error::ExpectedClosingParenthesis);
279                }
280                expression
281            },
282            Token::Literal(literal) => {
283                self.advance(1);
284                Expression::Literal(literal.into())
285            },
286            Token::VariableReference(_) => {
287                return Err(Error::CannotUseVariables);
290            },
291            _ => self.parse_step_expression()?,
292        };
293
294        let predicate_list = self.parse_predicates()?;
296        if !predicate_list.predicates.is_empty() {
297            expression = Expression::Filter(FilterExpression {
298                expression: Box::new(expression),
299                predicates: predicate_list,
300            });
301        }
302
303        Ok(expression)
304    }
305
306    fn parse_step_expression(&mut self) -> Result<Expression, Error> {
308        let axis;
309        let mut node_test = None;
310
311        match self.expect_current_token()? {
312            Token::AxisIdentifier(axis_name) => {
313                self.advance(1);
314                axis = match axis_name {
315                    "ancestor" => Axis::Ancestor,
316                    "ancestor-or-self" => Axis::AncestorOrSelf,
317                    "attribute" => Axis::Attribute,
318                    "child" => Axis::Child,
319                    "descendant" => Axis::Descendant,
320                    "descendant-or-self" => Axis::DescendantOrSelf,
321                    "following" => Axis::Following,
322                    "following-sibling" => Axis::FollowingSibling,
323                    "namespace" => Axis::Namespace,
324                    "parent" => Axis::Parent,
325                    "preceding" => Axis::Preceding,
326                    "preceding-sibling" => Axis::PrecedingSibling,
327                    "self" => Axis::Self_,
328                    _ => {
329                        log::debug!("Unknown XPath axis name: {axis_name:?}");
330                        return Err(Error::UnknownAxis);
331                    },
332                };
333            },
334            Token::AtSign => {
335                self.advance(1);
337                axis = Axis::Attribute;
338            },
339            Token::ParentNode => {
340                self.advance(1);
341                axis = Axis::Parent;
342                node_test = Some(NodeTest::Kind(KindTest::Node));
343            },
344            Token::SelfNode => {
345                self.advance(1);
346                axis = Axis::Self_;
347                node_test = Some(NodeTest::Kind(KindTest::Node));
348            },
349            _ => {
350                axis = Axis::Child;
351            },
352        }
353
354        let node_test = if let Some(node_test) = node_test {
355            node_test
356        } else if let Token::CName(name_token) = self.expect_current_token()? {
357            self.advance(1);
358
359            if name_token.local_name == "*" {
360                NodeTest::Wildcard
361            } else {
362                let namespace = name_token
363                    .prefix
364                    .map(|prefix| self.resolve_qualified_name(prefix))
365                    .transpose()?;
366
367                let local_name = if self.is_in_html_document && name_token.prefix.is_none() {
368                    LocalName::from(name_token.local_name.to_ascii_lowercase().as_str())
369                } else {
370                    LocalName::from(name_token.local_name)
371                };
372
373                let qualified_name = QualName {
374                    prefix: name_token.prefix.map(Prefix::from),
375                    ns: namespace.unwrap_or_default(),
376                    local: local_name,
377                };
378
379                NodeTest::Name(qualified_name)
380            }
381        } else {
382            self.parse_node_test()?
383        };
384
385        let predicate_list = self.parse_predicates()?;
386        Ok(Expression::LocationStep(LocationStepExpression {
387            axis,
388            node_test,
389            predicate_list,
390        }))
391    }
392
393    fn parse_node_test(&mut self) -> Result<NodeTest, Error> {
394        let kind_test = match self.expect_current_token()? {
395            Token::CommentTest => {
396                self.advance(1);
397                KindTest::Comment
398            },
399            Token::NodeTest => {
400                self.advance(1);
401                KindTest::Node
402            },
403            Token::ProcessingInstructionTest => {
404                self.advance(1);
405                let name = if let Token::Literal(LiteralToken::String(name)) =
406                    self.expect_current_token()?
407                {
408                    self.advance(1);
409                    Some(name)
410                } else {
411                    None
412                };
413                KindTest::PI(name.map(String::from))
414            },
415            Token::TextTest => {
416                self.advance(1);
417                KindTest::Text
418            },
419            _ => {
420                return Err(Error::ExpectedNodeTest);
421            },
422        };
423
424        if !self.advance_if_current_token_equals(Token::ClosingParenthesis) {
425            return Err(Error::TooManyFunctionArguments);
426        }
427
428        Ok(NodeTest::Kind(kind_test))
429    }
430
431    fn parse_predicates(&mut self) -> Result<PredicateListExpression, Error> {
433        let mut predicates = vec![];
434        while self.advance_if_current_token_equals(Token::OpeningBracket) {
435            let expression = self.parse_expression()?;
436            predicates.push(expression);
437            if !self.advance_if_current_token_equals(Token::ClosingBracket) {
438                return Err(Error::ExpectedClosingBracket);
439            }
440        }
441        Ok(PredicateListExpression { predicates })
442    }
443
444    fn parse_function_call(&mut self, function_name: &str) -> Result<Expression, Error> {
445        struct ArgumentIterator<'a, 'b, N>
446        where
447            N: NamespaceResolver,
448        {
449            parser: &'b mut Parser<'a, N>,
450            done: bool,
451        }
452
453        impl<'a, 'b, N> ArgumentIterator<'a, 'b, N>
454        where
455            N: NamespaceResolver,
456        {
457            fn maybe_next(&mut self) -> Result<Option<Expression>, Error> {
458                if self.done {
459                    return Ok(None);
460                }
461                let expression = self.parser.parse_expression()?;
462                if self
463                    .parser
464                    .advance_if_current_token_equals(Token::ClosingParenthesis)
465                {
466                    self.done = true;
467                } else if !self.parser.advance_if_current_token_equals(Token::Comma) {
468                    log::debug!("{:?}", self.parser.peek(0));
469                    return Err(Error::ExpectedSeperatorBetweenFunctionArguments);
470                }
471
472                Ok(Some(expression))
473            }
474
475            fn next(&mut self) -> Result<Expression, Error> {
476                self.maybe_next()
477                    .and_then(|maybe_argument| maybe_argument.ok_or(Error::TooFewFunctionArguments))
478            }
479        }
480
481        let mut arguments = ArgumentIterator {
482            done: self.advance_if_current_token_equals(Token::ClosingParenthesis),
483            parser: self,
484        };
485
486        let core_fn = match function_name {
487            "last" => CoreFunction::Last,
489            "position" => CoreFunction::Position,
490            "count" => CoreFunction::Count(Box::new(arguments.next()?)),
491            "id" => CoreFunction::Id(Box::new(arguments.next()?)),
492            "local-name" => CoreFunction::LocalName(arguments.maybe_next()?.map(Box::new)),
493            "namespace-uri" => CoreFunction::NamespaceUri(arguments.maybe_next()?.map(Box::new)),
494            "name" => CoreFunction::Name(arguments.maybe_next()?.map(Box::new)),
495
496            "string" => CoreFunction::String(arguments.maybe_next()?.map(Box::new)),
498            "concat" => {
499                let mut args = vec![];
500                while let Some(argument) = arguments.maybe_next()? {
501                    args.push(argument);
502                }
503                CoreFunction::Concat(args)
504            },
505            "starts-with" => {
506                CoreFunction::StartsWith(Box::new(arguments.next()?), Box::new(arguments.next()?))
507            },
508            "contains" => {
509                CoreFunction::Contains(Box::new(arguments.next()?), Box::new(arguments.next()?))
510            },
511            "substring-before" => CoreFunction::SubstringBefore(
512                Box::new(arguments.next()?),
513                Box::new(arguments.next()?),
514            ),
515            "substring-after" => CoreFunction::SubstringAfter(
516                Box::new(arguments.next()?),
517                Box::new(arguments.next()?),
518            ),
519            "substring" => CoreFunction::Substring(
520                Box::new(arguments.next()?),
521                Box::new(arguments.next()?),
522                arguments.maybe_next()?.map(Box::new),
523            ),
524            "string-length" => CoreFunction::StringLength(arguments.maybe_next()?.map(Box::new)),
525            "normalize-space" => {
526                CoreFunction::NormalizeSpace(arguments.maybe_next()?.map(Box::new))
527            },
528            "translate" => CoreFunction::Translate(
529                Box::new(arguments.next()?),
530                Box::new(arguments.next()?),
531                Box::new(arguments.next()?),
532            ),
533
534            "number" => CoreFunction::Number(arguments.maybe_next()?.map(Box::new)),
536            "sum" => CoreFunction::Sum(Box::new(arguments.next()?)),
537            "floor" => CoreFunction::Floor(Box::new(arguments.next()?)),
538            "ceiling" => CoreFunction::Ceiling(Box::new(arguments.next()?)),
539            "round" => CoreFunction::Round(Box::new(arguments.next()?)),
540
541            "boolean" => CoreFunction::Boolean(Box::new(arguments.next()?)),
543            "not" => CoreFunction::Not(Box::new(arguments.next()?)),
544            "true" => CoreFunction::True,
545            "false" => CoreFunction::False,
546            "lang" => CoreFunction::Lang(Box::new(arguments.next()?)),
547
548            _ => return Err(Error::UnknownFunction),
550        };
551
552        if !arguments.done {
554            return Err(Error::TooManyFunctionArguments);
555        }
556
557        Ok(Expression::Function(core_fn))
558    }
559}
560
561fn create_binary_expression(
562    lhs: Box<Expression>,
563    operator: OperatorToken,
564    rhs: Box<Expression>,
565) -> Expression {
566    let binary_operator = match operator {
567        OperatorToken::And => BinaryOperator::And,
568        OperatorToken::Or => BinaryOperator::Or,
569        OperatorToken::Multiply => BinaryOperator::Multiply,
570        OperatorToken::Divide => BinaryOperator::Divide,
571        OperatorToken::Modulo => BinaryOperator::Modulo,
572        OperatorToken::Add => BinaryOperator::Add,
573        OperatorToken::Subtract => BinaryOperator::Subtract,
574        OperatorToken::Equal => BinaryOperator::Equal,
575        OperatorToken::NotEqual => BinaryOperator::NotEqual,
576        OperatorToken::GreaterThan => BinaryOperator::GreaterThan,
577        OperatorToken::GreaterThanOrEqual => BinaryOperator::GreaterThanOrEqual,
578        OperatorToken::LessThan => BinaryOperator::LessThan,
579        OperatorToken::LessThanOrEqual => BinaryOperator::LessThanOrEqual,
580    };
581
582    Expression::Binary(lhs, binary_operator, rhs)
583}
584
585impl<'a> From<LiteralToken<'a>> for Literal {
586    fn from(value: LiteralToken<'a>) -> Self {
587        match value {
588            LiteralToken::Integer(integer) => Self::Integer(integer),
589            LiteralToken::Decimal(float) => Self::Decimal(float),
590            LiteralToken::String(string) => Self::String(string.to_owned()),
591        }
592    }
593}
594
595#[cfg(test)]
597mod tests {
598    use markup5ever::{LocalName, QualName, local_name, namespace_prefix, ns};
599
600    use super::*;
601    use crate::NamespaceResolver;
602
603    #[derive(Clone)]
604    struct DummyNamespaceResolver;
605
606    impl NamespaceResolver for DummyNamespaceResolver {
607        fn resolve_namespace_prefix(&self, _: &str) -> Option<String> {
608            Some("http://www.w3.org/1999/xhtml".to_owned())
609        }
610    }
611
612    #[test]
613    fn test_filter_expr() {
614        let cases = vec![
615            (
616                "processing-instruction('test')[2]",
617                Expression::LocationStep(LocationStepExpression {
618                    axis: Axis::Child,
619                    node_test: NodeTest::Kind(KindTest::PI(Some("test".to_string()))),
620                    predicate_list: PredicateListExpression {
621                        predicates: vec![Expression::Literal(Literal::Integer(2))],
622                    },
623                }),
624            ),
625            (
626                "concat('hello', ' ', 'world')",
627                Expression::Function(CoreFunction::Concat(vec![
628                    Expression::Literal(Literal::String("hello".to_string())),
629                    Expression::Literal(Literal::String(" ".to_string())),
630                    Expression::Literal(Literal::String("world".to_string())),
631                ])),
632            ),
633        ];
634
635        for (input, expected) in cases {
636            match parse(input, Some(DummyNamespaceResolver), true) {
637                Ok(result) => {
638                    assert_eq!(result, expected, "{:?} was parsed incorrectly", input);
639                },
640                Err(e) => panic!("Failed to parse '{}': {:?}", input, e),
641            }
642        }
643    }
644
645    #[test]
646    fn test_complex_paths() {
647        let cases = vec![
648            (
649                "//*[contains(@class, 'test')]",
650                Expression::Path(PathExpression {
651                    is_absolute: true,
652                    has_implicit_descendant_or_self_step: true,
653                    steps: vec![Expression::LocationStep(LocationStepExpression {
654                        axis: Axis::Child,
655                        node_test: NodeTest::Wildcard,
656                        predicate_list: PredicateListExpression {
657                            predicates: vec![Expression::Function(CoreFunction::Contains(
658                                Box::new(Expression::LocationStep(LocationStepExpression {
659                                    axis: Axis::Attribute,
660                                    node_test: NodeTest::Name(QualName {
661                                        prefix: None,
662                                        ns: ns!(),
663                                        local: local_name!("class"),
664                                    }),
665                                    predicate_list: PredicateListExpression { predicates: vec![] },
666                                })),
667                                Box::new(Expression::Literal(Literal::String("test".to_owned()))),
668                            ))],
669                        },
670                    })],
671                }),
672            ),
673            (
674                "//div[position() > 1]/*[last()]",
675                Expression::Path(PathExpression {
676                    is_absolute: true,
677                    has_implicit_descendant_or_self_step: true,
678                    steps: vec![
679                        Expression::LocationStep(LocationStepExpression {
680                            axis: Axis::Child,
681                            node_test: NodeTest::Name(QualName {
682                                prefix: None,
683                                ns: ns!(),
684                                local: local_name!("div"),
685                            }),
686                            predicate_list: PredicateListExpression {
687                                predicates: vec![Expression::Binary(
688                                    Box::new(Expression::Function(CoreFunction::Position)),
689                                    BinaryOperator::GreaterThan,
690                                    Box::new(Expression::Literal(Literal::Integer(1))),
691                                )],
692                            },
693                        }),
694                        Expression::LocationStep(LocationStepExpression {
695                            axis: Axis::Child,
696                            node_test: NodeTest::Wildcard,
697                            predicate_list: PredicateListExpression {
698                                predicates: vec![Expression::Function(CoreFunction::Last)],
699                            },
700                        }),
701                    ],
702                }),
703            ),
704            (
705                "//mu[@xml:id=\"id1\"]//rho[@title][@xml:lang=\"en-GB\"]",
706                Expression::Path(PathExpression {
707                    is_absolute: true,
708                    has_implicit_descendant_or_self_step: true,
709                    steps: vec![
710                        Expression::LocationStep(LocationStepExpression {
711                            axis: Axis::Child,
712                            node_test: NodeTest::Name(QualName {
713                                prefix: None,
714                                ns: ns!(),
715                                local: LocalName::from("mu"),
716                            }),
717                            predicate_list: PredicateListExpression {
718                                predicates: vec![Expression::Binary(
719                                    Box::new(Expression::LocationStep(LocationStepExpression {
720                                        axis: Axis::Attribute,
721                                        node_test: NodeTest::Name(QualName {
722                                            prefix: Some(namespace_prefix!("xml")),
723                                            ns: ns!(html),
724                                            local: local_name!("id"),
725                                        }),
726                                        predicate_list: PredicateListExpression {
727                                            predicates: vec![],
728                                        },
729                                    })),
730                                    BinaryOperator::Equal,
731                                    Box::new(Expression::Literal(Literal::String(
732                                        "id1".to_owned(),
733                                    ))),
734                                )],
735                            },
736                        }),
737                        Expression::LocationStep(LocationStepExpression {
738                            axis: Axis::DescendantOrSelf,
739                            node_test: NodeTest::Kind(KindTest::Node),
740                            predicate_list: PredicateListExpression { predicates: vec![] },
741                        }),
742                        Expression::LocationStep(LocationStepExpression {
743                            axis: Axis::Child,
744                            node_test: NodeTest::Name(QualName {
745                                prefix: None,
746                                ns: ns!(),
747                                local: LocalName::from("rho"),
748                            }),
749                            predicate_list: PredicateListExpression {
750                                predicates: vec![
751                                    Expression::LocationStep(LocationStepExpression {
752                                        axis: Axis::Attribute,
753                                        node_test: NodeTest::Name(QualName {
754                                            prefix: None,
755                                            ns: ns!(),
756                                            local: local_name!("title"),
757                                        }),
758                                        predicate_list: PredicateListExpression {
759                                            predicates: vec![],
760                                        },
761                                    }),
762                                    Expression::Binary(
763                                        Box::new(Expression::LocationStep(
764                                            LocationStepExpression {
765                                                axis: Axis::Attribute,
766                                                node_test: NodeTest::Name(QualName {
767                                                    prefix: Some(namespace_prefix!("xml")),
768                                                    ns: ns!(html),
769                                                    local: local_name!("lang"),
770                                                }),
771                                                predicate_list: PredicateListExpression {
772                                                    predicates: vec![],
773                                                },
774                                            },
775                                        )),
776                                        BinaryOperator::Equal,
777                                        Box::new(Expression::Literal(Literal::String(
778                                            "en-GB".to_owned(),
779                                        ))),
780                                    ),
781                                ],
782                            },
783                        }),
784                    ],
785                }),
786            ),
787        ];
788
789        for (input, expected) in cases {
790            match parse(input, Some(DummyNamespaceResolver), true) {
791                Ok(result) => {
792                    assert_eq!(result, expected, "{:?} was parsed incorrectly", input);
793                },
794                Err(e) => panic!("Failed to parse '{}': {:?}", input, e),
795            }
796        }
797    }
798
799    #[test]
800    fn parse_expression_in_parenthesis() {
801        let test_case = "(./span)";
802        let expected = Expression::Path(PathExpression {
803            is_absolute: false,
804            has_implicit_descendant_or_self_step: false,
805            steps: vec![
806                Expression::LocationStep(LocationStepExpression {
807                    axis: Axis::Self_,
808                    node_test: NodeTest::Kind(KindTest::Node),
809                    predicate_list: PredicateListExpression { predicates: vec![] },
810                }),
811                Expression::LocationStep(LocationStepExpression {
812                    axis: Axis::Child,
813                    node_test: NodeTest::Name(QualName {
814                        prefix: None,
815                        ns: ns!(),
816                        local: local_name!("span"),
817                    }),
818                    predicate_list: PredicateListExpression { predicates: vec![] },
819                }),
820            ],
821        });
822        match parse(test_case, Some(DummyNamespaceResolver), true) {
823            Ok(result) => {
824                assert_eq!(result, expected, "{:?} was parsed incorrectly", test_case);
825            },
826            Err(e) => panic!("Failed to parse '{}': {:?}", test_case, e),
827        }
828    }
829}