1
use crate::ast::{Expr, LambdaParams, WasmType};
2
use crate::error::{Error, Result};
3
use crate::runtime::{Symbol, SymbolKind, SymbolTable};
4

            
5
use super::super::context::CompileContext;
6
use super::super::emit::FunctionEmitter;
7
use super::super::expr::{
8
    compile_body, compile_body_for_stack, compile_expr, compile_for_effect, compile_for_stack,
9
    eval_value,
10
};
11

            
12
90
pub(super) fn compile_defun(
13
90
    ctx: &mut CompileContext,
14
90
    emit: &mut FunctionEmitter,
15
90
    symbols: &mut SymbolTable,
16
90
    args: &[Expr],
17
90
) -> Result<()> {
18
90
    let result = defun(symbols, args)?;
19
90
    compile_expr(ctx, emit, symbols, &result)
20
90
}
21

            
22
pub(super) fn compile_defvar(
23
    ctx: &mut CompileContext,
24
    emit: &mut FunctionEmitter,
25
    symbols: &mut SymbolTable,
26
    args: &[Expr],
27
) -> Result<()> {
28
    let result = defvar(symbols, args)?;
29
    compile_expr(ctx, emit, symbols, &result)
30
}
31

            
32
pub(super) fn compile_defparam(
33
    ctx: &mut CompileContext,
34
    emit: &mut FunctionEmitter,
35
    symbols: &mut SymbolTable,
36
    args: &[Expr],
37
) -> Result<()> {
38
    let result = defparameter(symbols, args)?;
39
    compile_expr(ctx, emit, symbols, &result)
40
}
41

            
42
660
pub(super) fn compile_let(
43
660
    ctx: &mut CompileContext,
44
660
    emit: &mut FunctionEmitter,
45
660
    symbols: &mut SymbolTable,
46
660
    args: &[Expr],
47
660
) -> Result<()> {
48
660
    if args.len() < 2 {
49
44
        return Err(Error::Compile(
50
44
            "LET requires a bindings list and at least one body form".to_string(),
51
44
        ));
52
616
    }
53
616
    let bindings = parse_bindings("LET", &args[0])?;
54
    // Evaluate all bindings in the outer scope (parallel semantics)
55
572
    let resolved: Vec<(String, Option<Expr>, Expr)> = bindings
56
572
        .into_iter()
57
748
        .map(|(name, init)| {
58
748
            let (orig, val) = match init {
59
704
                Some(expr) => {
60
704
                    let v = eval_value(symbols, &expr)?;
61
704
                    (Some(expr), v)
62
                }
63
44
                None => (None, Expr::Nil),
64
            };
65
748
            Ok((name, orig, val))
66
748
        })
67
572
        .collect::<Result<_>>()?;
68
572
    let mut local = symbols.clone();
69
748
    for (name, init_expr, val) in resolved {
70
748
        let bound = bind_runtime_or_const(ctx, emit, symbols, init_expr.as_ref(), &val)?;
71
748
        local.define(Symbol::new(&name, SymbolKind::Variable).with_value(bound));
72
    }
73
572
    compile_body(ctx, emit, &mut local, &args[1..])
74
660
}
75

            
76
1072
pub(super) fn compile_let_for_stack(
77
1072
    ctx: &mut CompileContext,
78
1072
    emit: &mut FunctionEmitter,
79
1072
    symbols: &mut SymbolTable,
80
1072
    args: &[Expr],
81
1072
) -> Result<WasmType> {
82
1072
    if args.len() < 2 {
83
        return Err(Error::Compile(
84
            "LET requires a bindings list and at least one body form".to_string(),
85
        ));
86
1072
    }
87
1072
    let bindings = parse_bindings("LET", &args[0])?;
88
1072
    let resolved: Vec<(String, Option<Expr>, Expr)> = bindings
89
1072
        .into_iter()
90
1072
        .map(|(name, init)| {
91
1072
            let (orig, val) = match init {
92
1072
                Some(expr) => {
93
1072
                    let v = eval_value(symbols, &expr)?;
94
1072
                    (Some(expr), v)
95
                }
96
                None => (None, Expr::Nil),
97
            };
98
1072
            Ok((name, orig, val))
99
1072
        })
100
1072
        .collect::<Result<_>>()?;
101
1072
    let mut local = symbols.clone();
102
1072
    for (name, init_expr, val) in resolved {
103
1072
        let bound = bind_runtime_or_const(ctx, emit, symbols, init_expr.as_ref(), &val)?;
104
1072
        local.define(Symbol::new(&name, SymbolKind::Variable).with_value(bound));
105
    }
106
1072
    compile_body_for_stack(ctx, emit, &mut local, &args[1..])
107
1072
}
108

            
109
572
pub(super) fn compile_let_star(
110
572
    ctx: &mut CompileContext,
111
572
    emit: &mut FunctionEmitter,
112
572
    symbols: &mut SymbolTable,
113
572
    args: &[Expr],
114
572
) -> Result<()> {
115
572
    if args.len() < 2 {
116
44
        return Err(Error::Compile(
117
44
            "LET* requires a bindings list and at least one body form".to_string(),
118
44
        ));
119
528
    }
120
528
    let bindings = parse_bindings("LET*", &args[0])?;
121
528
    let mut local = symbols.clone();
122
924
    for (name, init) in bindings {
123
924
        let (init_expr, val) = match init {
124
924
            Some(expr) => {
125
924
                let v = eval_value(&mut local, &expr)?;
126
924
                (Some(expr), v)
127
            }
128
            None => (None, Expr::Nil),
129
        };
130
924
        let bound = bind_runtime_or_const(ctx, emit, &mut local, init_expr.as_ref(), &val)?;
131
924
        local.define(Symbol::new(&name, SymbolKind::Variable).with_value(bound));
132
    }
133
528
    compile_body(ctx, emit, &mut local, &args[1..])
134
572
}
135

            
136
pub(super) fn compile_let_star_for_stack(
137
    ctx: &mut CompileContext,
138
    emit: &mut FunctionEmitter,
139
    symbols: &mut SymbolTable,
140
    args: &[Expr],
141
) -> Result<WasmType> {
142
    if args.len() < 2 {
143
        return Err(Error::Compile(
144
            "LET* requires a bindings list and at least one body form".to_string(),
145
        ));
146
    }
147
    let bindings = parse_bindings("LET*", &args[0])?;
148
    let mut local = symbols.clone();
149
    for (name, init) in bindings {
150
        let (init_expr, val) = match init {
151
            Some(expr) => {
152
                let v = eval_value(&mut local, &expr)?;
153
                (Some(expr), v)
154
            }
155
            None => (None, Expr::Nil),
156
        };
157
        let bound = bind_runtime_or_const(ctx, emit, &mut local, init_expr.as_ref(), &val)?;
158
        local.define(Symbol::new(&name, SymbolKind::Variable).with_value(bound));
159
    }
160
    compile_body_for_stack(ctx, emit, &mut local, &args[1..])
161
}
162

            
163
pub(super) fn compile_let_for_effect(
164
    ctx: &mut CompileContext,
165
    emit: &mut FunctionEmitter,
166
    symbols: &mut SymbolTable,
167
    args: &[Expr],
168
) -> Result<()> {
169
    if args.len() < 2 {
170
        return Err(Error::Compile(
171
            "LET requires a bindings list and at least one body form".to_string(),
172
        ));
173
    }
174
    let bindings = parse_bindings("LET", &args[0])?;
175
    let resolved: Vec<(String, Option<Expr>, Expr)> = bindings
176
        .into_iter()
177
        .map(|(name, init)| {
178
            let (orig, val) = match init {
179
                Some(expr) => {
180
                    let v = eval_value(symbols, &expr)?;
181
                    (Some(expr), v)
182
                }
183
                None => (None, Expr::Nil),
184
            };
185
            Ok((name, orig, val))
186
        })
187
        .collect::<Result<_>>()?;
188
    let mut local = symbols.clone();
189
    for (name, init_expr, val) in resolved {
190
        let bound = bind_runtime_or_const(ctx, emit, symbols, init_expr.as_ref(), &val)?;
191
        local.define(Symbol::new(&name, SymbolKind::Variable).with_value(bound));
192
    }
193
    for arg in &args[1..] {
194
        compile_for_effect(ctx, emit, &mut local, arg)?;
195
    }
196
    Ok(())
197
}
198

            
199
268
pub(super) fn compile_let_star_for_effect(
200
268
    ctx: &mut CompileContext,
201
268
    emit: &mut FunctionEmitter,
202
268
    symbols: &mut SymbolTable,
203
268
    args: &[Expr],
204
268
) -> Result<()> {
205
268
    if args.len() < 2 {
206
        return Err(Error::Compile(
207
            "LET* requires a bindings list and at least one body form".to_string(),
208
        ));
209
268
    }
210
268
    let bindings = parse_bindings("LET*", &args[0])?;
211
268
    let mut local = symbols.clone();
212
938
    for (name, init) in bindings {
213
938
        let (init_expr, val) = match init {
214
938
            Some(expr) => {
215
938
                let v = eval_value(&mut local, &expr)?;
216
938
                (Some(expr), v)
217
            }
218
            None => (None, Expr::Nil),
219
        };
220
938
        let bound = bind_runtime_or_const(ctx, emit, &mut local, init_expr.as_ref(), &val)?;
221
938
        local.define(Symbol::new(&name, SymbolKind::Variable).with_value(bound));
222
    }
223
268
    for arg in &args[1..] {
224
268
        compile_for_effect(ctx, emit, &mut local, arg)?;
225
    }
226
268
    Ok(())
227
268
}
228

            
229
/// If val is `WasmRuntime`, compile the init expression to the WASM stack,
230
/// allocate a local, and return `WasmLocal`. Otherwise return the constant value.
231
3682
fn bind_runtime_or_const(
232
3682
    ctx: &mut CompileContext,
233
3682
    emit: &mut FunctionEmitter,
234
3682
    symbols: &mut SymbolTable,
235
3682
    init_expr: Option<&Expr>,
236
3682
    val: &Expr,
237
3682
) -> Result<Expr> {
238
3682
    match val {
239
1422
        Expr::WasmRuntime(ty) => {
240
1422
            let expr = init_expr.ok_or_else(|| {
241
                Error::Compile("runtime binding requires an init expression".to_string())
242
            })?;
243
1422
            compile_for_stack(ctx, emit, symbols, expr)?;
244
1422
            let idx = ctx.alloc_local(*ty);
245
1422
            emit.local_set(idx);
246
1422
            Ok(Expr::WasmLocal(idx, *ty))
247
        }
248
        Expr::WasmLocal(_, _) => Ok(val.clone()),
249
2260
        _ => Ok(val.clone()),
250
    }
251
3682
}
252

            
253
3138
pub(super) fn defun(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
254
3138
    if args.len() < 3 {
255
        return Err(Error::Compile(
256
            "DEFUN requires a name, parameter list, and body".to_string(),
257
        ));
258
3138
    }
259
3138
    let name = match &args[0] {
260
3138
        Expr::Symbol(s) => s.clone(),
261
        other => {
262
            return Err(Error::Compile(format!(
263
                "DEFUN: expected symbol name, got {other:?}"
264
            )));
265
        }
266
    };
267
3138
    let params = parse_lambda_params("DEFUN", &args[1])?;
268
3138
    let (doc, body_idx) = match args.get(2) {
269
89
        Some(Expr::String(s)) if args.len() > 3 => (Some(s.clone()), 3),
270
3049
        _ => (None, 2),
271
    };
272
3138
    if body_idx >= args.len() {
273
        return Err(Error::Compile("DEFUN: missing body".to_string()));
274
3138
    }
275
3138
    let body = if args.len() == body_idx + 1 {
276
3094
        args[body_idx].clone()
277
    } else {
278
44
        let mut forms = Vec::with_capacity(args.len() - body_idx + 1);
279
44
        forms.push(Expr::Symbol("BEGIN".to_string()));
280
44
        forms.extend_from_slice(&args[body_idx..]);
281
44
        Expr::List(forms)
282
    };
283
3138
    let lambda = Expr::Lambda(params, Box::new(body));
284

            
285
3138
    if let Some(sym) = symbols.lookup_mut(&name) {
286
        sym.set_function(lambda);
287
        if let Some(d) = doc {
288
            sym.set_doc(d);
289
        }
290
    } else {
291
3138
        let mut sym = Symbol::new(&name, SymbolKind::Variable).with_function(lambda);
292
3138
        if let Some(d) = doc {
293
89
            sym = sym.with_doc(d);
294
3049
        }
295
3138
        symbols.define(sym);
296
    }
297
3138
    Ok(Expr::Quote(Box::new(Expr::Symbol(name))))
298
3138
}
299

            
300
264
pub(super) fn defvar(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
301
264
    if args.is_empty() {
302
        return Err(Error::Compile(
303
            "DEFVAR requires at least a name".to_string(),
304
        ));
305
264
    }
306
264
    let name = match &args[0] {
307
264
        Expr::Symbol(s) => s.clone(),
308
        other => {
309
            return Err(Error::Compile(format!(
310
                "DEFVAR: expected symbol name, got {other:?}"
311
            )));
312
        }
313
    };
314
264
    let initial = args.get(1).map(|e| eval_value(symbols, e)).transpose()?;
315
264
    let doc = match args.get(2) {
316
44
        Some(Expr::String(s)) => Some(s.clone()),
317
220
        _ => None,
318
    };
319

            
320
264
    if let Some(sym) = symbols.lookup_mut(&name) {
321
44
        if sym.value().is_none()
322
            && let Some(val) = initial
323
        {
324
            sym.set_value(val);
325
44
        }
326
44
        if let Some(d) = doc {
327
            sym.set_doc(d);
328
44
        }
329
    } else {
330
220
        let mut sym = Symbol::new(&name, SymbolKind::Variable);
331
220
        if let Some(val) = initial {
332
220
            sym = sym.with_value(val);
333
220
        }
334
220
        if let Some(d) = doc {
335
44
            sym = sym.with_doc(d);
336
176
        }
337
220
        symbols.define(sym);
338
    }
339
264
    Ok(Expr::Quote(Box::new(Expr::Symbol(name))))
340
264
}
341

            
342
88
pub(super) fn defparameter(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
343
88
    if args.len() < 2 {
344
        return Err(Error::Compile(
345
            "DEFPARAMETER requires a name and initial value".to_string(),
346
        ));
347
88
    }
348
88
    let name = match &args[0] {
349
88
        Expr::Symbol(s) => s.clone(),
350
        other => {
351
            return Err(Error::Compile(format!(
352
                "DEFPARAMETER: expected symbol name, got {other:?}"
353
            )));
354
        }
355
    };
356
88
    let value = eval_value(symbols, &args[1])?;
357
88
    let doc = match args.get(2) {
358
        Some(Expr::String(s)) => Some(s.clone()),
359
88
        _ => None,
360
    };
361

            
362
88
    if let Some(sym) = symbols.lookup_mut(&name) {
363
44
        sym.set_value(value);
364
44
        if let Some(d) = doc {
365
            sym.set_doc(d);
366
44
        }
367
    } else {
368
44
        let mut sym = Symbol::new(&name, SymbolKind::Variable).with_value(value);
369
44
        if let Some(d) = doc {
370
            sym = sym.with_doc(d);
371
44
        }
372
44
        symbols.define(sym);
373
    }
374
88
    Ok(Expr::Quote(Box::new(Expr::Symbol(name))))
375
88
}
376

            
377
2680
pub(super) fn let_form(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
378
2680
    if args.len() < 2 {
379
        return Err(Error::Compile(
380
            "LET requires a bindings list and at least one body form".to_string(),
381
        ));
382
2680
    }
383
2680
    let bindings = parse_bindings("LET", &args[0])?;
384
2680
    let resolved: Vec<(String, Expr)> = bindings
385
2680
        .into_iter()
386
2680
        .map(|(name, init)| {
387
2680
            let val = match init {
388
2680
                Some(expr) => eval_value(symbols, &expr)?,
389
                None => Expr::Nil,
390
            };
391
2680
            Ok((name, val))
392
2680
        })
393
2680
        .collect::<Result<_>>()?;
394
2680
    let mut local_symbols = symbols.clone();
395
2680
    for (name, val) in resolved {
396
2680
        local_symbols.define(Symbol::new(&name, SymbolKind::Variable).with_value(val));
397
2680
    }
398
2680
    eval_body(&mut local_symbols, &args[1..])
399
2680
}
400

            
401
402
pub(super) fn let_star(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
402
402
    if args.len() < 2 {
403
        return Err(Error::Compile(
404
            "LET* requires a bindings list and at least one body form".to_string(),
405
        ));
406
402
    }
407
402
    let bindings = parse_bindings("LET*", &args[0])?;
408
402
    let mut local_symbols = symbols.clone();
409
1474
    for (name, init) in bindings {
410
1474
        let val = match init {
411
1474
            Some(expr) => eval_value(&mut local_symbols, &expr)?,
412
            None => Expr::Nil,
413
        };
414
1474
        local_symbols.define(Symbol::new(&name, SymbolKind::Variable).with_value(val));
415
    }
416
402
    eval_body(&mut local_symbols, &args[1..])
417
402
}
418

            
419
3260
pub(super) fn eval_body(symbols: &mut SymbolTable, body: &[Expr]) -> Result<Expr> {
420
3260
    let mut has_runtime = false;
421
3260
    for expr in &body[..body.len() - 1] {
422
802
        let val = eval_value(symbols, expr)?;
423
802
        if val.is_wasm_runtime() {
424
670
            has_runtime = true;
425
670
        }
426
    }
427
3260
    let result = eval_value(symbols, body.last().unwrap())?;
428
3260
    if has_runtime && !result.is_wasm_runtime() {
429
670
        let ty = infer_runtime_type(&result);
430
670
        return Ok(Expr::WasmRuntime(ty));
431
2590
    }
432
2590
    Ok(result)
433
3260
}
434

            
435
670
fn infer_runtime_type(expr: &Expr) -> WasmType {
436
670
    match expr {
437
402
        Expr::Number(_) => WasmType::Ratio,
438
        Expr::Bool(_) => WasmType::I32,
439
268
        _ => WasmType::ConsRef,
440
    }
441
670
}
442

            
443
5566
pub(super) fn parse_bindings(context: &str, expr: &Expr) -> Result<Vec<(String, Option<Expr>)>> {
444
5566
    let list = match expr {
445
5566
        Expr::List(elems) => elems,
446
        _ => {
447
            return Err(Error::Compile(format!(
448
                "{context}: expected bindings list, got {expr:?}"
449
            )));
450
        }
451
    };
452
5566
    list.iter()
453
7836
        .map(|binding| match binding {
454
            Expr::Symbol(name) => Ok((name.clone(), None)),
455
7880
            Expr::List(elems) if elems.len() == 1 => {
456
44
                let name = elems[0].as_symbol().ok_or_else(|| {
457
                    Error::Compile(format!(
458
                        "{context}: binding name must be a symbol, got {:?}",
459
                        elems[0]
460
                    ))
461
                })?;
462
44
                Ok((name.to_string(), None))
463
            }
464
7836
            Expr::List(elems) if elems.len() == 2 => {
465
7836
                let name = elems[0].as_symbol().ok_or_else(|| {
466
44
                    Error::Compile(format!(
467
44
                        "{context}: binding name must be a symbol, got {:?}",
468
44
                        elems[0]
469
44
                    ))
470
44
                })?;
471
7792
                Ok((name.to_string(), Some(elems[1].clone())))
472
            }
473
            _ => Err(Error::Compile(format!(
474
                "{context}: malformed binding: {binding:?}"
475
            ))),
476
7880
        })
477
5566
        .collect()
478
5566
}
479

            
480
220
pub(super) fn parse_param_list(context: &str, expr: &Expr) -> Result<Vec<String>> {
481
220
    let params = parse_lambda_params(context, expr)?;
482
220
    if !params.optional.is_empty()
483
220
        || params.rest.is_some()
484
220
        || !params.key.is_empty()
485
220
        || !params.aux.is_empty()
486
    {
487
        return Err(Error::Compile(format!(
488
            "{context}: lambda list keywords not supported in this context"
489
        )));
490
220
    }
491
220
    Ok(params.required)
492
220
}
493

            
494
22190
pub(super) fn parse_lambda_params(context: &str, expr: &Expr) -> Result<LambdaParams> {
495
22190
    match expr {
496
22190
        Expr::List(ps) => {
497
22190
            let mut params = LambdaParams::simple(Vec::new());
498
22190
            let mut state = ParseState::Required;
499

            
500
23515
            for param in ps {
501
23515
                if let Some(sym) = param.as_symbol() {
502
23251
                    if sym.eq_ignore_ascii_case("&optional") {
503
132
                        if matches!(
504
132
                            state,
505
                            ParseState::Optional
506
                                | ParseState::Rest
507
                                | ParseState::Key
508
                                | ParseState::Aux
509
                        ) {
510
                            return Err(Error::Compile(format!(
511
                                "{context}: &optional after {}",
512
                                state.name()
513
                            )));
514
132
                        }
515
132
                        state = ParseState::Optional;
516
132
                        continue;
517
23119
                    }
518
23119
                    if sym.eq_ignore_ascii_case("&rest") {
519
176
                        if matches!(state, ParseState::Rest | ParseState::Key | ParseState::Aux) {
520
                            return Err(Error::Compile(format!(
521
                                "{context}: &rest after {}",
522
                                state.name()
523
                            )));
524
176
                        }
525
176
                        state = ParseState::Rest;
526
176
                        continue;
527
22943
                    }
528
22943
                    if sym.eq_ignore_ascii_case("&key") {
529
176
                        if matches!(state, ParseState::Key | ParseState::Aux) {
530
                            return Err(Error::Compile(format!(
531
                                "{context}: &key after {}",
532
                                state.name()
533
                            )));
534
176
                        }
535
176
                        state = ParseState::Key;
536
176
                        continue;
537
22767
                    }
538
22767
                    if sym.eq_ignore_ascii_case("&aux") {
539
88
                        if matches!(state, ParseState::Aux) {
540
                            return Err(Error::Compile(format!("{context}: &aux after aux")));
541
88
                        }
542
88
                        state = ParseState::Aux;
543
88
                        continue;
544
22679
                    }
545
264
                }
546

            
547
22943
                match state {
548
                    ParseState::Required => {
549
22371
                        let name = param
550
22371
                            .as_symbol()
551
22371
                            .ok_or_else(|| {
552
                                Error::Compile(format!(
553
                                    "{context}: required parameter must be a symbol, got {param:?}"
554
                                ))
555
                            })?
556
22371
                            .to_string();
557
22371
                        params.required.push(name);
558
                    }
559
                    ParseState::Optional => {
560
132
                        let (name, default) = parse_optional_param(context, param)?;
561
132
                        params.optional.push((name, default));
562
                    }
563
                    ParseState::Rest => {
564
176
                        let name = param
565
176
                            .as_symbol()
566
176
                            .ok_or_else(|| {
567
                                Error::Compile(format!(
568
                                    "{context}: &rest parameter must be a symbol, got {param:?}"
569
                                ))
570
                            })?
571
176
                            .to_string();
572
176
                        if params.rest.is_some() {
573
                            return Err(Error::Compile(format!(
574
                                "{context}: multiple &rest parameters"
575
                            )));
576
176
                        }
577
176
                        params.rest = Some(name);
578
176
                        state = ParseState::PostRest;
579
                    }
580
                    ParseState::PostRest => {
581
                        return Err(Error::Compile(format!(
582
                            "{context}: parameters after &rest must use &key or &aux"
583
                        )));
584
                    }
585
                    ParseState::Key => {
586
176
                        let (name, default) = parse_optional_param(context, param)?;
587
176
                        params.key.push((name, default));
588
                    }
589
                    ParseState::Aux => {
590
88
                        let (name, default) = parse_optional_param(context, param)?;
591
88
                        params.aux.push((name, default));
592
                    }
593
                }
594
            }
595

            
596
22190
            Ok(params)
597
        }
598
        other => Err(Error::Compile(format!(
599
            "{context}: expected parameter list, got {other:?}"
600
        ))),
601
    }
602
22190
}
603

            
604
#[derive(Debug, Clone)]
605
pub(super) enum ParseState {
606
    Required,
607
    Optional,
608
    Rest,
609
    PostRest,
610
    Key,
611
    Aux,
612
}
613

            
614
impl ParseState {
615
    fn name(&self) -> &'static str {
616
        match self {
617
            ParseState::Required => "required",
618
            ParseState::Optional => "&optional",
619
            ParseState::Rest => "&rest",
620
            ParseState::PostRest => "post-&rest",
621
            ParseState::Key => "&key",
622
            ParseState::Aux => "&aux",
623
        }
624
    }
625
}
626

            
627
396
fn parse_optional_param(context: &str, param: &Expr) -> Result<(String, Option<Expr>)> {
628
264
    match param {
629
132
        Expr::Symbol(name) => Ok((name.clone(), None)),
630
264
        Expr::List(elems) if elems.len() == 2 => {
631
264
            let name = elems[0]
632
264
                .as_symbol()
633
264
                .ok_or_else(|| {
634
                    Error::Compile(format!(
635
                        "{context}: parameter name must be a symbol, got {:?}",
636
                        elems[0]
637
                    ))
638
                })?
639
264
                .to_string();
640
264
            Ok((name, Some(elems[1].clone())))
641
        }
642
        _ => Err(Error::Compile(format!(
643
            "{context}: optional parameter must be a symbol or (symbol default), got {param:?}"
644
        ))),
645
    }
646
396
}