1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
//! Macro expansion pipeline.
use cljrs_builtins::form::form_to_value;
use cljrs_reader::Form;
use cljrs_reader::form::FormKind;
use cljrs_types::span::Span;
use cljrs_value::{Symbol, Value};
use std::sync::Arc;
use cljrs_env::env::Env;
use cljrs_env::error::{EvalError, EvalResult};
/// Expand a form one step. Returns the same form if it is not a macro call.
pub fn macroexpand_1(form: &Form, env: &mut Env) -> EvalResult<Form> {
// Only expand list forms whose head is a macro symbol.
if let FormKind::List(parts) = &form.kind
&& let Some(FormKind::Symbol(s)) = parts.first().map(|f| &f.kind)
&& let Some(macro_fn) = resolve_macro(s, env)
{
// Build &form value (the whole call as a list).
let form_val = form_to_value(form);
// Build &env value (local bindings as a map — empty at top level).
let env_val = {
let (names, vals) = env.all_local_bindings();
let mut m = cljrs_value::MapValue::empty();
for (name, val) in names.iter().zip(vals.iter()) {
m = m.assoc(Value::symbol(Symbol::simple(name.as_ref())), val.clone());
}
Value::Map(m)
};
let mut args = vec![form_val, env_val];
args.extend(parts[1..].iter().map(form_to_value));
let expanded = crate::apply::call_cljrs_fn(¯o_fn, &args, env)?;
let dummy = Span::new(Arc::new("<macro>".to_string()), 0, 0, 1, 1);
return value_to_form(&expanded, dummy);
}
Ok(form.clone())
}
/// Fully expand a form until the head is no longer a macro.
pub fn macroexpand(form: &Form, env: &mut Env) -> EvalResult<Form> {
let mut current = form.clone();
loop {
let expanded = macroexpand_1(¤t, env)?;
if expanded == current {
return Ok(current);
}
current = expanded;
}
}
/// Recursively macro-expand all forms in a tree.
///
/// First expands the top-level form, then walks into sub-forms.
/// Special forms like `quote` are not walked into.
pub fn macroexpand_all(form: &Form, env: &mut Env) -> EvalResult<Form> {
// First, expand the top level.
let expanded = macroexpand(form, env)?;
let span = expanded.span.clone();
let kind = match &expanded.kind {
FormKind::List(parts) if !parts.is_empty() => {
// Check if the head is a special form that shouldn't be walked.
let head_name = match &parts[0].kind {
FormKind::Symbol(s) => Some(s.as_str()),
_ => None,
};
match head_name {
// quote: don't expand inside quoted forms
Some("quote") => return Ok(expanded),
// fn*: expand body forms but not the param vector
Some("fn*") => {
let mut new_parts = vec![parts[0].clone()];
// fn* can have multiple arities: (fn* ([x] body) ([x y] body2))
// or single arity: (fn* [x] body)
if parts.len() > 1 {
if let FormKind::Vector(_) = &parts[1].kind {
// Single arity: (fn* [params] body...)
new_parts.push(parts[1].clone()); // params
for p in &parts[2..] {
new_parts.push(macroexpand_all(p, env)?);
}
} else {
// Multi-arity: (fn* ([params] body) ...)
for arity in &parts[1..] {
if let FormKind::List(arity_parts) = &arity.kind {
let mut new_arity = Vec::new();
if let Some(params) = arity_parts.first() {
new_arity.push(params.clone()); // param vector
}
for p in arity_parts.iter().skip(1) {
new_arity.push(macroexpand_all(p, env)?);
}
new_parts.push(Form::new(
FormKind::List(new_arity),
arity.span.clone(),
));
} else {
// Name or other token before arities
new_parts.push(arity.clone());
}
}
}
}
FormKind::List(new_parts)
}
// let*, loop*: expand bindings values and body, but not binding names
Some("let*") | Some("loop*") => {
let mut new_parts = vec![parts[0].clone()];
if parts.len() > 1 {
// Expand binding values (every other form in the vector)
if let FormKind::Vector(bindings) = &parts[1].kind {
let mut new_bindings = Vec::new();
for (i, b) in bindings.iter().enumerate() {
if i % 2 == 0 {
new_bindings.push(b.clone()); // binding name
} else {
new_bindings.push(macroexpand_all(b, env)?);
}
}
new_parts.push(Form::new(
FormKind::Vector(new_bindings),
parts[1].span.clone(),
));
} else {
new_parts.push(parts[1].clone());
}
for p in &parts[2..] {
new_parts.push(macroexpand_all(p, env)?);
}
}
FormKind::List(new_parts)
}
// catch/finally inside try: handled naturally by walking
_ => {
// Generic: expand all sub-forms
let new_parts = parts
.iter()
.map(|p| macroexpand_all(p, env))
.collect::<EvalResult<Vec<_>>>()?;
FormKind::List(new_parts)
}
}
}
FormKind::Vector(items) => {
let new_items = items
.iter()
.map(|i| macroexpand_all(i, env))
.collect::<EvalResult<Vec<_>>>()?;
FormKind::Vector(new_items)
}
FormKind::Map(items) => {
let new_items = items
.iter()
.map(|i| macroexpand_all(i, env))
.collect::<EvalResult<Vec<_>>>()?;
FormKind::Map(new_items)
}
FormKind::Set(items) => {
let new_items = items
.iter()
.map(|i| macroexpand_all(i, env))
.collect::<EvalResult<Vec<_>>>()?;
FormKind::Set(new_items)
}
// Atoms, keywords, strings, etc. — no sub-forms.
_ => return Ok(expanded),
};
Ok(Form::new(kind, span))
}
/// If `sym` resolves to a macro in the current env, return its CljxFn.
fn resolve_macro(sym: &str, env: &Env) -> Option<cljrs_value::CljxFn> {
let parsed = Symbol::parse(sym);
let ns = parsed.namespace.as_deref().unwrap_or(&env.current_ns);
let name = parsed.name.as_ref();
let v = env.globals.lookup_in_ns(ns, name)?;
if let Value::Macro(f) = v {
Some(f.get().clone())
} else {
None
}
}
/// Convert a `Value` to a `Form` (inverse of `form_to_value`).
///
/// Used to convert a macro's output back to a Form for further evaluation.
pub fn value_to_form(val: &Value, span: Span) -> EvalResult<Form> {
let kind = match val {
Value::Nil => FormKind::Nil,
Value::Bool(b) => FormKind::Bool(*b),
Value::Long(n) => FormKind::Int(*n),
Value::Double(f) => FormKind::Float(*f),
Value::Str(s) => FormKind::Str(s.get().clone()),
Value::Char(c) => FormKind::Char(*c),
Value::BigInt(b) => FormKind::BigInt(b.get().to_string()),
Value::BigDecimal(d) => FormKind::BigDecimal(d.get().to_string()),
Value::Ratio(r) => FormKind::Ratio(format!("{}/{}", r.get().numer(), r.get().denom())),
Value::Symbol(s) => FormKind::Symbol(s.get().full_name()),
Value::Keyword(k) => FormKind::Keyword(k.get().full_name()),
Value::List(l) => {
let items = l.get();
// Reconstruct reader special forms that were encoded as lists by form_to_value.
let head_sym = items.iter().next().and_then(|v| {
if let Value::Symbol(s) = v {
Some(s.get().name.clone())
} else {
None
}
});
match (head_sym.as_deref(), items.count()) {
(Some("syntax-quote"), 2) => {
let inner = value_to_form(items.iter().nth(1).unwrap(), span.clone())?;
FormKind::SyntaxQuote(Box::new(inner))
}
(Some("unquote"), 2) => {
let inner = value_to_form(items.iter().nth(1).unwrap(), span.clone())?;
FormKind::Unquote(Box::new(inner))
}
(Some("unquote-splicing"), 2) => {
let inner = value_to_form(items.iter().nth(1).unwrap(), span.clone())?;
FormKind::UnquoteSplice(Box::new(inner))
}
_ => {
let forms: Vec<Form> = items
.iter()
.map(|v| value_to_form(v, span.clone()))
.collect::<EvalResult<_>>()?;
FormKind::List(forms)
}
}
}
Value::Vector(v) => {
let forms: Vec<Form> = v
.get()
.iter()
.map(|v| value_to_form(v, span.clone()))
.collect::<EvalResult<_>>()?;
FormKind::Vector(forms)
}
Value::Map(m) => {
let mut forms = Vec::new();
let mut err: Option<EvalError> = None;
let sc = span.clone();
m.for_each(|k, v| {
if err.is_none() {
match (value_to_form(k, sc.clone()), value_to_form(v, sc.clone())) {
(Ok(kf), Ok(vf)) => {
forms.push(kf);
forms.push(vf);
}
(Err(e), _) | (_, Err(e)) => err = Some(e),
}
}
});
if let Some(e) = err {
return Err(e);
}
FormKind::Map(forms)
}
Value::Set(s) => {
let forms: Vec<Form> = s
.iter()
.map(|v| value_to_form(v, span.clone()))
.collect::<EvalResult<_>>()?;
FormKind::Set(forms)
}
// Lazy sequences and cons cells: materialize into a list form.
// This handles macro output like (cons 'do (map ...)).
Value::LazySeq(ls) => {
return value_to_form(&ls.get().realize(), span);
}
Value::Cons(c) => {
let mut items: Vec<Form> = Vec::new();
let mut cur = Value::Cons(c.clone());
loop {
match cur {
Value::Cons(cell) => {
items.push(value_to_form(&cell.get().head, span.clone())?);
cur = cell.get().tail.clone();
}
Value::LazySeq(ls) => cur = ls.get().realize(),
Value::List(l) => {
for v in l.get().iter() {
items.push(value_to_form(v, span.clone())?);
}
break;
}
Value::Nil => break,
_ => break,
}
}
FormKind::List(items)
}
Value::Uuid(u) => {
let uuid_str = uuid::Uuid::from_u128(*u).to_string();
FormKind::TaggedLiteral(
"uuid".to_string(),
Box::new(Form::new(FormKind::Str(uuid_str), span.clone())),
)
}
// WithMeta: strip metadata and convert the inner value.
Value::WithMeta(inner, _) => {
return value_to_form(inner, span);
}
Value::Pattern(p) => FormKind::Regex(p.get().as_str().to_string()),
// Non-data types: wrap in a symbol placeholder (best effort).
other => FormKind::Symbol(format!("#<{}>", other.type_name())),
};
Ok(Form::new(kind, span))
}