1
use crate::ast::{Expr, LambdaParams};
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::compile_body;
8
use super::binding::{eval_body, parse_param_list};
9

            
10
struct LabelDef {
11
    name: String,
12
    params: Vec<String>,
13
    body: Expr,
14
}
15

            
16
220
fn parse_labels_defs(args: &[Expr]) -> Result<(Vec<LabelDef>, &[Expr])> {
17
220
    if args.len() < 2 {
18
44
        return Err(Error::Compile(
19
44
            "LABELS requires a definitions list and at least one body form".to_string(),
20
44
        ));
21
176
    }
22
176
    let defs_list = args[0].as_list().ok_or_else(|| {
23
        Error::Compile(format!(
24
            "LABELS: expected definitions list, got {:?}",
25
            args[0]
26
        ))
27
    })?;
28
176
    let defs = defs_list
29
176
        .iter()
30
220
        .map(|def| {
31
220
            let elems = def.as_list().ok_or_else(|| {
32
                Error::Compile(format!("LABELS: expected function definition, got {def:?}"))
33
            })?;
34
220
            if elems.len() < 3 {
35
                return Err(Error::Compile(
36
                    "LABELS: each definition needs a name, params, and body".to_string(),
37
                ));
38
220
            }
39
220
            let name = elems[0]
40
220
                .as_symbol()
41
220
                .ok_or_else(|| {
42
                    Error::Compile(format!(
43
                        "LABELS: expected function name, got {:?}",
44
                        elems[0]
45
                    ))
46
                })?
47
220
                .to_string();
48
220
            let params = parse_param_list("LABELS", &elems[1])?;
49
220
            let body = if elems.len() == 3 {
50
220
                elems[2].clone()
51
            } else {
52
                let mut forms = Vec::with_capacity(elems.len() - 1);
53
                forms.push(Expr::Symbol("BEGIN".to_string()));
54
                forms.extend_from_slice(&elems[2..]);
55
                Expr::List(forms)
56
            };
57
220
            Ok(LabelDef { name, params, body })
58
220
        })
59
176
        .collect::<Result<Vec<_>>>()?;
60
176
    Ok((defs, &args[1..]))
61
220
}
62

            
63
176
fn define_labels(symbols: &mut SymbolTable, defs: Vec<LabelDef>) -> SymbolTable {
64
176
    let mut local = symbols.clone();
65
220
    for def in defs {
66
220
        let lambda = Expr::Lambda(LambdaParams::simple(def.params), Box::new(def.body));
67
220
        local.define(Symbol::new(&def.name, SymbolKind::Function).with_function(lambda));
68
220
    }
69
176
    local
70
176
}
71

            
72
pub(super) fn labels_form(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
73
    let (defs, body) = parse_labels_defs(args)?;
74
    let mut local = define_labels(symbols, defs);
75
    eval_body(&mut local, body)
76
}
77

            
78
220
pub(super) fn compile_labels(
79
220
    ctx: &mut CompileContext,
80
220
    emit: &mut FunctionEmitter,
81
220
    symbols: &mut SymbolTable,
82
220
    args: &[Expr],
83
220
) -> Result<()> {
84
220
    let (defs, body) = parse_labels_defs(args)?;
85
176
    let mut local = define_labels(symbols, defs);
86
176
    compile_body(ctx, emit, &mut local, body)
87
220
}