Files
lysp/src/vm/prelude/debug.rs
T

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()))
},
);
}