seq_runtime/
value.rs

1use crate::seqstring::SeqString;
2
3/// Value: What the language talks about
4///
5/// This is pure data with no pointers to other values.
6/// Values can be pushed on the stack, stored in variants, etc.
7/// The key insight: Value is independent of Stack structure.
8#[derive(Debug, Clone, PartialEq)]
9pub enum Value {
10    /// Integer value
11    Int(i64),
12
13    /// Floating-point value (IEEE 754 double precision)
14    Float(f64),
15
16    /// Boolean value
17    Bool(bool),
18
19    /// String (arena or globally allocated via SeqString)
20    String(SeqString),
21
22    /// Variant (sum type with tagged fields)
23    Variant(Box<VariantData>),
24
25    /// Quotation (stateless function pointer stored as usize for Send safety)
26    /// No captured environment - backward compatible
27    Quotation(usize),
28
29    /// Closure (quotation with captured environment)
30    /// Contains function pointer and boxed array of captured values
31    Closure {
32        /// Function pointer (transmuted to function taking Stack + environment)
33        fn_ptr: usize,
34        /// Captured values from creation site
35        /// Ordered top-down: env[0] is top of stack at creation
36        env: Box<[Value]>,
37    },
38}
39
40// Safety: Value can be sent between strands (green threads)
41// - Int, Float, Bool, String are all Send
42// - Variant contains only Send types (recursively)
43// - Quotation stores function pointer as usize (Send-safe)
44// - Closure: fn_ptr is usize (Send), env is Box<[Value]> (Send because Value is Send)
45// This is required for channel communication between strands
46unsafe impl Send for Value {}
47
48/// VariantData: Composite values (sum types)
49///
50/// Fields are stored in a heap-allocated array, NOT linked via next pointers.
51/// This is the key difference from cem2, which used StackCell.next for field linking.
52#[derive(Debug, Clone, PartialEq)]
53pub struct VariantData {
54    /// Tag identifies which variant constructor was used
55    pub tag: u32,
56
57    /// Fields stored as an owned array of values
58    /// This is independent of any stack structure
59    pub fields: Box<[Value]>,
60}
61
62impl VariantData {
63    /// Create a new variant with the given tag and fields
64    pub fn new(tag: u32, fields: Vec<Value>) -> Self {
65        Self {
66            tag,
67            fields: fields.into_boxed_slice(),
68        }
69    }
70}
71
72// We'll implement proper cleanup in Drop later
73// For now, Rust's ownership handles most of it