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
use std::{any::Any, rc::Rc};
use crate::model::{FloatType, HashMapRc, IntType, List, RuntimeError, Symbol, Value};
pub fn require_arg<'a>(
func_or_form_name: &str,
args: &'a [Value],
index: usize,
) -> Result<&'a Value, RuntimeError> {
args.get(index).ok_or_else(|| RuntimeError {
msg: format!(
"\"{}\" requires an argument {}",
func_or_form_name,
index + 1
),
})
}
pub fn require_typed_arg<'a, T>(
func_or_form_name: &str,
args: &'a [Value],
index: usize,
) -> Result<T, RuntimeError>
where
T: TryFrom<&'a Value> + TypeName,
{
require_arg(func_or_form_name, args, index)?
.try_into()
.map_err(|_| RuntimeError {
msg: format!(
"\"{}\" requires argument {} to be a {}; got {}",
func_or_form_name,
index + 1,
T::get_name(),
args.get(index).unwrap_or(&Value::NIL)
),
})
}
pub trait TypeName {
fn get_name() -> &'static str;
}
impl TypeName for IntType {
fn get_name() -> &'static str {
"int"
}
}
impl TypeName for FloatType {
fn get_name() -> &'static str {
"float"
}
}
impl TypeName for &String {
fn get_name() -> &'static str {
"string"
}
}
impl TypeName for &Symbol {
fn get_name() -> &'static str {
"symbol"
}
}
impl TypeName for &List {
fn get_name() -> &'static str {
"list"
}
}
impl TypeName for &HashMapRc {
fn get_name() -> &'static str {
"hash map"
}
}
impl TypeName for &Rc<dyn Any> {
fn get_name() -> &'static str {
"foreign value"
}
}