lysp: more string prelude, fallible set_global_value
This commit is contained in:
@@ -216,7 +216,8 @@ fn main() -> ExitCode {
|
||||
env.set_global_value(
|
||||
"*args*",
|
||||
Value::list_or_nil(arguments.into_iter().map(|arg| Value::String(arg.into()))),
|
||||
);
|
||||
)
|
||||
.ok();
|
||||
let result = match args.module.as_ref() {
|
||||
Some(module) => run_module(&compile_options, &mut vm, &env, module),
|
||||
None => run_interactive(&compile_options, &mut vm, &env),
|
||||
|
||||
@@ -27,7 +27,11 @@ pub enum Macro {
|
||||
|
||||
pub trait EnvironmentAccessHook {
|
||||
fn read_variable(&mut self, name: &str) -> Option<Value>;
|
||||
fn write_variable(&mut self, name: IdentifierValue, value: Value) -> bool;
|
||||
fn write_variable(
|
||||
&mut self,
|
||||
name: &IdentifierValue,
|
||||
value: &Value,
|
||||
) -> Result<bool, MachineError>;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -70,7 +74,8 @@ impl Environment {
|
||||
let identifier = identifier.into();
|
||||
let native = NativeFunction::new(identifier.clone(), docstring, function);
|
||||
let value = Value::NativeFunction(native);
|
||||
self.set_global_value(identifier, value.clone());
|
||||
self.set_global_value(identifier, value.clone())
|
||||
.expect("defun_native failed");
|
||||
value
|
||||
}
|
||||
|
||||
@@ -121,17 +126,20 @@ impl Environment {
|
||||
&self,
|
||||
identifier: S,
|
||||
value: V,
|
||||
) {
|
||||
) -> Result<(), MachineError> {
|
||||
let identifier = identifier.into();
|
||||
let value = value.into();
|
||||
|
||||
if let Some(hook) = &mut *self.access_hook.borrow_mut()
|
||||
&& hook.write_variable(identifier.clone(), value.clone())
|
||||
{
|
||||
return;
|
||||
if let Some(hook) = &mut *self.access_hook.borrow_mut() {
|
||||
match hook.write_variable(&identifier, &value) {
|
||||
Ok(true) => return Ok(()),
|
||||
Ok(false) => {}
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
}
|
||||
|
||||
self.globals.borrow_mut().insert(identifier, value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn global_macro<Q>(&self, identifier: &Q) -> Option<Macro>
|
||||
|
||||
@@ -196,7 +196,7 @@ impl Machine {
|
||||
));
|
||||
};
|
||||
let value = self.pop()?;
|
||||
env.set_global_value(identifier, value);
|
||||
env.set_global_value(identifier, value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -95,7 +95,10 @@ pub fn load(env: &Rc<Environment>) {
|
||||
let [arg] = args else {
|
||||
return Err(MachineError::InvalidArgumentCount);
|
||||
};
|
||||
Ok(Value::String(format!("{arg}").into()))
|
||||
match arg {
|
||||
Value::String(_) => Ok(arg.clone()),
|
||||
_ => Ok(Value::String(format!("{arg}").into())),
|
||||
}
|
||||
},
|
||||
);
|
||||
env.defun_native(
|
||||
|
||||
@@ -39,7 +39,7 @@ pub fn load(env: &Rc<Environment>) {
|
||||
}
|
||||
_ => todo!(),
|
||||
};
|
||||
env.set_global_value(symbol.clone(), value.clone());
|
||||
env.set_global_value(symbol.clone(), value.clone())?;
|
||||
Ok(Value::Nil)
|
||||
},
|
||||
);
|
||||
|
||||
@@ -163,8 +163,10 @@ pub fn load(env: &Rc<Environment>) {
|
||||
|
||||
// Stream API
|
||||
|
||||
env.set_global_value("stream/stdin", NativeValue::from(stdin));
|
||||
env.set_global_value("stream/stdout", NativeValue::from(stdout));
|
||||
env.set_global_value("stream/stdin", NativeValue::from(stdin))
|
||||
.expect("set_global_value failed");
|
||||
env.set_global_value("stream/stdout", NativeValue::from(stdout))
|
||||
.expect("set_global_value failed");
|
||||
|
||||
env.defun_native("stream/open", "Opens a file", |_, _, args| {
|
||||
let [path] = args else {
|
||||
|
||||
@@ -35,9 +35,11 @@ pub(super) fn load(env: &Rc<Environment>) {
|
||||
env.defun_native("+", "Adds values", builtin_add);
|
||||
env.defun_native("-", "Subtracts values", builtin_sub);
|
||||
let mul = env.defun_native("*", "Multiplies values", builtin_mul);
|
||||
env.set_global_value("·", mul); // alias for *
|
||||
env.set_global_value("·", mul)
|
||||
.expect("set_global_value failed"); // alias for *
|
||||
let div = env.defun_native("/", "Divides values", builtin_div);
|
||||
env.set_global_value("÷", div); // alias for /
|
||||
env.set_global_value("÷", div)
|
||||
.expect("set_global_value failed"); // alias for /
|
||||
env.defun_native(
|
||||
"%",
|
||||
"Calculates a modulo/remainder of value divison",
|
||||
@@ -54,7 +56,8 @@ pub(super) fn load(env: &Rc<Environment>) {
|
||||
"Returns #t if the arguments are monotonically non-increasing",
|
||||
builtin_cmp_ge,
|
||||
);
|
||||
env.set_global_value("≥", ge); // alias for >=
|
||||
env.set_global_value("≥", ge)
|
||||
.expect("set_global_value failed"); // alias for >=
|
||||
env.defun_native(
|
||||
"<",
|
||||
"Returns #t if the arguments are monotonically increasing",
|
||||
@@ -65,7 +68,8 @@ pub(super) fn load(env: &Rc<Environment>) {
|
||||
"Returns #t if the arguments are monotonically non-decreasing",
|
||||
builtin_cmp_le,
|
||||
);
|
||||
env.set_global_value("≤", le); // alias for <=
|
||||
env.set_global_value("≤", le)
|
||||
.expect("set_global_value failed"); // alias for <=
|
||||
env.defun_native(
|
||||
"=",
|
||||
"Returns #t if all the arguments are equal",
|
||||
@@ -76,7 +80,8 @@ pub(super) fn load(env: &Rc<Environment>) {
|
||||
"Returns #t if none of the arguments are equal",
|
||||
builtin_cmp_ne,
|
||||
);
|
||||
env.set_global_value("≠", ne); // alias for /=
|
||||
env.set_global_value("≠", ne)
|
||||
.expect("set_global_value failed"); // alias for /=
|
||||
|
||||
// env.defun_native("&", builtin_bitwise_and);
|
||||
// env.defun_native("|", builtin_bitwise_or);
|
||||
|
||||
@@ -99,6 +99,28 @@ pub fn load(env: &Rc<Environment>) {
|
||||
Ok(string.len().into())
|
||||
},
|
||||
);
|
||||
env.defun_native(
|
||||
"string/to-upper",
|
||||
"Converts a string to UPPERCASE",
|
||||
|_, _, args| {
|
||||
let [string] = args else {
|
||||
return Err(MachineError::InvalidArgumentCount);
|
||||
};
|
||||
let string = StringValue::try_from_value(string)?;
|
||||
Ok(Value::String(string.to_uppercase().into()))
|
||||
},
|
||||
);
|
||||
env.defun_native(
|
||||
"string/to-lower",
|
||||
"Converts a string to lowercase",
|
||||
|_, _, args| {
|
||||
let [string] = args else {
|
||||
return Err(MachineError::InvalidArgumentCount);
|
||||
};
|
||||
let string = StringValue::try_from_value(string)?;
|
||||
Ok(Value::String(string.to_lowercase().into()))
|
||||
},
|
||||
);
|
||||
|
||||
env.defun_native(
|
||||
"string/alpha?",
|
||||
|
||||
@@ -25,7 +25,7 @@ pub enum AnyFunction {
|
||||
}
|
||||
|
||||
macro_rules! impl_integer {
|
||||
($($ty:ty : $bits:literal),+ $(,)?) => {
|
||||
($($ty:ty : $bits:expr),+ $(,)?) => {
|
||||
$(
|
||||
impl TryFromValue<'_> for $ty {
|
||||
fn try_from_value(value: &Value) -> Result<Self, ValueConversionError> {
|
||||
@@ -240,5 +240,5 @@ impl_integer!(
|
||||
i16: 16,
|
||||
i32: 32,
|
||||
i64: 64,
|
||||
usize: 64,
|
||||
usize: usize::BITS,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user