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,
|
0x88 Nary "rgbaB" => rgba_b,
|
||||||
0x89 Nary "rgbaA" => rgba_a,
|
0x89 Nary "rgbaA" => rgba_a,
|
||||||
|
|
||||||
// NOTE: Not used right now, has been replaced with Opcode::List.
|
0x90 Nary "len" => len,
|
||||||
// Keeping it around to reserve a slot for data structure operations.
|
0x91 Nary "index" => index,
|
||||||
0x90 Nary "list (unused)" => list,
|
|
||||||
|
|
||||||
0xc0 Nary "toShape" => to_shape_f,
|
0xc0 Nary "toShape" => to_shape_f,
|
||||||
0xc1 Nary "line" => line,
|
0xc1 Nary "line" => line,
|
||||||
|
@ -552,11 +551,33 @@ pub mod fns {
|
||||||
Ok(Value::Number(rgba.r))
|
Ok(Value::Number(rgba.r))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list(vm: &mut Vm, args: FnArgs) -> Result<Value, Exception> {
|
pub fn len(vm: &mut Vm, args: FnArgs) -> Result<Value, Exception> {
|
||||||
let elements: Vec<_> = (0..args.num()).map(|i| args.get(vm, i)).collect();
|
if args.num() != 1 {
|
||||||
vm.track_array(&elements)?;
|
return Err(vm.create_exception("`len` expects a single argument (len list)"));
|
||||||
let id = vm.create_ref(Ref::List(List { elements }))?;
|
}
|
||||||
Ok(Value::Ref(id))
|
|
||||||
|
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> {
|
fn to_shape(value: Value, vm: &Vm) -> Option<Shape> {
|
||||||
|
|
|
@ -622,6 +622,23 @@ impl FnArgs {
|
||||||
};
|
};
|
||||||
Ok(closure)
|
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)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
|
|
@ -292,3 +292,20 @@ fn with_dotter_identity() {
|
||||||
"#;
|
"#;
|
||||||
assert_eq!(eval(code).unwrap(), Value::Ref(RefId::from_u32(2)))
|
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