preserves_path/
parse.rs

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(&regex)?;
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}