1use crate::context::Env;
2use crate::schemas::path;
3use crate::step::Node;
4use crate::CompilationError;
5
6use preserves::value::BinarySource;
7use preserves::value::BytesBinarySource;
8use preserves::value::IOValue;
9use preserves::value::NestedValue;
10use preserves::value::Reader;
11
12use std::iter::Iterator;
13
14#[derive(Debug)]
15enum Binop {
16 Union,
17 Intersection,
18}
19
20fn split_values_by_symbol<'a>(tokens: &'a [IOValue], separator: &str) -> Vec<&'a [IOValue]> {
21 tokens
22 .split(|t| matches!(t.value().as_symbol(), Some(s) if s == separator))
23 .collect()
24}
25
26fn split_binop(tokens: &[IOValue]) -> Result<(Vec<&[IOValue]>, Option<Binop>), CompilationError> {
27 let union_pieces = split_values_by_symbol(&tokens, "+");
28 let intersection_pieces = split_values_by_symbol(&tokens, "&");
29 match (union_pieces.len(), intersection_pieces.len()) {
30 (1, 1) => Ok((union_pieces, None)),
31 (_, 1) => Ok((union_pieces, Some(Binop::Union))),
32 (1, _) => Ok((intersection_pieces, Some(Binop::Intersection))),
33 _ => Err(CompilationError::MixedOperators),
34 }
35}
36
37pub fn parse_selector(env: &Env, tokens: &[IOValue]) -> Result<path::Selector, CompilationError> {
38 let mut steps = Vec::new();
39 let mut tokens = tokens;
40 while let Some((s, remaining)) = parse_step(env, tokens)? {
41 steps.push(s);
42 tokens = remaining;
43 }
44 Ok(path::Selector(steps))
45}
46
47pub fn parse_predicate(env: &Env, tokens: &[IOValue]) -> Result<path::Predicate, CompilationError> {
48 let (pieces, binop) = split_binop(tokens)?;
49 match binop {
50 None => parse_non_binop(env, &pieces[0]),
51 Some(o) => {
52 let preds = pieces
53 .into_iter()
54 .map(|ts| parse_non_binop(env, &ts))
55 .collect::<Result<_, _>>()?;
56 Ok(match o {
57 Binop::Union => path::Predicate::Or { preds },
58 Binop::Intersection => path::Predicate::And { preds },
59 })
60 }
61 }
62}
63
64fn parse_non_binop(env: &Env, tokens: &[IOValue]) -> Result<path::Predicate, CompilationError> {
65 if !tokens.is_empty() {
66 let t = tokens[0].value();
67
68 if let Some("!") = t.as_symbol().map(|s| s.as_str()) {
69 return Ok(path::Predicate::Not {
70 pred: Box::new(parse_non_binop(env, &tokens[1..])?),
71 });
72 }
73 }
74
75 Ok(path::Predicate::Selector(Box::new(parse_selector(
76 env, tokens,
77 )?)))
78}
79
80fn parse_schema_definition_name(
81 env: &Env,
82 token: &IOValue,
83) -> Result<(Vec<String>, String), CompilationError> {
84 let defpath = token
85 .value()
86 .to_symbol()
87 .map_err(|_| CompilationError::InvalidStep)?;
88 let mut module: Vec<String> = defpath.split('.').map(|s| s.to_string()).collect();
89 let name = module
90 .pop()
91 .expect("at least one element in the Schema name");
92 match env.lookup_definition(&module, &name) {
93 Some(_) => Ok((module, name)),
94 None => Err(CompilationError::UndefinedSchemaDefinitionName(format!(
95 "{:?}",
96 token
97 ))),
98 }
99}
100
101fn parse_step<'a>(
102 env: &Env,
103 tokens: &'a [IOValue],
104) -> Result<Option<(path::Step, &'a [IOValue])>, CompilationError> {
105 if tokens.is_empty() {
106 return Ok(None);
107 }
108
109 let remainder = &tokens[1..];
110
111 if tokens[0].value().is_sequence() {
112 return Ok(Some((
113 path::Step::Filter(Box::new(path::Filter::Test {
114 pred: Box::new(parse_predicate(
115 env,
116 tokens[0].value().as_sequence().unwrap(),
117 )?),
118 })),
119 remainder,
120 )));
121 }
122
123 match tokens[0].value().as_record(None) {
124 None => (),
125 Some(r) => match r.label().value().as_symbol() {
126 None => return Err(CompilationError::InvalidStep),
127 Some(t) => match t.as_str() {
128 "count" => {
129 return Ok(Some((
130 path::Step::Function(Box::new(path::Function {
131 selector: parse_selector(env, r.fields())?,
132 })),
133 remainder,
134 )))
135 }
136 _ => return Err(CompilationError::InvalidStep),
137 },
138 },
139 }
140
141 match tokens[0].value().as_symbol() {
142 None => return Err(CompilationError::InvalidStep),
143 Some(t) => match t.as_str() {
144 "/" => Ok(Some((
145 path::Step::Axis(Box::new(path::Axis::Values)),
146 remainder,
147 ))),
148 "//" => Ok(Some((
149 path::Step::Axis(Box::new(path::Axis::Descendants)),
150 remainder,
151 ))),
152 "." => {
153 let (key, remainder) = pop_step_arg(remainder)?;
154 Ok(Some((
155 path::Step::Axis(Box::new(path::Axis::At { key })),
156 remainder,
157 )))
158 }
159 ".^" => Ok(Some((
160 path::Step::Axis(Box::new(path::Axis::Label)),
161 remainder,
162 ))),
163 ".keys" => Ok(Some((
164 path::Step::Axis(Box::new(path::Axis::Keys)),
165 remainder,
166 ))),
167 ".length" => Ok(Some((
168 path::Step::Axis(Box::new(path::Axis::Length)),
169 remainder,
170 ))),
171 ".annotations" => Ok(Some((
172 path::Step::Axis(Box::new(path::Axis::Annotations)),
173 remainder,
174 ))),
175 ".embedded" => Ok(Some((
176 path::Step::Axis(Box::new(path::Axis::Embedded)),
177 remainder,
178 ))),
179 "%" => {
180 let (defpath, remainder) = pop_step_arg(remainder)?;
181 let (module, name) = parse_schema_definition_name(env, &defpath)?;
182 Ok(Some((
183 path::Step::Axis(Box::new(path::Axis::Parse { module, name })),
184 remainder,
185 )))
186 }
187 "%-" => {
188 let (defpath, remainder) = pop_step_arg(remainder)?;
189 let (module, name) = parse_schema_definition_name(env, &defpath)?;
190 Ok(Some((
191 path::Step::Axis(Box::new(path::Axis::Unparse { module, name })),
192 remainder,
193 )))
194 }
195 "*" => Ok(Some((
196 path::Step::Filter(Box::new(path::Filter::Nop)),
197 remainder,
198 ))),
199 "eq" | "=" => parse_comparison(remainder, path::Comparison::Eq),
200 "ne" | "!=" => parse_comparison(remainder, path::Comparison::Ne),
201 "lt" => parse_comparison(remainder, path::Comparison::Lt),
202 "gt" => parse_comparison(remainder, path::Comparison::Gt),
203 "le" => parse_comparison(remainder, path::Comparison::Le),
204 "ge" => parse_comparison(remainder, path::Comparison::Ge),
205 "re" | "=r" => {
206 let (regex_val, remainder) = pop_step_arg(remainder)?;
207 let regex = regex_val
208 .value()
209 .to_string()
210 .map_err(|_| CompilationError::InvalidStep)?
211 .clone();
212 let _ = regex::Regex::new(®ex)?;
213 Ok(Some((
214 path::Step::Filter(Box::new(path::Filter::Regex { regex })),
215 remainder,
216 )))
217 }
218 "^" => {
219 let (literal, remainder) = pop_step_arg(remainder)?;
220 Ok(Some((
221 path::Step::Filter(Box::new(path::Filter::Test {
222 pred: Box::new(path::Predicate::Selector(Box::new(path::Selector(vec![
223 path::Step::Axis(Box::new(path::Axis::Label)),
224 path::Step::Filter(Box::new(path::Filter::Compare {
225 op: Box::new(path::Comparison::Eq),
226 literal,
227 })),
228 ])))),
229 })),
230 remainder,
231 )))
232 }
233
234 "~real" => Ok(Some((
235 path::Step::Filter(Box::new(path::Filter::Real)),
236 remainder,
237 ))),
238 "~int" => Ok(Some((
239 path::Step::Filter(Box::new(path::Filter::Int)),
240 remainder,
241 ))),
242
243 "bool" => Ok(Some((
244 path::Step::from(path::ValueKind::Boolean),
245 remainder,
246 ))),
247 "double" => Ok(Some((path::Step::from(path::ValueKind::Double), remainder))),
248 "int" => Ok(Some((
249 path::Step::from(path::ValueKind::SignedInteger),
250 remainder,
251 ))),
252 "string" => Ok(Some((path::Step::from(path::ValueKind::String), remainder))),
253 "bytes" => Ok(Some((
254 path::Step::from(path::ValueKind::ByteString),
255 remainder,
256 ))),
257 "symbol" => Ok(Some((path::Step::from(path::ValueKind::Symbol), remainder))),
258 "rec" => Ok(Some((path::Step::from(path::ValueKind::Record), remainder))),
259 "seq" => Ok(Some((
260 path::Step::from(path::ValueKind::Sequence),
261 remainder,
262 ))),
263 "set" => Ok(Some((path::Step::from(path::ValueKind::Set), remainder))),
264 "dict" => Ok(Some((
265 path::Step::from(path::ValueKind::Dictionary),
266 remainder,
267 ))),
268 "embedded" => Ok(Some((
269 path::Step::from(path::ValueKind::Embedded),
270 remainder,
271 ))),
272
273 _ => Err(CompilationError::InvalidStep),
274 },
275 }
276}
277
278impl From<path::ValueKind> for path::Step {
279 fn from(k: path::ValueKind) -> Self {
280 path::Step::Filter(Box::new(path::Filter::Kind { kind: Box::new(k) }))
281 }
282}
283
284fn pop_step_arg(tokens: &[IOValue]) -> Result<(IOValue, &[IOValue]), CompilationError> {
285 if tokens.is_empty() {
286 return Err(CompilationError::InvalidStep);
287 }
288 Ok((tokens[0].clone(), &tokens[1..]))
289}
290
291fn parse_comparison(
292 tokens: &[IOValue],
293 op: path::Comparison,
294) -> Result<Option<(path::Step, &[IOValue])>, CompilationError> {
295 let (literal, remainder) = pop_step_arg(tokens)?;
296 Ok(Some((
297 path::Step::Filter(Box::new(path::Filter::Compare {
298 op: Box::new(op),
299 literal,
300 })),
301 remainder,
302 )))
303}
304
305impl path::Selector {
306 pub fn from_str(env: &Env, s: &str) -> Result<Self, CompilationError> {
307 parse_selector(
308 env,
309 &(BytesBinarySource::new(s.as_bytes())
310 .text_iovalues()
311 .configured(false)
312 .collect::<Result<Vec<_>, _>>()?),
313 )
314 }
315}
316
317impl Node {
318 pub fn from_str(env: &Env, s: &str) -> Result<Self, CompilationError> {
319 let expr = path::Selector::from_str(env, s)?;
320 expr.compile()
321 }
322}