Add string literals, fix instruction encoding
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
use std::slice;
|
||||
|
||||
use crate::{
|
||||
convert::{AnyFunction, TryFromValue},
|
||||
util::IteratorExt,
|
||||
vm::{
|
||||
machine::{Machine, MachineError},
|
||||
value::{Value, ValueString},
|
||||
},
|
||||
};
|
||||
|
||||
mod math;
|
||||
pub(crate) use math::*;
|
||||
|
||||
pub fn load(vm: &mut Machine) {
|
||||
// math
|
||||
vm.defun_native("+", builtin_add);
|
||||
vm.defun_native("-", builtin_sub);
|
||||
vm.defun_native("*", builtin_mul);
|
||||
vm.defun_native("%", builtin_mod);
|
||||
vm.defun_native("/", builtin_div);
|
||||
|
||||
vm.defun_native("&&", builtin_and);
|
||||
vm.defun_native("||", builtin_or);
|
||||
vm.defun_native("&", builtin_bitwise_and);
|
||||
vm.defun_native("|", builtin_bitwise_or);
|
||||
vm.defun_native("^", builtin_bitwise_xor);
|
||||
|
||||
vm.defun_native(">", builtin_cmp_gt);
|
||||
vm.defun_native("<", builtin_cmp_lt);
|
||||
vm.defun_native("=", builtin_cmp_eq);
|
||||
vm.defun_native("/=", builtin_cmp_ne);
|
||||
vm.defun_native(">=", builtin_cmp_ge);
|
||||
vm.defun_native("<=", builtin_cmp_le);
|
||||
|
||||
// conversion
|
||||
vm.defun_native("string->int", |_vm, args| {
|
||||
let [arg] = args else {
|
||||
return Err(MachineError::InvalidArgument);
|
||||
};
|
||||
let arg = ValueString::try_from_value(arg)?;
|
||||
let result = arg.parse::<i64>().map(Value::Integer).unwrap_or(Value::Nil);
|
||||
Ok(result)
|
||||
});
|
||||
vm.defun_native("int->string", |_vm, args| {
|
||||
let [arg] = args else {
|
||||
return Err(MachineError::InvalidArgument);
|
||||
};
|
||||
let arg = i64::try_from_value(arg)?;
|
||||
let result = Value::String(format!("{arg}").into());
|
||||
Ok(result)
|
||||
});
|
||||
|
||||
// lists
|
||||
vm.defun_native("map", |vm, args| {
|
||||
let [f, xs] = args else {
|
||||
return Err(MachineError::InvalidArgument);
|
||||
};
|
||||
let f = AnyFunction::try_from_value(f)?;
|
||||
let xs = xs.proper_iter(MachineError::InvalidArgument);
|
||||
let out = Value::try_list_or_nil(xs.map(|v| f.invoke(vm, slice::from_ref(v?))))?;
|
||||
Ok(out)
|
||||
});
|
||||
vm.defun_native("filter", |vm, args| {
|
||||
let [f, xs] = args else {
|
||||
return Err(MachineError::InvalidArgument);
|
||||
};
|
||||
let f = AnyFunction::try_from_value(f)?;
|
||||
let xs = xs
|
||||
.proper_iter(MachineError::InvalidArgument)
|
||||
.map(|x| x.cloned());
|
||||
let out = Value::try_list_or_nil(xs.try_filter(|v| {
|
||||
let result = f.invoke(vm, slice::from_ref(v))?;
|
||||
bool::try_from_value(&result)
|
||||
}))?;
|
||||
Ok(out)
|
||||
});
|
||||
vm.defun_native("list", |_, args| {
|
||||
let out = Value::list_or_nil(args.iter().cloned());
|
||||
Ok(out)
|
||||
});
|
||||
|
||||
// functional
|
||||
vm.defun_native("identity", |_, args| {
|
||||
let [arg] = args else {
|
||||
return Err(MachineError::InvalidArgument);
|
||||
};
|
||||
Ok(arg.clone())
|
||||
});
|
||||
|
||||
// eval
|
||||
vm.defun_native("apply", |vm, args| {
|
||||
let [f, xs] = args else {
|
||||
return Err(MachineError::InvalidArgument);
|
||||
};
|
||||
let f = AnyFunction::try_from_value(f)?;
|
||||
let args = xs
|
||||
.proper_iter(MachineError::InvalidArgument)
|
||||
.map(|x| x.cloned())
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
f.invoke(vm, &args[..])
|
||||
});
|
||||
vm.defun_native("assert", |vm, args| match args {
|
||||
[] => Err(MachineError::InvalidArgument),
|
||||
[cond] => {
|
||||
let cond = bool::try_from_value(cond)?;
|
||||
if !cond {
|
||||
let ip = vm.ip();
|
||||
if let Some(ip) = ip {
|
||||
eprintln!("Assertion failed at {ip}:");
|
||||
eprintln!();
|
||||
ip.module.dump(Some(ip.address), 8);
|
||||
}
|
||||
panic!("Assertion failed");
|
||||
}
|
||||
Ok(Value::Nil)
|
||||
}
|
||||
_ => todo!(),
|
||||
});
|
||||
vm.defun_native("assert-equal", |vm, args| match args {
|
||||
[] | [_] => Err(MachineError::InvalidArgument),
|
||||
[a, b] => {
|
||||
if a != b {
|
||||
let ip = vm.ip();
|
||||
if let Some(ip) = ip {
|
||||
eprintln!("Assertion failed at {ip}:");
|
||||
eprintln!();
|
||||
eprintln!(":: {a} ≠ {b}");
|
||||
eprintln!();
|
||||
ip.module.dump(Some(ip.address), 8);
|
||||
}
|
||||
panic!("Assertion failed");
|
||||
}
|
||||
Ok(Value::Nil)
|
||||
}
|
||||
[a, b, msg] => {
|
||||
if a != b {
|
||||
let ip = vm.ip();
|
||||
if let Some(ip) = ip {
|
||||
eprintln!("Assertion failed at {ip}: {msg}");
|
||||
eprintln!();
|
||||
eprintln!(":: {a} ≠ {b}");
|
||||
eprintln!();
|
||||
ip.module.dump(Some(ip.address), 8);
|
||||
}
|
||||
panic!("Assertion failed");
|
||||
}
|
||||
Ok(Value::Nil)
|
||||
}
|
||||
_ => todo!(),
|
||||
});
|
||||
|
||||
// io
|
||||
vm.defun_native("print", |_, args| {
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
if i != 0 {
|
||||
print!(" ");
|
||||
}
|
||||
print!("{arg}");
|
||||
}
|
||||
println!();
|
||||
Ok(Value::Nil)
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user