Add eval in env + env/create, env/load-prelude

This commit is contained in:
2026-05-21 14:55:03 +03:00
parent e956f7b68d
commit d21f927a24
22 changed files with 206 additions and 143 deletions
Generated
+2 -57
View File
@@ -52,28 +52,6 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "bitmatch"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a53e105d41966c9b4594b8e3b7cf8e81ae63cc83664880b049af8a11381a3ad"
dependencies = [
"boolean_expression",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "boolean_expression"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c33ef624481a2d2252fd352266c050e83203343d0884622f7ba09782abbfa83"
dependencies = [
"itertools",
"smallvec",
]
[[package]]
name = "clap"
version = "4.6.1"
@@ -105,7 +83,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.117",
"syn",
]
[[package]]
@@ -120,12 +98,6 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
[[package]]
name = "either"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "heck"
version = "0.5.0"
@@ -138,20 +110,10 @@ version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
[[package]]
name = "itertools"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
dependencies = [
"either",
]
[[package]]
name = "lysp"
version = "0.1.0"
dependencies = [
"bitmatch",
"clap",
"nom",
"thiserror",
@@ -196,29 +158,12 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.117"
@@ -247,7 +192,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.117",
"syn",
]
[[package]]
-1
View File
@@ -7,4 +7,3 @@ edition = "2024"
thiserror = "2.0.18"
clap = { version = "4.6.1", features = ["derive"] }
nom = "8.0.0"
bitmatch = "0.1.1"
+16
View File
@@ -0,0 +1,16 @@
; empty env
(setq custom-env (env/create nil))
(setq
custom-env-expr
'(progn
(defun my-function () 1234)
)
)
(defun my-function () 4321)
(assert (= 'ok (car (eval custom-env custom-env-expr))))
(assert (= 4321 (my-function)))
(assert (= '(ok 1234) (eval custom-env '(my-function))))
(assert (= 'err (car (eval custom-env '(print 1234))))) ;; print is not defined in custom-env
(env/load-prelude custom-env)
(assert (= '(ok nil) (eval custom-env '(print 1234))))
+1 -1
View File
@@ -13,7 +13,7 @@
(print "==>" value)
)
(defun repl-eval-print (expression)
(map-ok-err repl-print repl-eval-error (unquote (eval expression)))
(map-ok-err repl-print repl-eval-error (eval expression))
)
(defun repl-eval-error (error)
+5 -4
View File
@@ -3,6 +3,7 @@ use std::{
io::{self, BufReader},
path::{Path, PathBuf},
process::ExitCode,
rc::Rc,
str::FromStr,
};
@@ -124,7 +125,7 @@ fn handle_module_error(input: Either<MachineErrorAt, Vec<ParseError>>) -> Error
fn eval(
options: &CompileOptions,
vm: &mut Machine,
env: &Environment,
env: &Rc<Environment>,
value: Value,
) -> Option<Value> {
let result = vm.evaluate_value(
@@ -145,7 +146,7 @@ fn eval(
fn run_interactive(
compile_options: &CompileOptions,
vm: &mut Machine,
env: &Environment,
env: &Rc<Environment>,
) -> Result<(), Error> {
let mut reader = InteractiveReader::new("> ", ">> ");
@@ -171,7 +172,7 @@ fn run_interactive(
fn run_module<P: AsRef<Path>>(
compile_options: &CompileOptions,
vm: &mut Machine,
env: &Environment,
env: &Rc<Environment>,
path: P,
) -> Result<(), Error> {
let path = path.as_ref();
@@ -202,7 +203,7 @@ fn main() -> ExitCode {
vm.trace_calls = args.trace.contains(&Trace::Call);
vm.trace_returns = args.trace.contains(&Trace::Return);
vm.trace_stack = args.trace.contains(&Trace::Stack);
let env = Environment::default();
let env = Rc::new(Environment::default());
prelude::load(&env);
let mut arguments = vec![];
if let Some(script) = args.module.as_ref() {
+3 -3
View File
@@ -104,7 +104,7 @@ impl<R: BufRead> ModuleReader<R> {
pub fn read_expression(
&mut self,
options: &CompileOptions,
env: &Environment,
env: &Rc<Environment>,
) -> Result<Option<Rc<Expression>>, Either<MachineErrorAt, Vec<ParseError>>> {
loop {
let value =
@@ -127,7 +127,7 @@ impl<R: BufRead> ModuleReader<R> {
mut self,
module_name: Option<IdentifierValue>,
options: &CompileOptions,
env: &Environment,
env: &Rc<Environment>,
) -> Result<Rc<BytecodeFunction>, Either<MachineErrorAt, Vec<ParseError>>> {
let mut cx = CompileContext::new(options.clone(), module_name);
let mut body = FunctionBody {
@@ -249,7 +249,7 @@ fn read_inner<R: BufRead>(
pub fn read<R: Reader>(
reader: &mut R,
vm: &mut Machine,
env: &Environment,
env: &Rc<Environment>,
) -> Result<Option<Value>, MachineErrorAt> {
let raw_value = reader.read().map_err(Into::into)?;
let Some(raw_value) = raw_value else {
+47 -7
View File
@@ -1,20 +1,23 @@
use std::{borrow::Borrow, cell::RefCell, collections::HashMap, hash::Hash, rc::Rc};
use std::{borrow::Borrow, cell::RefCell, collections::HashMap, fmt, hash::Hash, rc::Rc};
use crate::{
error::MachineError,
vm::{
machine::Machine,
value::{BytecodeFunction, IdentifierValue, NativeFunction, StringValue, Value},
value::{
BytecodeFunction, IdentifierValue, NativeFunction, NativeObject, StringValue, Value,
convert::{AnyFunction, TryFromValue},
},
},
};
#[derive(Clone)]
#[derive(Clone, Debug)]
pub enum Macro {
Native(NativeFunction),
Bytecode(Rc<BytecodeFunction>),
}
#[derive(Default)]
#[derive(Default, Debug)]
pub struct Environment {
globals: RefCell<HashMap<IdentifierValue, Value>>,
macros: RefCell<HashMap<IdentifierValue, Macro>>,
@@ -22,11 +25,18 @@ pub struct Environment {
}
impl Environment {
pub fn new(parent: Option<Rc<Self>>) -> Self {
Self {
parent,
..Default::default()
}
}
pub fn defun_native<S, D, F>(&self, identifier: S, docstring: D, function: F) -> Value
where
S: Into<IdentifierValue>,
D: Into<StringValue>,
F: Fn(&mut Machine, &Environment, &[Value]) -> Result<Value, MachineError> + 'static,
F: Fn(&mut Machine, &Rc<Environment>, &[Value]) -> Result<Value, MachineError> + 'static,
{
let identifier = identifier.into();
let native = NativeFunction::new(identifier.clone(), docstring, function);
@@ -39,7 +49,7 @@ impl Environment {
where
S: Into<IdentifierValue>,
D: Into<StringValue>,
F: Fn(&mut Machine, &Environment, &[Value]) -> Result<Value, MachineError> + 'static,
F: Fn(&mut Machine, &Rc<Environment>, &[Value]) -> Result<Value, MachineError> + 'static,
{
let identifier = identifier.into();
let native = NativeFunction::new(identifier.clone(), docstring, function);
@@ -63,7 +73,7 @@ impl Environment {
pub fn global_value<Q>(&self, identifier: &Q) -> Option<Value>
where
IdentifierValue: Borrow<Q>,
Q: Hash + Eq,
Q: Hash + Eq + ?Sized,
{
self.globals.borrow().get(identifier).cloned().or_else(|| {
self.parent
@@ -93,4 +103,34 @@ impl Environment {
.and_then(|parent| parent.global_macro(identifier))
})
}
pub fn evaluate_global_function<Q>(
self: &Rc<Self>,
vm: &mut Machine,
identifier: &Q,
arguments: &[Value],
) -> Result<Value, MachineError>
where
IdentifierValue: Borrow<Q>,
Q: Hash + Eq + ?Sized,
for<'a> &'a Q: Into<IdentifierValue>,
{
let value = self
.global_value(identifier)
.ok_or_else(|| MachineError::UnboundIdentifier(identifier.into()))?;
let function = AnyFunction::try_from_value(&value)?;
function.invoke(vm, self, arguments)
}
}
impl fmt::Display for Environment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "environment")
}
}
impl NativeObject for Environment {
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
+26 -20
View File
@@ -1,3 +1,5 @@
use std::rc::Rc;
use crate::{
compile::{CompileContext, CompileOptions},
error::{
@@ -150,7 +152,7 @@ impl Machine {
Ok(())
}
fn execute_get_global(&mut self, env: &Environment) -> Result<(), MachineError> {
fn execute_get_global(&mut self, env: &Rc<Environment>) -> Result<(), MachineError> {
let identifier = self.pop()?;
let Value::Identifier(identifier) = identifier else {
return Err(MachineError::InvalidInstructionArgument(
@@ -168,7 +170,7 @@ impl Machine {
Ok(())
}
fn execute_set_global(&mut self, env: &Environment) -> Result<(), MachineError> {
fn execute_set_global(&mut self, env: &Rc<Environment>) -> Result<(), MachineError> {
let identifier = self.pop()?;
let Value::Identifier(identifier) = identifier else {
return Err(MachineError::InvalidInstructionArgument(
@@ -186,7 +188,7 @@ impl Machine {
fn execute_call(
&mut self,
env: &Environment,
env: &Rc<Environment>,
argument_count: usize,
) -> Result<(), MachineError> {
let base_pointer = self
@@ -380,7 +382,7 @@ impl Machine {
Ok(())
}
fn execute_declare_macro(&mut self, env: &Environment) -> Result<(), MachineError> {
fn execute_declare_macro(&mut self, env: &Rc<Environment>) -> Result<(), MachineError> {
let identifier = self.pop()?;
let function = self.pop()?;
let Value::Identifier(identifier) = identifier else {
@@ -448,7 +450,7 @@ impl Machine {
frame.closure.function.disassemble(frame.ip, 0, 0, false);
}
fn execute_next(&mut self, env: &Environment) -> Result<(), MachineError> {
fn execute_next(&mut self, env: &Rc<Environment>) -> Result<(), MachineError> {
if self.trace_instructions {
if self.trace_stack {
self.trace_stack();
@@ -571,7 +573,7 @@ impl Machine {
pub fn evaluate_closure(
&mut self,
env: &Environment,
env: &Rc<Environment>,
closure: ClosureValue,
argument_count: usize,
) -> Result<Value, MachineErrorAt> {
@@ -593,7 +595,7 @@ impl Machine {
pub fn evaluate_closure_args(
&mut self,
env: &Environment,
env: &Rc<Environment>,
closure: ClosureValue,
args: &[Value],
) -> Result<Value, MachineErrorAt> {
@@ -635,7 +637,7 @@ impl Machine {
&mut self,
compile_options: CompileOptions,
chunk_name: Option<IdentifierValue>,
env: &Environment,
env: &Rc<Environment>,
value: Value,
) -> Result<Value, MachineErrorAt> {
let value = value.macro_expand(self, env, false)?;
@@ -669,7 +671,7 @@ mod tests {
};
fn try_eval(
env: &Environment,
env: &Rc<Environment>,
mut instructions: Vec<u8>,
constants: Vec<Value>,
) -> (Machine, Result<Value, MachineErrorAt>) {
@@ -691,7 +693,11 @@ mod tests {
(machine, result)
}
fn eval0(env: &Environment, instructions: Vec<u8>, constants: Vec<Value>) -> (Machine, Value) {
fn eval0(
env: &Rc<Environment>,
instructions: Vec<u8>,
constants: Vec<Value>,
) -> (Machine, Value) {
let (machine, value) = try_eval(env, instructions, constants);
let value = value.expect("evaluation failed");
(machine, value)
@@ -699,16 +705,16 @@ mod tests {
#[test]
fn test_stack_execution() {
let mut env = Environment::default();
let (m, v) = eval0(&mut env, vec![Instruction::PushNil.into()], vec![]);
let env = Rc::new(Environment::default());
let (m, v) = eval0(&env, vec![Instruction::PushNil.into()], vec![]);
assert_eq!(v, Value::Nil);
assert!(m.data_stack.is_empty());
assert!(m.call_stack.is_empty());
let (m, v) = eval0(&mut env, vec![Instruction::PushTrue.into()], vec![]);
let (m, v) = eval0(&env, vec![Instruction::PushTrue.into()], vec![]);
assert_eq!(v, true.into());
assert!(m.data_stack.is_empty());
assert!(m.call_stack.is_empty());
let (m, v) = eval0(&mut env, vec![Instruction::PushFalse.into()], vec![]);
let (m, v) = eval0(&env, vec![Instruction::PushFalse.into()], vec![]);
assert_eq!(v, false.into());
assert!(m.data_stack.is_empty());
assert!(m.call_stack.is_empty());
@@ -716,9 +722,9 @@ mod tests {
#[test]
fn test_unwind() {
let mut env = Environment::default();
let env = Rc::new(Environment::default());
// Cause data stack underflow for unwind
let (m, r) = try_eval(&mut env, vec![Instruction::Drop.into()], vec![]);
let (m, r) = try_eval(&env, vec![Instruction::Drop.into()], vec![]);
let e = r.unwrap_err();
assert_eq!(e.location.map(|a| a.offset), Some(1));
assert_eq!(e.error, MachineError::DataStackUnderflow);
@@ -728,7 +734,7 @@ mod tests {
#[test]
fn test_closure_call_no_upvalues_yes_locals() {
let mut env = Environment::default();
let env = Rc::new(Environment::default());
// (lambda (y) (let (x 123) (+ x y)))
let lambda_function = Rc::new(BytecodeFunction {
identifier: None,
@@ -756,7 +762,7 @@ mod tests {
max_arity: 1,
});
let (m, r) = eval0(
&mut env,
&env,
vec![
Instruction::PushConstant.into(),
0,
@@ -776,7 +782,7 @@ mod tests {
#[test]
fn test_closure_call_no_upvalues_no_locals() {
let mut env = Environment::default();
let env = Rc::new(Environment::default());
// (lambda (x y) (+ x y))
let lambda_function = Rc::new(BytecodeFunction {
identifier: None,
@@ -797,7 +803,7 @@ mod tests {
max_arity: 2,
});
let (m, r) = eval0(
&mut env,
&env,
vec![
Instruction::PushConstant.into(),
0,
+2 -2
View File
@@ -13,7 +13,7 @@ pub trait MacroExpand: Sized {
fn macro_expand(
&self,
vm: &mut Machine,
env: &Environment,
env: &Rc<Environment>,
tail: bool,
) -> Result<Self, MachineErrorAt>;
}
@@ -22,7 +22,7 @@ impl MacroExpand for Value {
fn macro_expand(
&self,
vm: &mut Machine,
env: &Environment,
env: &Rc<Environment>,
tail: bool,
) -> Result<Self, MachineErrorAt> {
match self {
+1 -1
View File
@@ -9,7 +9,7 @@ use crate::{
},
};
pub fn load(env: &Environment) {
pub fn load(env: &Rc<Environment>) {
// // vectors
// env.defun_native("getv", |vm, _, args| {
// let [vec, index] = args else {
+3 -1
View File
@@ -1,3 +1,5 @@
use std::rc::Rc;
use crate::{
error::MachineError,
vm::{
@@ -7,7 +9,7 @@ use crate::{
},
};
pub fn load(env: &Environment) {
pub fn load(env: &Rc<Environment>) {
env.defun_native(
"->string",
"Converts a value to string representation",
+3 -1
View File
@@ -1,9 +1,11 @@
use std::rc::Rc;
use crate::{
error::MachineError,
vm::{Value, env::Environment, value::Keyword},
};
pub fn load(env: &Environment) {
pub fn load(env: &Rc<Environment>) {
env.defun_native(
"explain",
"Provides an explanation for a given value",
+33 -9
View File
@@ -1,26 +1,50 @@
use std::rc::Rc;
use crate::{
error::MachineError,
read::{self, InteractiveReader},
vm::{Value, env::Environment},
vm::{Value, env::Environment, value::NativeObject},
};
pub fn load(env: &Environment) {
pub fn load(env: &Rc<Environment>) {
env.defun_native("eval", "Evaluates the given expression", |vm, env, args| {
// TODO eval in env
let [value] = args else {
return Err(MachineError::InvalidArgumentCount);
let (env, value) = match args {
[value] => (env.clone(), value),
[env, value] => (env.as_native()?, value),
_ => return Err(MachineError::InvalidArgumentCount),
};
let outcome =
match vm.evaluate_value(Default::default(), Some("eval".into()), env, value.clone()) {
Ok(result) => Value::list_or_nil([Value::Identifier("ok".into()), result]).quote(),
match vm.evaluate_value(Default::default(), Some("eval".into()), &env, value.clone()) {
Ok(result) => Value::list_or_nil([Value::Identifier("ok".into()), result]),
Err(error) => Value::list_or_nil([
Value::Identifier("err".into()),
Value::String(format!("{error}").into()),
])
.quote(),
]),
};
Ok(outcome)
});
env.defun_native("env/create", "Create a new environment", |_, env, args| {
let parent = match args {
[] => Some(env.clone()),
[env] if env.is_nil() => None,
[env] => Some(env.as_native()?),
_ => return Err(MachineError::InvalidArgumentCount),
};
let environment: Rc<dyn NativeObject> = Rc::new(Environment::new(parent));
Ok(Value::NativeValue(environment.into()))
});
env.defun_native(
"env/load-prelude",
"Adds prelude definitions to the environment",
|_, _, args| {
let [env] = args else {
return Err(MachineError::InvalidArgumentCount);
};
let env = env.as_native::<Environment>()?;
super::load(&env);
Ok(Value::Nil)
},
);
env.defun_native(
"read",
"Reads a form from standard input",
+3 -1
View File
@@ -1,3 +1,5 @@
use std::rc::Rc;
use crate::{
error::{MachineError, ValueConversionError},
vm::{
@@ -6,7 +8,7 @@ use crate::{
},
};
pub fn load(env: &Environment) {
pub fn load(env: &Rc<Environment>) {
// env.defun_native("map", |vm, env, args| {
// let [f, xs] = args else {
// return Err(vm.error_at_ip(MachineErrorKind::InvalidArgument));
+1 -1
View File
@@ -76,7 +76,7 @@ impl Stream {
}
}
pub fn load(env: &Environment) {
pub fn load(env: &Rc<Environment>) {
let stdin: Rc<dyn NativeObject> = Rc::new(Stream::Stdin);
let stdout: Rc<dyn NativeObject> = Rc::new(Stream::Stdout);
+21 -20
View File
@@ -1,4 +1,4 @@
use std::{cmp::Ordering, ops::Mul};
use std::{cmp::Ordering, ops::Mul, rc::Rc};
use crate::{
error::MachineError,
@@ -10,9 +10,10 @@ use crate::{
},
};
#[allow(clippy::type_complexity)]
pub(crate) fn dispatch_arithmetic(
instruction: Instruction,
) -> fn(&mut Machine, &Environment, &[Value]) -> Result<Value, MachineError> {
) -> fn(&mut Machine, &Rc<Environment>, &[Value]) -> Result<Value, MachineError> {
match instruction {
Instruction::Add => builtin_add,
Instruction::Sub => builtin_sub,
@@ -30,7 +31,7 @@ pub(crate) fn dispatch_arithmetic(
}
}
pub(super) fn load(env: &Environment) {
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);
@@ -137,14 +138,14 @@ where
pub(crate) fn builtin_add(
_vm: &mut Machine,
_env: &Environment,
_env: &Rc<Environment>,
args: &[Value],
) -> Result<Value, MachineError> {
builtin_fold(value_add, Value::Number(0.into()), args)
}
pub(crate) fn builtin_sub(
_vm: &mut Machine,
_env: &Environment,
_env: &Rc<Environment>,
args: &[Value],
) -> Result<Value, MachineError> {
match args {
@@ -165,14 +166,14 @@ pub(crate) fn builtin_sub(
}
pub(crate) fn builtin_mul(
_vm: &mut Machine,
_env: &Environment,
_env: &Rc<Environment>,
args: &[Value],
) -> Result<Value, MachineError> {
builtin_fold_t(Mul::mul, NumberValue::from(1), args)
}
pub(crate) fn builtin_mod(
_vm: &mut Machine,
_env: &Environment,
_env: &Rc<Environment>,
args: &[Value],
) -> Result<Value, MachineError> {
let [x, y] = args else {
@@ -184,7 +185,7 @@ pub(crate) fn builtin_mod(
}
pub(crate) fn builtin_div(
_vm: &mut Machine,
_env: &Environment,
_env: &Rc<Environment>,
args: &[Value],
) -> Result<Value, MachineError> {
match args {
@@ -206,35 +207,35 @@ pub(crate) fn builtin_div(
// pub(crate) fn builtin_and(
// vm: &mut Machine,
// _env: &Environment,
// _env: &Rc<Environment>,
// args: &[Value],
// ) -> Result<Value, MachineError> {
// builtin_fold_t(BitAnd::bitand, true, args)
// }
// pub(crate) fn builtin_or(
// vm: &mut Machine,
// _env: &Environment,
// _env: &Rc<Environment>,
// args: &[Value],
// ) -> Result<Value, MachineError> {
// builtin_fold_t(BitOr::bitor, false, args)
// }
// pub(crate) fn builtin_bitwise_and(
// vm: &mut Machine,
// _env: &Environment,
// _env: &Rc<Environment>,
// args: &[Value],
// ) -> Result<Value, MachineError> {
// builtin_fold_t(BitAnd::bitand, 1, args)
// }
// pub(crate) fn builtin_bitwise_or(
// vm: &mut Machine,
// _env: &Environment,
// _env: &Rc<Environment>,
// args: &[Value],
// ) -> Result<Value, MachineError> {
// builtin_fold_t(BitOr::bitor, 0, args)
// }
// pub(crate) fn builtin_bitwise_xor(
// vm: &mut Machine,
// _env: &Environment,
// _env: &Rc<Environment>,
// args: &[Value],
// ) -> Result<Value, MachineError> {
// builtin_fold_t(BitXor::bitxor, 0, args)
@@ -296,42 +297,42 @@ pub(crate) fn builtin_cmp(
}
pub(crate) fn builtin_cmp_eq(
vm: &mut Machine,
_env: &Environment,
_env: &Rc<Environment>,
args: &[Value],
) -> Result<Value, MachineError> {
builtin_cmp(vm, args, CompareOperation::Eq)
}
pub(crate) fn builtin_cmp_ne(
vm: &mut Machine,
_env: &Environment,
_env: &Rc<Environment>,
args: &[Value],
) -> Result<Value, MachineError> {
builtin_cmp(vm, args, CompareOperation::Ne)
}
pub(crate) fn builtin_cmp_gt(
vm: &mut Machine,
_env: &Environment,
_env: &Rc<Environment>,
args: &[Value],
) -> Result<Value, MachineError> {
builtin_cmp(vm, args, CompareOperation::Gt)
}
pub(crate) fn builtin_cmp_lt(
vm: &mut Machine,
_env: &Environment,
_env: &Rc<Environment>,
args: &[Value],
) -> Result<Value, MachineError> {
builtin_cmp(vm, args, CompareOperation::Lt)
}
pub(crate) fn builtin_cmp_ge(
vm: &mut Machine,
_env: &Environment,
_env: &Rc<Environment>,
args: &[Value],
) -> Result<Value, MachineError> {
builtin_cmp(vm, args, CompareOperation::Ge)
}
pub(crate) fn builtin_cmp_le(
vm: &mut Machine,
_env: &Environment,
_env: &Rc<Environment>,
args: &[Value],
) -> Result<Value, MachineError> {
builtin_cmp(vm, args, CompareOperation::Le)
@@ -339,7 +340,7 @@ pub(crate) fn builtin_cmp_le(
pub(crate) fn builtin_not(
_vm: &mut Machine,
_env: &Environment,
_env: &Rc<Environment>,
args: &[Value],
) -> Result<Value, MachineError> {
let [x] = args else {
+3 -1
View File
@@ -1,3 +1,5 @@
use std::rc::Rc;
use crate::vm::env::Environment;
mod collections;
@@ -10,7 +12,7 @@ mod math;
pub(crate) use math::*;
pub fn load(env: &Environment) {
pub fn load(env: &Rc<Environment>) {
math::load(env);
eval::load(env);
functional::load(env);
+1 -1
View File
@@ -144,7 +144,7 @@ impl AnyFunction {
pub fn invoke(
&self,
vm: &mut Machine,
env: &Environment,
env: &Rc<Environment>,
args: &[Value],
) -> Result<Value, MachineError> {
match self {
+7 -1
View File
@@ -1,4 +1,4 @@
use std::{fmt, rc::Rc};
use std::{borrow::Borrow, fmt, rc::Rc};
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct IdentifierValue(Rc<str>);
@@ -21,6 +21,12 @@ impl AsRef<str> for IdentifierValue {
}
}
impl Borrow<str> for IdentifierValue {
fn borrow(&self) -> &str {
self.as_ref()
}
}
impl fmt::Display for IdentifierValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
+10
View File
@@ -188,6 +188,16 @@ impl Value {
}),
}
}
pub fn as_native_ref<T: NativeObject>(&self) -> Result<&T, ValueConversionError> {
match self {
Self::NativeValue(value) if let Some(value) = value.cast_ref() => Ok(value),
_ => Err(ValueConversionError {
expected: "native value".into(),
got: self.clone(),
}),
}
}
}
impl fmt::Display for Value {
+7 -3
View File
@@ -22,7 +22,7 @@ pub trait NativeObject: Any + fmt::Debug + fmt::Display {
pub struct NativeValue(Rc<dyn NativeObject>);
pub type NativeFunctionImpl =
Rc<dyn Fn(&mut Machine, &Environment, &[Value]) -> Result<Value, MachineError> + 'static>;
Rc<dyn Fn(&mut Machine, &Rc<Environment>, &[Value]) -> Result<Value, MachineError> + 'static>;
#[derive(Clone)]
pub struct NativeFunction {
@@ -36,7 +36,7 @@ impl NativeFunction {
where
S: Into<IdentifierValue>,
D: Into<StringValue>,
F: Fn(&mut Machine, &Environment, &[Value]) -> Result<Value, MachineError> + 'static,
F: Fn(&mut Machine, &Rc<Environment>, &[Value]) -> Result<Value, MachineError> + 'static,
{
Self {
name: name.into(),
@@ -56,7 +56,7 @@ impl NativeFunction {
pub fn invoke(
&self,
machine: &mut Machine,
environment: &Environment,
environment: &Rc<Environment>,
arguments: &[Value],
) -> Result<Value, MachineError> {
(self.inner)(machine, environment, arguments)
@@ -102,6 +102,10 @@ impl NativeValue {
pub fn cast_rc<T: NativeObject>(&self) -> Option<Rc<T>> {
Rc::downcast(self.0.clone()).ok()
}
pub fn cast_ref<T: NativeObject>(&self) -> Option<&T> {
self.0.as_any().downcast_ref()
}
}
impl From<Rc<dyn NativeObject + 'static>> for NativeValue {
+11 -8
View File
@@ -1,4 +1,7 @@
use std::io::{self, BufReader, Read};
use std::{
io::{self, BufReader, Read},
rc::Rc,
};
use lysp::{
error::MachineErrorAt,
@@ -18,7 +21,7 @@ impl Read for SliceReader<'_> {
}
#[track_caller]
fn eval_str_in(code: &str, env: &Environment) -> Result<Value, MachineErrorAt> {
fn eval_str_in(code: &str, env: &Rc<Environment>) -> Result<Value, MachineErrorAt> {
let mut machine = Machine::default();
let reader = BufReader::new(SliceReader(code.as_bytes()));
let mut reader = FileReader::new(reader);
@@ -39,16 +42,16 @@ fn eval_str_in(code: &str, env: &Environment) -> Result<Value, MachineErrorAt> {
#[track_caller]
fn eval_str(code: &str) -> Value {
let mut env = Environment::default();
prelude::load(&mut env);
eval_str_in(code, &mut env).expect("expression evaluation failed")
let env = Rc::new(Environment::default());
prelude::load(&env);
eval_str_in(code, &env).expect("expression evaluation failed")
}
#[track_caller]
fn eval_str_err(code: &str) -> MachineErrorAt {
let mut env = Environment::default();
prelude::load(&mut env);
eval_str_in(code, &mut env).expect_err("expression was expected to fail")
let env = Rc::new(Environment::default());
prelude::load(&env);
eval_str_in(code, &env).expect_err("expression was expected to fail")
}
#[test]