cljrs_runtime/interp/
destructure.rs1use crate::builtins::form::form_to_value;
4use cljrs_gc::GcPtr;
5use cljrs_reader::Form;
6use cljrs_reader::form::FormKind;
7use cljrs_value::{Keyword, PersistentList, Symbol, Value};
8use std::sync::Arc;
9
10use crate::env::env::Env;
11use crate::env::error::{EvalError, EvalResult};
12
13pub fn bind_pattern(pattern: &Form, val: Value, env: &mut Env) -> EvalResult<()> {
19 match &pattern.kind {
20 FormKind::Symbol(s) => {
21 env.bind(Arc::from(s.as_str()), val);
23 Ok(())
24 }
25 FormKind::Vector(forms) => bind_sequential(forms, &val, env),
26 FormKind::Map(forms) => bind_associative(forms, &val, env),
27 FormKind::Meta(_, inner) => bind_pattern(inner, val, env),
30 _ => Err(EvalError::Runtime(format!(
31 "unsupported binding pattern: {:?}",
32 pattern.kind
33 ))),
34 }
35}
36
37pub fn bind_sequential(pattern: &[Form], val: &Value, env: &mut Env) -> EvalResult<()> {
44 let items = value_to_seq_vec(val);
45 let mut idx = 0usize;
46 let mut i = 0usize;
47
48 while i < pattern.len() {
49 let p = &pattern[i];
50
51 if matches!(&p.kind, FormKind::Symbol(s) if s == "&") {
53 i += 1;
54 let rest_pat = pattern
55 .get(i)
56 .ok_or_else(|| EvalError::Runtime("& in destructuring requires a name".into()))?;
57 let rest_list = if idx < items.len() {
58 let rest_vals: Vec<Value> = items[idx..].to_vec();
59 Value::List(GcPtr::new(PersistentList::from_iter(rest_vals)))
60 } else {
61 Value::Nil
62 };
63 bind_pattern(rest_pat, rest_list, env)?;
64 i += 1;
65 if i < pattern.len()
67 && let FormKind::Keyword(k) = &pattern[i].kind
68 && k == "as"
69 {
70 i += 1;
71 let alias = pattern
72 .get(i)
73 .ok_or_else(|| EvalError::Runtime(":as requires a name".into()))?;
74 bind_pattern(alias, val.clone(), env)?;
75 }
76 break;
77 }
78
79 if let FormKind::Keyword(k) = &p.kind
81 && k == "as"
82 {
83 i += 1;
84 let alias = pattern
85 .get(i)
86 .ok_or_else(|| EvalError::Runtime(":as requires a name".into()))?;
87 bind_pattern(alias, val.clone(), env)?;
88 break;
89 }
90
91 let item = items.get(idx).cloned().unwrap_or(Value::Nil);
93 bind_pattern(p, item, env)?;
94 idx += 1;
95 i += 1;
96 }
97
98 Ok(())
99}
100
101pub fn value_to_seq_vec(val: &Value) -> Vec<Value> {
103 match val {
104 Value::WithMeta(inner, _) => value_to_seq_vec(inner),
105 Value::Nil => vec![],
106 Value::LazySeq(ls) => value_to_seq_vec(&ls.get().realize()),
107 Value::Cons(c) => {
108 let mut result = vec![c.get().head.clone()];
109 let mut tail = c.get().tail.clone();
110 loop {
111 match tail {
112 Value::Nil => break,
113 Value::List(l) => {
114 result.extend(l.get().iter().cloned());
115 break;
116 }
117 Value::Cons(next_c) => {
118 result.push(next_c.get().head.clone());
119 tail = next_c.get().tail.clone();
120 }
121 Value::LazySeq(ls) => {
122 tail = ls.get().realize();
123 }
124 _ => break,
125 }
126 }
127 result
128 }
129 Value::List(l) => l.get().iter().cloned().collect(),
130 Value::Vector(v) => v.get().iter().cloned().collect(),
131 Value::Set(s) => s.iter().cloned().collect(),
132 Value::Map(m) => {
133 let mut result = Vec::new();
134 m.for_each(|k, v| {
135 result.push(Value::map_entry(k.clone(), v.clone()));
136 });
137 result
138 }
139 _ => vec![],
140 }
141}
142
143pub fn bind_associative(pattern: &[Form], val: &Value, env: &mut Env) -> EvalResult<()> {
157 let mut defaults: std::collections::HashMap<String, Value> = std::collections::HashMap::new();
159 let mut i = 0;
160 while i + 1 < pattern.len() {
161 let k = &pattern[i];
162 let v = &pattern[i + 1];
163 if let FormKind::Keyword(kw) = &k.kind
164 && kw == "or"
165 {
166 if let FormKind::Map(or_forms) = &v.kind {
168 let mut j = 0;
169 while j + 1 < or_forms.len() {
170 if let FormKind::Symbol(sym) = &or_forms[j].kind {
171 defaults.insert(sym.clone(), form_to_value(&or_forms[j + 1])?);
172 }
173 j += 2;
174 }
175 }
176 }
177 i += 2;
178 }
179
180 let get_val = |key: &Value| -> Value {
181 match val.unwrap_meta() {
182 Value::Map(m) => m.get(key).unwrap_or(Value::Nil),
183 _ => Value::Nil,
184 }
185 };
186
187 let mut i = 0;
188 while i + 1 < pattern.len() {
189 let k = &pattern[i];
190 let v = &pattern[i + 1];
191 i += 2;
192
193 let directive_ns = if let FormKind::Keyword(kw) = &k.kind {
198 Keyword::parse(kw).namespace
199 } else {
200 None
201 };
202 let directive_name = if let FormKind::Keyword(kw) = &k.kind {
203 Keyword::parse(kw).name.to_string()
204 } else {
205 String::new()
206 };
207
208 match &k.kind {
209 FormKind::Keyword(_) if directive_name == "keys" => {
210 if let FormKind::Vector(syms) = &v.kind {
211 for sym_form in syms {
212 if let FormKind::Symbol(sym) = &sym_form.kind {
213 let parsed = Symbol::parse(sym);
214 let key =
215 match parsed.namespace.clone().or_else(|| directive_ns.clone()) {
216 Some(ns) => {
217 Value::keyword(Keyword::qualified(ns, parsed.name.clone()))
218 }
219 None => Value::keyword(Keyword::simple(parsed.name.clone())),
220 };
221 let mut bound_val = get_val(&key);
222 if matches!(bound_val, Value::Nil)
223 && let Some(d) = defaults.get(parsed.name.as_ref())
224 {
225 bound_val = d.clone();
226 }
227 env.bind(parsed.name.clone(), bound_val);
228 }
229 }
230 }
231 }
232 FormKind::Keyword(kw) if kw == "strs" => {
233 if let FormKind::Vector(syms) = &v.kind {
234 for sym_form in syms {
235 if let FormKind::Symbol(sym) = &sym_form.kind {
236 let key = Value::string(sym.clone());
237 let mut bound_val = get_val(&key);
238 if matches!(bound_val, Value::Nil)
239 && let Some(d) = defaults.get(sym.as_str())
240 {
241 bound_val = d.clone();
242 }
243 env.bind(Arc::from(sym.as_str()), bound_val);
244 }
245 }
246 }
247 }
248 FormKind::Keyword(_) if directive_name == "syms" => {
249 if let FormKind::Vector(syms) = &v.kind {
250 for sym_form in syms {
251 if let FormKind::Symbol(sym) = &sym_form.kind {
252 let parsed = Symbol::parse(sym);
253 let key =
254 match parsed.namespace.clone().or_else(|| directive_ns.clone()) {
255 Some(ns) => {
256 Value::symbol(Symbol::qualified(ns, parsed.name.clone()))
257 }
258 None => Value::symbol(Symbol::simple(parsed.name.clone())),
259 };
260 let mut bound_val = get_val(&key);
261 if matches!(bound_val, Value::Nil)
262 && let Some(d) = defaults.get(parsed.name.as_ref())
263 {
264 bound_val = d.clone();
265 }
266 env.bind(parsed.name.clone(), bound_val);
267 }
268 }
269 }
270 }
271 FormKind::Keyword(kw) if kw == "as" => {
272 if let FormKind::Symbol(sym) = &v.kind {
273 env.bind(Arc::from(sym.as_str()), val.clone());
274 }
275 }
276 FormKind::Keyword(kw) if kw == "or" => {
277 }
279 _ => {
280 let lookup_key = form_to_value(v)?;
284 let mut bound_val = get_val(&lookup_key);
285 if matches!(bound_val, Value::Nil)
287 && let FormKind::Symbol(sym) = &k.kind
288 && let Some(d) = defaults.get(sym.as_str())
289 {
290 bound_val = d.clone();
291 }
292 bind_pattern(k, bound_val, env)?;
294 }
295 }
296 }
297 Ok(())
298}