160 lines
4.9 KiB
Rust
160 lines
4.9 KiB
Rust
use crate::{symbol::{SYM_END_ITERATION, SYM_INDEX_ERROR, SYM_TYPE_ERROR}, value::function::NativeFunc, vmcalliter, Vm, exception::{Result, throw}};
|
|
|
|
use super::{Value, range::RangeType};
|
|
|
|
impl Value {
|
|
pub fn index(&self, idx: Self) -> Result<Self> {
|
|
use Value as V;
|
|
match (self, idx) {
|
|
(V::List(l), V::Int(i)) => {
|
|
let l = l.borrow();
|
|
if i >= 0 && (i as usize) < l.len() {
|
|
Ok(l[i as usize].clone())
|
|
} else {
|
|
throw!(*SYM_INDEX_ERROR, "index {i} out of bounds for list of length {}", l.len())
|
|
}
|
|
},
|
|
(V::Range(r), V::Int(i)) => {
|
|
if i >= 0 && (
|
|
r.ty == RangeType::Endless
|
|
|| i < r.stop
|
|
|| (r.ty == RangeType::Closed && i == r.stop)
|
|
) {
|
|
Ok((r.start + i).into())
|
|
} else {
|
|
throw!(*SYM_INDEX_ERROR, "index {i} out of bounds for range {self}")
|
|
}
|
|
},
|
|
(V::Table(t), i) if i.hashable() => {
|
|
let t = t.borrow();
|
|
let i = i.try_into()?;
|
|
Ok(t.get(&i).cloned().unwrap_or(Value::Nil))
|
|
},
|
|
(V::String(s), V::Range(r)) => {
|
|
let slen = s.len();
|
|
match r.ty {
|
|
RangeType::Open => {
|
|
if r.start < 0 || r.start > slen as i64 {
|
|
throw!(*SYM_INDEX_ERROR,
|
|
"index {} out of bounds for string of length {}", r.stop, slen)
|
|
}
|
|
if r.stop < 0 || r.stop > slen as i64 {
|
|
throw!(*SYM_INDEX_ERROR,
|
|
"index {} out of bounds for string of length {}", r.stop, slen)
|
|
}
|
|
Ok(s[r.start as usize..r.stop as usize].into())
|
|
},
|
|
RangeType::Closed => {
|
|
if r.start < 0 || r.start > slen as i64 {
|
|
throw!(*SYM_INDEX_ERROR,
|
|
"index {} out of bounds for string of length {}", r.stop, slen)
|
|
}
|
|
if r.stop < 0 || r.stop >= slen as i64 {
|
|
throw!(*SYM_INDEX_ERROR,
|
|
"index {} out of bounds for string of length {}", r.stop, slen)
|
|
}
|
|
Ok(s[r.start as usize..=r.stop as usize].into())
|
|
},
|
|
RangeType::Endless => {
|
|
if r.start < 0 || r.start > slen as i64 {
|
|
throw!(*SYM_INDEX_ERROR,
|
|
"index {} out of bounds for string of length {}", r.stop, slen)
|
|
}
|
|
Ok(s[r.start as usize..].into())
|
|
},
|
|
}
|
|
},
|
|
(col, idx) => if let Ok(ii) = idx.clone().to_iter_function() {
|
|
let col = col.clone();
|
|
let func = move |vm: &mut Vm, _| {
|
|
match vmcalliter!(vm; ii.clone())? {
|
|
Some(i) => col.index(i),
|
|
None => Ok(Value::from(*SYM_END_ITERATION)),
|
|
}
|
|
};
|
|
Ok(NativeFunc::new(Box::new(func), 0).into())
|
|
} else {
|
|
throw!(*SYM_TYPE_ERROR, "cannot index {col:#} with {idx:#}")
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn store_index(&self, vm: &mut Vm, idx: Self, val: Self) -> Result<()> {
|
|
use Value as V;
|
|
match (self, idx) {
|
|
(V::List(l), V::Int(i)) => {
|
|
let mut l = l.borrow_mut();
|
|
if i >= 0 && (i as usize) < l.len() {
|
|
l[i as usize] = val;
|
|
Ok(())
|
|
} else {
|
|
throw!(*SYM_INDEX_ERROR, "index {i} out of bounds for list of length {}", l.len())
|
|
}
|
|
},
|
|
(V::Table(t), i) if i.hashable() => {
|
|
let mut t = t.borrow_mut();
|
|
let i = i.try_into()?;
|
|
t.insert(i, val);
|
|
Ok(())
|
|
},
|
|
(V::List(t), V::Range(r)) => {
|
|
let iter = val.to_iter_function()?;
|
|
let mut vals = Vec::new();
|
|
while let Some(v) = vmcalliter!(vm; iter.clone())? {
|
|
vals.push(v);
|
|
}
|
|
let mut tm = t.borrow_mut();
|
|
match r.ty {
|
|
RangeType::Open => {
|
|
if r.start < 0 || r.start > tm.len() as i64 {
|
|
throw!(*SYM_INDEX_ERROR,
|
|
"index {} out of bounds for list of length {}", r.stop, tm.len())
|
|
}
|
|
if r.stop < 0 || r.stop > tm.len() as i64 {
|
|
throw!(*SYM_INDEX_ERROR,
|
|
"index {} out of bounds for list of length {}", r.stop, tm.len())
|
|
}
|
|
let end = tm.split_off(r.stop as usize);
|
|
tm.truncate(r.start as usize);
|
|
tm.extend(vals.into_iter().chain(end));
|
|
},
|
|
RangeType::Closed => {
|
|
if r.start < 0 || r.start > tm.len() as i64 {
|
|
throw!(*SYM_INDEX_ERROR,
|
|
"index {} out of bounds for list of length {}", r.stop, tm.len())
|
|
}
|
|
if r.stop < 0 || r.stop >= tm.len() as i64 {
|
|
throw!(*SYM_INDEX_ERROR,
|
|
"index {} out of bounds for list of length {}", r.stop, tm.len())
|
|
}
|
|
let end = tm.split_off(r.stop as usize + 1);
|
|
tm.truncate(r.start as usize);
|
|
tm.extend(vals.into_iter().chain(end));
|
|
},
|
|
RangeType::Endless => {
|
|
if r.start < 0 || r.start > tm.len() as i64 {
|
|
throw!(*SYM_INDEX_ERROR,
|
|
"index {} out of bounds for list of length {}", r.stop, tm.len())
|
|
}
|
|
tm.truncate(r.start as usize);
|
|
tm.extend(vals);
|
|
},
|
|
}
|
|
Ok(())
|
|
},
|
|
(col, idx) => if let Ok(ii) = idx.clone().to_iter_function() {
|
|
let val = val.to_iter_function()?;
|
|
while let Some(i) = vmcalliter!(vm; ii.clone())? {
|
|
let Some(v) = vmcalliter!(vm; val.clone())? else {
|
|
throw!(*SYM_INDEX_ERROR, "not enough values provided for store index")
|
|
};
|
|
col.store_index(vm, i, v)?;
|
|
}
|
|
Ok(())
|
|
} else {
|
|
throw!(*SYM_TYPE_ERROR, "cannot index {self:#} with {idx:#}")
|
|
},
|
|
}
|
|
}
|
|
}
|