use crate::parser::ast::{Expr, DestructurePattern};
use crate::parser::types::Value;
use crate::parser::interpreter::Interpreter;
use std::sync::{Arc, Mutex};
pub fn bool_like(v: &Value) -> Result<bool, String> {
match v {
Value::Bool(b) => Ok(*b),
Value::Int(i) => Ok(*i != 0),
Value::Float(ff) => Ok(*ff != 0.0),
Value::Long(l) => Ok(*l != 0),
_ => Err(format!("Cannot interpret as boolean: {:?}", v)),
}
}
pub fn eval_bracketed_array(interp: &mut Interpreter, exprs: &[Expr]) -> Result<Value, String> {
let mut subvals = Vec::with_capacity(exprs.len());
for e in exprs {
let val = interp.eval_expression(e)?;
subvals.push(val);
}
if subvals.is_empty() {
return Ok(Value::IntArray(vec![]));
}
if subvals.iter().all(|v| matches!(v, Value::SingleString(_))) {
let ss = subvals.into_iter().map(|v| match v {
Value::SingleString(s) => s,
_ => unreachable!(),
}).collect();
return Ok(Value::StrArray(ss));
}
let is_all_arrays = subvals.iter().all(|v| matches!(v, Value::IntArray(_) | Value::FloatArray(_) | Value::StrArray(_) | Value::BoolArray(_)));
let same_len = if is_all_arrays {
let first_len = match &subvals[0] {
Value::IntArray(xs) => xs.len(),
Value::FloatArray(xs) => xs.len(),
Value::StrArray(xs) => xs.len(),
Value::BoolArray(xs) => xs.len(),
_ => 0,
};
subvals.iter().all(|v| match v {
Value::IntArray(xs) => xs.len() == first_len,
Value::FloatArray(xs) => xs.len() == first_len,
Value::StrArray(xs) => xs.len() == first_len,
Value::BoolArray(xs) => xs.len() == first_len,
_ => false,
})
} else {
false
};
if is_all_arrays && same_len && !subvals.is_empty() {
let mut only_int = true;
let mut has_float = false;
for v in &subvals {
match v {
Value::FloatArray(_) => {
only_int = false;
has_float = true;
}
Value::IntArray(_) => {}
_ => {
only_int = false;
}
}
}
if only_int {
let mut int_rows = Vec::new();
for v in subvals {
match v {
Value::IntArray(xs) => int_rows.push(xs),
_ => {}
}
}
return Ok(Value::Int2DArray(int_rows));
} else if has_float && subvals.iter().all(|v| matches!(v, Value::IntArray(_) | Value::FloatArray(_))) {
let mut float_rows = Vec::new();
for v in subvals {
match v {
Value::IntArray(xs) => float_rows.push(xs.iter().map(|&i| i as f64).collect()),
Value::FloatArray(fs) => float_rows.push(fs),
_ => {}
}
}
return Ok(Value::Float2DArray(float_rows));
} else if subvals.iter().all(|v| matches!(v, Value::FloatArray(_))) {
let mut float_rows = Vec::new();
for v in subvals {
match v {
Value::FloatArray(fs) => float_rows.push(fs),
_ => {}
}
}
return Ok(Value::Float2DArray(float_rows));
} else {
return Ok(Value::MixedArray(subvals));
}
}
let mut found_int = false;
let mut found_float = false;
let mut found_bool = false;
let mut found_str = false;
let mut found_other = false;
let mut ints = Vec::new();
let mut floats = Vec::new();
let mut bools = Vec::new();
let mut strs = Vec::new();
for item in &subvals {
match item {
Value::Int(i) => {
if found_str || found_bool || found_other {
found_other = true;
} else if found_float {
floats.push(*i as f64);
} else {
found_int = true;
ints.push(*i);
}
}
Value::Float(ff) => {
if found_str || found_bool || found_other {
found_other = true;
} else {
if !found_float {
found_float = true;
for old_i in ints.drain(..) {
floats.push(old_i as f64);
}
}
floats.push(*ff);
}
}
Value::Long(l) => {
if found_str || found_bool || found_other {
found_other = true;
} else if found_float {
floats.push(*l as f64);
} else {
found_int = true;
ints.push(*l as i32);
}
}
Value::Bool(b) => {
if found_int || found_float || found_str || found_other {
found_other = true;
} else {
found_bool = true;
bools.push(*b);
}
}
Value::SingleString(s) => {
if found_int || found_float || found_bool || found_other {
found_other = true;
} else {
found_str = true;
strs.push(s.clone());
}
}
_ => {
found_other = true;
}
}
}
if found_other {
return Ok(Value::MixedArray(subvals));
}
if found_float {
return Ok(Value::FloatArray(floats));
}
if found_int {
return Ok(Value::IntArray(ints));
}
if found_bool {
return Ok(Value::BoolArray(bools));
}
if found_str {
return Ok(Value::StrArray(strs));
}
Ok(Value::IntArray(vec![]))
}
pub fn eval_keyed_array(interp: &mut Interpreter, kv_pairs: &[(String, Expr)]) -> Result<Value, String> {
use indexmap::IndexMap;
let mut map = IndexMap::new();
for (k, subexpr) in kv_pairs {
let val = interp.eval_expression(subexpr)?;
map.insert(k.clone(), val);
}
Ok(Value::KeyedArray(map))
}
pub fn assign_to_expr(interp: &mut Interpreter, left_expr: &Expr, value: Value) -> Result<(), String> {
match left_expr {
Expr::Ident { name, .. } => {
interp.set_variable(name, value);
Ok(())
}
Expr::Index { base, index, .. } => {
assign_index(interp, base, index, value)
}
_ => Err("Left side of assignment must be a variable or array index".to_string()),
}
}
pub fn assign_keyed_destructure(interp: &mut Interpreter, pattern: &DestructurePattern, value: Value) -> Result<(), String> {
match pattern {
DestructurePattern::Keyed(keys) => {
match value {
Value::KeyedArray(map) => {
for k in keys {
if let Some(v) = map.get(k) {
interp.set_variable(k, v.clone());
} else {
interp.set_variable(k, Value::Placeholder);
}
}
Ok(())
}
other => Err(format!("Keyed destructure requires a KeyedArray, got {:?}", other)),
}
}
DestructurePattern::Tuple(names) => {
match value {
Value::IntArray(xs) => {
for (i, name) in names.iter().enumerate() {
if i < xs.len() {
interp.set_variable(name, Value::Int(xs[i]));
} else {
interp.set_variable(name, Value::Placeholder);
}
}
Ok(())
}
Value::FloatArray(xs) => {
for (i, name) in names.iter().enumerate() {
if i < xs.len() {
interp.set_variable(name, Value::Float(xs[i]));
} else {
interp.set_variable(name, Value::Placeholder);
}
}
Ok(())
}
Value::StrArray(xs) => {
for (i, name) in names.iter().enumerate() {
if i < xs.len() {
interp.set_variable(name, Value::SingleString(xs[i].clone()));
} else {
interp.set_variable(name, Value::Placeholder);
}
}
Ok(())
}
Value::MixedArray(xs) => {
for (i, name) in names.iter().enumerate() {
if i < xs.len() {
interp.set_variable(name, xs[i].clone());
} else {
interp.set_variable(name, Value::Placeholder);
}
}
Ok(())
}
v => {
for name in names {
interp.set_variable(name, v.clone());
}
Ok(())
}
}
}
}
}
fn extract_mutex_for_indexing(val: &Value) -> Option<Arc<Mutex<Value>>> {
match val {
Value::Ref(arc_mutex) => Some(arc_mutex.clone()),
_ => None,
}
}
fn assign_index(interp: &mut Interpreter, base: &Expr, idx_expr: &Expr, new_val: Value) -> Result<(), String> {
let base_val = interp.eval_expression(base)?;
let idx_val = interp.eval_expression(idx_expr)?;
if let Some(arc_mutex) = extract_mutex_for_indexing(&base_val) {
let mut mut_val = arc_mutex.lock().unwrap();
return match (&mut *mut_val, idx_val, new_val) {
(Value::IntArray(ref mut xs), Value::Int(i), Value::Int(new_i)) => {
if i < 0 || (i as usize) >= xs.len() {
return Err(format!("Array index out of range: {}", i));
}
xs[i as usize] = new_i;
Ok(())
}
(Value::FloatArray(ref mut xs), Value::Int(i), Value::Float(new_f)) => {
if i < 0 || (i as usize) >= xs.len() {
return Err(format!("Array index out of range: {}", i));
}
xs[i as usize] = new_f;
Ok(())
}
(Value::FloatArray(ref mut xs), Value::Int(i), Value::Int(new_i)) => {
if i < 0 || (i as usize) >= xs.len() {
return Err(format!("Array index out of range: {}", i));
}
xs[i as usize] = new_i as f64;
Ok(())
}
(Value::StrArray(ref mut xs), Value::Int(i), Value::SingleString(new_s)) => {
if i < 0 || (i as usize) >= xs.len() {
return Err(format!("Array index out of range: {}", i));
}
xs[i as usize] = new_s;
Ok(())
}
(Value::Int2DArray(ref mut rows), Value::Int(i), Value::IntArray(new_row)) => {
if i < 0 || (i as usize) >= rows.len() {
return Err(format!("Array index out of range: {}", i));
}
rows[i as usize] = new_row;
Ok(())
}
(Value::Float2DArray(ref mut rows), Value::Int(i), Value::FloatArray(new_row)) => {
if i < 0 || (i as usize) >= rows.len() {
return Err(format!("Array index out of range: {}", i));
}
rows[i as usize] = new_row;
Ok(())
}
(Value::Float2DArray(ref mut rows), Value::Int(i), Value::IntArray(new_row)) => {
if i < 0 || (i as usize) >= rows.len() {
return Err(format!("Array index out of range: {}", i));
}
rows[i as usize] = new_row.iter().map(|&n| n as f64).collect();
Ok(())
}
(Value::MixedArray(ref mut items), Value::Int(i), nv) => {
if i < 0 || (i as usize) >= items.len() {
return Err(format!("Array index out of range: {}", i));
}
items[i as usize] = nv;
Ok(())
}
_ => Err("Unsupported or type-mismatched index assignment through Ref".to_string()),
};
}
match (base_val, idx_val, new_val) {
(Value::IntArray(xs), Value::Int(i), Value::Int(new_i)) => {
if i < 0 || (i as usize) >= xs.len() {
return Err(format!("Array index out of range: {}", i));
}
let mut copy = xs.clone();
copy[i as usize] = new_i;
match base {
Expr::Ident { name, .. } => {
interp.set_variable(name, Value::IntArray(copy));
Ok(())
}
Expr::Index { base: prev_base, index: prev_idx, .. } => {
assign_index(interp, prev_base, prev_idx, Value::IntArray(copy))
}
_ => Err("Unsupported nested indexing base".to_string()),
}
}
(Value::FloatArray(xs), Value::Int(i), Value::Float(new_f)) => {
if i < 0 || (i as usize) >= xs.len() {
return Err(format!("Array index out of range: {}", i));
}
let mut copy = xs.clone();
copy[i as usize] = new_f;
match base {
Expr::Ident { name, .. } => {
interp.set_variable(name, Value::FloatArray(copy));
Ok(())
}
Expr::Index { base: prev_base, index: prev_idx, .. } => {
assign_index(interp, prev_base, prev_idx, Value::FloatArray(copy))
}
_ => Err("Unsupported nested indexing base".to_string()),
}
}
(Value::FloatArray(xs), Value::Int(i), Value::Int(new_i)) => {
if i < 0 || (i as usize) >= xs.len() {
return Err(format!("Array index out of range: {}", i));
}
let mut copy = xs.clone();
copy[i as usize] = new_i as f64;
match base {
Expr::Ident { name, .. } => {
interp.set_variable(name, Value::FloatArray(copy));
Ok(())
}
Expr::Index { base: prev_base, index: prev_idx, .. } => {
assign_index(interp, prev_base, prev_idx, Value::FloatArray(copy))
}
_ => Err("Unsupported nested indexing base".to_string()),
}
}
(Value::StrArray(xs), Value::Int(i), Value::SingleString(new_s)) => {
if i < 0 || (i as usize) >= xs.len() {
return Err(format!("Array index out of range: {}", i));
}
let mut copy = xs.clone();
copy[i as usize] = new_s;
match base {
Expr::Ident { name, .. } => {
interp.set_variable(name, Value::StrArray(copy));
Ok(())
}
Expr::Index { base: prev_base, index: prev_idx, .. } => {
assign_index(interp, prev_base, prev_idx, Value::StrArray(copy))
}
_ => Err("Unsupported nested indexing base".to_string()),
}
}
(Value::Int2DArray(rows), Value::Int(i), Value::IntArray(new_row)) => {
if i < 0 || (i as usize) >= rows.len() {
return Err(format!("Array index out of range: {}", i));
}
let mut copy = rows.clone();
copy[i as usize] = new_row;
match base {
Expr::Ident { name, .. } => {
interp.set_variable(name, Value::Int2DArray(copy));
Ok(())
}
Expr::Index { base: prev_base, index: prev_idx, .. } => {
assign_index(interp, prev_base, prev_idx, Value::Int2DArray(copy))
}
_ => Err("Unsupported nested indexing base".to_string()),
}
}
(Value::Float2DArray(rows), Value::Int(i), Value::FloatArray(new_row)) => {
if i < 0 || (i as usize) >= rows.len() {
return Err(format!("Array index out of range: {}", i));
}
let mut copy = rows.clone();
copy[i as usize] = new_row;
match base {
Expr::Ident { name, .. } => {
interp.set_variable(name, Value::Float2DArray(copy));
Ok(())
}
Expr::Index { base: prev_base, index: prev_idx, .. } => {
assign_index(interp, prev_base, prev_idx, Value::Float2DArray(copy))
}
_ => Err("Unsupported nested indexing base".to_string()),
}
}
(Value::Float2DArray(rows), Value::Int(i), Value::IntArray(new_row)) => {
if i < 0 || (i as usize) >= rows.len() {
return Err(format!("Array index out of range: {}", i));
}
let mut copy = rows.clone();
copy[i as usize] = new_row.iter().map(|&n| n as f64).collect();
match base {
Expr::Ident { name, .. } => {
interp.set_variable(name, Value::Float2DArray(copy));
Ok(())
}
Expr::Index { base: prev_base, index: prev_idx, .. } => {
assign_index(interp, prev_base, prev_idx, Value::Float2DArray(copy))
}
_ => Err("Unsupported nested indexing base".to_string()),
}
}
(Value::MixedArray(mut items), Value::Int(i), nv) => {
if i < 0 || (i as usize) >= items.len() {
return Err(format!("Array index out of range: {}", i));
}
items[i as usize] = nv;
match base {
Expr::Ident { name, .. } => {
interp.set_variable(name, Value::MixedArray(items));
Ok(())
}
Expr::Index { base: prev_b, index: prev_i, .. } => {
assign_index(interp, prev_b, prev_i, Value::MixedArray(items))
}
_ => Err("Unsupported nested indexing base for MixedArray".to_string()),
}
}
_ => Err(format!("Cannot assign via array index with provided types.")),
}
}
pub fn deep_flatten_upcast_array(items: &[Value]) -> Value {
let mut floats = Vec::new();
let mut ints = Vec::new();
let mut strs = Vec::new();
let mut found_float = false;
let mut found_int = false;
let mut found_str = false;
let mut found_other = false;
fn flatten(
v: &Value,
ints: &mut Vec<i32>,
floats: &mut Vec<f64>,
strs: &mut Vec<String>,
found_int: &mut bool,
found_float: &mut bool,
found_str: &mut bool,
found_other: &mut bool,
) {
match v {
Value::Int(i) => {
*found_int = true;
ints.push(*i);
}
Value::Float(f) => {
*found_float = true;
floats.push(*f);
}
Value::SingleString(s) => {
*found_str = true;
strs.push(s.clone());
}
Value::StrArray(ss) => {
*found_str = true;
strs.extend(ss.clone());
}
Value::IntArray(xs) => {
*found_int = true;
ints.extend(xs.iter().cloned());
}
Value::FloatArray(fs) => {
*found_float = true;
floats.extend(fs.iter().cloned());
}
Value::MixedArray(inner) => for x in inner {
flatten(x, ints, floats, strs, found_int, found_float, found_str, found_other)
},
_ => {
*found_other = true;
}
}
}
for v in items {
flatten(v, &mut ints, &mut floats, &mut strs, &mut found_int, &mut found_float, &mut found_str, &mut found_other);
}
if found_other {
let mut out = Vec::new();
for v in items {
match v {
Value::MixedArray(inner) => out.extend(inner.clone()),
_ => out.push(v.clone())
}
}
Value::MixedArray(out)
} else if found_float || (found_int && found_float) {
let mut all_floats = floats;
all_floats.extend(ints.iter().map(|&i| i as f64));
Value::FloatArray(all_floats)
} else if found_int {
Value::IntArray(ints)
} else if found_str {
Value::StrArray(strs)
} else {
Value::MixedArray(items.to_vec())
}
}