use super::combinators::stack_depth;
use crate::error::set_runtime_error;
use crate::stack::{Stack, heap_value_mut, pop, push};
use crate::value::{Value, VariantData};
use std::sync::Arc;
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_list_get(stack: Stack) -> Stack {
unsafe {
if stack_depth(stack) < 2 {
set_runtime_error("list.get: stack underflow (need 2 values)");
return stack;
}
let (stack, index_val) = pop(stack);
let (stack, list_val) = pop(stack);
let index = match index_val {
Value::Int(i) => i,
_ => {
set_runtime_error(format!(
"list.get: expected Int (index), got {:?}",
index_val
));
let stack = push(stack, Value::Int(0));
return push(stack, Value::Bool(false));
}
};
let variant_data = match list_val {
Value::Variant(v) => v,
_ => {
set_runtime_error(format!(
"list.get: expected Variant (list), got {:?}",
list_val
));
let stack = push(stack, Value::Int(0));
return push(stack, Value::Bool(false));
}
};
if index < 0 || index as usize >= variant_data.fields.len() {
let stack = push(stack, Value::Int(0)); push(stack, Value::Bool(false))
} else {
let value = variant_data.fields[index as usize].clone();
let stack = push(stack, value);
push(stack, Value::Bool(true))
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_list_set(stack: Stack) -> Stack {
unsafe {
if stack_depth(stack) < 3 {
set_runtime_error("list.set: stack underflow (need 3 values)");
return stack;
}
if let Some(Value::Variant(variant_arc)) = heap_value_mut(stack.sub(3))
&& let Some(data) = Arc::get_mut(variant_arc)
{
let index_sv = *stack.sub(2);
if crate::tagged_stack::is_tagged_int(index_sv) {
let index = crate::tagged_stack::untag_int(index_sv);
if index >= 0 && (index as usize) < data.fields.len() {
let (stack, value) = pop(stack);
let (stack, _index) = pop(stack);
data.fields[index as usize] = value;
return push(stack, Value::Bool(true));
}
let (stack, _value) = pop(stack);
let (stack, _index) = pop(stack);
return push(stack, Value::Bool(false));
}
}
let (stack, value) = pop(stack);
let (stack, index_val) = pop(stack);
let (stack, list_val) = pop(stack);
let index = match index_val {
Value::Int(i) => i,
_ => {
set_runtime_error(format!(
"list.set: expected Int (index), got {:?}",
index_val
));
let stack = push(stack, list_val);
return push(stack, Value::Bool(false));
}
};
let mut arc = match list_val {
Value::Variant(v) => v,
other => {
set_runtime_error(format!(
"list.set: expected Variant (list), got {:?}",
other
));
let stack = push(stack, other);
return push(stack, Value::Bool(false));
}
};
if index < 0 || index as usize >= arc.fields.len() {
let stack = push(stack, Value::Variant(arc));
push(stack, Value::Bool(false))
} else if let Some(data) = Arc::get_mut(&mut arc) {
data.fields[index as usize] = value;
let stack = push(stack, Value::Variant(arc));
push(stack, Value::Bool(true))
} else {
let mut new_fields: Vec<Value> = arc.fields.to_vec();
new_fields[index as usize] = value;
let new_list = Value::Variant(Arc::new(VariantData::new(arc.tag.clone(), new_fields)));
let stack = push(stack, new_list);
push(stack, Value::Bool(true))
}
}
}