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(®ex)?;
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}