1use tan::{
2 context::Context,
3 error::Error,
4 expr::{expr_clone, format_value, Expr},
5 util::{
6 args::{unpack_map_arg, unpack_map_mut_arg, unpack_stringable_arg},
7 module_util::require_module,
8 },
9};
10
11pub fn map_eq(args: &[Expr]) -> Result<Expr, Error> {
14 let a = unpack_map_arg(args, 0, "a")?;
19 let b = unpack_map_arg(args, 1, "b")?;
20
21 Ok(Expr::Bool(*a == *b))
22}
23
24pub fn map_contains_key(args: &[Expr]) -> Result<Expr, Error> {
28 let [map, key] = args else {
29 return Err(Error::invalid_arguments(
30 "requires `this` and `key` argument",
31 None,
32 ));
33 };
34
35 let Some(items) = map.as_map_mut() else {
36 return Err(Error::invalid_arguments(
37 "`map` argument should be a Map",
38 map.range(),
39 ));
40 };
41
42 let key = format_value(key);
47
48 Ok(Expr::Bool(items.contains_key(&key)))
51}
52
53pub fn map_put(args: &[Expr]) -> Result<Expr, Error> {
57 let [map, key, value] = args else {
58 return Err(Error::invalid_arguments(
59 "requires `this`, `key`, and `value` arguments",
60 None,
61 ));
62 };
63
64 let Some(mut items) = map.as_map_mut() else {
65 return Err(Error::invalid_arguments(
66 "`map` argument should be a Map",
67 map.range(),
68 ));
69 };
70
71 let key = format_value(key);
83
84 items.insert(key.clone(), value.unpack().clone()); Ok(Expr::None)
90}
91
92pub fn map_update_mut(args: &[Expr]) -> Result<Expr, Error> {
98 let [this, other] = args else {
99 return Err(Error::invalid_arguments(
100 "requires `this` and `other` argument",
101 None,
102 ));
103 };
104
105 let Some(mut this_items) = this.as_map_mut() else {
106 return Err(Error::invalid_arguments(
107 "`this` argument should be a Map",
108 this.range(),
109 ));
110 };
111
112 let Some(other_items) = other.as_map() else {
113 return Err(Error::invalid_arguments(
114 "`other` argument should be a Map",
115 other.range(),
116 ));
117 };
118
119 for (key, value) in other_items.iter() {
125 this_items.insert(key.clone(), value.clone());
126 }
127
128 Ok(Expr::None)
131}
132
133pub fn map_get_or(args: &[Expr]) -> Result<Expr, Error> {
139 let [map, key, default_value] = args else {
141 return Err(Error::invalid_arguments(
142 "requires `this` and `key` argument",
143 None,
144 ));
145 };
146
147 let Some(items) = map.as_map_mut() else {
148 return Err(Error::invalid_arguments(
149 "`map` argument should be a Map",
150 map.range(),
151 ));
152 };
153
154 let key = format_value(key);
166
167 let value = items.get(&key);
170
171 if let Some(value) = value {
174 Ok(expr_clone(value))
175 } else {
176 Ok(expr_clone(default_value))
177 }
178}
179
180pub fn map_remove(args: &[Expr]) -> Result<Expr, Error> {
182 let mut map = unpack_map_mut_arg(args, 0, "map")?;
183 let key = unpack_stringable_arg(args, 1, "key")?;
184
185 let value = map.remove(key);
188
189 Ok(value.unwrap_or(Expr::None))
191}
192
193pub fn map_get_keys(args: &[Expr]) -> Result<Expr, Error> {
197 let [map] = args else {
198 return Err(Error::invalid_arguments("requires `this` argument", None));
199 };
200
201 let Some(items) = map.as_map_mut() else {
202 return Err(Error::invalid_arguments(
203 "`map` argument should be a Map",
204 map.range(),
205 ));
206 };
207
208 let keys: Vec<_> = items.keys().map(Expr::string).collect();
209
210 Ok(Expr::array(keys))
211}
212
213pub fn map_get_values(args: &[Expr]) -> Result<Expr, Error> {
214 let [map] = args else {
215 return Err(Error::invalid_arguments("requires `this` argument", None));
216 };
217
218 let Some(items) = map.as_map_mut() else {
219 return Err(Error::invalid_arguments(
220 "`map` argument should be a Map",
221 map.range(),
222 ));
223 };
224
225 let keys: Vec<_> = items.values().map(expr_clone).collect();
226
227 Ok(Expr::array(keys))
228}
229
230pub fn map_get_entries(args: &[Expr]) -> Result<Expr, Error> {
233 let [map] = args else {
234 return Err(Error::invalid_arguments("requires `this` argument", None));
235 };
236
237 let Some(items) = map.as_map_mut() else {
238 return Err(Error::invalid_arguments(
239 "`map` argument should be a Map",
240 map.range(),
241 ));
242 };
243
244 let entries: Vec<_> = items
248 .iter()
249 .map(|(k, v)| Expr::array(vec![Expr::KeySymbol(k.clone()), expr_clone(v)]))
250 .collect();
251
252 Ok(Expr::array(entries))
253}
254
255pub fn setup_lib_map(context: &mut Context) {
256 let module = require_module("prelude", context);
257
258 module.insert_invocable("=$$Map$$Map", Expr::foreign_func(&map_eq));
261
262 module.insert_invocable("contains-key?", Expr::foreign_func(&map_contains_key));
264 module.insert_invocable("contains-key", Expr::foreign_func(&map_contains_key));
266 module.insert_invocable("put", Expr::foreign_func(&map_put));
267 module.insert_invocable("put$$Map", Expr::foreign_func(&map_put));
268 module.insert_invocable("update!", Expr::foreign_func(&map_update_mut));
269 module.insert_invocable("get-or", Expr::foreign_func(&map_get_or));
270
271 module.insert_invocable("remove", Expr::foreign_func(&map_remove));
273
274 module.insert_invocable("get-keys", Expr::foreign_func(&map_get_keys));
276 module.insert_invocable("get-values", Expr::foreign_func(&map_get_values));
277 module.insert_invocable("get-entries", Expr::foreign_func(&map_get_entries));
278 module.insert_invocable("keys-of", Expr::foreign_func(&map_get_keys));
280 module.insert_invocable("values-of", Expr::foreign_func(&map_get_values));
281 module.insert_invocable("entries-of", Expr::foreign_func(&map_get_entries));
282}