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

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

            
50
340
pub(super) fn compile_form(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
51
340
    if args.len() != 1 {
52
68
        return Err(Error::Arity {
53
68
            name: "compile".to_string(),
54
68
            expected: 1,
55
68
            actual: args.len(),
56
68
        });
57
272
    }
58
272
    let name = match &args[0] {
59
204
        Expr::Quote(inner) => match inner.as_ref() {
60
204
            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
68
            return Err(Error::Compile(
89
68
                "compile: argument must be a quoted symbol".to_string(),
90
68
            ));
91
        }
92
    };
93
204
    compile_form_with_name(symbols, name)
94
340
}
95

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

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