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
852
fn parse_labels_defs(args: &[Expr]) -> Result<(Vec<LabelDef>, &[Expr])> {
26
852
    if args.len() < 2 {
27
142
        return Err(Error::Compile(
28
142
            "LABELS requires a definitions list and at least one body form".to_string(),
29
142
        ));
30
710
    }
31
710
    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
710
    let defs = defs_list
38
710
        .iter()
39
852
        .map(|def| {
40
852
            let elems = def.as_list().ok_or_else(|| {
41
                Error::Compile(format!("LABELS: expected function definition, got {def:?}"))
42
            })?;
43
852
            if elems.len() < 3 {
44
71
                return Err(Error::Compile(
45
71
                    "LABELS: each definition needs a name, params, and body".to_string(),
46
71
                ));
47
781
            }
48
781
            let name = elems[0]
49
781
                .as_symbol()
50
781
                .ok_or_else(|| {
51
                    Error::Compile(format!(
52
                        "LABELS: expected function name, got {:?}",
53
                        elems[0]
54
                    ))
55
                })?
56
781
                .to_string();
57
781
            let params = parse_param_list("LABELS", &elems[1])?;
58
781
            let body = if elems.len() == 3 {
59
781
                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
781
            Ok(LabelDef { name, params, body })
67
852
        })
68
710
        .collect::<Result<Vec<_>>>()?;
69
639
    Ok((defs, &args[1..]))
70
852
}
71

            
72
639
fn define_labels(symbols: &mut SymbolTable, defs: Vec<LabelDef>) -> SymbolTable {
73
639
    let mut local = symbols.clone();
74
781
    for def in defs {
75
781
        let lambda = Expr::Lambda(LambdaParams::simple(def.params), Box::new(def.body));
76
781
        local.define(Symbol::new(&def.name, SymbolKind::Function).with_function(lambda));
77
781
    }
78
639
    local
79
639
}
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
852
pub(super) fn compile_labels(
88
852
    ctx: &mut CompileContext,
89
852
    emit: &mut FunctionEmitter,
90
852
    symbols: &mut SymbolTable,
91
852
    args: &[Expr],
92
852
) -> Result<()> {
93
852
    let (defs, body) = parse_labels_defs(args)?;
94
639
    let mut local = define_labels(symbols, defs);
95
639
    compile_body(ctx, emit, &mut local, body)
96
852
}