Skip to main content

sda_lib/
stdlib.rs

1use crate::number::ExactNum;
2use crate::eval::{apply_lambda, ensure_comparable, EvalError};
3use crate::Value;
4
5pub fn call_stdlib(name: &str, args: Vec<Value>) -> Option<Result<Value, EvalError>> {
6    match name {
7        "typeOf" => Some(stdlib_type_of(args)),
8        "keys" => Some(stdlib_keys(args)),
9        "values" => Some(stdlib_values(args)),
10        "count" => Some(stdlib_count(args)),
11        "normalizeUnique" => Some(stdlib_normalize_unique(args)),
12        "normalizeFirst" => Some(stdlib_normalize_first(args)),
13        "normalizeLast" => Some(stdlib_normalize_last(args)),
14        "Bind" => Some(stdlib_bind(args)),
15        "asBagKV" => Some(stdlib_as_bag_kv(args)),
16        "mapOpt" => Some(stdlib_map_opt(args)),
17        "bindOpt" => Some(stdlib_bind_opt(args)),
18        "orElseOpt" => Some(stdlib_or_else_opt(args)),
19        "mapRes" => Some(stdlib_map_res(args)),
20        "bindRes" => Some(stdlib_bind_res(args)),
21        "orElseRes" => Some(stdlib_or_else_res(args)),
22        _ => None,
23    }
24}
25
26fn wrong_shape() -> Value {
27    Value::Fail_("t_sda_wrong_shape".to_string(), "wrong shape".to_string())
28}
29
30fn check_arity(_name: &str, args: &[Value], expected: usize) -> Result<(), EvalError> {
31    if args.len() != expected {
32        Err(EvalError::ArityMismatch {
33            expected,
34            got: args.len(),
35        })
36    } else {
37        Ok(())
38    }
39}
40
41fn stdlib_type_of(args: Vec<Value>) -> Result<Value, EvalError> {
42    check_arity("typeOf", &args, 1)?;
43    let type_str = match &args[0] {
44        Value::Null => "null",
45        Value::Bool(_) => "bool",
46        Value::Num(_) => "num",
47        Value::Str(_) => "str",
48        Value::Bytes(_) => "bytes",
49        Value::Seq(_) => "seq",
50        Value::Set(_) => "set",
51        Value::Bag(_) => "bag",
52        Value::Map(_) => "map",
53        Value::Prod(_) => "prod",
54        Value::BagKV(_) => "bagkv",
55        Value::Bind(_, _) => "bind",
56        Value::Some_(_) => "some",
57        Value::None_ => "none",
58        Value::Ok_(_) => "ok",
59        Value::Fail_(_, _) => "fail",
60        Value::Lambda(_, _, _) => "fn",
61    };
62    Ok(Value::Str(type_str.to_string()))
63}
64
65fn stdlib_keys(args: Vec<Value>) -> Result<Value, EvalError> {
66    check_arity("keys", &args, 1)?;
67    match &args[0] {
68        Value::Map(entries) => Ok(Value::Set(
69            entries
70                .iter()
71                .map(|(k, _)| Value::Str(k.clone()))
72                .collect(),
73        )),
74        _ => Ok(wrong_shape()),
75    }
76}
77
78fn stdlib_values(args: Vec<Value>) -> Result<Value, EvalError> {
79    check_arity("values", &args, 1)?;
80    match &args[0] {
81        Value::Map(entries) => {
82            let mut sorted = entries.clone();
83            sorted.sort_by(|(left_key, _), (right_key, _)| left_key.cmp(right_key));
84            Ok(Value::Seq(sorted.into_iter().map(|(_, v)| v).collect()))
85        }
86        _ => Ok(wrong_shape()),
87    }
88}
89
90fn stdlib_count(args: Vec<Value>) -> Result<Value, EvalError> {
91    check_arity("count", &args, 2)?;
92    let mut iter = args.into_iter();
93    let needle = iter.next().unwrap();
94    let haystack = iter.next().unwrap();
95    if ensure_comparable(&needle).is_err() {
96        return Ok(wrong_shape());
97    }
98    let n = match &haystack {
99        Value::Bag(items) => {
100            for item in items {
101                if ensure_comparable(item).is_err() {
102                    return Ok(wrong_shape());
103                }
104            }
105            items.iter().filter(|v| *v == &needle).count()
106        }
107        _ => return Ok(wrong_shape()),
108    };
109    Ok(Value::Num(ExactNum::from_usize(n)))
110}
111
112fn stdlib_normalize_unique(args: Vec<Value>) -> Result<Value, EvalError> {
113    check_arity("normalizeUnique", &args, 1)?;
114    match args.into_iter().next().unwrap() {
115        Value::BagKV(pairs) => {
116            let mut map: Vec<(String, Value)> = Vec::new();
117            for (k, v) in pairs {
118                let key_str = match value_as_map_key(&k) {
119                    Ok(key) => key,
120                    Err(_) => {
121                        return Ok(Value::Fail_(
122                            "t_sda_wrong_shape".to_string(),
123                            "wrong shape".to_string(),
124                        ))
125                    }
126                };
127                if map.iter().any(|(existing_key, _)| existing_key == &key_str) {
128                    return Ok(Value::Fail_(
129                        "t_sda_duplicate_key".to_string(),
130                        "duplicate key".to_string(),
131                    ));
132                }
133                map.push((key_str, v));
134            }
135            Ok(Value::Ok_(Box::new(Value::Map(map))))
136        }
137        _ => Ok(Value::Fail_(
138            "t_sda_wrong_shape".to_string(),
139            "wrong shape".to_string(),
140        )),
141    }
142}
143
144fn stdlib_normalize_first(args: Vec<Value>) -> Result<Value, EvalError> {
145    check_arity("normalizeFirst", &args, 1)?;
146    match args.into_iter().next().unwrap() {
147        Value::BagKV(pairs) => {
148            let mut map: Vec<(String, Value)> = Vec::new();
149            for (k, v) in pairs {
150                let key_str = match value_as_map_key(&k) {
151                    Ok(key) => key,
152                    Err(_) => {
153                        return Ok(Value::Fail_(
154                            "t_sda_wrong_shape".to_string(),
155                            "wrong shape".to_string(),
156                        ))
157                    }
158                };
159                if !map.iter().any(|(existing_key, _)| existing_key == &key_str) {
160                    map.push((key_str, v));
161                }
162            }
163            Ok(Value::Map(map))
164        }
165        _ => Ok(Value::Fail_(
166            "t_sda_wrong_shape".to_string(),
167            "wrong shape".to_string(),
168        )),
169    }
170}
171
172fn stdlib_normalize_last(args: Vec<Value>) -> Result<Value, EvalError> {
173    check_arity("normalizeLast", &args, 1)?;
174    match args.into_iter().next().unwrap() {
175        Value::BagKV(pairs) => {
176            let mut map: Vec<(String, Value)> = Vec::new();
177            for (k, v) in pairs {
178                let key_str = match value_as_map_key(&k) {
179                    Ok(key) => key,
180                    Err(_) => {
181                        return Ok(Value::Fail_(
182                            "t_sda_wrong_shape".to_string(),
183                            "wrong shape".to_string(),
184                        ))
185                    }
186                };
187                if let Some(existing) = map.iter_mut().find(|(existing_key, _)| existing_key == &key_str) {
188                    existing.1 = v;
189                } else {
190                    map.push((key_str, v));
191                }
192            }
193            Ok(Value::Map(map))
194        }
195        _ => Ok(Value::Fail_(
196            "t_sda_wrong_shape".to_string(),
197            "wrong shape".to_string(),
198        )),
199    }
200}
201
202fn value_as_map_key(v: &Value) -> Result<String, EvalError> {
203    match v {
204        Value::Str(s) => Ok(s.clone()),
205        other => Err(EvalError::TypeError(format!(
206            "Map key must be a string, got {other:?}"
207        ))),
208    }
209}
210
211fn stdlib_bind(args: Vec<Value>) -> Result<Value, EvalError> {
212    check_arity("Bind", &args, 2)?;
213    let mut iter = args.into_iter();
214    let k = iter.next().unwrap();
215    let v = iter.next().unwrap();
216    Ok(Value::Bind(Box::new(k), Box::new(v)))
217}
218
219fn stdlib_as_bag_kv(args: Vec<Value>) -> Result<Value, EvalError> {
220    check_arity("asBagKV", &args, 1)?;
221    match args.into_iter().next().unwrap() {
222        Value::Bag(items) => {
223            let mut pairs = Vec::new();
224            for item in items {
225                match item {
226                    Value::Bind(k, v) => match *k {
227                        Value::Str(s) => pairs.push((Value::Str(s), *v)),
228                        _ => {
229                            return Ok(Value::Fail_(
230                                "t_sda_wrong_shape".to_string(),
231                                "wrong shape".to_string(),
232                            ))
233                        }
234                    },
235                    _ => {
236                        return Ok(Value::Fail_(
237                            "t_sda_wrong_shape".to_string(),
238                            "wrong shape".to_string(),
239                        ))
240                    }
241                }
242            }
243            Ok(Value::Ok_(Box::new(Value::BagKV(pairs))))
244        }
245        _ => Ok(Value::Fail_(
246            "t_sda_wrong_shape".to_string(),
247            "wrong shape".to_string(),
248        )),
249    }
250}
251
252fn stdlib_map_opt(args: Vec<Value>) -> Result<Value, EvalError> {
253    check_arity("mapOpt", &args, 2)?;
254    let mut iter = args.into_iter();
255    let opt = iter.next().unwrap();
256    let f = iter.next().unwrap();
257    match opt {
258        Value::Some_(inner) => {
259            let result = apply_lambda(f, vec![*inner])?;
260            Ok(Value::Some_(Box::new(result)))
261        }
262        Value::None_ => Ok(Value::None_),
263        _ => Ok(wrong_shape()),
264    }
265}
266
267fn stdlib_bind_opt(args: Vec<Value>) -> Result<Value, EvalError> {
268    check_arity("bindOpt", &args, 2)?;
269    let mut iter = args.into_iter();
270    let opt = iter.next().unwrap();
271    let f = iter.next().unwrap();
272    match opt {
273        Value::Some_(inner) => apply_lambda(f, vec![*inner]),
274        Value::None_ => Ok(Value::None_),
275        _ => Ok(wrong_shape()),
276    }
277}
278
279fn stdlib_or_else_opt(args: Vec<Value>) -> Result<Value, EvalError> {
280    check_arity("orElseOpt", &args, 2)?;
281    let mut iter = args.into_iter();
282    let opt = iter.next().unwrap();
283    let default = iter.next().unwrap();
284    match opt {
285        Value::Some_(inner) => Ok(Value::Some_(inner)),
286        Value::None_ => Ok(default),
287        _ => Ok(wrong_shape()),
288    }
289}
290
291fn stdlib_map_res(args: Vec<Value>) -> Result<Value, EvalError> {
292    check_arity("mapRes", &args, 2)?;
293    let mut iter = args.into_iter();
294    let res = iter.next().unwrap();
295    let f = iter.next().unwrap();
296    match res {
297        Value::Ok_(inner) => {
298            let result = apply_lambda(f, vec![*inner])?;
299            Ok(Value::Ok_(Box::new(result)))
300        }
301        Value::Fail_(c, m) => Ok(Value::Fail_(c, m)),
302        _ => Ok(wrong_shape()),
303    }
304}
305
306fn stdlib_bind_res(args: Vec<Value>) -> Result<Value, EvalError> {
307    check_arity("bindRes", &args, 2)?;
308    let mut iter = args.into_iter();
309    let res = iter.next().unwrap();
310    let f = iter.next().unwrap();
311    match res {
312        Value::Ok_(inner) => apply_lambda(f, vec![*inner]),
313        Value::Fail_(c, m) => Ok(Value::Fail_(c, m)),
314        _ => Ok(wrong_shape()),
315    }
316}
317
318fn stdlib_or_else_res(args: Vec<Value>) -> Result<Value, EvalError> {
319    check_arity("orElseRes", &args, 2)?;
320    let mut iter = args.into_iter();
321    let res = iter.next().unwrap();
322    let default = iter.next().unwrap();
323    match res {
324        Value::Ok_(inner) => Ok(Value::Ok_(inner)),
325        Value::Fail_(_, _) => Ok(default),
326        _ => Ok(wrong_shape()),
327    }
328}