use std::cmp::Ordering; use crate::prelude::*; macro_rules! error { ($($arg:tt)*) => { Err(exception!(VALUE_EXCEPTION, $($arg)*)) }; } impl Value { pub fn val_cmp(&self, other: &Self) -> Result { self.partial_cmp(other) .map_or_else(|| error!("cannot compare: {self:?} and {other:?}"), Ok) } fn index_single(&self, index: &Value) -> Result { use Value as V; match (self, index) { (V::Table(t), index) => { Ok(t.get(index)?.unwrap_or(&Value::Nil).clone()) }, (V::List(l), V::Int(i)) => { if *i < 0 || *i as usize >= l.len() { return error!("{i} out of bounds for {self:?}") } Ok(l[*i as usize].clone()) }, (V::Matrix(m), V::Int(i)) => { if *i < 0 || *i as usize >= m.values.len() { return error!("{i} out of bounds for {self:?}") } Ok(m.values[*i as usize].clone()) }, _ => return error!("{index:?} cant index {self:?}") } } fn index_multiple(&self, indexes: &Vec) -> Result { use Value as V; match self { V::List(..) => { let mut ret = Vec::new(); for index in indexes { let res = self.index_single(index)?; ret.push(res); } Ok(V::List(ret.into())) } V::Table(..) => { let mut ret = ValueMap::new(); for index in indexes { let res = self.index_single(index)?; ret.insert(index.clone(), res)?; } Ok(V::Table(ret.into())) } V::Matrix(m) => { let err = || error!("{self:?} can be index by [Int] or [Int;Int]"); if indexes.len() != 2 { return err() } let lhs = indexes[0].clone(); let rhs = indexes[1].clone(); match (lhs, rhs) { (V::Nil, V::Nil) => { Ok(V::Matrix(m.shallow_clone())) }, (V::Int(row), V::Nil) => { let Some((_, row)) = m.rows().enumerate().filter(|(idx, _)| *idx as i64 == row).next() else { return err(); }; let row: Vec = row.into_iter().map(|e| e.clone()).collect(); Ok(V::Matrix(Matrix::new(row.len(), 1, row).into())) }, (V::Nil, V::Int(col)) => { let Some((_, col)) = m.cols().enumerate().filter(|(idx, _)| *idx as i64 == col).next() else { return err(); }; let col: Vec = col.into_iter().map(|e| e.clone()).collect(); Ok(V::Matrix(Matrix::new(1, col.len(), col).into())) }, (V::Int(row), V::Int(col)) => { if row < 0 || col < 0 { return err(); } m.get(row as usize, col as usize) } _ => return err() } } _ => return error!("cannot index {self:?}") } } pub fn index(&self, index: &Vec) -> Result { if index.len() == 0 { Ok(self.shallow_clone()) } else if index.len() == 1 { self.index_single(&index[0]) } else { self.index_multiple(index) } } fn store_index_single(&mut self, index: &Value, store: Value) -> Result<()> { use Value as V; let err = format!("{self:?}"); match (self, index) { (V::Table(t), index) => { t.insert(index.clone(), store) }, (V::List(l), V::Int(i)) => { if *i < 0 || *i as usize >= l.len() { return error!("{i} out of bounds for {err}") } l[*i as usize] = store; Ok(()) }, (V::Matrix(m), V::Int(i)) => { if *i < 0 || *i as usize >= m.values.len() { return error!("{i} out of bounds for {err}") } m.values[*i as usize] = store; Ok(()) }, _ => return error!("{index:?} cant index {err}") } } fn store_index_multiple(&mut self, indexes: &Vec, store: Value) -> Result<()> { use Value as V; match self { V::List(..) => { for index in indexes { self.store_index_single(index, store.clone())?; } Ok(()) } V::Table(..) => { for index in indexes { self.store_index_single(index, store.clone())?; } Ok(()) } _ => return error!("cannot index {self:?}") } } pub fn store_index(&mut self, index: &Vec, store: Value) -> Result<()> { if index.len() == 0 { Ok(()) } else if index.len() == 1 { self.store_index_single(&index[0], store) } else { self.store_index_multiple(index, store) } } pub fn store_field_access(&mut self, ident: &str, val: Value) -> Result<()> { use Value as V; match self { V::Table(t) => { let key = V::String(Rc::from(ident)); Ok(t.insert(key, val)?) }, _ => return error!("cannot field access assign {self:?}") } } pub fn field_access(&self, ident: &str) -> Result { use Value as V; match self { V::Table(t) => { let key = V::String(Rc::from(ident)); Ok(t.get(&key)?.unwrap_or(&V::Nil).clone()) }, _ => return error!("cannot field access {self:?}") } } } impl Value { pub fn into_iter_fn(self) -> Result> { let Value::Iter(iter) = self.into_iter()? else { return error!("bypassed iter check") }; Ok(iter) } pub fn into_iter(self) -> Result { use Value as V; Ok(match self { V::Iter(..) => self, V::List(l) => { let iter = RefCell::new(l.into_inner().into_iter()); iter!(move |_,_| { match iter.borrow_mut().next() { Some(v) => Ok(v), None => Ok(V::Nil), } }) }, V::Range(r) => { let r = (*r).clone(); let lhs = RefCell::new(r.0); let rhs = r.1; iter!(move |_,_| { let val = *lhs.borrow(); let next = *lhs.borrow() + 1; if (!r.2 && *lhs.borrow() < rhs) || (r.2 && *lhs.borrow() <= rhs) { *lhs.borrow_mut() = next; return Ok(Value::Int(val)) } Ok(Value::Nil) }) }, V::Function(f) => { if f.arity > 0 || f.variadic { return error!("iterator functions cannot be varadic or take arguments") } V::Iter(f) }, val => return error!("cannot turn {val:?} into an iterator") }) } }