lysp: more string prelude, fallible set_global_value

This commit is contained in:
2026-06-04 17:35:30 +03:00
parent 1f670a66a4
commit 1736582613
9 changed files with 61 additions and 20 deletions
+2 -1
View File
@@ -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),
+15 -7
View File
@@ -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>
+1 -1
View File
@@ -196,7 +196,7 @@ impl Machine {
));
};
let value = self.pop()?;
env.set_global_value(identifier, value);
env.set_global_value(identifier, value)?;
Ok(())
}
+4 -1
View File
@@ -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(
+1 -1
View File
@@ -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)
},
);
+4 -2
View File
@@ -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 {
+10 -5
View File
@@ -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?",
+2 -2
View File
@@ -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,
);