Skip to main content

swan_core/
value.rs

1//! Runtime values of the Swan language.
2//!
3//! The central type is [`Value`], which represents every first-class Swan
4//! value: scalars (`Nothing`, `Bool`, `Numb`, `Text`), collections (`List`,
5//! `Namespace`, `Tuple`), callables (`Func`, `Builtin`), asynchronous results
6//! (`Promise`), and the non-throwing error value `Undefined`.
7//!
8//! # Tuples
9//!
10//! Every `Value` is conceptually a tuple. `Nothing` is the empty tuple, any
11//! non-`Tuple` value is a one-element tuple, and `Value::Tuple` is a tuple of
12//! two or more items. [`Value::items`], [`Value::pair`], [`Value::map`] and
13//! [`Value::normalize`] all work with this view. Tuples are always flat and
14//! never contain `Nothing` once normalized.
15//!
16//! # Submodules
17//!
18//! - [`Scope`]: lexical environment, also used as the storage of `Namespace`.
19//! - [`Undef`]: description of why an operation was undefined.
20//! - [`BuiltinFn`]: wrapper around a native Rust function.
21//! - [`Promise`]: single-assignment asynchronous value.
22//!
23//! # Comparison and conversion
24//!
25//! `Value` implements `PartialEq` and `PartialOrd` by hand (see the impl docs)
26//! and converts to `bool` through `From<Value> for bool`.
27
28use std::rc::Rc;
29use std::cell::RefCell;
30use std::collections::HashMap;
31use std::cmp::Ordering;
32use std::fmt;
33use crate::ast::Node;
34
35// Lexical scopes and namespaces
36mod scope;
37pub use scope::Scope;
38
39// Explanations of why an operation is undefined
40mod undef;
41pub use undef::Undef;
42
43// Native Rust functions callable from Swan
44mod func;
45pub use func::BuiltinFn;
46
47// Single-assignment asynchronous values
48mod promise;
49pub use promise::Promise;
50
51
52
53// ----------------------------------------------------------------------------
54//  Value  (every first-class Swan value)
55// ----------------------------------------------------------------------------
56
57/// Any first-class Swan value.
58///
59/// Cloning is cheap: heap-backed variants (`Text`, `List`, `Tuple`, `Name`)
60/// use `Rc`, and `Scope`, `Promise` and `BuiltinFn` are handles that share
61/// state when cloned.
62///
63/// The Swan type name of each variant (as returned by the `type` built-in) is
64/// the variant name, except that `Builtin` reports `Func`.
65///
66/// # Examples
67///
68/// ```
69/// use swan_core::value::Value;
70///
71/// let t = Value::tuple(vec![Value::Numb(1.0), Value::Nothing, Value::Numb(2.0)]);
72/// assert_eq!(t.items().count(), 2);
73/// assert!(bool::from(t));
74/// ```
75#[derive(Debug, Clone)]
76pub enum Value {
77
78    /// The empty tuple `()`. Also the result of failed lookups such as out-of-range list indexing.
79    Nothing,
80
81    /// A boolean, `TRUE` or `FALSE`.
82    Bool(bool),
83
84    /// A 64-bit floating-point number.
85    Numb(f64),
86
87    /// An immutable UTF-8 string.
88    Text(Rc<str>),
89
90    /// An ordered, integer-indexed sequence — `[a, b, c]`.
91    List(Rc<Vec<Value>>),
92
93    /// A first-class namespace — `{ x: 1, y: 2 }`.
94    ///
95    /// Backed by a [`Scope`]. Applying a namespace to a `Text` key performs an
96    /// own-only lookup (parent scopes are not consulted) and yields `Nothing`
97    /// if the key is absent. Equality compares bindings (and parents) by value.
98    Namespace(Scope),
99
100    /// A user-defined function.
101    Func {
102        /// Parameter pattern: a `Name` or a tuple of names.
103        params:  Box<Value>,
104        /// Unevaluated body expression.
105        body:    Box<Node>,
106        /// Scope captured at definition time.
107        closure: Scope,
108    },
109
110    /// A native Rust function callable from Swan.
111    Builtin(BuiltinFn),
112
113    /// A promise. It resolves at most once and never rejects; an `Undefined` result resolves to `Nothing`.
114    Promise(Promise),
115
116    /// The result of an invalid operation, such as `"a" - 1`.
117    ///
118    /// Swan expressions do not throw exceptions; they return `Undefined`
119    /// values instead. The [`Undef`] payload describes what went wrong.
120    Undefined(Undef),
121
122    /// The Swan product type — a heterogeneous sequence of items produced by
123    /// the comma operator `a, b, c`.  A Tuple of zero items is `Nothing`.
124    /// A Tuple of exactly one item normalises to that item.
125    /// Construct with [`Value::tuple`] so the result is normalized.
126    Tuple(Rc<Vec<Value>>),
127
128    /// An identifier in a binding position: the left side of `=`, `:` or
129    /// `->`, or the operand of `$`. It is produced only while evaluating those
130    /// positions and has no meaning as a runtime result.
131    Name(Rc<str>),
132}
133
134
135impl Value {
136
137    /// Builds `Undefined` for unary operation `op` applied to `val`; `pos` is the source byte offset.
138    #[inline]
139    pub fn undef_unary(op: &'static str, val: Value, pos: usize) -> Value {
140        Value::Undefined(Undef::UnaryOperation {
141            op,
142            val: Box::new(val),
143            pos
144        })
145    }
146
147    /// Builds `Undefined` for binary operation `op` applied to `lhv` and `rhv`; `pos` is the source byte offset.
148    #[inline]
149    pub fn undef_binary(op: &'static str, lhv: Value, rhv: Value, pos: usize) -> Value {
150        Value::Undefined(Undef::BinaryOperation {
151            op,
152            lhv: Box::new(lhv),
153            rhv: Box::new(rhv),
154            pos
155        })
156    }
157
158    /// Builds a `List` from `items`.
159    #[inline]
160    pub fn list(items: Vec<Value>) -> Value {
161        Value::List(Rc::new(items))
162    }
163    
164    /// Builds a normalized tuple from `items`.
165    ///
166    /// Zero items give `Nothing`. One item gives that item. Nested tuples are
167    /// flattened and `Nothing` items are dropped (see [`Value::normalize`]).
168    #[inline]
169    pub fn tuple(items: Vec<Value>) -> Value {
170        match items.len() {
171            0 => Value::Nothing,
172            _ => Value::Tuple(Rc::new(items)).normalize(),
173        }
174    }
175}
176
177
178
179// ----------------------------------------------------------------------------
180//  Implement equality and order for Value
181// ----------------------------------------------------------------------------
182
183/// Structural equality.
184///
185/// Values of different variants are never equal. `Promise`s are equal only
186/// if they are the same promise (pointer identity). `Func`, `Builtin` and
187/// `Name` are never equal to anything, including themselves. `Undefined`
188/// values compare by operation and operands, ignoring source position.
189impl PartialEq for Value {
190    fn eq(&self, other: &Self) -> bool {
191        match (self, other) {
192            (Value::Bool(a),      Value::Bool(b))      => a == b,
193            (Value::Numb(a),      Value::Numb(b))      => a == b,
194            (Value::Text(a),      Value::Text(b))      => a == b,
195            (Value::List(a),      Value::List(b))      => a == b,
196            (Value::Tuple(a),     Value::Tuple(b))     => a == b,
197            (Value::Namespace(a), Value::Namespace(b)) => a == b,
198            (Value::Undefined(a), Value::Undefined(b)) => a == b,
199            (Value::Promise(a),   Value::Promise(b))   => Rc::ptr_eq(&a.0, &b.0),
200            (Value::Nothing,      Value::Nothing)      => true,
201            // Every other pair is never equal
202            _ => false,
203        }
204    }
205}
206
207/// Partial ordering between values.
208///
209/// Only values of the same variant are comparable (`Bool`, `Numb`, `Text`,
210/// `List`, `Tuple`); lists and tuples compare lexicographically, with the
211/// shorter sequence ordering first. `Nothing` equals `Nothing` and orders
212/// before every other value. Every other pair returns `None`
213/// (e.g. `NaN`, mixed types, `Func`, `Builtin`, `Namespace`, `Promise`, `Undefined`).
214impl PartialOrd for Value {
215    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
216        match (self, other) {
217            (Value::Bool(a),  Value::Bool(b))  => a.partial_cmp(b),
218            (Value::Numb(a),  Value::Numb(b))  => a.partial_cmp(b),
219            (Value::Text(a),  Value::Text(b))  => a.partial_cmp(b),
220            (Value::List(a),  Value::List(b))  => compare_iterators(a.iter(), b.iter()),
221            (Value::Tuple(a), Value::Tuple(b)) => compare_iterators(a.iter(), b.iter()),
222            // Nothing is equal to Nothing and less that anything else.
223            (Value::Nothing,  Value::Nothing)  => Some(Ordering::Equal),
224            (Value::Nothing,  _)               => Some(Ordering::Less),
225            (_,  Value::Nothing)               => Some(Ordering::Greater),
226            
227            // All other pairs are unordered.
228            _ => None,
229        }
230    }
231}
232
233/// Helper function to perform lexicographical comparison between item iterators.
234/// Returns `None` as soon as two corresponding items are unordered.
235fn compare_iterators<'a>(
236    mut it1: impl Iterator<Item = &'a Value>,
237    mut it2: impl Iterator<Item = &'a Value>,
238) -> Option<Ordering> {
239    loop {
240        match (it1.next(), it2.next()) {
241            (None, None)    => return Some(Ordering::Equal),
242            (None, Some(_)) => return Some(Ordering::Less),    // Shorter tuple/list is Less
243            (Some(_), None) => return Some(Ordering::Greater), // Longer tuple/list is Greater
244            (Some(a), Some(b)) => match a.partial_cmp(b) {
245                Some(Ordering::Equal) => continue,
246                non_eq => return non_eq,
247            },
248        }
249    }
250}
251
252
253
254// ----------------------------------------------------------------------------
255//  ValueIter  (generic "tuple item" iterator over any Value)
256//
257//  Every Value in Swan is conceptually a Tuple: `Nothing` is the empty tuple,
258//  any non-Tuple Item behaves like a 1-element tuple, and `Value::Tuple`
259//  behaves like the sequence of its elements. `ValueIter` implements this
260//  view uniformly, mirroring `Term.items()` in the JS reference.
261//
262//  Nested tuples are flattened (defensively — well-formed values should never
263//  contain a Tuple element after normalisation, but the iterator handles it
264//  anyway) and `Nothing` items are skipped, so `(1, (), 2)` yields `1, 2`,
265//  not `1, Nothing, 2`.
266// ----------------------------------------------------------------------------
267
268/// An iterator over the items of a value seen as a tuple.
269///
270/// Created by [`Value::items`]. Nested tuples are flattened and `Nothing`
271/// items are skipped.
272#[derive(Debug, Clone)]
273pub struct ValueIter {
274    /// Stack of (tuple, next_index) frames; the last entry is the tuple
275    /// currently being consumed. Nested tuples push a new frame; exhausted
276    /// frames are popped.
277    stack: Vec<(Rc<Vec<Value>>, usize)>,
278}
279
280impl ValueIter {
281    /// Creates an iterator over `value` viewed as a tuple: `Nothing` is empty, a `Tuple` yields its items, and any other value yields itself once.
282    fn new(value: Value) -> Self {
283        match value {
284            Value::Nothing  => ValueIter { stack: Vec::new() },
285            Value::Tuple(v) => ValueIter { stack: vec![(v, 0)] },
286            other           => ValueIter { stack: vec![(Rc::new(vec![other]), 0)] },
287        }
288    }
289}
290
291impl Iterator for ValueIter {
292    type Item = Value;
293
294    fn next(&mut self) -> Option<Value> {
295        loop {
296            let (items, idx) = self.stack.last_mut()?;
297
298            if *idx >= items.len() {
299                self.stack.pop();
300                continue;
301            }
302
303            let item = items[*idx].clone();
304            *idx += 1;
305
306            match item {
307                Value::Nothing  => continue,          // skip Nothing items
308                Value::Tuple(v) => self.stack.push((v, 0)),  // flatten
309                other           => return Some(other),
310            }
311        }
312    }
313}
314
315impl std::iter::FusedIterator for ValueIter {}
316
317
318
319// ----------------------------------------------------------------------------
320//  Pairs  (generic "tuple item pair" iterator over two Values)
321//
322//  Yields corresponding pairs of items from two values (each treated as a
323//  tuple), mirroring `Term.iterPairs(other)` in the JS reference.
324//
325//  When the two tuples have different lengths, the missing items from the
326//  shorter tuple are replaced with `Value::Nothing`.
327// ----------------------------------------------------------------------------
328
329/// An iterator over the corresponding items of two values seen as tuples.
330///
331/// Created by [`Value::pair`] or [`Pairs::new`]. When one value has fewer
332/// items, the missing items are [`Value::Nothing`].
333#[derive(Debug, Clone)]
334pub struct Pairs {
335    iter1: ValueIter,
336    iter2: ValueIter,
337}
338
339impl Pairs {
340    /// Creates a new `Pairs` iterator from two values.
341    pub fn new(first: &Value, second: &Value) -> Self {
342        Self {
343            iter1: first.items(),
344            iter2: second.items(),
345        }
346    }
347}
348
349impl Iterator for Pairs {
350    type Item = (Value, Value);
351
352    fn next(&mut self) -> Option<Self::Item> {
353        let item1 = self.iter1.next();
354        let item2 = self.iter2.next();
355
356        match (item1, item2) {
357            (None, None) => None,
358            (Some(v1), Some(v2)) => Some((v1, v2)),
359            (Some(v1), None) => Some((v1, Value::Nothing)),
360            (None, Some(v2)) => Some((Value::Nothing, v2)),
361        }
362    }
363}
364
365impl std::iter::FusedIterator for Pairs {}
366
367
368
369// ----------------------------------------------------------------------------
370//  Value tuple methods
371// ----------------------------------------------------------------------------
372
373impl Value {
374    /// Returns an iterator over this value's items, treating it as a tuple.
375    ///
376    /// - `Nothing` yields no items.
377    /// - `Tuple` yields its items (recursively flattened, `Nothing` skipped).
378    /// - Any other value yields itself as the single item.
379    pub fn items(&self) -> ValueIter {
380        ValueIter::new(self.clone())
381    }
382
383    /// Returns an iterator yielding corresponding pairs of items between
384    /// `self` and `other`, treating each value as a tuple.
385    ///
386    /// If the two values have different lengths, the missing items from the
387    /// shorter tuple are replaced with [`Value::Nothing`].
388    pub fn pair(&self, other: &Value) -> Pairs {
389        Pairs::new(self, other)
390    }
391
392    /// Returns the canonical form of this value.
393    ///
394    /// For a `Tuple`, nested tuples are flattened and `Nothing` items are
395    /// removed. The result is `Nothing` if no items remain, the sole item if
396    /// one remains, and a `Tuple` otherwise. Non-tuple values are returned
397    /// unchanged (cloned).
398    pub fn normalize(&self) -> Self {
399        if matches!(self, Value::Tuple(_)) {
400            let flat_items: Vec<_> = self.items().collect();
401            match flat_items.len() {
402                0 => Value::Nothing,
403                1 => flat_items[0].clone(),
404                _ => Value::Tuple(Rc::new(flat_items)),
405            }
406        } else {
407            self.clone()
408        }
409    }
410
411    /// Maps a function `f: Value -> Value` over this `Value`:
412    /// - `Value::Nothing` -> `Value::Nothing`
413    /// - `Value::Tuple`   -> `Value::Tuple` containing `f(v1), f(v2), ..., f(vn)`
414    /// - Any other value  -> `f(self)`
415    /// The result of mapping over a tuple is normalized, so items that map to `Nothing` are dropped.
416    pub fn map(&self, f: impl Fn(Value) -> Value + 'static) -> Value {
417        match self {
418            Value::Nothing => Value::Nothing,
419            Value::Tuple(items) => {
420                let mapped_items: Vec<Value> = items
421                    .iter()
422                    .map(|item| f(item.clone()))
423                    .collect();
424                Value::tuple(mapped_items)
425            }
426            _ => f(self.clone()),
427        }
428    }
429}
430
431
432
433// ----------------------------------------------------------------------------
434//  Value type casting
435// ----------------------------------------------------------------------------
436
437/// Truthiness of a value.
438///
439/// - `Nothing` and `Undefined` are false.
440/// - `Bool` is itself; `Numb` is false only for `0`; `Text` and `List` are
441///   true when non-empty; `Namespace` is true when it has at least one binding.
442/// - `Func` and `Builtin` are always true.
443/// - A `Promise` is true once it is resolved (whatever its value) and false
444///   while it is pending.
445/// - A `Name` has no boolean meaning and is false.
446/// - A `Tuple` is true if at least one item is true.
447impl From<Value> for bool {
448    fn from(val: Value) -> Self {
449        match val {
450            Value::Nothing      => false,
451            Value::Bool(b)      => b,
452            Value::Numb(n)      => n != 0.0,
453            Value::Text(t)      => !t.is_empty(),
454            Value::List(v)      => !v.is_empty(),
455            Value::Func{..}     => true,
456            Value::Builtin(_)   => true,
457            Value::Undefined(_) => false,
458            Value::Namespace(s) => s.0.borrow().bindings.len() > 0,
459            Value::Tuple(_) => {
460                // Returns true if AT LEAST ONE item in the tuple converts to true.
461                // If ALL items map to false, `.any()` returns false.
462                val.items().any(|item| bool::from(item))
463            }
464            Value::Promise(p)   => p.0.borrow().value.is_some(),
465            Value::Name(_)      => false,
466        }
467    }
468}
469
470
471
472// ============================================================================
473//  Tests
474// ============================================================================
475
476#[cfg(test)]
477mod tuple_tests {
478    use super::*;
479    // Tests for tuple iteration, pairing and normalization.
480
481    #[test]
482    fn test_pairs_same_length() {
483        let t1 = Value::tuple(vec![Value::Numb(1.0), Value::Numb(2.0), Value::Numb(3.0)]);
484        let t2 = Value::tuple(vec![Value::Numb(10.0), Value::Numb(20.0), Value::Numb(30.0)]);
485
486        let pairs: Vec<(Value, Value)> = t1.pair(&t2).collect();
487        assert_eq!(pairs.len(), 3);
488        assert_eq!(pairs[0], (Value::Numb(1.0), Value::Numb(10.0)));
489        assert_eq!(pairs[1], (Value::Numb(2.0), Value::Numb(20.0)));
490        assert_eq!(pairs[2], (Value::Numb(3.0), Value::Numb(30.0)));
491    }
492
493    #[test]
494    fn test_pairs_first_longer() {
495        let t1 = Value::tuple(vec![Value::Numb(1.0), Value::Numb(2.0), Value::Numb(3.0)]);
496        let t2 = Value::tuple(vec![Value::Numb(10.0), Value::Numb(20.0)]);
497
498        let pairs: Vec<(Value, Value)> = t1.pair(&t2).collect();
499        assert_eq!(pairs.len(), 3);
500        assert_eq!(pairs[0], (Value::Numb(1.0), Value::Numb(10.0)));
501        assert_eq!(pairs[1], (Value::Numb(2.0), Value::Numb(20.0)));
502        assert_eq!(pairs[2], (Value::Numb(3.0), Value::Nothing));
503    }
504
505    #[test]
506    fn test_pairs_second_longer() {
507        let t1 = Value::tuple(vec![Value::Numb(1.0), Value::Numb(2.0)]);
508        let t2 = Value::tuple(vec![Value::Numb(10.0), Value::Numb(20.0), Value::Numb(30.0)]);
509
510        let pairs: Vec<(Value, Value)> = t1.pair(&t2).collect();
511        assert_eq!(pairs.len(), 3);
512        assert_eq!(pairs[0], (Value::Numb(1.0), Value::Numb(10.0)));
513        assert_eq!(pairs[1], (Value::Numb(2.0), Value::Numb(20.0)));
514        assert_eq!(pairs[2], (Value::Nothing, Value::Numb(30.0)));
515    }
516
517    #[test]
518    fn test_pairs_both_empty() {
519        let t1 = Value::Nothing;
520        let t2 = Value::Nothing;
521
522        let pairs: Vec<(Value, Value)> = t1.pair(&t2).collect();
523        assert!(pairs.is_empty());
524    }
525
526    #[test]
527    fn test_pairs_first_empty() {
528        let t1 = Value::Nothing;
529        let t2 = Value::tuple(vec![Value::Numb(10.0), Value::Numb(20.0)]);
530
531        let pairs: Vec<(Value, Value)> = t1.pair(&t2).collect();
532        assert_eq!(pairs.len(), 2);
533        assert_eq!(pairs[0], (Value::Nothing, Value::Numb(10.0)));
534        assert_eq!(pairs[1], (Value::Nothing, Value::Numb(20.0)));
535    }
536
537    #[test]
538    fn test_pairs_second_empty() {
539        let t1 = Value::tuple(vec![Value::Numb(1.0), Value::Numb(2.0)]);
540        let t2 = Value::Nothing;
541
542        let pairs: Vec<(Value, Value)> = t1.pair(&t2).collect();
543        assert_eq!(pairs.len(), 2);
544        assert_eq!(pairs[0], (Value::Numb(1.0), Value::Nothing));
545        assert_eq!(pairs[1], (Value::Numb(2.0), Value::Nothing));
546    }
547
548    #[test]
549    fn test_pairs_scalars() {
550        let v1 = Value::Numb(42.0);
551        let v2 = Value::Text("swan".into());
552
553        let pairs: Vec<(Value, Value)> = v1.pair(&v2).collect();
554        assert_eq!(pairs.len(), 1);
555        assert_eq!(pairs[0], (Value::Numb(42.0), Value::Text("swan".into())));
556    }
557
558    #[test]
559    fn test_pairs_nested_tuples_flattened() {
560        let inner = Value::tuple(vec![Value::Numb(2.0), Value::Numb(3.0)]);
561        let t1 = Value::tuple(vec![Value::Numb(1.0), inner]);
562        let t2 = Value::tuple(vec![Value::Numb(10.0), Value::Numb(20.0), Value::Numb(30.0)]);
563
564        let pairs: Vec<(Value, Value)> = t1.pair(&t2).collect();
565        assert_eq!(pairs.len(), 3);
566        assert_eq!(pairs[0], (Value::Numb(1.0), Value::Numb(10.0)));
567        assert_eq!(pairs[1], (Value::Numb(2.0), Value::Numb(20.0)));
568        assert_eq!(pairs[2], (Value::Numb(3.0), Value::Numb(30.0)));
569    }
570
571    #[test]
572    fn test_pairs_skips_nothing_in_tuples() {
573        let t1 = Value::tuple(vec![Value::Numb(1.0), Value::Nothing, Value::Numb(2.0)]);
574        let t2 = Value::tuple(vec![Value::Numb(10.0), Value::Numb(20.0)]);
575
576        let pairs: Vec<(Value, Value)> = t1.pair(&t2).collect();
577        assert_eq!(pairs.len(), 2);
578        assert_eq!(pairs[0], (Value::Numb(1.0), Value::Numb(10.0)));
579        assert_eq!(pairs[1], (Value::Numb(2.0), Value::Numb(20.0)));
580    }
581
582    #[test]
583    fn test_pairs_fused_iterator() {
584        let t1 = Value::Nothing;
585        let t2 = Value::Nothing;
586
587        let mut pairs = t1.pair(&t2);
588        assert_eq!(pairs.next(), None);
589        assert_eq!(pairs.next(), None);
590        assert_eq!(pairs.next(), None);
591    }
592}
593
594
595
596#[cfg(test)]
597mod boolean_conversion_tests {
598    use super::*;
599    // Tests for `From<Value> for bool`.
600
601    #[test]
602    fn test_primitives_to_bool() {
603        assert!(!bool::from(Value::Nothing));
604        assert!(!bool::from(Value::Bool(false)));
605        assert!(bool::from(Value::Bool(true)));
606        assert!(!bool::from(Value::Numb(0.0)));
607        assert!(bool::from(Value::Numb(1.5)));
608        assert!(!bool::from(Value::Text("".into())));
609        assert!(bool::from(Value::Text("hello".into())));
610        assert!(!bool::from(Value::list(vec![])));
611        assert!(bool::from(Value::list(vec![Value::Numb(1.0)])));
612    }
613
614    #[test]
615    fn test_tuple_all_false_maps_to_false() {
616        // A tuple where all items map to false
617        let all_false_tuple = Value::tuple(vec![
618            Value::Bool(false),
619            Value::Numb(0.0),
620            Value::Text("".into()),
621            Value::Nothing,
622        ]);
623
624        assert!(!bool::from(all_false_tuple));
625    }
626
627    #[test]
628    fn test_tuple_at_least_one_true_maps_to_true() {
629        // A tuple where at least one item maps to true
630        let one_true_tuple = Value::tuple(vec![
631            Value::Bool(false),
632            Value::Numb(0.0),
633            Value::Text("truthy".into()),
634            Value::Nothing,
635        ]);
636
637        assert!(bool::from(one_true_tuple));
638    }
639
640    #[test]
641    fn test_nested_tuple_all_false_maps_to_false() {
642        // Nested tuples evaluate elements recursively via items()
643        let inner_false = Value::tuple(vec![Value::Numb(0.0), Value::Bool(false)]);
644        let nested_all_false = Value::tuple(vec![Value::Nothing, inner_false]);
645
646        assert!(!bool::from(nested_all_false));
647    }
648
649    #[test]
650    fn test_promise_is_true_once_resolved() {
651        let p = crate::value::Promise::new();
652        assert!(!bool::from(Value::Promise(p.clone())));
653
654        // Resolved: true, even when the value itself is false
655        p.resolve(Value::Bool(false));
656        assert!(bool::from(Value::Promise(p)));
657
658        let q = crate::value::Promise::new();
659        q.resolve(Value::Nothing);
660        assert!(bool::from(Value::Promise(q)));
661    }
662
663    #[test]
664    fn test_name_maps_to_false() {
665        assert!(!bool::from(Value::Name("x".into())));
666    }
667}