1use std::borrow::Cow;
2use std::ops::Index;
3
4use bitflags::bitflags;
5use bumpalo::boxed::Box;
6use bumpalo::Bump;
7use hashbrown::HashMap;
8
9use crate::ast::{Ast, AstKind};
10use crate::frame::Frame;
11use crate::functions::FunctionContext;
12use crate::{Error, Result};
13
14pub mod iterator;
15mod range;
16pub mod serialize;
17
18use self::range::Range;
19use self::serialize::{DumpFormatter, PrettyFormatter, Serializer};
20pub use iterator::MemberIterator;
21
22bitflags! {
23 pub struct ArrayFlags: u8 {
24 const SEQUENCE = 0b00000001;
25 const SINGLETON = 0b00000010;
26 const CONS = 0b00000100;
27 const WRAPPED = 0b00001000;
28 }
29}
30
31pub const UNDEFINED: Value = Value::Undefined;
32
33pub enum Value<'a> {
40 Undefined,
41 Null,
42 Number(f64),
43 Bool(bool),
44 String(String),
45 Array(Box<'a, Vec<&'a Value<'a>>>, ArrayFlags),
46 Object(Box<'a, HashMap<String, &'a Value<'a>>>),
47 Lambda {
48 ast: Ast,
49 input: &'a Value<'a>,
50 frame: Frame<'a>,
51 },
52 NativeFn {
53 name: String,
54 arity: usize,
55 func: fn(FunctionContext<'a, '_>, &'a Value<'a>) -> Result<&'a Value<'a>>,
56 },
57 Range(Range<'a>),
58}
59
60#[allow(clippy::mut_from_ref)]
61impl<'a> Value<'a> {
62 pub fn undefined() -> &'a Value<'a> {
63 unsafe { std::mem::transmute::<&Value<'static>, &'a Value<'a>>(&UNDEFINED) }
66 }
67
68 pub fn null(arena: &Bump) -> &mut Value {
69 arena.alloc(Value::Null)
70 }
71
72 pub fn bool(arena: &Bump, value: bool) -> &mut Value {
73 arena.alloc(Value::Bool(value))
74 }
75
76 pub fn number(arena: &Bump, value: impl Into<f64>) -> &mut Value {
77 arena.alloc(Value::Number(value.into()))
78 }
79
80 pub fn string(arena: &Bump, value: impl Into<String>) -> &mut Value {
81 arena.alloc(Value::String(value.into()))
82 }
83
84 pub fn array(arena: &Bump, flags: ArrayFlags) -> &mut Value {
85 arena.alloc(Value::Array(Box::new_in(Vec::new(), arena), flags))
86 }
87
88 pub fn array_with_capacity(arena: &Bump, capacity: usize, flags: ArrayFlags) -> &mut Value {
89 arena.alloc(Value::Array(
90 Box::new_in(Vec::with_capacity(capacity), arena),
91 flags,
92 ))
93 }
94
95 pub fn object(arena: &Bump) -> &mut Value {
96 arena.alloc(Value::Object(Box::new_in(HashMap::new(), arena)))
97 }
98
99 pub fn object_with_capacity(arena: &Bump, capacity: usize) -> &mut Value {
100 arena.alloc(Value::Object(Box::new_in(
101 HashMap::with_capacity(capacity),
102 arena,
103 )))
104 }
105
106 pub fn lambda(
107 arena: &'a Bump,
108 node: &Ast,
109 input: &'a Value<'a>,
110 frame: Frame<'a>,
111 ) -> &'a mut Value<'a> {
112 arena.alloc(Value::Lambda {
113 ast: node.clone(),
114 input,
115 frame,
116 })
117 }
118
119 pub fn nativefn(
120 arena: &'a Bump,
121 name: &str,
122 arity: usize,
123 func: fn(FunctionContext<'a, '_>, &'a Value<'a>) -> Result<&'a Value<'a>>,
124 ) -> &'a mut Value<'a> {
125 arena.alloc(Value::NativeFn {
126 name: name.to_string(),
127 arity,
128 func,
129 })
130 }
131
132 pub fn range(arena: &'a Bump, start: isize, end: isize) -> &'a mut Value<'a> {
133 arena.alloc(Value::Range(Range::new(arena, start, end)))
134 }
135
136 pub fn is_undefined(&self) -> bool {
137 matches!(*self, Value::Undefined)
138 }
139
140 pub fn is_null(&self) -> bool {
141 matches!(*self, Value::Null)
142 }
143
144 pub fn is_bool(&self) -> bool {
145 matches!(&self, Value::Bool(..))
146 }
147
148 pub fn is_number(&self) -> bool {
149 matches!(&self, Value::Number(..))
150 }
151
152 pub fn is_integer(&self) -> bool {
153 match self {
154 Value::Number(n) => match n.classify() {
155 std::num::FpCategory::Nan
156 | std::num::FpCategory::Infinite
157 | std::num::FpCategory::Subnormal => false,
158 _ => {
159 let mantissa = n.trunc();
160 n - mantissa == 0.0
161 }
162 },
163 _ => false,
164 }
165 }
166
167 pub fn is_array_of_valid_numbers(&self) -> Result<bool> {
168 match self {
169 Value::Array(ref a, _) => {
170 for member in a.iter() {
171 if !member.is_valid_number()? {
172 return Ok(false);
173 }
174 }
175 Ok(true)
176 }
177 _ => Ok(false),
178 }
179 }
180
181 pub fn is_valid_number(&self) -> Result<bool> {
182 match self {
183 Value::Number(n) => {
184 if n.is_nan() {
185 Ok(false)
186 } else if n.is_infinite() {
187 Err(Error::D1001NumberOfOutRange(*n))
188 } else {
189 Ok(true)
190 }
191 }
192 _ => Ok(false),
193 }
194 }
195
196 pub fn is_nan(&self) -> bool {
197 matches!(*self, Value::Number(n) if n.is_nan())
198 }
199
200 pub fn is_finite(&self) -> bool {
201 match self {
202 Value::Number(n) => n.is_finite(),
203 _ => false,
204 }
205 }
206
207 pub fn is_string(&self) -> bool {
208 matches!(*self, Value::String(..))
209 }
210
211 pub fn is_array(&self) -> bool {
212 matches!(*self, Value::Array(..) | Value::Range(..))
213 }
214
215 pub fn is_object(&self) -> bool {
216 matches!(*self, Value::Object(..))
217 }
218
219 pub fn is_function(&self) -> bool {
220 matches!(*self, Value::Lambda { .. } | Value::NativeFn { .. })
221 }
222
223 pub fn is_truthy(&'a self) -> bool {
224 match *self {
225 Value::Undefined => false,
226 Value::Null => false,
227 Value::Number(n) => n != 0.0,
228 Value::Bool(ref b) => *b,
229 Value::String(ref s) => !s.is_empty(),
230 Value::Array(ref a, _) => match a.len() {
231 0 => false,
232 1 => self.get_member(0).is_truthy(),
233 _ => {
234 for item in self.members() {
235 if item.is_truthy() {
236 return true;
237 }
238 }
239 false
240 }
241 },
242 Value::Object(ref o) => !o.is_empty(),
243 Value::Lambda { .. } | Value::NativeFn { .. } => false,
244 Value::Range(ref r) => !r.is_empty(),
245 }
246 }
247
248 pub fn get_member(&'a self, index: usize) -> &Value {
249 match *self {
250 Value::Array(ref array, _) => {
251 array.get(index).copied().unwrap_or_else(Value::undefined)
252 }
253 Value::Range(ref range) => range.nth(index).unwrap_or_else(Value::undefined),
254 _ => panic!("Not an array"),
255 }
256 }
257
258 pub fn members(&'a self) -> MemberIterator<'a> {
259 match self {
260 Value::Array(..) | Value::Range(..) => MemberIterator::new(self),
261 _ => panic!("Not an array"),
262 }
263 }
264
265 pub fn entries(&self) -> hashbrown::hash_map::Iter<'_, String, &'a Value> {
266 match self {
267 Value::Object(map) => map.iter(),
268 _ => panic!("Not an object"),
269 }
270 }
271
272 pub fn arity(&self) -> usize {
273 match *self {
274 Value::Lambda { ref ast, .. } => {
275 if let AstKind::Lambda { ref args, .. } = ast.kind {
276 args.len()
277 } else {
278 panic!("Not a lambda function")
279 }
280 }
281 Value::NativeFn { arity, .. } => arity,
282 _ => panic!("Not a function"),
283 }
284 }
285
286 pub fn as_bool(&self) -> bool {
287 match *self {
288 Value::Bool(ref b) => *b,
289 _ => panic!("Not a bool"),
290 }
291 }
292
293 pub fn as_f64(&self) -> f64 {
294 match *self {
295 Value::Number(n) => n,
296 _ => panic!("Not a number"),
297 }
298 }
299
300 pub fn as_usize(&self) -> usize {
302 match *self {
303 Value::Number(n) => n as usize,
304 _ => panic!("Not a number"),
305 }
306 }
307
308 pub fn as_isize(&self) -> isize {
310 match *self {
311 Value::Number(n) => n as isize,
312 _ => panic!("Not a number"),
313 }
314 }
315
316 pub fn as_str(&self) -> Cow<'_, str> {
317 match *self {
318 Value::String(ref s) => Cow::from(s),
319 _ => panic!("Not a string"),
320 }
321 }
322
323 pub fn len(&self) -> usize {
324 match *self {
325 Value::Array(ref array, _) => array.len(),
326 Value::Range(ref range) => range.len(),
327 _ => panic!("Not an array"),
328 }
329 }
330
331 pub fn is_empty(&self) -> bool {
332 match *self {
333 Value::Array(ref array, _) => array.is_empty(),
334 Value::Range(ref range) => range.is_empty(),
335 _ => panic!("Not an array"),
336 }
337 }
338
339 pub fn get_entry(&'a self, key: &str) -> &Value {
340 match *self {
341 Value::Object(ref map) => match map.get(key) {
342 Some(value) => value,
343 None => Value::undefined(),
344 },
345 _ => panic!("Not an object"),
346 }
347 }
348
349 pub fn push(&mut self, value: &'a Value<'a>) {
350 match *self {
351 Value::Array(ref mut array, _) => array.push(value),
352 _ => panic!("Not an array"),
353 }
354 }
355
356 pub fn insert(&mut self, key: &str, value: &'a Value<'a>) {
357 match *self {
358 Value::Object(ref mut map) => {
359 map.insert(key.to_owned(), value);
360 }
361 _ => panic!("Not an object"),
362 }
363 }
364
365 pub fn flatten(&'a self, arena: &'a Bump) -> &'a mut Value<'a> {
366 let flattened = Self::array(arena, ArrayFlags::empty());
367 self._flatten(flattened)
368 }
369
370 fn _flatten(&'a self, flattened: &'a mut Value<'a>) -> &'a mut Value<'a> {
371 let mut flattened = flattened;
372
373 if self.is_array() {
374 for member in self.members() {
375 flattened = member._flatten(flattened);
376 }
377 } else {
378 flattened.push(self)
379 }
380
381 flattened
382 }
383
384 pub fn wrap_in_array(
385 arena: &'a Bump,
386 value: &'a Value<'a>,
387 flags: ArrayFlags,
388 ) -> &'a Value<'a> {
389 arena.alloc(Value::Array(Box::new_in(vec![value], arena), flags))
390 }
391
392 pub fn wrap_in_array_if_needed(
393 arena: &'a Bump,
394 value: &'a Value<'a>,
395 flags: ArrayFlags,
396 ) -> &'a Value<'a> {
397 if value.is_array() {
398 value
399 } else {
400 Value::wrap_in_array(arena, value, flags)
401 }
402 }
403
404 pub fn get_flags(&self) -> ArrayFlags {
405 match *self {
406 Value::Array(_, flags) => flags,
407 _ => panic!("Not an array"),
408 }
409 }
410
411 pub fn has_flags(&self, check_flags: ArrayFlags) -> bool {
412 match *self {
413 Value::Array(_, flags) => flags.contains(check_flags),
414 _ => false,
415 }
416 }
417
418 pub fn clone_array_with_flags(&self, arena: &'a Bump, flags: ArrayFlags) -> &'a Value<'a> {
419 match *self {
420 Value::Array(ref array, _) => arena.alloc(Value::Array(
421 Box::new_in(array.as_ref().clone(), arena),
422 flags,
423 )),
424 _ => panic!("Not an array"),
425 }
426 }
427
428 pub fn serialize(&'a self, pretty: bool) -> String {
429 if pretty {
430 let serializer = Serializer::new(PrettyFormatter::default(), false);
431 serializer.serialize(self).expect("Shouldn't fail")
432 } else {
433 let serializer = Serializer::new(DumpFormatter, false);
434 serializer.serialize(self).expect("Shouldn't fail")
435 }
436 }
437}
438
439impl<'a> PartialEq<Value<'a>> for Value<'a> {
440 fn eq(&self, other: &Value<'a>) -> bool {
441 match (self, other) {
442 (Value::Undefined, Value::Undefined) => true,
443 (Value::Null, Value::Null) => true,
444 (Value::Number(l), Value::Number(r)) => *l == *r,
445 (Value::Bool(l), Value::Bool(r)) => *l == *r,
446 (Value::String(l), Value::String(r)) => *l == *r,
447 (Value::Array(l, ..), Value::Array(r, ..)) => *l == *r,
448 (Value::Object(l), Value::Object(r)) => *l == *r,
449 (Value::Range(l), Value::Range(r)) => *l == *r,
450 _ => false,
451 }
452 }
453}
454
455impl PartialEq<bool> for Value<'_> {
456 fn eq(&self, other: &bool) -> bool {
457 match *self {
458 Value::Bool(ref b) => *b == *other,
459 _ => false,
460 }
461 }
462}
463
464impl PartialEq<usize> for Value<'_> {
465 fn eq(&self, other: &usize) -> bool {
466 match self {
467 Value::Number(..) => self.as_usize() == *other,
468 _ => false,
469 }
470 }
471}
472
473impl PartialEq<isize> for Value<'_> {
474 fn eq(&self, other: &isize) -> bool {
475 match self {
476 Value::Number(..) => self.as_isize() == *other,
477 _ => false,
478 }
479 }
480}
481
482impl PartialEq<&str> for Value<'_> {
483 fn eq(&self, other: &&str) -> bool {
484 match *self {
485 Value::String(ref s) => s == *other,
486 _ => false,
487 }
488 }
489}
490
491impl<'a> Index<&str> for Value<'a> {
492 type Output = Value<'a>;
493
494 fn index(&self, index: &str) -> &Self::Output {
495 match *self {
496 Value::Object(ref o) => match o.get(index) {
497 Some(value) => value,
498 None => Value::undefined(),
499 },
500 _ => Value::undefined(),
501 }
502 }
503}
504
505impl<'a> Index<usize> for Value<'a> {
506 type Output = Value<'a>;
507
508 fn index(&self, index: usize) -> &Self::Output {
509 match *self {
510 Value::Array(ref a, _) => match a.get(index) {
511 Some(value) => value,
512 None => Value::undefined(),
513 },
514 Value::Range(ref r) => &r[index],
515 _ => Value::undefined(),
516 }
517 }
518}
519
520impl std::fmt::Debug for Value<'_> {
521 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
522 match self {
523 Self::Undefined => write!(f, "undefined"),
524 Self::Null => write!(f, "null"),
525 Self::Number(n) => n.fmt(f),
526 Self::Bool(b) => b.fmt(f),
527 Self::String(s) => s.fmt(f),
528 Self::Array(a, _) => a.fmt(f),
529 Self::Object(o) => o.fmt(f),
530 Self::Lambda { .. } => write!(f, "<lambda>"),
531 Self::NativeFn { .. } => write!(f, "<nativefn>"),
532 Self::Range(r) => write!(f, "<range({},{})>", r.start(), r.end()),
533 }
534 }
535}
536
537impl std::string::ToString for Value<'_> {
538 fn to_string(&self) -> String {
539 match self {
540 Self::Undefined => "undefined".to_string(),
541 Self::Null => "null".to_string(),
542 Self::Number(n) => n.to_string(),
543 Self::Bool(b) => b.to_string(),
544 Self::String(s) => s.clone(),
545 Self::Array(..) => "<array>".to_string(),
546 Self::Object(..) => "<object>".to_string(),
547 Self::Lambda { .. } => "<lambda>".to_string(),
548 Self::NativeFn { .. } => "<nativefn>".to_string(),
549 Self::Range(r) => format!("<range({},{})>", r.start(), r.end()),
550 }
551 }
552}