#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Axis {
Ancestor,
AncestorOrSelf,
Attribute,
Child,
Descendant,
DescendantOrSelf,
Following,
FollowingSibling,
Namespace,
Parent,
Preceding,
PrecedingSibling,
Self_,
}
impl Axis {
pub fn is_reverse(&self) -> bool {
matches!(
self,
Axis::Ancestor | Axis::AncestorOrSelf | Axis::Preceding | Axis::PrecedingSibling
)
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum NodeTest {
AnyNode,
Text,
Comment,
PI(Option<String>),
Document(Option<Box<NodeTest>>),
Wildcard,
PrefixWildcard(String),
LocalNameOnly(String),
LocalName(String),
QName(String, String),
DefaultNamespaceName { uri: String, local: String },
}
#[derive(Debug, Clone)]
pub struct Step {
pub axis: Axis,
pub node_test: NodeTest,
pub predicates: Vec<Expr>,
pub filter: Option<Box<Expr>>,
}
#[derive(Debug, Clone)]
pub enum LocationPath {
Absolute(Vec<Step>),
Relative(Vec<Step>),
}
#[derive(Debug, Clone)]
pub enum Expr {
Or(Box<Expr>, Box<Expr>),
And(Box<Expr>, Box<Expr>),
Eq(Box<Expr>, Box<Expr>),
Ne(Box<Expr>, Box<Expr>),
Lt(Box<Expr>, Box<Expr>),
Gt(Box<Expr>, Box<Expr>),
Le(Box<Expr>, Box<Expr>),
Ge(Box<Expr>, Box<Expr>),
ValueEq(Box<Expr>, Box<Expr>),
ValueNe(Box<Expr>, Box<Expr>),
ValueLt(Box<Expr>, Box<Expr>),
ValueGt(Box<Expr>, Box<Expr>),
ValueLe(Box<Expr>, Box<Expr>),
ValueGe(Box<Expr>, Box<Expr>),
Add(Box<Expr>, Box<Expr>),
Sub(Box<Expr>, Box<Expr>),
Mul(Box<Expr>, Box<Expr>),
Div(Box<Expr>, Box<Expr>),
Mod(Box<Expr>, Box<Expr>),
Neg(Box<Expr>),
Union(Box<Expr>, Box<Expr>),
Path(LocationPath),
FilterPath {
primary: Box<Expr>,
predicates: Vec<Expr>,
steps: Vec<Step>,
},
FunctionCall(String, Vec<Expr>),
Variable(String),
Literal(String),
Integer(i64),
Decimal(rust_decimal::Decimal),
Double(f64),
IfThenElse {
cond: Box<Expr>,
then_branch: Box<Expr>,
else_branch: Box<Expr>,
},
For {
bindings: Vec<(String, Expr)>,
body: Box<Expr>,
},
Let {
bindings: Vec<(String, Expr)>,
body: Box<Expr>,
},
Range(Box<Expr>, Box<Expr>),
SimpleMap(Box<Expr>, Box<Expr>),
NodeBefore(Box<Expr>, Box<Expr>),
NodeAfter(Box<Expr>, Box<Expr>),
NodeIs(Box<Expr>, Box<Expr>),
Sequence(Vec<Expr>),
Quantified {
kind: QuantifierKind,
bindings: Vec<(String, Expr)>,
test: Box<Expr>,
},
IDiv(Box<Expr>, Box<Expr>),
Intersect(Box<Expr>, Box<Expr>),
Except(Box<Expr>, Box<Expr>),
InstanceOf(Box<Expr>, SequenceType),
CastAs(Box<Expr>, SingleType),
TryCatch {
body: Box<Expr>,
catches: Vec<XPathCatch>,
},
CastableAs(Box<Expr>, SingleType),
TreatAs(Box<Expr>, SequenceType),
WithDefaultCollation(String, Box<Expr>),
BackwardsCompat(Box<Expr>),
MapConstructor(Vec<(Expr, Expr)>),
ArrayConstructor { members: Vec<Expr>, square: bool },
Lookup(Box<Expr>, LookupKey),
UnaryLookup(LookupKey),
InlineFunction {
params: Vec<String>,
sig: Box<FunctionSig>,
body: Box<Expr>,
},
ContextItem,
NamedFunctionRef { name: String, arity: usize },
DynamicCall { func: Box<Expr>, args: Vec<Expr> },
Placeholder,
}
#[derive(Debug, Clone)]
pub enum LookupKey {
Wildcard,
Name(String),
Integer(i64),
Expr(Box<Expr>),
}
#[derive(Debug, Clone, PartialEq)]
pub struct SequenceType {
pub item: ItemType,
pub occurrence: Occurrence,
}
#[derive(Debug, Clone, PartialEq)]
pub struct FunctionSig {
pub params: Vec<SequenceType>,
pub ret: SequenceType,
}
pub type SingleType = SequenceType;
#[derive(Debug, Clone, PartialEq)]
pub enum ItemType {
Any,
Atomic(String),
AnyNode,
Element(Option<String>),
Attribute(Option<String>),
Text,
Comment,
PI(Option<String>),
Document,
Function(Option<Box<FunctionSig>>),
Map,
Array,
EmptySequence,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Occurrence {
One,
Optional,
OneOrMore,
ZeroOrMore,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum QuantifierKind { Some, Every }
#[derive(Debug, Clone)]
pub struct XPathCatch {
pub matchers: Vec<CatchNameTest>,
pub body: Expr,
}
#[derive(Debug, Clone)]
pub enum CatchNameTest {
Any,
LocalNameOnly(String),
PrefixWildcard(String),
QName { prefix: Option<String>, local: String },
}
pub fn max_predicate_nesting(expr: &Expr) -> u32 {
fn expr_depth(e: &Expr) -> u32 {
match e {
Expr::Or(a, b) | Expr::And(a, b)
| Expr::Eq(a, b) | Expr::Ne(a, b)
| Expr::Lt(a, b) | Expr::Gt(a, b) | Expr::Le(a, b) | Expr::Ge(a, b)
| Expr::ValueEq(a, b) | Expr::ValueNe(a, b)
| Expr::ValueLt(a, b) | Expr::ValueGt(a, b)
| Expr::ValueLe(a, b) | Expr::ValueGe(a, b)
| Expr::Add(a, b) | Expr::Sub(a, b)
| Expr::Mul(a, b) | Expr::Div(a, b) | Expr::Mod(a, b)
| Expr::Union(a, b)
| Expr::NodeBefore(a, b) | Expr::NodeAfter(a, b) | Expr::NodeIs(a, b) => expr_depth(a).max(expr_depth(b)),
Expr::Neg(a) => expr_depth(a),
Expr::Path(p) => path_depth(p),
Expr::FilterPath { primary, predicates, steps } => {
let primary_d = expr_depth(primary);
let pred_d = predicates.iter()
.map(|p| 1 + expr_depth(p))
.max()
.unwrap_or(0);
let step_d = steps.iter().map(step_depth).max().unwrap_or(0);
primary_d.max(pred_d).max(step_d)
}
Expr::FunctionCall(_, args) =>
args.iter().map(expr_depth).max().unwrap_or(0),
Expr::Variable(_) | Expr::Literal(_)
| Expr::Integer(_) | Expr::Decimal(_) | Expr::Double(_) => 0,
Expr::IfThenElse { cond, then_branch, else_branch } =>
expr_depth(cond)
.max(expr_depth(then_branch))
.max(expr_depth(else_branch)),
Expr::For { bindings, body } | Expr::Let { bindings, body } => {
let body_d = expr_depth(body);
bindings.iter().map(|(_, e)| expr_depth(e)).max().unwrap_or(0).max(body_d)
}
Expr::Range(a, b) => expr_depth(a).max(expr_depth(b)),
Expr::SimpleMap(a, b) => expr_depth(a).max(expr_depth(b)),
Expr::Sequence(items) =>
items.iter().map(expr_depth).max().unwrap_or(0),
Expr::Quantified { bindings, test, .. } => {
let t = expr_depth(test);
bindings.iter().map(|(_, e)| expr_depth(e)).max().unwrap_or(0).max(t)
}
Expr::IDiv(a, b) | Expr::Intersect(a, b) | Expr::Except(a, b)
=> expr_depth(a).max(expr_depth(b)),
Expr::InstanceOf(a, _) | Expr::CastAs(a, _) | Expr::CastableAs(a, _)
| Expr::TreatAs(a, _) => expr_depth(a),
Expr::TryCatch { body, catches } => {
let b = expr_depth(body);
catches.iter().map(|c| expr_depth(&c.body)).max().unwrap_or(0).max(b)
}
Expr::WithDefaultCollation(_, inner) => expr_depth(inner),
Expr::BackwardsCompat(inner) => expr_depth(inner),
Expr::MapConstructor(entries) => entries.iter()
.map(|(k, v)| expr_depth(k).max(expr_depth(v))).max().unwrap_or(0),
Expr::ArrayConstructor { members, .. } =>
members.iter().map(expr_depth).max().unwrap_or(0),
Expr::Lookup(base, key) => expr_depth(base).max(lookup_key_depth(key)),
Expr::UnaryLookup(key) => lookup_key_depth(key),
Expr::InlineFunction { body, .. } => expr_depth(body),
Expr::NamedFunctionRef { .. } | Expr::Placeholder | Expr::ContextItem => 0,
Expr::DynamicCall { func, args } => expr_depth(func)
.max(args.iter().map(expr_depth).max().unwrap_or(0)),
}
}
fn lookup_key_depth(k: &LookupKey) -> u32 {
match k {
LookupKey::Expr(e) => expr_depth(e),
_ => 0,
}
}
fn step_depth(s: &Step) -> u32 {
s.predicates.iter()
.map(|p| 1 + expr_depth(p))
.max()
.unwrap_or(0)
}
fn path_depth(p: &LocationPath) -> u32 {
let steps = match p {
LocationPath::Absolute(s) | LocationPath::Relative(s) => s,
};
steps.iter().map(step_depth).max().unwrap_or(0)
}
expr_depth(expr)
}