1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//! XPath 1.0 implementation (§25, §85 Phase 5).
//!
//! Complete XPath 1.0 engine: location paths, axes, node tests, predicates,
//! functions, variables, namespaces, node sets, boolean/number/string
//! conversion, comparison semantics, NaN/infinity/negative zero, document
//! order, context position/size, extension functions, compiled expressions.
//!
//! # Modules
//!
//! - `ast` — expression AST types (axes, node tests, steps, operators)
//! - `lexer` — tokenizer
//! - `parser` — recursive descent parser
//! - `types` — XPath value types (node sets, numbers, strings, booleans)
//! - `context` — evaluation context (variables, namespaces, functions)
//! - `axes` — axis traversal
//! - `functions` — core function library (25 XPath 1.0 functions)
//! - `eval` — evaluation engine
//!
//! # Upstream contract
//!
//! Mirrors upstream `xpath.c` / `xpathInternals.h`
//! (`SRC-LIBXML2-2.15.0-XPATH-C`, parity target libxml2 2.15.3 oracle):
//! expression compilation, the 13 axes, node tests, predicates, the core
//! function library, value stack semantics and the `xmlXPathObject` /
//! `xmlXPathCompExpr` / `xmlXPathContext` C types (R-000126 restored the
//! full xpathInternals.h header surface; R-000128 fixed the opLimit/
//! opCount field types).
//!
//! # Conceptual behavior
//!
//! The engine implements XPath 1.0 (W3C-XPATH-1.0): the lexer/parser build
//! an AST, `eval` walks it with document-order node-set semantics,
//! IEEE 754 number handling (NaN/infinity/negative zero), boolean/string
//! conversion per §4, context position/size, and the extension-function
//! registry bridged to C callbacks (R-000162).
//!
//! # Ownership & safety invariants
//!
//! `xmlXPathCompile` results are freed with `xmlXPathFreeCompExpr`; XPath
//! objects with `xmlXPathFreeObject` (object owns its node-set/string/
//! number storage). Node-set entries are borrowed tree pointers — the tree
//! outlives evaluation (types.rs `XPathNode` SAFETY note). The parser
//! context bridge owns the value stack and the popped-string copy
//! (R-000169 fixed xml_strdup on a non-NUL-terminated Rust String).
//!
//! # Historical quirks & epochs
//!
//! R-000102 (absolute paths evaluate from the document root node),
//! R-000159 (predicate position() semantics) and R-000166 (number
//! formatting, 1e9/1e-5 threshold, DBL_DIG=15) are upstream behaviors
//! locked by residuals. The node-set dump became newline-separated in the
//! 2.9.10 epoch (E-001, commit da35eeae, an upstream-documented breaking
//! change); the empty-node-set exit-code epochs (E-003) sit at the
//! xmllint layer this engine feeds.
//!
//! # Deliberate oddities
//!
//! `xmlXPathCastNumberToString` trailing-zero trimming, the integer
//! shortcut and the `e+NN`/`e-NN` exponent form are reproduced exactly
//! (R-000166) rather than delegating to Rust float formatting, which
//! differs on exponent width and trimming.
//!
//! # Proving courts
//!
//! XPATH / XPOINTER / XINCLUDE court families, XPATH-001 differential
//! probes (courts/suites/data-abi/*), the 967/967 number() corpus and
//! CLI-XSLTPROC-0014/0015/0017 (format-number) require byte-identical
//! output vs the oracle; cargo test runs the engine suites.
//!
//! # Tempting simplifications that would break parity
//!
//! Do not swap number formatting to `format!("{}")`: the 1e9/1e-5
//! scientific threshold, 15-digit fraction computation and exponent
//! padding are oracle-observable (R-000166). Do not deduplicate node-sets
//! by value instead of pointer, and do not drop the borrowed-node
//! invariant — the C ABI hands out raw node pointers.
use CompiledExpr;
use XPathContext;
use parse_xpath;
use XPathValue;
/// Parse and compile an XPath expression string.
///
/// Returns `None` on parse error.
/// Parse and compile an XPath expression string, exposing the parse error
/// (message + byte offset) for upstream-faithful diagnostics
/// (HOSTILE-FAILURE F3).
/// Evaluate a compiled XPath expression.
///
/// Returns `None` on evaluation error; the error message is recorded on the
/// context (`XPathContext::error`) so callers can surface it exactly as
/// upstream does ("XPath error : ...").
/// Parse and evaluate in one step.