1use std::fmt::Display;
2
3use aiscript_arena::{Collect, Gc, Mutation, RefLock, lock::GcRefLock};
4
5use crate::{
6 NativeFn,
7 ai::Agent,
8 object::{BoundMethod, Class, Closure, Enum, EnumVariant, Instance, List, ListKind, Object},
9 string::{InternedString, StringValue},
10 vm::{Context, VmError},
11};
12
13#[derive(Copy, Clone, Default, Collect)]
14#[collect(no_drop)]
15pub enum Value<'gc> {
16 Number(f64),
17 Boolean(bool),
18 String(InternedString<'gc>),
20 IoString(Gc<'gc, String>),
22 Closure(Gc<'gc, Closure<'gc>>),
23 NativeFunction(NativeFn<'gc>),
24 List(GcRefLock<'gc, List<'gc>>),
26 Object(GcRefLock<'gc, Object<'gc>>),
27 Enum(GcRefLock<'gc, Enum<'gc>>),
28 EnumVariant(Gc<'gc, EnumVariant<'gc>>),
29 Class(GcRefLock<'gc, Class<'gc>>),
30 Instance(GcRefLock<'gc, Instance<'gc>>),
31 BoundMethod(Gc<'gc, BoundMethod<'gc>>),
32 Module(InternedString<'gc>),
33 Agent(Gc<'gc, Agent<'gc>>),
34 #[default]
35 Nil,
36}
37
38impl PartialEq for Value<'_> {
39 fn eq(&self, other: &Self) -> bool {
40 self.equals(other)
41 }
42}
43
44impl Display for Value<'_> {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 match self {
47 Value::Number(v) => write!(f, "{}", v),
48 Value::Boolean(b) => write!(f, "{}", b),
49 Value::String(s) => write!(f, "{}", s),
50 Value::IoString(s) => write!(f, "{}", s),
51 Value::Closure(closure) => {
52 if let Some(name) = closure.function.name {
53 write!(f, "<fn {}>", name)
54 } else {
55 write!(f, "<script>")
56 }
57 }
58 Value::NativeFunction(_) => write!(f, "<native fn>"),
59 Value::List(list) => {
60 let list = list.borrow();
61 match list.kind {
62 ListKind::Array => {
63 write!(f, "[")?;
64 for (i, value) in list.data.iter().enumerate() {
65 if i > 0 {
66 write!(f, ", ")?;
67 }
68 write!(f, "{}", value)?;
69 }
70 write!(f, "]")
71 }
72 ListKind::Tuple => {
73 write!(f, "(")?;
74 for (i, value) in list.data.iter().enumerate() {
75 if i > 0 {
76 write!(f, ", ")?;
77 }
78 write!(f, "{}", value)?;
79 }
80 if list.data.len() == 1 {
82 write!(f, ",")?;
83 }
84 write!(f, ")")
85 }
86 }
87 }
88 Value::Object(obj) => {
89 write!(f, "{{")?;
90 let mut first = true;
91 for (key, value) in &obj.borrow().fields {
92 if !first {
93 write!(f, ", ")?;
94 }
95 write!(f, "{}: {}", key, value)?;
96 first = false;
97 }
98 write!(f, "}}")
99 }
100 Value::Enum(enum_) => write!(f, "enum {}", enum_.borrow().name),
101 Value::EnumVariant(variant) => {
102 write!(f, "{}::{}", variant.enum_.borrow().name, variant.name)?;
103 if !variant.value.is_nil() {
104 write!(f, "({})", variant.value)
105 } else {
106 Ok(())
107 }
108 }
109 Value::Class(class) => write!(f, "{}", class.borrow().name),
110 Value::Instance(instance) => {
111 let mut s = format!("{} {{", instance.borrow().class.borrow().name);
112 for (i, (key, value)) in instance.borrow().fields.iter().enumerate() {
113 s.push_str(&format!("{}: {}", key, value));
114 if i != instance.borrow().fields.len() - 1 {
115 s.push_str(", ");
116 }
117 }
118 s.push('}');
119 write!(f, "{}", s)
120 }
121 Value::BoundMethod(bm) => write!(f, "{}", bm.method.function),
122 Value::Agent(agent) => write!(f, "agent {}", agent.name),
123 Value::Module(module) => write!(f, "module {}", module),
124 Value::Nil => write!(f, "nil"),
125 }
126 }
127}
128
129impl<'gc> Value<'gc> {
130 #[inline]
131 pub fn array(mc: &Mutation<'gc>, data: Vec<Value<'gc>>) -> Self {
132 Value::List(Gc::new(mc, RefLock::new(List::array(data))))
133 }
134
135 #[inline]
136 pub fn equals(&self, other: &Value<'gc>) -> bool {
137 match (self, other) {
138 (Value::Number(a), Value::Number(b)) => a == b,
139 (Value::Boolean(a), Value::Boolean(b)) => a == b,
140 (Value::String(a), Value::String(b)) => a.equals(b),
141 (Value::IoString(a), Value::IoString(b)) => *a == *b,
142 (Value::String(a), Value::IoString(b)) => a.as_bytes() == b.as_bytes(),
143 (Value::IoString(a), Value::String(b)) => a.as_bytes() == b.as_bytes(),
144 (Value::List(a), Value::List(b)) => a.borrow().equals(&b.borrow()),
145 (Value::Object(a), Value::Object(b)) => Gc::ptr_eq(*a, *b),
146 (Value::Enum(a), Value::Enum(b)) => Gc::ptr_eq(*a, *b),
147 (Value::EnumVariant(a), Value::EnumVariant(b)) => {
148 Gc::ptr_eq(a.enum_, b.enum_) && a.name == b.name
151 }
152 (Value::Class(a), Value::Class(b)) => Gc::ptr_eq(*a, *b),
153 (Value::Closure(a), Value::Closure(b)) => Gc::ptr_eq(*a, *b),
154 (Value::Instance(a), Value::Instance(b)) => Gc::ptr_eq(*a, *b),
155 (Value::BoundMethod(a), Value::BoundMethod(b)) => Gc::ptr_eq(*a, *b),
156 (Value::Agent(a), Value::Agent(b)) => Gc::ptr_eq(*a, *b),
157 (Value::Nil, Value::Nil) => true,
158 _ => false,
160 }
161 }
162
163 pub fn as_number(self) -> Result<f64, VmError> {
164 match self {
165 Value::Number(value) => Ok(value),
166 a => Err(VmError::RuntimeError(format!(
167 "cannot convert to number: {}",
168 a
169 ))),
170 }
171 }
172
173 pub fn as_boolean(&self) -> bool {
174 match self {
175 Value::Boolean(value) => *value,
176 Value::Number(value) => *value != 0.0,
177 Value::String(s) => !s.is_empty(),
178 _ => false,
179 }
180 }
181
182 pub fn as_string(self) -> Result<InternedString<'gc>, VmError> {
183 match self {
184 Value::String(value) => Ok(value),
185 v => Err(VmError::RuntimeError(format!(
186 "cannot convert to string, the value is {v}"
187 ))),
188 }
189 }
190
191 pub fn as_string_value(&self) -> Result<StringValue<'gc>, VmError> {
193 match self {
194 Value::String(s) => Ok(StringValue::Interned(*s)),
195 Value::IoString(s) => Ok(StringValue::Dynamic(*s)),
196 _ => Err(VmError::RuntimeError("Not a string value".into())),
197 }
198 }
199
200 pub fn new_string(ctx: Context<'gc>, s: &str, should_intern: bool) -> Value<'gc> {
202 if should_intern {
203 Value::String(ctx.intern(s.as_bytes()))
204 } else {
205 Value::IoString(Gc::new(&ctx, s.to_string()))
206 }
207 }
208
209 pub fn as_closure(self) -> Result<Gc<'gc, Closure<'gc>>, VmError> {
210 match self {
211 Value::Closure(closure) => Ok(closure),
212 v => Err(VmError::RuntimeError(format!(
213 "cannot convert to closure, the value is {v}"
214 ))),
215 }
216 }
217
218 pub fn as_array(self) -> Result<GcRefLock<'gc, List<'gc>>, VmError> {
219 match self {
220 Value::List(list) => Ok(list),
221 v => Err(VmError::RuntimeError(format!(
222 "cannot convert to array, the value is {v}"
223 ))),
224 }
225 }
226
227 pub fn as_agent(self) -> Result<Gc<'gc, Agent<'gc>>, VmError> {
228 match self {
229 Value::Agent(agent) => Ok(agent),
230 _ => Err(VmError::RuntimeError("cannot convert to agent.".into())),
231 }
232 }
233
234 pub fn as_class(self) -> Result<GcRefLock<'gc, Class<'gc>>, VmError> {
235 match self {
236 Value::Class(class) => Ok(class),
237 v => Err(VmError::RuntimeError(format!(
238 "cannot convert to class, the value is {v}"
239 ))),
240 }
241 }
242
243 pub fn is_error(&self) -> bool {
244 match self {
245 Value::Instance(instance) => instance.borrow().class.borrow().is_error_type(),
247 Value::EnumVariant(variant) => variant.enum_.borrow().is_error_type(),
249 _ => false,
250 }
251 }
252
253 pub fn is_object(&self) -> bool {
254 matches!(self, Value::Object(_))
255 }
256
257 pub fn is_bound_method(&self) -> bool {
258 matches!(self, Value::BoundMethod(_))
259 }
260
261 pub fn is_class(&self) -> bool {
262 matches!(self, Value::Class(_))
263 }
264
265 pub fn is_instance(&self) -> bool {
266 matches!(self, Value::Instance(_))
267 }
268
269 pub fn is_closure(&self) -> bool {
270 matches!(self, Value::Closure(_))
271 }
272
273 pub fn is_native_function(&self) -> bool {
274 matches!(self, Value::NativeFunction(_))
275 }
276
277 pub fn is_nil(&self) -> bool {
278 matches!(self, Value::Nil)
279 }
280
281 pub fn is_number(&self) -> bool {
282 matches!(self, Value::Number(_))
283 }
284
285 pub fn is_boolean(&self) -> bool {
286 matches!(self, Value::Boolean(_) | Value::Nil)
287 }
288
289 pub fn is_true(&self) -> bool {
290 !self.is_falsy()
291 }
292
293 pub fn is_falsy(&self) -> bool {
294 self.is_nil() || (self.is_boolean() && !self.as_boolean())
295 }
296
297 pub fn from_serde_value(ctx: Context<'gc>, value: &serde_json::Value) -> Value<'gc> {
298 match value {
299 serde_json::Value::Bool(b) => Value::Boolean(*b),
300 serde_json::Value::Number(number) => Value::Number(number.as_f64().unwrap()),
301 serde_json::Value::String(str) => {
302 let s = ctx.intern(str.as_bytes());
303 Value::from(s)
304 }
305 serde_json::Value::Object(obj) => {
306 let fields = obj
307 .into_iter()
308 .map(|(key, value)| {
309 (
310 ctx.intern(key.as_bytes()),
311 Value::from_serde_value(ctx, value),
312 )
313 })
314 .collect();
315 Value::Object(Gc::new(&ctx, RefLock::new(Object { fields })))
316 }
317 serde_json::Value::Array(array) => {
318 let data = array
319 .iter()
320 .map(|value| Value::from_serde_value(ctx, value))
321 .collect();
322 Value::array(&ctx, data)
323 }
324 serde_json::Value::Null => Value::Nil,
325 }
326 }
327
328 pub fn to_serde_value(&self) -> serde_json::Value {
329 match self {
330 Value::Number(n) => (*n).into(),
331 Value::Boolean(b) => (*b).into(),
332 Value::String(str) => str.to_string().into(),
333 Value::IoString(str) => str.to_string().into(),
334 Value::List(list) => serde_json::Value::Array(
335 list.borrow()
336 .data
337 .iter()
338 .map(|v| v.to_serde_value())
339 .collect(),
340 ),
341 Value::Object(obj) => serde_json::Value::Object(
342 obj.borrow()
343 .fields
344 .iter()
345 .map(|(k, v)| (k.to_string(), v.to_serde_value()))
346 .collect(),
347 ),
348 Value::Instance(instance) => instance
349 .borrow()
350 .fields
351 .iter()
352 .map(|(k, v)| (k.to_string(), v.to_serde_value()))
353 .collect(),
354 Value::EnumVariant(variant) => variant.value.to_serde_value(),
355 _ => serde_json::Value::Null,
356 }
357 }
358}
359
360impl Value<'_> {
362 pub fn is_enum(&self) -> bool {
363 matches!(self, Value::Enum(_))
364 }
365
366 pub fn is_enum_variant(&self) -> bool {
367 matches!(self, Value::EnumVariant { .. })
368 }
369}
370
371impl From<u64> for Value<'_> {
372 fn from(value: u64) -> Self {
373 Value::Number(value as f64)
374 }
375}
376
377impl From<f64> for Value<'_> {
378 fn from(value: f64) -> Self {
379 Value::Number(value)
380 }
381}
382
383impl From<bool> for Value<'_> {
384 fn from(value: bool) -> Self {
385 Value::Boolean(value)
386 }
387}
388
389impl<'gc> From<InternedString<'gc>> for Value<'gc> {
390 fn from(value: InternedString<'gc>) -> Self {
391 Value::String(value)
392 }
393}
394
395impl<'gc> From<Gc<'gc, String>> for Value<'gc> {
396 fn from(value: Gc<'gc, String>) -> Self {
397 Value::IoString(value)
398 }
399}
400
401impl<'gc> From<Gc<'gc, Closure<'gc>>> for Value<'gc> {
402 fn from(value: Gc<'gc, Closure<'gc>>) -> Self {
403 Value::Closure(value)
404 }
405}
406
407impl<'gc> From<GcRefLock<'gc, Class<'gc>>> for Value<'gc> {
408 fn from(value: GcRefLock<'gc, Class<'gc>>) -> Self {
409 Value::Class(value)
410 }
411}
412
413impl<'gc> From<GcRefLock<'gc, Instance<'gc>>> for Value<'gc> {
414 fn from(value: GcRefLock<'gc, Instance<'gc>>) -> Self {
415 Value::Instance(value)
416 }
417}
418
419impl<'gc> From<Gc<'gc, BoundMethod<'gc>>> for Value<'gc> {
420 fn from(value: Gc<'gc, BoundMethod<'gc>>) -> Self {
421 Value::BoundMethod(value)
422 }
423}
424
425impl<'gc> From<Gc<'gc, Agent<'gc>>> for Value<'gc> {
426 fn from(value: Gc<'gc, Agent<'gc>>) -> Self {
427 Value::Agent(value)
428 }
429}