Skip to main content

oxilean_runtime/object/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use oxilean_kernel::Name;
6use std::collections::HashMap;
7use std::hash::{Hash, Hasher};
8
9use super::functions::BoxInto;
10use super::rtobject_type::RtObject;
11
12/// Data for a big integer.
13#[derive(Clone, Debug)]
14pub struct BigIntData {
15    /// Object header.
16    pub header: ObjectHeader,
17    /// Sign: true = negative.
18    pub negative: bool,
19    /// Magnitude as limbs.
20    pub digits: Vec<u64>,
21}
22/// Data for a string object.
23#[derive(Clone, Debug)]
24pub struct StringData {
25    /// Object header.
26    pub header: ObjectHeader,
27    /// The string value.
28    pub value: String,
29    /// Cached hash.
30    pub cached_hash: Option<u64>,
31}
32/// Data for a big natural number.
33#[derive(Clone, Debug)]
34pub struct BigNatData {
35    /// Object header.
36    pub header: ObjectHeader,
37    /// Limbs (base-2^64 digits, least significant first).
38    pub digits: Vec<u64>,
39}
40/// Thunk state.
41#[derive(Clone, Debug)]
42pub enum ThunkState {
43    /// Thunk has not been evaluated.
44    Unevaluated {
45        /// Closure to evaluate.
46        closure: RtObject,
47    },
48    /// Thunk is currently being evaluated (cycle detection).
49    Evaluating,
50    /// Thunk has been evaluated and the result is cached.
51    Evaluated {
52        /// The cached result.
53        value: RtObject,
54    },
55    /// Thunk evaluation resulted in an exception.
56    Excepted {
57        /// The exception value.
58        exception: RtObject,
59    },
60}
61/// Data for a boxed float.
62#[derive(Clone, Debug)]
63pub struct BoxedFloatData {
64    /// Object header.
65    pub header: ObjectHeader,
66    /// The float value.
67    pub value: f64,
68}
69/// Data for a mutual recursive closure group.
70#[derive(Clone, Debug)]
71pub struct MutRecData {
72    /// Object header.
73    pub header: ObjectHeader,
74    /// The closures in the mutual recursive group.
75    pub closures: Vec<RtObject>,
76    /// Which closure in the group this reference points to.
77    pub index: u32,
78}
79/// Access fields of constructor objects.
80pub struct FieldAccess;
81impl FieldAccess {
82    /// Get a field of a constructor object by index.
83    pub fn get_field(obj: &RtObject, field_index: usize) -> Option<RtObject> {
84        obj.with_heap(|heap| {
85            if let HeapObject::Constructor(data) = heap {
86                data.object_fields.get(field_index).cloned()
87            } else {
88                None
89            }
90        })
91        .flatten()
92    }
93    /// Set a field of a constructor object by index (requires unique ownership).
94    pub fn set_field(obj: &RtObject, field_index: usize, value: RtObject) -> bool {
95        obj.with_heap_mut(|heap| {
96            if let HeapObject::Constructor(data) = heap {
97                if field_index < data.object_fields.len() {
98                    data.object_fields[field_index] = value;
99                    return true;
100                }
101            }
102            false
103        })
104        .unwrap_or(false)
105    }
106    /// Get the constructor index of an object.
107    pub fn get_ctor_index(obj: &RtObject) -> Option<u32> {
108        if let Some(idx) = obj.as_small_ctor() {
109            return Some(idx);
110        }
111        obj.with_heap(|heap| {
112            if let HeapObject::Constructor(data) = heap {
113                Some(data.ctor_index)
114            } else {
115                None
116            }
117        })
118        .flatten()
119    }
120    /// Get the number of fields of a constructor object.
121    pub fn num_fields(obj: &RtObject) -> Option<usize> {
122        if obj.is_small_ctor() {
123            return Some(0);
124        }
125        obj.with_heap(|heap| {
126            if let HeapObject::Constructor(data) = heap {
127                Some(data.object_fields.len())
128            } else {
129                None
130            }
131        })
132        .flatten()
133    }
134    /// Get a scalar field of a constructor object.
135    pub fn get_scalar_field(obj: &RtObject, field_index: usize) -> Option<u64> {
136        obj.with_heap(|heap| {
137            if let HeapObject::Constructor(data) = heap {
138                data.scalar_fields.get(field_index).copied()
139            } else {
140                None
141            }
142        })
143        .flatten()
144    }
145    /// Project a field from a Prod (pair) type.
146    pub fn proj_fst(obj: &RtObject) -> Option<RtObject> {
147        Self::get_field(obj, 0)
148    }
149    /// Project the second field from a Prod (pair) type.
150    pub fn proj_snd(obj: &RtObject) -> Option<RtObject> {
151        Self::get_field(obj, 1)
152    }
153}
154/// A heap-allocated runtime object.
155#[derive(Clone, Debug)]
156pub enum HeapObject {
157    /// A closure with captured environment.
158    Closure(ClosureData),
159    /// A constructor with fields.
160    Constructor(ConstructorData),
161    /// An array of runtime objects.
162    Array(ArrayData),
163    /// A string value.
164    StringObj(StringData),
165    /// A big natural number.
166    BigNat(BigNatData),
167    /// A big integer.
168    BigInt(BigIntData),
169    /// A thunk (lazy value).
170    Thunk(ThunkData),
171    /// An IO action.
172    IoAction(IoActionData),
173    /// A task (concurrent computation).
174    Task(TaskData),
175    /// An external/opaque value.
176    External(ExternalData),
177    /// A partial application.
178    Pap(PapData),
179    /// A mutual recursive closure group.
180    MutRec(MutRecData),
181    /// A boxed float.
182    BoxedFloat(BoxedFloatData),
183    /// A byte array.
184    ByteArray(ByteArrayData),
185}
186impl HeapObject {
187    /// Get the type tag for this heap object.
188    pub fn type_tag(&self) -> TypeTag {
189        match self {
190            HeapObject::Closure(_) => TypeTag::Closure,
191            HeapObject::Constructor(_) => TypeTag::Constructor,
192            HeapObject::Array(_) => TypeTag::Array,
193            HeapObject::StringObj(_) => TypeTag::StringObj,
194            HeapObject::BigNat(_) => TypeTag::BigNat,
195            HeapObject::BigInt(_) => TypeTag::BigInt,
196            HeapObject::Thunk(_) => TypeTag::Thunk,
197            HeapObject::IoAction(_) => TypeTag::IoAction,
198            HeapObject::Task(_) => TypeTag::Task,
199            HeapObject::External(_) => TypeTag::External,
200            HeapObject::Pap(_) => TypeTag::Pap,
201            HeapObject::MutRec(_) => TypeTag::MutRec,
202            HeapObject::BoxedFloat(_) => TypeTag::BoxedFloat,
203            HeapObject::ByteArray(_) => TypeTag::ByteArray,
204        }
205    }
206    /// Get the object header.
207    pub fn header(&self) -> &ObjectHeader {
208        match self {
209            HeapObject::Closure(d) => &d.header,
210            HeapObject::Constructor(d) => &d.header,
211            HeapObject::Array(d) => &d.header,
212            HeapObject::StringObj(d) => &d.header,
213            HeapObject::BigNat(d) => &d.header,
214            HeapObject::BigInt(d) => &d.header,
215            HeapObject::Thunk(d) => &d.header,
216            HeapObject::IoAction(d) => &d.header,
217            HeapObject::Task(d) => &d.header,
218            HeapObject::External(d) => &d.header,
219            HeapObject::Pap(d) => &d.header,
220            HeapObject::MutRec(d) => &d.header,
221            HeapObject::BoxedFloat(d) => &d.header,
222            HeapObject::ByteArray(d) => &d.header,
223        }
224    }
225    /// Get the mutable object header.
226    pub fn header_mut(&mut self) -> &mut ObjectHeader {
227        match self {
228            HeapObject::Closure(d) => &mut d.header,
229            HeapObject::Constructor(d) => &mut d.header,
230            HeapObject::Array(d) => &mut d.header,
231            HeapObject::StringObj(d) => &mut d.header,
232            HeapObject::BigNat(d) => &mut d.header,
233            HeapObject::BigInt(d) => &mut d.header,
234            HeapObject::Thunk(d) => &mut d.header,
235            HeapObject::IoAction(d) => &mut d.header,
236            HeapObject::Task(d) => &mut d.header,
237            HeapObject::External(d) => &mut d.header,
238            HeapObject::Pap(d) => &mut d.header,
239            HeapObject::MutRec(d) => &mut d.header,
240            HeapObject::BoxedFloat(d) => &mut d.header,
241            HeapObject::ByteArray(d) => &mut d.header,
242        }
243    }
244}
245/// IO action kinds.
246#[derive(Clone, Debug)]
247pub enum IoActionKind {
248    /// Pure value: `pure a`.
249    Pure(RtObject),
250    /// Bind: `x >>= f`.
251    Bind {
252        /// First action.
253        action: Box<IoActionKind>,
254        /// Continuation.
255        continuation: RtObject,
256    },
257    /// Print a string.
258    PrintLn(String),
259    /// Read a line from stdin.
260    ReadLn,
261    /// Read a file.
262    ReadFile(String),
263    /// Write a file.
264    WriteFile {
265        /// File path.
266        path: String,
267        /// Contents to write.
268        contents: String,
269    },
270    /// Get the current time.
271    GetTime,
272    /// Exit with a code.
273    Exit(i32),
274    /// Throw an exception.
275    Throw(RtObject),
276    /// Catch an exception.
277    Catch {
278        /// Action that might throw.
279        action: Box<IoActionKind>,
280        /// Handler for exceptions.
281        handler: RtObject,
282    },
283    /// Create a mutable reference.
284    NewRef(RtObject),
285    /// Read a mutable reference.
286    ReadRef(u64),
287    /// Write a mutable reference.
288    WriteRef(u64, RtObject),
289    /// Spawn a new task.
290    Spawn(RtObject),
291    /// Wait for a task to complete.
292    Wait(u64),
293}
294/// Operations on array objects.
295pub struct ArrayOps;
296impl ArrayOps {
297    /// Get the length of an array.
298    pub fn len(obj: &RtObject) -> Option<usize> {
299        obj.with_heap(|heap| {
300            if let HeapObject::Array(data) = heap {
301                Some(data.elements.len())
302            } else {
303                None
304            }
305        })
306        .flatten()
307    }
308    /// Check if an array is empty.
309    pub fn is_empty(obj: &RtObject) -> Option<bool> {
310        Self::len(obj).map(|l| l == 0)
311    }
312    /// Get an element by index.
313    pub fn get(obj: &RtObject, index: usize) -> Option<RtObject> {
314        obj.with_heap(|heap| {
315            if let HeapObject::Array(data) = heap {
316                data.elements.get(index).cloned()
317            } else {
318                None
319            }
320        })
321        .flatten()
322    }
323    /// Set an element by index (in-place if unique, otherwise copy).
324    pub fn set(obj: &RtObject, index: usize, value: RtObject) -> Option<RtObject> {
325        let mutated = obj.with_heap_mut(|heap| {
326            if let HeapObject::Array(data) = heap {
327                if data.header.is_unique() && index < data.elements.len() {
328                    data.elements[index] = value.clone();
329                    return true;
330                }
331            }
332            false
333        });
334        if mutated == Some(true) {
335            return Some(obj.clone());
336        }
337        obj.with_heap(|heap| {
338            if let HeapObject::Array(data) = heap {
339                if index < data.elements.len() {
340                    let mut new_elements = data.elements.clone();
341                    new_elements[index] = value;
342                    Some(RtObject::array(new_elements))
343                } else {
344                    None
345                }
346            } else {
347                None
348            }
349        })
350        .flatten()
351    }
352    /// Push an element onto the end of an array.
353    pub fn push(obj: &RtObject, value: RtObject) -> Option<RtObject> {
354        let pushed = obj.with_heap_mut(|heap| {
355            if let HeapObject::Array(data) = heap {
356                if data.header.is_unique() {
357                    data.elements.push(value.clone());
358                    return true;
359                }
360            }
361            false
362        });
363        if pushed == Some(true) {
364            return Some(obj.clone());
365        }
366        obj.with_heap(|heap| {
367            if let HeapObject::Array(data) = heap {
368                let mut new_elements = data.elements.clone();
369                new_elements.push(value);
370                Some(RtObject::array(new_elements))
371            } else {
372                None
373            }
374        })
375        .flatten()
376    }
377    /// Pop the last element from an array.
378    pub fn pop(obj: &RtObject) -> Option<(RtObject, RtObject)> {
379        obj.with_heap(|heap| {
380            if let HeapObject::Array(data) = heap {
381                if data.elements.is_empty() {
382                    return None;
383                }
384                let mut new_elements = data.elements.clone();
385                let last = new_elements
386                    .pop()
387                    .expect("elements is non-empty as verified by the is_empty check above");
388                Some((RtObject::array(new_elements), last))
389            } else {
390                None
391            }
392        })
393        .flatten()
394    }
395    /// Create an array of the given size filled with a default value.
396    pub fn mk_array(size: usize, default: RtObject) -> RtObject {
397        let elements = vec![default; size];
398        RtObject::array(elements)
399    }
400    /// Concatenate two arrays.
401    pub fn concat(a: &RtObject, b: &RtObject) -> Option<RtObject> {
402        let elems_a = a
403            .with_heap(|heap| {
404                if let HeapObject::Array(data) = heap {
405                    Some(data.elements.clone())
406                } else {
407                    None
408                }
409            })
410            .flatten()?;
411        let elems_b = b
412            .with_heap(|heap| {
413                if let HeapObject::Array(data) = heap {
414                    Some(data.elements.clone())
415                } else {
416                    None
417                }
418            })
419            .flatten()?;
420        let mut combined = elems_a;
421        combined.extend(elems_b);
422        Some(RtObject::array(combined))
423    }
424    /// Slice an array.
425    pub fn slice(obj: &RtObject, start: usize, end: usize) -> Option<RtObject> {
426        obj.with_heap(|heap| {
427            if let HeapObject::Array(data) = heap {
428                let end = end.min(data.elements.len());
429                if start > end {
430                    return Some(RtObject::array(Vec::new()));
431                }
432                Some(RtObject::array(data.elements[start..end].to_vec()))
433            } else {
434                None
435            }
436        })
437        .flatten()
438    }
439    /// Reverse an array.
440    pub fn reverse(obj: &RtObject) -> Option<RtObject> {
441        obj.with_heap(|heap| {
442            if let HeapObject::Array(data) = heap {
443                let mut rev = data.elements.clone();
444                rev.reverse();
445                Some(RtObject::array(rev))
446            } else {
447                None
448            }
449        })
450        .flatten()
451    }
452}
453/// Operations on string objects.
454pub struct StringOps;
455impl StringOps {
456    /// Get the length of a string in bytes.
457    pub fn byte_len(obj: &RtObject) -> Option<usize> {
458        obj.with_heap(|heap| {
459            if let HeapObject::StringObj(data) = heap {
460                Some(data.value.len())
461            } else {
462                None
463            }
464        })
465        .flatten()
466    }
467    /// Get the length of a string in characters.
468    pub fn char_len(obj: &RtObject) -> Option<usize> {
469        obj.with_heap(|heap| {
470            if let HeapObject::StringObj(data) = heap {
471                Some(data.value.chars().count())
472            } else {
473                None
474            }
475        })
476        .flatten()
477    }
478    /// Get the string value.
479    pub fn as_str(obj: &RtObject) -> Option<String> {
480        obj.with_heap(|heap| {
481            if let HeapObject::StringObj(data) = heap {
482                Some(data.value.clone())
483            } else {
484                None
485            }
486        })
487        .flatten()
488    }
489    /// Concatenate two strings.
490    pub fn concat(a: &RtObject, b: &RtObject) -> Option<RtObject> {
491        let sa = Self::as_str(a)?;
492        let sb = Self::as_str(b)?;
493        Some(RtObject::string(format!("{}{}", sa, sb)))
494    }
495    /// Get a character at an index.
496    pub fn char_at(obj: &RtObject, index: usize) -> Option<RtObject> {
497        obj.with_heap(|heap| {
498            if let HeapObject::StringObj(data) = heap {
499                data.value.chars().nth(index).map(RtObject::char_val)
500            } else {
501                None
502            }
503        })
504        .flatten()
505    }
506    /// Take a substring.
507    pub fn substring(obj: &RtObject, start: usize, len: usize) -> Option<RtObject> {
508        obj.with_heap(|heap| {
509            if let HeapObject::StringObj(data) = heap {
510                let s: String = data.value.chars().skip(start).take(len).collect();
511                Some(RtObject::string(s))
512            } else {
513                None
514            }
515        })
516        .flatten()
517    }
518    /// Convert a string to a list of characters.
519    pub fn to_char_list(obj: &RtObject) -> Option<Vec<RtObject>> {
520        obj.with_heap(|heap| {
521            if let HeapObject::StringObj(data) = heap {
522                Some(data.value.chars().map(RtObject::char_val).collect())
523            } else {
524                None
525            }
526        })
527        .flatten()
528    }
529    /// Convert a natural number to its string representation.
530    pub fn nat_to_string(n: &RtObject) -> Option<RtObject> {
531        let v = n.as_small_nat()?;
532        Some(RtObject::string(format!("{}", v)))
533    }
534    /// Append a character to a string.
535    pub fn push_char(s: &RtObject, c: &RtObject) -> Option<RtObject> {
536        let sv = Self::as_str(s)?;
537        let cv = c.as_char()?;
538        let mut result = sv;
539        result.push(cv);
540        Some(RtObject::string(result))
541    }
542}
543/// Object comparison utilities.
544#[allow(dead_code)]
545pub struct RtObjectCmp;
546#[allow(dead_code)]
547impl RtObjectCmp {
548    /// Returns true if two RtObjects are numerically equal (both Int or both Float).
549    pub fn numeric_eq(a: &RtObject, b: &RtObject) -> bool {
550        match (a.as_small_int(), b.as_small_int()) {
551            (Some(x), Some(y)) => return x == y,
552            _ => {}
553        }
554        match (a.as_float_bits(), b.as_float_bits()) {
555            (Some(x), Some(y)) => return x == y,
556            _ => {}
557        }
558        false
559    }
560    /// Returns true if `a` is strictly less than `b` (integers only).
561    pub fn int_lt(a: &RtObject, b: &RtObject) -> Option<bool> {
562        match (a.as_small_int(), b.as_small_int()) {
563            (Some(x), Some(y)) => Some(x < y),
564            _ => None,
565        }
566    }
567}
568/// Runtime type information for a type.
569#[derive(Clone, Debug)]
570pub struct TypeInfo {
571    /// Fully qualified name of the type.
572    pub name: Name,
573    /// Number of type parameters.
574    pub num_params: u32,
575    /// Whether this is a proposition (proof-irrelevant).
576    pub is_prop: bool,
577    /// Constructor descriptors.
578    pub constructors: Vec<CtorInfo>,
579    /// Whether this type has a special optimized representation.
580    pub special_repr: Option<SpecialRepr>,
581}
582/// Registry of all known runtime types.
583pub struct TypeRegistry {
584    /// Map from type name to type info.
585    types: HashMap<String, TypeInfo>,
586}
587impl TypeRegistry {
588    /// Create a new empty type registry.
589    pub fn new() -> Self {
590        TypeRegistry {
591            types: HashMap::new(),
592        }
593    }
594    /// Register a type.
595    pub fn register(&mut self, info: TypeInfo) {
596        let key = format!("{}", info.name);
597        self.types.insert(key, info);
598    }
599    /// Look up type information by name.
600    pub fn lookup(&self, name: &str) -> Option<&TypeInfo> {
601        self.types.get(name)
602    }
603    /// Get all registered types.
604    pub fn all_types(&self) -> impl Iterator<Item = &TypeInfo> {
605        self.types.values()
606    }
607    /// Number of registered types.
608    pub fn len(&self) -> usize {
609        self.types.len()
610    }
611    /// Check if the registry is empty.
612    pub fn is_empty(&self) -> bool {
613        self.types.is_empty()
614    }
615    /// Register built-in types (Nat, Bool, Unit, etc.).
616    pub fn register_builtins(&mut self) {
617        self.register(TypeInfo {
618            name: Name::str("Nat"),
619            num_params: 0,
620            is_prop: false,
621            constructors: vec![
622                CtorInfo {
623                    name: Name::str("Nat").append_str("zero"),
624                    index: 0,
625                    num_scalar_fields: 0,
626                    num_object_fields: 0,
627                    field_names: Vec::new(),
628                },
629                CtorInfo {
630                    name: Name::str("Nat").append_str("succ"),
631                    index: 1,
632                    num_scalar_fields: 0,
633                    num_object_fields: 1,
634                    field_names: vec!["n".to_string()],
635                },
636            ],
637            special_repr: Some(SpecialRepr::InlineNat),
638        });
639        self.register(TypeInfo {
640            name: Name::str("Bool"),
641            num_params: 0,
642            is_prop: false,
643            constructors: vec![
644                CtorInfo {
645                    name: Name::str("Bool").append_str("false"),
646                    index: 0,
647                    num_scalar_fields: 0,
648                    num_object_fields: 0,
649                    field_names: Vec::new(),
650                },
651                CtorInfo {
652                    name: Name::str("Bool").append_str("true"),
653                    index: 1,
654                    num_scalar_fields: 0,
655                    num_object_fields: 0,
656                    field_names: Vec::new(),
657                },
658            ],
659            special_repr: Some(SpecialRepr::InlineBool),
660        });
661        self.register(TypeInfo {
662            name: Name::str("Unit"),
663            num_params: 0,
664            is_prop: false,
665            constructors: vec![CtorInfo {
666                name: Name::str("Unit").append_str("unit"),
667                index: 0,
668                num_scalar_fields: 0,
669                num_object_fields: 0,
670                field_names: Vec::new(),
671            }],
672            special_repr: Some(SpecialRepr::InlineUnit),
673        });
674        self.register(TypeInfo {
675            name: Name::str("Option"),
676            num_params: 1,
677            is_prop: false,
678            constructors: vec![
679                CtorInfo {
680                    name: Name::str("Option").append_str("none"),
681                    index: 0,
682                    num_scalar_fields: 0,
683                    num_object_fields: 0,
684                    field_names: Vec::new(),
685                },
686                CtorInfo {
687                    name: Name::str("Option").append_str("some"),
688                    index: 1,
689                    num_scalar_fields: 0,
690                    num_object_fields: 1,
691                    field_names: vec!["val".to_string()],
692                },
693            ],
694            special_repr: None,
695        });
696        self.register(TypeInfo {
697            name: Name::str("List"),
698            num_params: 1,
699            is_prop: false,
700            constructors: vec![
701                CtorInfo {
702                    name: Name::str("List").append_str("nil"),
703                    index: 0,
704                    num_scalar_fields: 0,
705                    num_object_fields: 0,
706                    field_names: Vec::new(),
707                },
708                CtorInfo {
709                    name: Name::str("List").append_str("cons"),
710                    index: 1,
711                    num_scalar_fields: 0,
712                    num_object_fields: 2,
713                    field_names: vec!["head".to_string(), "tail".to_string()],
714                },
715            ],
716            special_repr: None,
717        });
718        self.register(TypeInfo {
719            name: Name::str("Prod"),
720            num_params: 2,
721            is_prop: false,
722            constructors: vec![CtorInfo {
723                name: Name::str("Prod").append_str("mk"),
724                index: 0,
725                num_scalar_fields: 0,
726                num_object_fields: 2,
727                field_names: vec!["fst".to_string(), "snd".to_string()],
728            }],
729            special_repr: None,
730        });
731    }
732}
733/// Flags that can be set on a heap-allocated object.
734#[derive(Clone, Copy, Debug, PartialEq, Eq)]
735pub struct ObjectFlags(u8);
736impl ObjectFlags {
737    /// No flags set.
738    pub fn empty() -> Self {
739        ObjectFlags(0)
740    }
741    /// Object has been moved (for compacting GC, if used).
742    pub fn moved() -> Self {
743        ObjectFlags(0x01)
744    }
745    /// Object is pinned and must not be relocated.
746    pub fn pinned() -> Self {
747        ObjectFlags(0x02)
748    }
749    /// Object is shared across threads (uses atomic RC).
750    pub fn shared() -> Self {
751        ObjectFlags(0x04)
752    }
753    /// Object is finalized (destructor has been called).
754    pub fn finalized() -> Self {
755        ObjectFlags(0x08)
756    }
757    /// Object is immutable.
758    pub fn immutable() -> Self {
759        ObjectFlags(0x10)
760    }
761    /// Check if a specific flag is set.
762    pub fn has(&self, flag: ObjectFlags) -> bool {
763        (self.0 & flag.0) != 0
764    }
765    /// Set a flag.
766    pub fn set(&mut self, flag: ObjectFlags) {
767        self.0 |= flag.0;
768    }
769    /// Clear a flag.
770    pub fn clear(&mut self, flag: ObjectFlags) {
771        self.0 &= !flag.0;
772    }
773    /// Get raw bits.
774    pub fn bits(&self) -> u8 {
775        self.0
776    }
777}
778/// A trivial object pool for reuse.
779#[allow(dead_code)]
780#[derive(Debug, Default)]
781pub struct RtObjectPool {
782    free: Vec<RtObject>,
783}
784#[allow(dead_code)]
785impl RtObjectPool {
786    pub fn new() -> Self {
787        Self::default()
788    }
789    pub fn acquire_unit(&mut self) -> RtObject {
790        self.free.pop().unwrap_or_else(RtObject::unit)
791    }
792    pub fn release(&mut self, obj: RtObject) {
793        if self.free.len() < 64 {
794            self.free.push(obj);
795        }
796    }
797    pub fn free_count(&self) -> usize {
798        self.free.len()
799    }
800}
801/// Data for a byte array.
802#[derive(Clone, Debug)]
803pub struct ByteArrayData {
804    /// Object header.
805    pub header: ObjectHeader,
806    /// The byte data.
807    pub bytes: Vec<u8>,
808}
809/// Constructor information for runtime dispatch.
810#[derive(Clone, Debug)]
811pub struct CtorInfo {
812    /// Constructor name.
813    pub name: Name,
814    /// Constructor index.
815    pub index: u32,
816    /// Number of scalar (unboxed) fields.
817    pub num_scalar_fields: u16,
818    /// Number of object (boxed) fields.
819    pub num_object_fields: u16,
820    /// Field names (if named constructor).
821    pub field_names: Vec<String>,
822}
823/// Runtime type tag for heap-allocated objects.
824#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
825#[repr(u8)]
826pub enum TypeTag {
827    /// A closure object.
828    Closure = 0,
829    /// A constructor with fields.
830    Constructor = 1,
831    /// An array.
832    Array = 2,
833    /// A string.
834    StringObj = 3,
835    /// A big natural number (arbitrary precision).
836    BigNat = 4,
837    /// A big integer (arbitrary precision).
838    BigInt = 5,
839    /// A thunk (lazy value).
840    Thunk = 6,
841    /// An IO action.
842    IoAction = 7,
843    /// A task (concurrent computation).
844    Task = 8,
845    /// An external/opaque object.
846    External = 9,
847    /// A partial application (PAP).
848    Pap = 10,
849    /// A mutual recursive closure group.
850    MutRec = 11,
851    /// An environment captured by a closure.
852    ClosureEnv = 12,
853    /// A boxed float (full precision).
854    BoxedFloat = 13,
855    /// A byte array.
856    ByteArray = 14,
857    /// A module object.
858    Module = 15,
859}
860impl TypeTag {
861    /// Convert from raw u8.
862    pub fn from_u8(v: u8) -> Option<TypeTag> {
863        match v {
864            0 => Some(TypeTag::Closure),
865            1 => Some(TypeTag::Constructor),
866            2 => Some(TypeTag::Array),
867            3 => Some(TypeTag::StringObj),
868            4 => Some(TypeTag::BigNat),
869            5 => Some(TypeTag::BigInt),
870            6 => Some(TypeTag::Thunk),
871            7 => Some(TypeTag::IoAction),
872            8 => Some(TypeTag::Task),
873            9 => Some(TypeTag::External),
874            10 => Some(TypeTag::Pap),
875            11 => Some(TypeTag::MutRec),
876            12 => Some(TypeTag::ClosureEnv),
877            13 => Some(TypeTag::BoxedFloat),
878            14 => Some(TypeTag::ByteArray),
879            15 => Some(TypeTag::Module),
880            _ => None,
881        }
882    }
883    /// Convert to raw u8.
884    pub fn as_u8(self) -> u8 {
885        self as u8
886    }
887}
888/// Header placed at the beginning of every heap-allocated object.
889///
890/// Layout:
891/// - `rc_count` (u32): reference count
892/// - `type_tag` (TypeTag): which kind of heap object
893/// - `flags` (ObjectFlags): status flags
894/// - `size` (u16): total object size in 8-byte words (max 512 KB)
895#[derive(Clone, Debug)]
896pub struct ObjectHeader {
897    /// Reference count.
898    pub rc_count: u32,
899    /// Type tag for the heap object.
900    pub type_tag: TypeTag,
901    /// Object flags.
902    pub flags: ObjectFlags,
903    /// Size of the object in 8-byte words.
904    pub size_words: u16,
905}
906impl ObjectHeader {
907    /// Create a new object header.
908    pub fn new(type_tag: TypeTag, size_words: u16) -> Self {
909        ObjectHeader {
910            rc_count: 1,
911            type_tag,
912            flags: ObjectFlags::empty(),
913            size_words,
914        }
915    }
916    /// Increment the reference count.
917    pub fn inc_ref(&mut self) {
918        self.rc_count = self.rc_count.saturating_add(1);
919    }
920    /// Decrement the reference count. Returns true if the count reaches zero.
921    pub fn dec_ref(&mut self) -> bool {
922        if self.rc_count == 0 {
923            return true;
924        }
925        self.rc_count -= 1;
926        self.rc_count == 0
927    }
928    /// Check if the object has a single owner.
929    pub fn is_unique(&self) -> bool {
930        self.rc_count == 1
931    }
932    /// Check if the object is shared.
933    pub fn is_shared(&self) -> bool {
934        self.rc_count > 1 || self.flags.has(ObjectFlags::shared())
935    }
936    /// Total size in bytes.
937    pub fn size_bytes(&self) -> usize {
938        self.size_words as usize * 8
939    }
940    /// Encode header into a u64 for compact storage.
941    pub fn encode(&self) -> u64 {
942        let rc = self.rc_count as u64;
943        let tag = self.type_tag.as_u8() as u64;
944        let flags = self.flags.bits() as u64;
945        let size = self.size_words as u64;
946        (rc << 32) | (tag << 24) | (flags << 16) | size
947    }
948    /// Decode header from a u64.
949    pub fn decode(bits: u64) -> Option<Self> {
950        let rc = (bits >> 32) as u32;
951        let tag_byte = ((bits >> 24) & 0xFF) as u8;
952        let flags_byte = ((bits >> 16) & 0xFF) as u8;
953        let size = (bits & 0xFFFF) as u16;
954        let type_tag = TypeTag::from_u8(tag_byte)?;
955        Some(ObjectHeader {
956            rc_count: rc,
957            type_tag,
958            flags: ObjectFlags(flags_byte),
959            size_words: size,
960        })
961    }
962}
963/// Data for a partial application (PAP).
964#[derive(Clone, Debug)]
965pub struct PapData {
966    /// Object header.
967    pub header: ObjectHeader,
968    /// The closure being partially applied.
969    pub closure: RtObject,
970    /// Total arity of the closure.
971    pub arity: u16,
972    /// Arguments applied so far.
973    pub args: Vec<RtObject>,
974}
975/// Data for a task.
976#[derive(Clone, Debug)]
977pub struct TaskData {
978    /// Object header.
979    pub header: ObjectHeader,
980    /// Task state.
981    pub state: TaskState,
982    /// Task ID.
983    pub task_id: u64,
984}
985/// Operations on thunk objects.
986pub struct ThunkOps;
987impl ThunkOps {
988    /// Check if a thunk has been evaluated.
989    pub fn is_evaluated(obj: &RtObject) -> Option<bool> {
990        obj.with_heap(|heap| {
991            if let HeapObject::Thunk(data) = heap {
992                Some(matches!(data.state, ThunkState::Evaluated { .. }))
993            } else {
994                None
995            }
996        })
997        .flatten()
998    }
999    /// Get the cached value of an evaluated thunk.
1000    pub fn get_value(obj: &RtObject) -> Option<RtObject> {
1001        obj.with_heap(|heap| {
1002            if let HeapObject::Thunk(data) = heap {
1003                if let ThunkState::Evaluated { ref value } = data.state {
1004                    Some(value.clone())
1005                } else {
1006                    None
1007                }
1008            } else {
1009                None
1010            }
1011        })
1012        .flatten()
1013    }
1014    /// Set the value of a thunk (mark as evaluated).
1015    pub fn set_value(obj: &RtObject, value: RtObject) -> bool {
1016        obj.with_heap_mut(|heap| {
1017            if let HeapObject::Thunk(data) = heap {
1018                data.state = ThunkState::Evaluated { value };
1019                true
1020            } else {
1021                false
1022            }
1023        })
1024        .unwrap_or(false)
1025    }
1026    /// Mark a thunk as currently evaluating (for cycle detection).
1027    pub fn mark_evaluating(obj: &RtObject) -> bool {
1028        obj.with_heap_mut(|heap| {
1029            if let HeapObject::Thunk(data) = heap {
1030                data.state = ThunkState::Evaluating;
1031                true
1032            } else {
1033                false
1034            }
1035        })
1036        .unwrap_or(false)
1037    }
1038    /// Check if a thunk is in the evaluating state (cycle).
1039    pub fn is_evaluating(obj: &RtObject) -> Option<bool> {
1040        obj.with_heap(|heap| {
1041            if let HeapObject::Thunk(data) = heap {
1042                Some(matches!(data.state, ThunkState::Evaluating))
1043            } else {
1044                None
1045            }
1046        })
1047        .flatten()
1048    }
1049}
1050/// Allocation statistics.
1051#[derive(Clone, Debug, Default)]
1052pub struct AllocationStats {
1053    /// Total number of allocations.
1054    pub total_allocations: u64,
1055    /// Total number of deallocations.
1056    pub total_deallocations: u64,
1057    /// Current number of live objects.
1058    pub live_objects: u64,
1059    /// Peak number of live objects.
1060    pub peak_objects: u64,
1061    /// Total bytes allocated.
1062    pub total_bytes_allocated: u64,
1063}
1064/// Data for a constructor object.
1065#[derive(Clone, Debug)]
1066pub struct ConstructorData {
1067    /// Object header.
1068    pub header: ObjectHeader,
1069    /// Constructor index within the inductive type.
1070    pub ctor_index: u32,
1071    /// Number of fields.
1072    pub num_fields: u16,
1073    /// Scalar fields (unboxed small values).
1074    pub scalar_fields: Vec<u64>,
1075    /// Object fields (boxed values).
1076    pub object_fields: Vec<RtObject>,
1077    /// The name of the constructor (optional).
1078    pub name: Option<Name>,
1079}
1080/// Data for a thunk (lazy value).
1081#[derive(Clone, Debug)]
1082pub struct ThunkData {
1083    /// Object header.
1084    pub header: ObjectHeader,
1085    /// Current thunk state.
1086    pub state: ThunkState,
1087}
1088/// Data for a closure object.
1089#[derive(Clone, Debug)]
1090pub struct ClosureData {
1091    /// Object header.
1092    pub header: ObjectHeader,
1093    /// Function pointer index into the code table.
1094    pub fn_index: u32,
1095    /// Arity of the function (total number of parameters).
1096    pub arity: u16,
1097    /// Number of captured environment variables.
1098    pub env_size: u16,
1099    /// Captured environment values.
1100    pub env: Vec<RtObject>,
1101}
1102/// Special representation hints for common types.
1103#[derive(Clone, Debug)]
1104pub enum SpecialRepr {
1105    /// This type is represented as a small nat inline.
1106    InlineNat,
1107    /// This type is represented as a bool inline.
1108    InlineBool,
1109    /// This type is represented as a unit inline.
1110    InlineUnit,
1111    /// This type is represented as a char inline.
1112    InlineChar,
1113    /// This type uses enum-style representation (no fields).
1114    EnumTag {
1115        /// Number of constructors.
1116        num_ctors: u32,
1117    },
1118    /// This type uses a packed struct representation.
1119    PackedStruct {
1120        /// Total size in bytes.
1121        size_bytes: u32,
1122    },
1123    /// This type is represented as a boxed array.
1124    BoxedArray,
1125    /// This type is represented as a string.
1126    BoxedString,
1127}
1128/// Thread-local storage for heap objects.
1129///
1130/// Uses a `Vec<Option<HeapObject>>` with a free-list for O(1) alloc/free.
1131/// A production implementation could use mmap'd regions for large heaps,
1132/// but the current design is correct and suitable for the interpreter.
1133pub struct ObjectStore {
1134    /// All allocated objects, indexed by their ID.
1135    objects: Vec<Option<HeapObject>>,
1136    /// Free list for reuse.
1137    free_list: Vec<usize>,
1138    /// Statistics.
1139    stats: AllocationStats,
1140}
1141impl ObjectStore {
1142    /// Create a new empty object store.
1143    pub fn new() -> Self {
1144        ObjectStore {
1145            objects: Vec::new(),
1146            free_list: Vec::new(),
1147            stats: AllocationStats::default(),
1148        }
1149    }
1150    /// Create a new object store with pre-allocated capacity.
1151    pub fn with_capacity(cap: usize) -> Self {
1152        ObjectStore {
1153            objects: Vec::with_capacity(cap),
1154            free_list: Vec::new(),
1155            stats: AllocationStats::default(),
1156        }
1157    }
1158    /// Allocate a new heap object and return its ID.
1159    pub fn allocate(&mut self, obj: HeapObject) -> usize {
1160        self.stats.total_allocations += 1;
1161        self.stats.live_objects += 1;
1162        if self.stats.live_objects > self.stats.peak_objects {
1163            self.stats.peak_objects = self.stats.live_objects;
1164        }
1165        self.stats.total_bytes_allocated += obj.header().size_bytes() as u64;
1166        if let Some(id) = self.free_list.pop() {
1167            self.objects[id] = Some(obj);
1168            id
1169        } else {
1170            let id = self.objects.len();
1171            self.objects.push(Some(obj));
1172            id
1173        }
1174    }
1175    /// Deallocate a heap object by ID.
1176    pub fn deallocate(&mut self, id: usize) -> Option<HeapObject> {
1177        if id >= self.objects.len() {
1178            return None;
1179        }
1180        let obj = self.objects[id].take();
1181        if obj.is_some() {
1182            self.free_list.push(id);
1183            self.stats.total_deallocations += 1;
1184            self.stats.live_objects = self.stats.live_objects.saturating_sub(1);
1185        }
1186        obj
1187    }
1188    /// Get a reference to a heap object by ID.
1189    pub fn get(&self, id: usize) -> Option<&HeapObject> {
1190        self.objects.get(id).and_then(|o| o.as_ref())
1191    }
1192    /// Get a mutable reference to a heap object by ID.
1193    pub fn get_mut(&mut self, id: usize) -> Option<&mut HeapObject> {
1194        self.objects.get_mut(id).and_then(|o| o.as_mut())
1195    }
1196    /// Get allocation statistics.
1197    pub fn stats(&self) -> &AllocationStats {
1198        &self.stats
1199    }
1200    /// Number of live objects.
1201    pub fn live_count(&self) -> usize {
1202        self.stats.live_objects as usize
1203    }
1204    /// Total capacity (including free slots).
1205    pub fn capacity(&self) -> usize {
1206        self.objects.capacity()
1207    }
1208    /// Access the global store via a thread-local.
1209    pub(super) fn global_store<R>(f: impl FnOnce(&mut ObjectStore) -> R) -> R {
1210        thread_local! {
1211            static STORE : std::cell::RefCell < ObjectStore > =
1212            std::cell::RefCell::new(ObjectStore::new());
1213        }
1214        STORE.with(|store| f(&mut store.borrow_mut()))
1215    }
1216}
1217/// Data for an array object.
1218#[derive(Clone, Debug)]
1219pub struct ArrayData {
1220    /// Object header.
1221    pub header: ObjectHeader,
1222    /// Array elements.
1223    pub elements: Vec<RtObject>,
1224    /// Capacity (for pre-allocated arrays).
1225    pub capacity: usize,
1226}
1227/// Data for an IO action.
1228#[derive(Clone, Debug)]
1229pub struct IoActionData {
1230    /// Object header.
1231    pub header: ObjectHeader,
1232    /// The IO action kind.
1233    pub kind: IoActionKind,
1234}
1235/// Task state.
1236#[derive(Clone, Debug)]
1237pub enum TaskState {
1238    /// Task is pending (not yet started or in progress).
1239    Pending,
1240    /// Task is running.
1241    Running,
1242    /// Task has completed with a result.
1243    Completed(RtObject),
1244    /// Task has failed with an error.
1245    Failed(RtObject),
1246    /// Task has been cancelled.
1247    Cancelled,
1248}
1249/// Data for an external/opaque value.
1250#[derive(Clone, Debug)]
1251pub struct ExternalData {
1252    /// Object header.
1253    pub header: ObjectHeader,
1254    /// Type name for the external value.
1255    pub type_name: String,
1256    /// Opaque payload (serialized or boxed).
1257    pub payload: Vec<u8>,
1258}
1259/// A table mapping names to runtime objects.
1260///
1261/// Used for the global constant table, module exports, etc.
1262pub struct ObjectTable {
1263    /// Map from name to object.
1264    entries: HashMap<String, RtObject>,
1265    /// Insertion order (for deterministic iteration).
1266    order: Vec<String>,
1267}
1268impl ObjectTable {
1269    /// Create a new empty object table.
1270    pub fn new() -> Self {
1271        ObjectTable {
1272            entries: HashMap::new(),
1273            order: Vec::new(),
1274        }
1275    }
1276    /// Insert an entry.
1277    pub fn insert(&mut self, name: String, obj: RtObject) {
1278        if !self.entries.contains_key(&name) {
1279            self.order.push(name.clone());
1280        }
1281        self.entries.insert(name, obj);
1282    }
1283    /// Look up an entry by name.
1284    pub fn get(&self, name: &str) -> Option<&RtObject> {
1285        self.entries.get(name)
1286    }
1287    /// Check if a name exists.
1288    pub fn contains(&self, name: &str) -> bool {
1289        self.entries.contains_key(name)
1290    }
1291    /// Number of entries.
1292    pub fn len(&self) -> usize {
1293        self.entries.len()
1294    }
1295    /// Check if the table is empty.
1296    pub fn is_empty(&self) -> bool {
1297        self.entries.is_empty()
1298    }
1299    /// Iterate entries in insertion order.
1300    pub fn iter(&self) -> impl Iterator<Item = (&str, &RtObject)> {
1301        self.order
1302            .iter()
1303            .filter_map(move |name| self.entries.get(name).map(|obj| (name.as_str(), obj)))
1304    }
1305    /// Remove an entry.
1306    pub fn remove(&mut self, name: &str) -> Option<RtObject> {
1307        if let Some(obj) = self.entries.remove(name) {
1308            self.order.retain(|n| n != name);
1309            Some(obj)
1310        } else {
1311            None
1312        }
1313    }
1314    /// Clear all entries.
1315    pub fn clear(&mut self) {
1316        self.entries.clear();
1317        self.order.clear();
1318    }
1319}
1320/// Arithmetic operations on runtime objects.
1321pub struct RtArith;
1322impl RtArith {
1323    /// Add two natural numbers.
1324    pub fn nat_add(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1325        let av = a.as_small_nat()?;
1326        let bv = b.as_small_nat()?;
1327        Some(RtObject::nat(av.wrapping_add(bv)))
1328    }
1329    /// Subtract two natural numbers (saturating).
1330    pub fn nat_sub(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1331        let av = a.as_small_nat()?;
1332        let bv = b.as_small_nat()?;
1333        Some(RtObject::nat(av.saturating_sub(bv)))
1334    }
1335    /// Multiply two natural numbers.
1336    pub fn nat_mul(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1337        let av = a.as_small_nat()?;
1338        let bv = b.as_small_nat()?;
1339        Some(RtObject::nat(av.wrapping_mul(bv)))
1340    }
1341    /// Divide two natural numbers (integer division, rounds toward zero).
1342    pub fn nat_div(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1343        let av = a.as_small_nat()?;
1344        let bv = b.as_small_nat()?;
1345        if bv == 0 {
1346            return Some(RtObject::nat(0));
1347        }
1348        Some(RtObject::nat(av / bv))
1349    }
1350    /// Modulo of two natural numbers.
1351    pub fn nat_mod(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1352        let av = a.as_small_nat()?;
1353        let bv = b.as_small_nat()?;
1354        if bv == 0 {
1355            return Some(RtObject::nat(av));
1356        }
1357        Some(RtObject::nat(av % bv))
1358    }
1359    /// Compare two natural numbers (less than or equal).
1360    pub fn nat_le(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1361        let av = a.as_small_nat()?;
1362        let bv = b.as_small_nat()?;
1363        Some(RtObject::bool_val(av <= bv))
1364    }
1365    /// Compare two natural numbers (less than).
1366    pub fn nat_lt(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1367        let av = a.as_small_nat()?;
1368        let bv = b.as_small_nat()?;
1369        Some(RtObject::bool_val(av < bv))
1370    }
1371    /// Compare two natural numbers for equality.
1372    pub fn nat_eq(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1373        let av = a.as_small_nat()?;
1374        let bv = b.as_small_nat()?;
1375        Some(RtObject::bool_val(av == bv))
1376    }
1377    /// Boolean AND.
1378    pub fn bool_and(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1379        let av = a.as_bool()?;
1380        let bv = b.as_bool()?;
1381        Some(RtObject::bool_val(av && bv))
1382    }
1383    /// Boolean OR.
1384    pub fn bool_or(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1385        let av = a.as_bool()?;
1386        let bv = b.as_bool()?;
1387        Some(RtObject::bool_val(av || bv))
1388    }
1389    /// Boolean NOT.
1390    pub fn bool_not(a: &RtObject) -> Option<RtObject> {
1391        let av = a.as_bool()?;
1392        Some(RtObject::bool_val(!av))
1393    }
1394    /// Integer addition.
1395    pub fn int_add(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1396        let av = a.as_small_int()?;
1397        let bv = b.as_small_int()?;
1398        Some(av.wrapping_add(bv).box_into())
1399    }
1400    /// Integer subtraction.
1401    pub fn int_sub(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1402        let av = a.as_small_int()?;
1403        let bv = b.as_small_int()?;
1404        Some(av.wrapping_sub(bv).box_into())
1405    }
1406    /// Integer multiplication.
1407    pub fn int_mul(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1408        let av = a.as_small_int()?;
1409        let bv = b.as_small_int()?;
1410        Some(av.wrapping_mul(bv).box_into())
1411    }
1412    /// Integer negation.
1413    pub fn int_neg(a: &RtObject) -> Option<RtObject> {
1414        let av = a.as_small_int()?;
1415        Some(av.wrapping_neg().box_into())
1416    }
1417}