PureXML/Sources/XPath/Expression.swift
Mihaela Mihaljevic d83e5a88ce feat(xpath): expression engine and the four-type model
Compile and evaluate full XPath 1.0 expressions, not just location paths.
Add the four-type Value (node-set, boolean, number, string) with the spec's
coercion rules and canonical number formatting, a recursive-descent parser
for the operator grammar (or/and, equality, relational, additive,
multiplicative, unary minus, union) whose grammatical position disambiguates
* and the operator keywords, function calls, variable references, and filter
expressions. Predicates are now arbitrary expressions (a numeric predicate
is a position test). Comparison follows the node-set quantification rules.
Query gains value/number/string/boolean accessors and a $variable binding
map; the core functions last, position, count, not, true, false, boolean,
number, and string ship with it.

Closes #42
2026-06-08 05:33:13 +02:00

44 lines
1.5 KiB
Swift

extension PureXML.XPath {
/// A binary operator of the XPath expression language, grouped by the
/// precedence level its parser method handles.
enum BinaryOperator: Equatable {
case logicalOr
case logicalAnd
case equal
case notEqual
case lessThan
case lessOrEqual
case greaterThan
case greaterOrEqual
case add
case subtract
case multiply
case divide
case modulo
}
/// A compiled XPath expression. A bare location path is ``path``; the operator
/// grammar, function calls, variables, and filter expressions build on it.
indirect enum Expression: Equatable, Sendable {
/// A location path: absolute when rooted, with its ordered steps.
case path(absolute: Bool, steps: [Step])
/// A binary operation.
case binary(BinaryOperator, Expression, Expression)
/// Unary minus.
case negate(Expression)
/// A node-set union (`|`).
case union(Expression, Expression)
/// A numeric literal.
case number(Double)
/// A string literal.
case string(String)
/// A function call.
case function(name: String, arguments: [Expression])
/// A variable reference (`$name`).
case variable(String)
/// A primary expression with predicates and an optional trailing path
/// (`(expr)[p]/step`, `id('x')/step`).
case filter(primary: Expression, predicates: [Expression], steps: [Step])
}
}