xpath_eval/ast.rs
1//! Abstract syntax tree for XPath 1.0 expressions (production numbers as in
2//! the [XPath 1.0 grammar](https://www.w3.org/TR/1999/REC-xpath-19991116/#exprlex),
3//! see `plan/02-lexer-parser.md`).
4//!
5//! Abbreviated syntax (`@name`, `.`, `..`, `//`) is desugared during parsing
6//! into its equivalent explicit-axis form — there is no separate
7//! "abbreviated step" representation here, only `Step { axis, .. }` with the
8//! axis the abbreviation stands for.
9
10/// A qualified name (`NCName (':' NCName)?`, XML Namespaces §3).
11#[derive(Debug, Clone, PartialEq, Eq, Hash)]
12pub struct QName {
13 pub prefix: Option<String>,
14 pub local: String,
15}
16
17/// The 13 XPath axes ([6] `AxisName`). Abbreviated forms (`@`, `.`, `..`)
18/// are represented as their equivalent explicit axis, not as a separate
19/// variant.
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum Axis {
22 Ancestor,
23 AncestorOrSelf,
24 Attribute,
25 Child,
26 Descendant,
27 DescendantOrSelf,
28 Following,
29 FollowingSibling,
30 Namespace,
31 Parent,
32 Preceding,
33 PrecedingSibling,
34 SelfAxis,
35}
36
37impl Axis {
38 /// Maps an `AxisName` token text to its `Axis`, or `None` if `name` is
39 /// not one of the 13 known axis names.
40 pub fn from_name(name: &str) -> Option<Axis> {
41 Some(match name {
42 "ancestor" => Axis::Ancestor,
43 "ancestor-or-self" => Axis::AncestorOrSelf,
44 "attribute" => Axis::Attribute,
45 "child" => Axis::Child,
46 "descendant" => Axis::Descendant,
47 "descendant-or-self" => Axis::DescendantOrSelf,
48 "following" => Axis::Following,
49 "following-sibling" => Axis::FollowingSibling,
50 "namespace" => Axis::Namespace,
51 "parent" => Axis::Parent,
52 "preceding" => Axis::Preceding,
53 "preceding-sibling" => Axis::PrecedingSibling,
54 "self" => Axis::SelfAxis,
55 _ => return None,
56 })
57 }
58}
59
60/// [7] `NodeTest` — includes the `NameTest` alternatives (`*`, `prefix:*`,
61/// `QName`) and the `NodeType`/`processing-instruction(Literal)` forms.
62#[derive(Debug, Clone, PartialEq)]
63pub enum NodeTest {
64 /// `*`
65 AnyName,
66 /// `prefix:*`
67 NamespaceWildcard(String),
68 /// `QName` (possibly namespace-prefixed local name test)
69 QName(QName),
70 /// `node()`
71 Node,
72 /// `text()`
73 Text,
74 /// `comment()`
75 Comment,
76 /// `processing-instruction()` or `processing-instruction('target')`
77 ProcessingInstruction(Option<String>),
78}
79
80/// [4] `Step` — `AxisSpecifier NodeTest Predicate*`, with `AbbreviatedStep`
81/// (`.` / `..`) desugared into the equivalent `self`/`parent` axis step.
82#[derive(Debug, Clone, PartialEq)]
83pub struct Step {
84 pub axis: Axis,
85 pub node_test: NodeTest,
86 pub predicates: Vec<Expr>,
87}
88
89/// [1]/[2]/[3] `LocationPath` — `//` is desugared into an explicit
90/// `descendant-or-self::node()` step prepended to (or inserted into) `steps`.
91#[derive(Debug, Clone, PartialEq)]
92pub struct LocationPath {
93 pub is_absolute: bool,
94 pub steps: Vec<Step>,
95}
96
97/// [16] `FunctionCall` — name plus argument expressions. Not validated
98/// against the core function library in this phase; any syntactically
99/// valid `QName` is accepted.
100#[derive(Debug, Clone, PartialEq)]
101pub struct FunctionCall {
102 pub name: QName,
103 pub args: Vec<Expr>,
104}
105
106/// [15] `PrimaryExpr`.
107#[derive(Debug, Clone, PartialEq)]
108pub enum PrimaryExpr {
109 /// [36] `VariableReference` — `$QName`.
110 Variable(QName),
111 /// `'(' Expr ')'`
112 Parenthesized(Box<Expr>),
113 /// [29] `Literal`.
114 Literal(String),
115 /// [30] `Number`.
116 Number(f64),
117 /// [16] `FunctionCall`.
118 Function(FunctionCall),
119}
120
121/// [20] `FilterExpr` — a `PrimaryExpr` with zero or more predicates.
122#[derive(Debug, Clone, PartialEq)]
123pub struct FilterExpr {
124 pub primary: PrimaryExpr,
125 pub predicates: Vec<Expr>,
126}
127
128/// [19] `PathExpr`.
129#[derive(Debug, Clone, PartialEq)]
130pub enum PathExpr {
131 /// A bare `LocationPath`.
132 Location(LocationPath),
133 /// A bare `FilterExpr` (no trailing `/` or `//`).
134 Filter(FilterExpr),
135 /// `FilterExpr '/' RelativeLocationPath` or, with `//` desugared into a
136 /// prepended `descendant-or-self::node()` step,
137 /// `FilterExpr '//' RelativeLocationPath`.
138 FilterLocation(FilterExpr, LocationPath),
139}
140
141#[derive(Debug, Clone, Copy, PartialEq, Eq)]
142pub enum EqualityOp {
143 Eq,
144 Ne,
145}
146
147#[derive(Debug, Clone, Copy, PartialEq, Eq)]
148pub enum RelationalOp {
149 Lt,
150 Gt,
151 Le,
152 Ge,
153}
154
155#[derive(Debug, Clone, Copy, PartialEq, Eq)]
156pub enum AdditiveOp {
157 Add,
158 Sub,
159}
160
161#[derive(Debug, Clone, Copy, PartialEq, Eq)]
162pub enum MultiplicativeOp {
163 Mul,
164 Div,
165 Mod,
166}
167
168/// [14] `Expr` and the full operator-precedence chain [18]/[21]-[27] in a
169/// single flat enum: each precedence level either produces a node here or,
170/// when its operator is absent, simply returns the inner expression from
171/// the next-tighter level (standard precedence-climbing shortcut).
172#[derive(Debug, Clone, PartialEq)]
173pub enum Expr {
174 /// [21] `OrExpr`.
175 Or(Box<Expr>, Box<Expr>),
176 /// [22] `AndExpr`.
177 And(Box<Expr>, Box<Expr>),
178 /// [23] `EqualityExpr`.
179 Equality(Box<Expr>, EqualityOp, Box<Expr>),
180 /// [24] `RelationalExpr`.
181 Relational(Box<Expr>, RelationalOp, Box<Expr>),
182 /// [25] `AdditiveExpr`.
183 Additive(Box<Expr>, AdditiveOp, Box<Expr>),
184 /// [26] `MultiplicativeExpr`.
185 Multiplicative(Box<Expr>, MultiplicativeOp, Box<Expr>),
186 /// [27] `UnaryExpr ::= '-' UnaryExpr`.
187 Negate(Box<Expr>),
188 /// [18] `UnionExpr`.
189 Union(Box<Expr>, Box<Expr>),
190 /// [19] `PathExpr`.
191 Path(PathExpr),
192}