haku: add len
and index
functions for reading lists
This commit is contained in:
parent
dd955b0649
commit
e2f9538156
|
@ -247,9 +247,8 @@ pub mod fns {
|
|||
0x88 Nary "rgbaB" => rgba_b,
|
||||
0x89 Nary "rgbaA" => rgba_a,
|
||||
|
||||
// NOTE: Not used right now, has been replaced with Opcode::List.
|
||||
// Keeping it around to reserve a slot for data structure operations.
|
||||
0x90 Nary "list (unused)" => list,
|
||||
0x90 Nary "len" => len,
|
||||
0x91 Nary "index" => index,
|
||||
|
||||
0xc0 Nary "toShape" => to_shape_f,
|
||||
0xc1 Nary "line" => line,
|
||||
|
@ -552,11 +551,33 @@ pub mod fns {
|
|||
Ok(Value::Number(rgba.r))
|
||||
}
|
||||
|
||||
pub fn list(vm: &mut Vm, args: FnArgs) -> Result<Value, Exception> {
|
||||
let elements: Vec<_> = (0..args.num()).map(|i| args.get(vm, i)).collect();
|
||||
vm.track_array(&elements)?;
|
||||
let id = vm.create_ref(Ref::List(List { elements }))?;
|
||||
Ok(Value::Ref(id))
|
||||
pub fn len(vm: &mut Vm, args: FnArgs) -> Result<Value, Exception> {
|
||||
if args.num() != 1 {
|
||||
return Err(vm.create_exception("`len` expects a single argument (len list)"));
|
||||
}
|
||||
|
||||
let list = args.get_list(vm, 0, "argument to (len list) must be a list")?;
|
||||
Ok(Value::Number(list.elements.len() as f32))
|
||||
}
|
||||
|
||||
pub fn index(vm: &mut Vm, args: FnArgs) -> Result<Value, Exception> {
|
||||
if args.num() != 2 {
|
||||
return Err(vm.create_exception("`index` expects two arguments (index list i)"));
|
||||
}
|
||||
|
||||
let list = args.get_list(vm, 0, "1st argument to (index list i) must be a list")?;
|
||||
let i = args.get_number(vm, 1, "2nd argument to (index list i) must be a number")?;
|
||||
if i >= 0.0 {
|
||||
let i = i as usize;
|
||||
if i < list.elements.len() {
|
||||
return Ok(list.elements[i]);
|
||||
}
|
||||
}
|
||||
Err(vm.create_exception(format!(
|
||||
"list index out of bounds (length of list is {}, index is {})",
|
||||
list.elements.len(),
|
||||
i
|
||||
)))
|
||||
}
|
||||
|
||||
fn to_shape(value: Value, vm: &Vm) -> Option<Shape> {
|
||||
|
|
|
@ -622,6 +622,23 @@ impl FnArgs {
|
|||
};
|
||||
Ok(closure)
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn get_list<'vm>(
|
||||
&self,
|
||||
vm: &'vm Vm,
|
||||
index: usize,
|
||||
message: &'static str,
|
||||
) -> Result<&'vm List, Exception> {
|
||||
let value = self.get(vm, index);
|
||||
let (_, any_ref) = vm
|
||||
.get_ref_value(value)
|
||||
.ok_or_else(|| vm.create_exception(message))?;
|
||||
let Ref::List(list) = any_ref else {
|
||||
return Err(vm.create_exception(message));
|
||||
};
|
||||
Ok(list)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
|
|
@ -292,3 +292,20 @@ fn with_dotter_identity() {
|
|||
"#;
|
||||
assert_eq!(eval(code).unwrap(), Value::Ref(RefId::from_u32(2)))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn system_len() {
|
||||
expect_number("len []", 0.0, 0.0001);
|
||||
expect_number("len [1, 2]", 2.0, 0.0001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn system_index() {
|
||||
expect_number("index [1] 0", 1.0, 0.0001);
|
||||
expect_number("index [1, 2] 0", 1.0, 0.0001);
|
||||
expect_number("index [1, 2] 1", 2.0, 0.0001);
|
||||
expect_number("index [1] 0.5", 1.0, 0.0001);
|
||||
expect_number("index [1, 2] 0.5", 1.0, 0.0001);
|
||||
assert!(eval("index [1] (-1)").is_err());
|
||||
assert!(eval("index [1] 1").is_err());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue