1use std::fmt::Display;
4
5use crate::{
6 builtins::BuiltinFn,
7 errors::{ExprResult, RuntimeError},
8 types::Type,
9};
10
11#[derive(Debug, Clone, PartialEq)]
12pub enum Value {
13 String(String),
14 Fn(Box<BuiltinFn<'static>>),
15 Bool(bool),
16 Type(Box<Type>),
17}
18
19impl Value {
20 pub fn get_type(&self) -> Type {
21 self.clone().into()
22 }
23
24 pub fn get_string(&self) -> ExprResult<&str> {
25 match self {
26 Value::String(s) => Ok(s.as_str()),
27 _ => Err(vec![(
28 RuntimeError::TypeMismatch {
29 expected: Type::String,
30 actual: self.get_type(),
31 }
32 .into(),
33 0..0,
34 )]),
35 }
36 }
37
38 pub fn get_func(&self) -> ExprResult<Box<BuiltinFn>> {
39 match self {
40 Value::Fn(f) => Ok(f.clone()),
41 _ => Err(vec![(
42 RuntimeError::TypeMismatch {
43 expected: Type::Fn {
44 args: vec![],
45 variadic_arg: Some(Type::Value.into()),
46 returns: Type::Value.into(),
47 },
48 actual: self.get_type(),
49 }
50 .into(),
51 0..0,
52 )]),
53 }
54 }
55
56 pub fn get_bool(&self) -> ExprResult<bool> {
57 match self {
58 Value::Bool(s) => Ok(*s),
59 _ => Err(vec![(
60 RuntimeError::TypeMismatch {
61 expected: Type::Bool,
62 actual: self.get_type(),
63 }
64 .into(),
65 0..0,
66 )]),
67 }
68 }
69}
70
71impl Display for Value {
72 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
73 match self {
74 Value::String(string) => write!(f, "`{}`", string),
75 Value::Fn(builtin) => write!(f, "{builtin:?}"),
76 Value::Bool(value) => write!(f, "{}", value),
77 Value::Type(ty) => write!(f, "Type<{}>", ty),
78 }
79 }
80}
81
82impl From<bool> for Value {
83 fn from(value: bool) -> Self {
84 Self::Bool(value)
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 use pretty_assertions::assert_eq;
93
94 fn example_builtin(_args: Vec<Value>) -> ExprResult<Value> {
95 Ok(Value::String("".to_string()))
96 }
97
98 #[test]
99 fn get_bool_on_string() {
100 assert_eq!(
101 Err(vec![(
102 RuntimeError::TypeMismatch {
103 expected: Type::Bool,
104 actual: Type::String
105 }
106 .into(),
107 0..0
108 )]),
109 Value::String("string".to_string()).get_bool()
110 );
111 }
112
113 #[test]
114 fn get_bool_on_bool_true() {
115 assert_eq!(Ok(true), Value::Bool(true).get_bool());
116 }
117
118 #[test]
119 fn get_string_on_bool() {
120 assert_eq!(
121 Err(vec![(
122 RuntimeError::TypeMismatch {
123 expected: Type::String,
124 actual: Type::Bool
125 }
126 .into(),
127 0..0
128 )]),
129 Value::Bool(true).get_string()
130 );
131 }
132
133 #[test]
134 fn get_string_on_string() {
135 let value = Value::String("test".to_string());
136 assert_eq!(Ok("test"), value.get_string());
137 }
138
139 #[test]
140 fn get_func_on_string() {
141 let value = Value::String("not a function".to_string());
142 assert_eq!(
143 Err(vec![(
144 RuntimeError::TypeMismatch {
145 expected: Type::Fn {
146 args: vec![],
147 variadic_arg: Some(Type::Value.into()),
148 returns: Type::Value.into()
149 },
150 actual: Type::String
151 }
152 .into(),
153 0..0
154 )]),
155 value.get_func()
156 );
157 }
158
159 #[test]
160 fn get_func_on_func() {
161 let expected_fn: Box<BuiltinFn> = BuiltinFn {
162 name: "name",
163 args: &[],
164 return_type: Type::Unknown,
165 func: example_builtin,
166 }
167 .into();
168
169 let value = Value::Fn(expected_fn.clone());
170
171 assert_eq!(Ok(expected_fn), value.get_func());
172 }
173
174 #[test]
175 fn get_func_on_bool() {
176 let value = Value::Bool(true);
177 assert_eq!(
178 Err(vec![(
179 RuntimeError::TypeMismatch {
180 expected: Type::Fn {
181 args: vec![],
182 variadic_arg: Some(Type::Value.into()),
183 returns: Type::Value.into()
184 },
185 actual: Type::Bool
186 }
187 .into(),
188 0..0
189 )]),
190 value.get_func()
191 );
192 }
193
194 }