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

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

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

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

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

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

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

            
141
5304
fn macroexpand_1_impl(symbols: &mut SymbolTable, form: &Expr) -> Result<Expr> {
142
5304
    match form {
143
5304
        Expr::Quote(inner) => match inner.as_ref() {
144
5236
            Expr::List(elems) if !elems.is_empty() => {
145
5236
                if let Some(name) = macro_head_name(&elems[0])
146
5236
                    && let Some(sym) = symbols.lookup(name)
147
5236
                    && sym.kind() == SymbolKind::Macro
148
4896
                    && 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
4896
                    symbols.enter_macro_expansion()?;
157
4828
                    let expanded =
158
4828
                        super::super::expr::expand_macro(symbols, &params, &body, &elems[1..]);
159
4828
                    symbols.exit_macro_expansion();
160
4828
                    return expanded;
161
340
                }
162
340
                Ok(form.clone())
163
            }
164
68
            _ => Ok(form.clone()),
165
        },
166
        _ => Ok(form.clone()),
167
    }
168
5304
}
169

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