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::{compile_body, compile_body_for_stack};
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: Some(compile_labels_for_stack),
16
    effect: None,
17
}];
18

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

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

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

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

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

            
98
166
pub(super) fn compile_labels_for_stack(
99
166
    ctx: &mut CompileContext,
100
166
    emit: &mut FunctionEmitter,
101
166
    symbols: &mut SymbolTable,
102
166
    args: &[Expr],
103
166
) -> Result<WasmType> {
104
166
    let (defs, body) = parse_labels_defs(args)?;
105
166
    let mut local = define_labels(symbols, defs);
106
166
    compile_body_for_stack(ctx, emit, &mut local, body)
107
166
}