Skip to main content

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}