1
use super::super::context::CompileContext;
2
use super::super::emit::FunctionEmitter;
3
use super::super::expr::{compile_expr, compile_for_stack, eval_value, format_expr};
4
use crate::ast::{Expr, WasmType};
5
use crate::error::{Error, Result};
6
use crate::runtime::SymbolTable;
7

            
8
1188
pub(super) fn list(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
9
1188
    let resolved: Vec<Expr> = args
10
1188
        .iter()
11
3564
        .map(|a| eval_value(symbols, a))
12
1188
        .collect::<Result<_>>()?;
13
1188
    Ok(Expr::Quote(Box::new(Expr::List(resolved))))
14
1188
}
15

            
16
484
pub(super) fn cons(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
17
484
    if args.len() != 2 {
18
88
        return Err(Error::Arity {
19
88
            name: "CONS".to_string(),
20
88
            expected: 2,
21
88
            actual: args.len(),
22
88
        });
23
396
    }
24
396
    let car = eval_value(symbols, &args[0])?;
25
396
    let cdr = eval_value(symbols, &args[1])?;
26
396
    if car.is_wasm_runtime() || cdr.is_wasm_runtime() || cdr.wasm_type() == Some(WasmType::ConsRef)
27
    {
28
308
        return Ok(Expr::WasmRuntime(WasmType::ConsRef));
29
88
    }
30
88
    match cdr {
31
44
        Expr::Quote(inner) => match *inner {
32
44
            Expr::List(mut elems) => {
33
44
                elems.insert(0, car);
34
44
                Ok(Expr::Quote(Box::new(Expr::List(elems))))
35
            }
36
            Expr::Nil => Ok(Expr::Quote(Box::new(Expr::List(vec![car])))),
37
            other => Ok(Expr::Quote(Box::new(Expr::cons(car, other)))),
38
        },
39
44
        Expr::Nil => Ok(Expr::Quote(Box::new(Expr::List(vec![car])))),
40
        other => Ok(Expr::Quote(Box::new(Expr::cons(car, other)))),
41
    }
42
484
}
43

            
44
1640
pub(super) fn car(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
45
1640
    if args.len() != 1 {
46
44
        return Err(Error::Arity {
47
44
            name: "CAR".to_string(),
48
44
            expected: 1,
49
44
            actual: args.len(),
50
44
        });
51
1596
    }
52
1596
    let arg = eval_value(symbols, &args[0])?;
53
1596
    if arg.wasm_type() == Some(WasmType::ConsRef) {
54
980
        return Ok(Expr::WasmRuntime(WasmType::I32));
55
616
    }
56
    match arg {
57
44
        Expr::Nil => Ok(Expr::Nil),
58
        Expr::RuntimeValue(crate::runtime::Value::Struct { name, .. }) => Ok(Expr::Symbol(name)),
59
        Expr::List(elems) => {
60
            if elems.is_empty() {
61
                Ok(Expr::Nil)
62
            } else {
63
                Ok(elems[0].clone())
64
            }
65
        }
66
        Expr::Cons(car, _) => Ok(*car),
67
528
        Expr::Quote(inner) => match *inner {
68
528
            Expr::List(elems) => {
69
528
                if elems.is_empty() {
70
44
                    Ok(Expr::Nil)
71
                } else {
72
484
                    Ok(elems[0].clone())
73
                }
74
            }
75
            Expr::Cons(car, _) => Ok(*car),
76
            Expr::Nil => Ok(Expr::Nil),
77
            other => Err(Error::Compile(format!(
78
                "CAR expects a list, got {}",
79
                format_expr(&other)
80
            ))),
81
        },
82
44
        other => Err(Error::Compile(format!(
83
44
            "CAR expects a list, got {}",
84
44
            format_expr(&other)
85
44
        ))),
86
    }
87
1640
}
88

            
89
710
pub(super) fn cdr(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
90
710
    if args.len() != 1 {
91
44
        return Err(Error::Arity {
92
44
            name: "CDR".to_string(),
93
44
            expected: 1,
94
44
            actual: args.len(),
95
44
        });
96
666
    }
97
666
    let arg = eval_value(symbols, &args[0])?;
98
666
    if arg.wasm_type() == Some(WasmType::ConsRef) {
99
490
        return Ok(Expr::WasmRuntime(WasmType::ConsRef));
100
176
    }
101
    match arg {
102
44
        Expr::Nil => Ok(Expr::Nil),
103
        Expr::RuntimeValue(crate::runtime::Value::Struct { fields, .. }) => {
104
            let tail = fields
105
                .into_iter()
106
                .map(|v| match v {
107
                    crate::runtime::Value::Nil => Expr::Nil,
108
                    crate::runtime::Value::Bool(b) => Expr::Bool(b),
109
                    crate::runtime::Value::Number(n) => Expr::Number(n),
110
                    crate::runtime::Value::String(s) => Expr::String(s),
111
                    crate::runtime::Value::Symbol(s) => Expr::Symbol(s),
112
                    other => Expr::RuntimeValue(other),
113
                })
114
                .collect::<Vec<_>>();
115
            Ok(Expr::Quote(Box::new(Expr::List(tail))))
116
        }
117
        Expr::List(elems) => {
118
            if elems.len() <= 1 {
119
                Ok(Expr::Nil)
120
            } else {
121
                Ok(Expr::Quote(Box::new(Expr::List(elems[1..].to_vec()))))
122
            }
123
        }
124
        Expr::Cons(_, cdr) => Ok(*cdr),
125
88
        Expr::Quote(inner) => match *inner {
126
88
            Expr::List(elems) => {
127
88
                if elems.len() <= 1 {
128
44
                    Ok(Expr::Nil)
129
                } else {
130
44
                    let tail = elems[1..].to_vec();
131
44
                    Ok(Expr::Quote(Box::new(Expr::List(tail))))
132
                }
133
            }
134
            Expr::Cons(_, cdr) => Ok(*cdr),
135
            Expr::Nil => Ok(Expr::Nil),
136
            other => Err(Error::Compile(format!(
137
                "CDR expects a list, got {}",
138
                format_expr(&other)
139
            ))),
140
        },
141
44
        other => Err(Error::Compile(format!(
142
44
            "CDR expects a list, got {}",
143
44
            format_expr(&other)
144
44
        ))),
145
    }
146
710
}
147

            
148
528
pub(super) fn map_fn(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
149
528
    if args.len() < 2 {
150
44
        return Err(Error::Arity {
151
44
            name: "MAP".to_string(),
152
44
            expected: 2,
153
44
            actual: args.len(),
154
44
        });
155
484
    }
156

            
157
484
    let function_arg = &args[0];
158
484
    let list_args = &args[1..];
159

            
160
    // Resolve all list arguments
161
484
    let lists: Vec<Vec<Expr>> = list_args
162
484
        .iter()
163
616
        .map(|arg| {
164
616
            let resolved = eval_value(symbols, arg)?;
165
616
            extract_list_elements(&resolved)
166
616
        })
167
484
        .collect::<Result<_>>()?;
168

            
169
    // Find the shortest list to determine iteration count
170
440
    let min_len = lists.iter().map(std::vec::Vec::len).min().unwrap_or(0);
171

            
172
440
    let mut results = Vec::new();
173

            
174
1364
    fn as_literal_arg(expr: &Expr) -> Expr {
175
1364
        match expr {
176
            Expr::Symbol(_) | Expr::List(_) | Expr::Cons(_, _) => {
177
308
                Expr::Quote(Box::new(expr.clone()))
178
            }
179
1056
            _ => expr.clone(),
180
        }
181
1364
    }
182

            
183
    // Apply function to corresponding elements
184
1056
    for i in 0..min_len {
185
1056
        let mut call_args = vec![function_arg.clone()];
186
1364
        for list in &lists {
187
1364
            call_args.push(as_literal_arg(&list[i]));
188
1364
        }
189

            
190
        // Call the function with the current elements
191
1056
        let result = super::super::expr::call(symbols, &call_args)?;
192
1056
        let resolved_result = eval_value(symbols, &result)?;
193
1056
        results.push(resolved_result);
194
    }
195

            
196
440
    Ok(Expr::Quote(Box::new(Expr::List(results))))
197
528
}
198

            
199
616
pub(super) fn extract_list_elements(expr: &Expr) -> Result<Vec<Expr>> {
200
616
    match expr {
201
        Expr::List(elems) => Ok(elems.clone()),
202
        Expr::Nil => Ok(vec![]),
203
572
        Expr::Quote(inner) => match inner.as_ref() {
204
572
            Expr::List(elems) => Ok(elems.clone()),
205
            Expr::Nil => Ok(vec![]),
206
            other => Err(Error::Compile(format!(
207
                "MAP expects list arguments, got quoted {}",
208
                format_expr(other)
209
            ))),
210
        },
211
44
        other => Err(Error::Compile(format!(
212
44
            "MAP expects list arguments, got {}",
213
44
            format_expr(other)
214
44
        ))),
215
    }
216
616
}
217

            
218
176
pub(super) fn compile_list(
219
176
    ctx: &mut CompileContext,
220
176
    emit: &mut FunctionEmitter,
221
176
    symbols: &mut SymbolTable,
222
176
    args: &[Expr],
223
176
) -> Result<()> {
224
176
    let result = list(symbols, args)?;
225
176
    compile_expr(ctx, emit, symbols, &result)
226
176
}
227

            
228
176
pub(super) fn compile_cons(
229
176
    ctx: &mut CompileContext,
230
176
    emit: &mut FunctionEmitter,
231
176
    symbols: &mut SymbolTable,
232
176
    args: &[Expr],
233
176
) -> Result<()> {
234
176
    let result = cons(symbols, args)?;
235
88
    if result.wasm_type() == Some(WasmType::ConsRef) {
236
        let ty = compile_cons_to_stack(ctx, emit, symbols, args)?;
237
        super::super::expr::serialize_stack_to_output(ctx, emit, ty);
238
        return Ok(());
239
88
    }
240
88
    compile_expr(ctx, emit, symbols, &result)
241
176
}
242

            
243
44
pub(super) fn compile_car(
244
44
    ctx: &mut CompileContext,
245
44
    emit: &mut FunctionEmitter,
246
44
    symbols: &mut SymbolTable,
247
44
    args: &[Expr],
248
44
) -> Result<()> {
249
44
    let result = car(symbols, args)?;
250
44
    if result.wasm_type() == Some(WasmType::I32) && args.len() == 1 {
251
44
        let arg = eval_value(symbols, &args[0])?;
252
44
        if arg.wasm_type() == Some(WasmType::ConsRef) {
253
44
            let ty = compile_car_to_stack(ctx, emit, symbols, args)?;
254
44
            super::super::expr::serialize_stack_to_output(ctx, emit, ty);
255
44
            return Ok(());
256
        }
257
    }
258
    compile_expr(ctx, emit, symbols, &result)
259
44
}
260

            
261
pub(super) fn compile_cdr(
262
    ctx: &mut CompileContext,
263
    emit: &mut FunctionEmitter,
264
    symbols: &mut SymbolTable,
265
    args: &[Expr],
266
) -> Result<()> {
267
    let result = cdr(symbols, args)?;
268
    if result.wasm_type() == Some(WasmType::ConsRef) {
269
        let ty = compile_cdr_to_stack(ctx, emit, symbols, args)?;
270
        super::super::expr::serialize_stack_to_output(ctx, emit, ty);
271
        return Ok(());
272
    }
273
    compile_expr(ctx, emit, symbols, &result)
274
}
275

            
276
1114
pub(super) fn compile_cons_to_stack(
277
1114
    ctx: &mut CompileContext,
278
1114
    emit: &mut FunctionEmitter,
279
1114
    symbols: &mut SymbolTable,
280
1114
    args: &[Expr],
281
1114
) -> Result<WasmType> {
282
1114
    let car_ty = compile_for_stack(ctx, emit, symbols, &args[0])?;
283
1114
    match car_ty {
284
222
        WasmType::I32 => {}
285
892
        WasmType::Ratio => {
286
892
            emit.struct_get(ctx.type_idx("ratio"), 0);
287
892
            emit.i32_wrap_i64();
288
892
        }
289
        WasmType::ConsRef | WasmType::StringRef => {
290
            return Err(Error::Compile(
291
                "CONS car must be i32 or ratio, not cons".to_string(),
292
            ));
293
        }
294
    }
295
1114
    let cdr_resolved = eval_value(symbols, &args[1])?;
296
1114
    if matches!(cdr_resolved, Expr::Nil) {
297
88
        emit.ref_null(ctx.type_idx("cons"));
298
88
    } else {
299
1026
        compile_for_stack(ctx, emit, symbols, &args[1])?;
300
    }
301
1114
    emit.struct_new(ctx.type_idx("cons"));
302
1114
    Ok(WasmType::ConsRef)
303
1114
}
304

            
305
356
pub(super) fn compile_car_to_stack(
306
356
    ctx: &mut CompileContext,
307
356
    emit: &mut FunctionEmitter,
308
356
    symbols: &mut SymbolTable,
309
356
    args: &[Expr],
310
356
) -> Result<WasmType> {
311
356
    compile_for_stack(ctx, emit, symbols, &args[0])?;
312
356
    emit.struct_get(ctx.type_idx("cons"), 0);
313
356
    Ok(WasmType::I32)
314
356
}
315

            
316
178
pub(super) fn compile_cdr_to_stack(
317
178
    ctx: &mut CompileContext,
318
178
    emit: &mut FunctionEmitter,
319
178
    symbols: &mut SymbolTable,
320
178
    args: &[Expr],
321
178
) -> Result<WasmType> {
322
178
    compile_for_stack(ctx, emit, symbols, &args[0])?;
323
178
    emit.struct_get(ctx.type_idx("cons"), 1);
324
178
    Ok(WasmType::ConsRef)
325
178
}
326

            
327
pub(super) fn compile_map(
328
    ctx: &mut CompileContext,
329
    emit: &mut FunctionEmitter,
330
    symbols: &mut SymbolTable,
331
    args: &[Expr],
332
) -> Result<()> {
333
    if args.len() < 2 {
334
        return Err(Error::Arity {
335
            name: "MAP".to_string(),
336
            expected: 2,
337
            actual: args.len(),
338
        });
339
    }
340

            
341
    // For compilation, evaluate the map call and compile the result
342
    let result = map_fn(symbols, args)?;
343
    compile_expr(ctx, emit, symbols, &result)
344
}