97 lines
3.6 KiB
Rust
97 lines
3.6 KiB
Rust
use crate::{
|
|
error::MachineError,
|
|
vm::{Value, env::Environment, value::Keyword},
|
|
};
|
|
|
|
pub fn load(env: &mut Environment) {
|
|
env.defun_native(
|
|
"explain",
|
|
"Provides an explanation for a given value",
|
|
|_, _, args| {
|
|
let [argument] = args else {
|
|
return Err(MachineError::InvalidArgumentCount);
|
|
};
|
|
let explanation = match argument {
|
|
Value::Nil => "an empty list".into(),
|
|
Value::Cons(_) => "a cons-cell".into(),
|
|
Value::Number(_) => "a number".into(),
|
|
Value::Boolean(_) => "a boolean value".into(),
|
|
Value::Quasi(_) => "a quasi-quoted value".into(),
|
|
Value::Quote(_) => "a quoted value".into(),
|
|
Value::Unquote(_) => "an un-quoted value".into(),
|
|
Value::Identifier(identifier) => format!("an identifier {:?}", identifier.as_ref()),
|
|
Value::Vector(_) => "a vector".into(),
|
|
Value::String(_) => "a string".into(),
|
|
Value::Keyword(_) => "a keyword".into(),
|
|
Value::Closure(closure) => {
|
|
format!(
|
|
"function {}: {}",
|
|
closure.function.name(),
|
|
closure.function.docstring()
|
|
)
|
|
}
|
|
Value::Function(function) => {
|
|
format!("function {}: {}", function.name(), function.docstring())
|
|
}
|
|
Value::NativeFunction(function) => {
|
|
format!(
|
|
"built-in function {}: {}",
|
|
function.name(),
|
|
function.docstring()
|
|
)
|
|
}
|
|
Value::NativeValue(_) => "a native value".into(),
|
|
};
|
|
Ok(Value::String(explanation.into()))
|
|
},
|
|
);
|
|
env.defun_native(
|
|
"type",
|
|
"Returns the data type of the argument",
|
|
|_, _, args| {
|
|
let [argument] = args else {
|
|
return Err(MachineError::InvalidArgumentCount);
|
|
};
|
|
Ok(argument.type_id())
|
|
},
|
|
);
|
|
env.defmacro_native(
|
|
"assert",
|
|
"Checks that the condition is true, otherwise aborts the execution",
|
|
|vm, _, args| match args {
|
|
[] => Err(MachineError::InvalidArgumentCount),
|
|
[cond] => {
|
|
let assertion_failure_msg = match vm.current_location() {
|
|
Some(ip) => format!("{ip}: assertion failed: {cond}"),
|
|
None => format!("<undefined>: assertion failed: {cond}"),
|
|
};
|
|
let assertion_failure = Value::list_or_nil([
|
|
Value::Identifier("abort".into()),
|
|
Value::String(assertion_failure_msg.into()),
|
|
]);
|
|
Ok(Value::list_or_nil([
|
|
Value::Keyword(Keyword::If),
|
|
cond.clone(),
|
|
Value::Nil,
|
|
assertion_failure,
|
|
]))
|
|
}
|
|
_ => Err(MachineError::InvalidArgumentCount),
|
|
},
|
|
);
|
|
env.defun_native(
|
|
"abort",
|
|
"Aborts the execution with the given reason message",
|
|
|_, _, args| {
|
|
let mut message = String::new();
|
|
for (i, arg) in args.iter().enumerate() {
|
|
if i != 0 {
|
|
message.push(' ');
|
|
}
|
|
message.push_str(&format!("{arg}"));
|
|
}
|
|
Err(MachineError::Abort(message.into()))
|
|
},
|
|
);
|
|
}
|