1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
//! Special-form dispatch.
//!
//! Phase 2.2 scaffold: enum placeholder for the forms the evaluator
//! recognizes. Implementation lands in Phase 2.3.
/// The set of special forms the evaluator handles directly (as opposed to
/// dispatching through function application).
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SpecialForm {
Quote,
Quasiquote,
If,
Cond,
When,
Unless,
Let,
LetStar,
LetRec,
Lambda,
Define,
Set,
Begin,
And,
Or,
Not,
/// `(try body... (catch (binding) handler...))` —
/// runs body sequentially; if any form raises an `EvalError::User`
/// (i.e., a Lisp-level `(throw ...)`), the carried Value is bound
/// to `binding` and `handler...` runs. Bare Rust-side errors
/// (TypeMismatch, ArityMismatch, etc.) are wrapped into a
/// `Value::Error` with tag `:runtime` so they can be caught too.
Try,
/// `(macroexpand-1 'form)` — evaluate the argument to a code value,
/// run ONE level of macro expansion if the head is a registered
/// macro, and return the expanded code as a Value. Useful for
/// debugging macros — see exactly what one expansion produces.
MacroexpandOne,
/// `(macroexpand 'form)` — like macroexpand-1, but fully expand
/// until no macro calls remain.
MacroexpandAll,
/// `(delay expr)` — wrap `expr` as a memoizing thunk. The first
/// `(force p)` triggers evaluation; subsequent forces return the
/// cached value. Returns a `Value::Promise`.
Delay,
/// `(eval form)` — evaluate `form` (a runtime Value representing
/// code, typically a quoted list) at top-level, returning the
/// result. Unlocks runtime metaprogramming.
Eval,
/// `(provide name1 name2 ...)` — declare that the names are
/// exported from the current module. Errors at top-level (i.e.
/// outside a `(require)` load).
Provide,
/// `(require "path")` — load and evaluate the module at `path`,
/// register it. With `:as alias`, every exported name becomes
/// reachable as `alias/name`. With `:refer (a b)`, only the listed
/// names are imported as bare unqualified bindings.
Require,
}
impl SpecialForm {
/// Match a head symbol to a special form. Returns `None` if the symbol
/// is not a recognized special form (interpret as a function call).
pub fn from_symbol(s: &str) -> Option<Self> {
Some(match s {
"quote" => Self::Quote,
"quasiquote" => Self::Quasiquote,
"if" => Self::If,
"cond" => Self::Cond,
"when" => Self::When,
"unless" => Self::Unless,
"let" => Self::Let,
"let*" => Self::LetStar,
"letrec" => Self::LetRec,
"lambda" => Self::Lambda,
"define" => Self::Define,
"set!" => Self::Set,
"begin" => Self::Begin,
"and" => Self::And,
"or" => Self::Or,
"not" => Self::Not,
"try" => Self::Try,
"macroexpand-1" => Self::MacroexpandOne,
"macroexpand" => Self::MacroexpandAll,
"delay" => Self::Delay,
"eval" => Self::Eval,
"provide" => Self::Provide,
"require" => Self::Require,
_ => return None,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn recognizes_core_forms() {
assert_eq!(SpecialForm::from_symbol("if"), Some(SpecialForm::If));
assert_eq!(
SpecialForm::from_symbol("lambda"),
Some(SpecialForm::Lambda)
);
assert_eq!(SpecialForm::from_symbol("let*"), Some(SpecialForm::LetStar));
assert_eq!(SpecialForm::from_symbol("set!"), Some(SpecialForm::Set));
assert_eq!(SpecialForm::from_symbol("foo"), None);
}
}