1
//! `COMPILE` and `EVAL` reflective forms.
2
//!
3
//! `COMPILE` resolves a quoted symbol to its function definition and
4
//! returns a quoted symbol marking it as compiled (the marker is what
5
//! the next pipeline stage picks up; today the marker just round-
6
//! trips). `EVAL` resolves its argument and re-runs the evaluator on
7
//! the inner form.
8

            
9
use tracing::debug;
10

            
11
use crate::ast::{Expr, WasmType};
12
use crate::compiler::context::CompileContext;
13
use crate::compiler::emit::FunctionEmitter;
14
use crate::compiler::expr::{compile_expr, compile_for_stack, eval_value, resolve_arg};
15
use crate::error::{Error, Result};
16
use crate::runtime::SymbolTable;
17

            
18
use super::compile_static_result_for_stack;
19

            
20
355
pub(super) fn compile_compile_form(
21
355
    ctx: &mut CompileContext,
22
355
    emit: &mut FunctionEmitter,
23
355
    symbols: &mut SymbolTable,
24
355
    args: &[Expr],
25
355
) -> Result<()> {
26
355
    let result = compile_form(symbols, args)?;
27
142
    compile_expr(ctx, emit, symbols, &result)
28
355
}
29

            
30
568
pub(super) fn compile_eval_form(
31
568
    ctx: &mut CompileContext,
32
568
    emit: &mut FunctionEmitter,
33
568
    symbols: &mut SymbolTable,
34
568
    args: &[Expr],
35
568
) -> Result<()> {
36
568
    if args.len() != 1 {
37
71
        return Err(Error::Arity {
38
71
            name: "eval".to_string(),
39
71
            expected: 1,
40
71
            actual: args.len(),
41
71
        });
42
497
    }
43
497
    let resolved = resolve_arg(symbols, &args[0])?;
44
497
    match &resolved {
45
284
        Expr::Quote(inner) => compile_expr(ctx, emit, symbols, inner),
46
213
        _ => compile_expr(ctx, emit, symbols, &resolved),
47
    }
48
568
}
49

            
50
355
pub(super) fn compile_form(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
51
355
    if args.len() != 1 {
52
71
        return Err(Error::Arity {
53
71
            name: "compile".to_string(),
54
71
            expected: 1,
55
71
            actual: args.len(),
56
71
        });
57
284
    }
58
284
    let name = match &args[0] {
59
213
        Expr::Quote(inner) => match inner.as_ref() {
60
213
            Expr::Symbol(s) => s,
61
            _ => {
62
                return Err(Error::Compile(
63
                    "compile: argument must be a quoted symbol".to_string(),
64
                ));
65
            }
66
        },
67
        Expr::Symbol(_) => {
68
            let resolved = resolve_arg(symbols, &args[0])?;
69
            match &resolved {
70
                Expr::Quote(inner) => match inner.as_ref() {
71
                    Expr::Symbol(s) => {
72
                        return compile_form_with_name(symbols, s);
73
                    }
74
                    _ => {
75
                        return Err(Error::Compile(
76
                            "compile: argument must be a quoted symbol".to_string(),
77
                        ));
78
                    }
79
                },
80
                _ => {
81
                    return Err(Error::Compile(
82
                        "compile: argument must be a quoted symbol".to_string(),
83
                    ));
84
                }
85
            }
86
        }
87
        _ => {
88
71
            return Err(Error::Compile(
89
71
                "compile: argument must be a quoted symbol".to_string(),
90
71
            ));
91
        }
92
    };
93
213
    compile_form_with_name(symbols, name)
94
355
}
95

            
96
213
pub(super) fn compile_form_with_name(symbols: &mut SymbolTable, name: &str) -> Result<Expr> {
97
213
    debug!(function = %name, "compiling compile");
98
213
    let sym = symbols
99
213
        .lookup(name)
100
213
        .ok_or_else(|| Error::UndefinedSymbol(name.to_string()))?;
101
142
    if sym.function().is_none() {
102
        return Err(Error::Compile(format!(
103
            "compile: '{name}' is not a function"
104
        )));
105
142
    }
106
142
    Ok(Expr::Quote(Box::new(Expr::Symbol(name.to_string()))))
107
213
}
108

            
109
142
pub(super) fn eval_form(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
110
142
    if args.len() != 1 {
111
        return Err(Error::Arity {
112
            name: "eval".to_string(),
113
            expected: 1,
114
            actual: args.len(),
115
        });
116
142
    }
117
142
    let resolved = eval_value(symbols, &args[0])?;
118
142
    debug!(expr = ?resolved, "compiling eval");
119
142
    match &resolved {
120
142
        Expr::Quote(inner) => eval_value(symbols, inner),
121
        _ => eval_value(symbols, &resolved),
122
    }
123
142
}
124

            
125
pub(super) fn compile_compile_form_for_stack(
126
    ctx: &mut CompileContext,
127
    emit: &mut FunctionEmitter,
128
    symbols: &mut SymbolTable,
129
    args: &[Expr],
130
) -> Result<WasmType> {
131
    let result = compile_form(symbols, args)?;
132
    compile_static_result_for_stack(ctx, emit, symbols, &result)
133
}
134

            
135
pub(super) fn compile_eval_form_for_stack(
136
    ctx: &mut CompileContext,
137
    emit: &mut FunctionEmitter,
138
    symbols: &mut SymbolTable,
139
    args: &[Expr],
140
) -> Result<WasmType> {
141
    if args.len() != 1 {
142
        return Err(Error::Arity {
143
            name: "eval".to_string(),
144
            expected: 1,
145
            actual: args.len(),
146
        });
147
    }
148
    let resolved = resolve_arg(symbols, &args[0])?;
149
    match &resolved {
150
        Expr::Quote(inner) => compile_for_stack(ctx, emit, symbols, inner),
151
        _ => compile_for_stack(ctx, emit, symbols, &resolved),
152
    }
153
}