Skip to main content

seq_runtime/variant_ops/
access.rs

1//! Variant field access: count, tag lookup, field access.
2
3use crate::stack::{Stack, pop, push};
4use crate::value::Value;
5
6/// Get the number of fields in a variant
7///
8/// Stack effect: ( Variant -- Int )
9///
10/// # Safety
11/// Stack must have a Variant on top
12#[unsafe(no_mangle)]
13pub unsafe extern "C" fn patch_seq_variant_field_count(stack: Stack) -> Stack {
14    unsafe {
15        let (stack, value) = pop(stack);
16
17        match value {
18            Value::Variant(variant_data) => {
19                let count = variant_data.fields.len() as i64;
20                push(stack, Value::Int(count))
21            }
22            _ => panic!("variant-field-count: expected Variant, got {:?}", value),
23        }
24    }
25}
26
27/// Get the tag of a variant
28///
29/// Stack effect: ( Variant -- Symbol )
30///
31/// # Safety
32/// Stack must have a Variant on top
33#[unsafe(no_mangle)]
34pub unsafe extern "C" fn patch_seq_variant_tag(stack: Stack) -> Stack {
35    unsafe {
36        let (stack, value) = pop(stack);
37
38        match value {
39            Value::Variant(variant_data) => {
40                // Return the tag as a Symbol
41                push(stack, Value::Symbol(variant_data.tag.clone()))
42            }
43            _ => panic!("variant-tag: expected Variant, got {:?}", value),
44        }
45    }
46}
47
48/// Compare a symbol tag with a C string literal
49///
50/// Used by pattern matching codegen to dispatch on variant tags.
51/// The stack should have a Symbol on top (typically from variant-tag).
52/// Compares with the provided C string and pushes Bool result.
53///
54/// Stack effect: ( Symbol -- Bool )
55///
56/// # Safety
57/// - Stack must have a Symbol on top
58/// - c_str must be a valid null-terminated C string
59#[unsafe(no_mangle)]
60pub unsafe extern "C" fn patch_seq_symbol_eq_cstr(stack: Stack, c_str: *const i8) -> Stack {
61    use std::ffi::CStr;
62
63    unsafe {
64        let (stack, value) = pop(stack);
65        let symbol_str = match value {
66            Value::Symbol(s) => s,
67            _ => panic!("symbol_eq_cstr: expected Symbol, got {:?}", value),
68        };
69
70        let expected = CStr::from_ptr(c_str)
71            .to_str()
72            .expect("Invalid UTF-8 in variant name");
73
74        let is_equal = symbol_str.as_str() == expected;
75        push(stack, Value::Bool(is_equal))
76    }
77}
78
79/// Get a field from a variant at the given index
80///
81/// Stack effect: ( Variant Int -- Value )
82///
83/// Returns a clone of the field value at the specified index.
84/// Panics if index is out of bounds (this is a programming bug, not recoverable).
85/// Use variant.field-count to check bounds first if needed.
86///
87/// # Safety
88/// Stack must have a Variant and Int on top
89#[unsafe(no_mangle)]
90pub unsafe extern "C" fn patch_seq_variant_field_at(stack: Stack) -> Stack {
91    unsafe {
92        let (stack, index_val) = pop(stack);
93        let index = match index_val {
94            Value::Int(i) => i,
95            _ => panic!(
96                "variant-field-at: expected Int (index), got {:?}",
97                index_val
98            ),
99        };
100
101        if index < 0 {
102            panic!("variant-field-at: index cannot be negative: {}", index);
103        }
104
105        let (stack, variant_val) = pop(stack);
106
107        match variant_val {
108            Value::Variant(variant_data) => {
109                let idx = index as usize;
110                if idx >= variant_data.fields.len() {
111                    panic!(
112                        "variant-field-at: index {} out of bounds (variant has {} fields)",
113                        index,
114                        variant_data.fields.len()
115                    );
116                }
117
118                // Clone the field value and push it
119                let field = variant_data.fields[idx].clone();
120                push(stack, field)
121            }
122            _ => panic!("variant-field-at: expected Variant, got {:?}", variant_val),
123        }
124    }
125}