1
use crate::ast::Expr;
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_expr, resolve_arg};
8
use super::SpecialFormSpec;
9
use super::binding::parse_lambda_params;
10

            
11
pub(super) const FORMS: &[SpecialFormSpec] = &[
12
    SpecialFormSpec {
13
        name: "DEFMACRO",
14
        eval: defmacro,
15
        compile: compile_defmacro_form,
16
        stack: None,
17
        effect: None,
18
    },
19
    SpecialFormSpec {
20
        name: "MACROEXPAND-1",
21
        eval: macroexpand_1,
22
        compile: compile_macroexpand_1_form,
23
        stack: None,
24
        effect: None,
25
    },
26
    SpecialFormSpec {
27
        name: "MACROEXPAND",
28
        eval: macroexpand,
29
        compile: compile_macroexpand_form,
30
        stack: None,
31
        effect: None,
32
    },
33
];
34

            
35
26062
pub(super) fn compile_defmacro_form(
36
26062
    ctx: &mut CompileContext,
37
26062
    emit: &mut FunctionEmitter,
38
26062
    symbols: &mut SymbolTable,
39
26062
    args: &[Expr],
40
26062
) -> Result<()> {
41
26062
    let result = defmacro(symbols, args)?;
42
25813
    compile_expr(ctx, emit, symbols, &result)
43
26062
}
44

            
45
415
pub(super) fn compile_macroexpand_1_form(
46
415
    ctx: &mut CompileContext,
47
415
    emit: &mut FunctionEmitter,
48
415
    symbols: &mut SymbolTable,
49
415
    args: &[Expr],
50
415
) -> Result<()> {
51
415
    let result = macroexpand_1(symbols, args)?;
52
332
    compile_expr(ctx, emit, symbols, &result)
53
415
}
54

            
55
415
pub(super) fn compile_macroexpand_form(
56
415
    ctx: &mut CompileContext,
57
415
    emit: &mut FunctionEmitter,
58
415
    symbols: &mut SymbolTable,
59
415
    args: &[Expr],
60
415
) -> Result<()> {
61
415
    let result = macroexpand(symbols, args)?;
62
332
    compile_expr(ctx, emit, symbols, &result)
63
415
}
64

            
65
54199
pub(super) fn defmacro(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
66
54199
    if args.len() < 3 {
67
83
        return Err(Error::Compile(
68
83
            "DEFMACRO requires a name, parameter list, and body".to_string(),
69
83
        ));
70
54116
    }
71
54116
    let name = match &args[0] {
72
54033
        Expr::Symbol(s) => s.clone(),
73
83
        other => {
74
83
            return Err(Error::Compile(format!(
75
83
                "DEFMACRO: expected symbol name, got {other:?}"
76
83
            )));
77
        }
78
    };
79
54033
    let params = parse_lambda_params("DEFMACRO", &args[1])?;
80
54033
    if !params.aux.is_empty() {
81
83
        return Err(Error::Compile(
82
83
            "DEFMACRO: &aux is not yet supported".to_string(),
83
83
        ));
84
53950
    }
85
53950
    let (doc, body_idx) = match args.get(2) {
86
166
        Some(Expr::String(s)) if args.len() > 3 => (Some(s.clone()), 3),
87
53784
        _ => (None, 2),
88
    };
89
53950
    if body_idx >= args.len() {
90
        return Err(Error::Compile("DEFMACRO: missing body".to_string()));
91
53950
    }
92
53950
    let body = if args.len() == body_idx + 1 {
93
53867
        args[body_idx].clone()
94
    } else {
95
83
        let mut forms = Vec::with_capacity(args.len() - body_idx + 1);
96
83
        forms.push(Expr::Symbol("BEGIN".to_string()));
97
83
        forms.extend_from_slice(&args[body_idx..]);
98
83
        Expr::List(forms)
99
    };
100
53950
    let lambda = Expr::Lambda(params, Box::new(body));
101

            
102
53950
    let mut sym = Symbol::new(&name, SymbolKind::Macro).with_function(lambda);
103
53950
    if let Some(d) = doc {
104
166
        sym = sym.with_doc(d);
105
53784
    }
106
53950
    symbols.define(sym);
107
53950
    Ok(Expr::Quote(Box::new(Expr::Symbol(name))))
108
54199
}
109

            
110
5810
pub(super) fn macroexpand_1(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
111
5810
    if args.len() != 1 {
112
83
        return Err(Error::Arity {
113
83
            name: "MACROEXPAND-1".to_string(),
114
83
            expected: 1,
115
83
            actual: args.len(),
116
83
        });
117
5727
    }
118
5727
    let form = resolve_arg(symbols, &args[0])?;
119
5727
    macroexpand_1_impl(symbols, &form)
120
5810
}
121

            
122
415
pub(super) fn macroexpand(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
123
415
    if args.len() != 1 {
124
83
        return Err(Error::Arity {
125
83
            name: "MACROEXPAND".to_string(),
126
83
            expected: 1,
127
83
            actual: args.len(),
128
83
        });
129
332
    }
130
332
    let mut form = resolve_arg(symbols, &args[0])?;
131
    loop {
132
747
        let expanded = macroexpand_1_impl(symbols, &form)?;
133
747
        if expanded == form {
134
332
            break;
135
415
        }
136
415
        form = expanded;
137
    }
138
332
    Ok(form)
139
415
}
140

            
141
6474
fn macroexpand_1_impl(symbols: &mut SymbolTable, form: &Expr) -> Result<Expr> {
142
6474
    match form {
143
6474
        Expr::Quote(inner) => match inner.as_ref() {
144
6391
            Expr::List(elems) if !elems.is_empty() => {
145
6391
                if let Some(name) = macro_head_name(&elems[0])
146
6391
                    && let Some(sym) = symbols.lookup(name)
147
6391
                    && sym.kind() == SymbolKind::Macro
148
5976
                    && let Some(Expr::Lambda(params, body)) = sym.function().cloned()
149
                {
150
                    // `macroexpand-1` is one-step, but expanding the macro
151
                    // evaluates its body — which may itself call
152
                    // `macroexpand-1` on the same macro, recursing
153
                    // unboundedly. Bracket with the shared depth guard so a
154
                    // self-referential expander errors instead of
155
                    // overflowing the native stack.
156
5976
                    symbols.enter_macro_expansion()?;
157
5893
                    let expanded =
158
5893
                        super::super::expr::expand_macro(symbols, &params, &body, &elems[1..]);
159
5893
                    symbols.exit_macro_expansion();
160
5893
                    return expanded;
161
415
                }
162
415
                Ok(form.clone())
163
            }
164
83
            _ => Ok(form.clone()),
165
        },
166
        _ => Ok(form.clone()),
167
    }
168
6474
}
169

            
170
6391
fn macro_head_name(expr: &Expr) -> Option<&str> {
171
6391
    match expr {
172
6225
        Expr::Symbol(name) => Some(name),
173
166
        Expr::Quote(inner) => match inner.as_ref() {
174
166
            Expr::Symbol(name) => Some(name),
175
            _ => None,
176
        },
177
        _ => None,
178
    }
179
6391
}