preserves_path/
parse.rs

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