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

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

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

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

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

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

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

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

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