2020-03-03 19:51:02 -05:00
|
|
|
use std::collections::HashMap;
|
2020-02-02 21:09:29 -05:00
|
|
|
|
2020-03-20 12:09:08 -04:00
|
|
|
use num_traits::cast::ToPrimitive;
|
|
|
|
|
2020-02-14 10:10:51 -05:00
|
|
|
use super::Builtin;
|
2020-03-19 16:24:31 -04:00
|
|
|
use crate::unit::Unit;
|
2020-02-14 10:10:51 -05:00
|
|
|
use crate::value::{Number, Value};
|
|
|
|
|
2020-03-03 19:51:02 -05:00
|
|
|
pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
2020-03-16 10:35:38 -04:00
|
|
|
f.insert(
|
|
|
|
"length".to_owned(),
|
|
|
|
Box::new(|args, _| {
|
2020-03-20 10:03:54 -04:00
|
|
|
max_args!(args, 1);
|
2020-03-16 10:35:38 -04:00
|
|
|
let len = match arg!(args, 0, "list") {
|
|
|
|
Value::List(v, _) => Number::from(v.len()),
|
|
|
|
_ => Number::from(1),
|
|
|
|
};
|
|
|
|
Ok(Value::Dimension(len, Unit::None))
|
|
|
|
}),
|
|
|
|
);
|
2020-03-20 12:09:08 -04:00
|
|
|
f.insert(
|
|
|
|
"nth".to_owned(),
|
|
|
|
Box::new(|args, _| {
|
|
|
|
max_args!(args, 2);
|
|
|
|
let list = match arg!(args, 0, "list") {
|
|
|
|
Value::List(v, _) => v,
|
|
|
|
_ => return Err("Missing argument $list.".into()),
|
|
|
|
};
|
|
|
|
let n = match arg!(args, 1, "n") {
|
|
|
|
Value::Dimension(num, _) => num,
|
|
|
|
v => return Err(format!("$n: {} is not a number.", v).into()),
|
|
|
|
};
|
|
|
|
|
|
|
|
if n == Number::from(0) {
|
|
|
|
return Err("$n: List index may not be 0.".into());
|
|
|
|
}
|
|
|
|
|
|
|
|
if n.abs() > Number::from(list.len()) {
|
|
|
|
return Err(format!(
|
|
|
|
"$n: Invalid index {} for a list with {} elements.",
|
|
|
|
n,
|
|
|
|
list.len()
|
|
|
|
)
|
|
|
|
.into());
|
|
|
|
}
|
|
|
|
|
|
|
|
if n.is_decimal() {
|
|
|
|
return Err(format!("$n: {} is not an int.", n).into());
|
|
|
|
}
|
|
|
|
|
|
|
|
if n > Number::from(0) {
|
|
|
|
Ok(list[n.to_integer().to_usize().unwrap() - 1].clone())
|
|
|
|
} else {
|
|
|
|
Ok(list[list.len() - n.abs().to_integer().to_usize().unwrap()].clone())
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
);
|
2020-02-14 10:10:51 -05:00
|
|
|
}
|