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::SpecialFormSpec;
9
use super::binding::{eval_body, parse_param_list};
10

            
11
pub(super) const FORMS: &[SpecialFormSpec] = &[SpecialFormSpec {
12
    name: "LABELS",
13
    eval: labels_form,
14
    compile: compile_labels,
15
    stack: None,
16
    effect: None,
17
}];
18

            
19
struct LabelDef {
20
    name: String,
21
    params: Vec<String>,
22
    body: Expr,
23
}
24

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

            
72
612
fn define_labels(symbols: &mut SymbolTable, defs: Vec<LabelDef>) -> SymbolTable {
73
612
    let mut local = symbols.clone();
74
748
    for def in defs {
75
748
        let lambda = Expr::Lambda(LambdaParams::simple(def.params), Box::new(def.body));
76
748
        local.define(Symbol::new(&def.name, SymbolKind::Function).with_function(lambda));
77
748
    }
78
612
    local
79
612
}
80

            
81
pub(super) fn labels_form(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
82
    let (defs, body) = parse_labels_defs(args)?;
83
    let mut local = define_labels(symbols, defs);
84
    eval_body(&mut local, body)
85
}
86

            
87
816
pub(super) fn compile_labels(
88
816
    ctx: &mut CompileContext,
89
816
    emit: &mut FunctionEmitter,
90
816
    symbols: &mut SymbolTable,
91
816
    args: &[Expr],
92
816
) -> Result<()> {
93
816
    let (defs, body) = parse_labels_defs(args)?;
94
612
    let mut local = define_labels(symbols, defs);
95
612
    compile_body(ctx, emit, &mut local, body)
96
816
}