From 3a88d7a9b38eea79e820932a38d17508711e6c96 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Wed, 6 May 2026 16:31:19 +0300 Subject: [PATCH] Split Environment and Machine --- src/compile/block.rs | 17 ------ src/convert.rs | 14 ++++- src/main.rs | 20 ++++--- src/vm/env.rs | 32 ++++++++++ src/vm/machine.rs | 130 +++++++++++++++++++---------------------- src/vm/mod.rs | 1 + src/vm/native.rs | 8 ++- src/vm/prelude/math.rs | 87 ++++++++++++++++++++++----- src/vm/prelude/mod.rs | 63 ++++++++++---------- 9 files changed, 228 insertions(+), 144 deletions(-) create mode 100644 src/vm/env.rs diff --git a/src/compile/block.rs b/src/compile/block.rs index bea4b72..f651916 100644 --- a/src/compile/block.rs +++ b/src/compile/block.rs @@ -558,23 +558,6 @@ mod tests { assert_eq!(v, CompileValue::Integer(1)); } - #[test] - fn test_macro_expansion() { - let (_, f, v) = test_compile(Expression::Call(CallExpression { - callee: Rc::new(Expression::Identifier("test-macro-1".into())), - arguments: vec![Rc::new(Expression::IntegerLiteral(2))], - })); - assert_eq!( - &f.instructions, - &[ - Instruction::PushInteger(U::truncate(1)), - Instruction::PushInteger(U::truncate(2)), - Instruction::Math(MathInstruction::Add, U::truncate(2)), - ] - ); - assert_eq!(v, CompileValue::Stack); - } - #[test] fn test_comparison_compile() { let (m, f, v) = test_compile(Expression::Call(CallExpression { diff --git a/src/convert.rs b/src/convert.rs index e430f50..6b99c86 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -1,4 +1,5 @@ use crate::vm::{ + env::Environment, machine::{Machine, MachineError}, native::NativeFunction, value::{BytecodeFunction, ConsCell, Keyword, Value, ValueString}, @@ -52,10 +53,17 @@ macro_rules! impl_primitive_value { } impl AnyFunction { - pub fn invoke(&self, vm: &mut Machine, args: &[Value]) -> Result { + pub fn invoke( + &self, + vm: &mut Machine, + env: &mut Environment, + args: &[Value], + ) -> Result { match self { - Self::Bytecode(bytecode) => Ok(vm.eval_bytecode_call(bytecode.clone(), args).unwrap()), - Self::Native(native) => native.invoke(vm, args), + Self::Bytecode(bytecode) => { + Ok(vm.eval_bytecode_call(env, bytecode.clone(), args).unwrap()) + } + Self::Native(native) => native.invoke(vm, env, args), } } } diff --git a/src/main.rs b/src/main.rs index d1c1b0f..0ef3d66 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,7 @@ use lysp::{ error::EvalError, parse::{parse_value, skip_comment_and_whitespace}, vm::{ + env::Environment, machine::{EvalResult, Machine, MachineError}, prelude, }, @@ -37,7 +38,7 @@ struct Args { module: Option, } -fn run_interactive(vm: &mut Machine) -> Result<(), Error> { +fn run_interactive(vm: &mut Machine, env: &mut Environment) -> Result<(), Error> { let mut input = String::new(); let stdin = stdin(); let mut stdout = stdout(); @@ -76,7 +77,7 @@ fn run_interactive(vm: &mut Machine) -> Result<(), Error> { } }; - let result = vm.eval_value(value.clone()); + let result = vm.eval_value(env, value.clone()); let result = match result { EvalResult::Ok(r) => r, EvalResult::Err(module, ip, error) => { @@ -133,7 +134,11 @@ fn run_interactive(vm: &mut Machine) -> Result<(), Error> { Ok(()) } -fn run_module>(vm: &mut Machine, path: P) -> Result<(), Error> { +fn run_module>( + vm: &mut Machine, + env: &mut Environment, + path: P, +) -> Result<(), Error> { let path = path.as_ref(); let mut input = String::new(); let mut reader = BufReader::new(File::open(path)?); @@ -219,7 +224,7 @@ fn run_module>(vm: &mut Machine, path: P) -> Result<(), Error> { )?; let module = module.compile_module()?; - match vm.eval_module(module.into()) { + match vm.eval_module(env, module.into()) { EvalResult::Ok(_) => Ok(()), EvalResult::Err(module, ip, error) => { let ip_address = ip.map(|ip| ip.address); @@ -239,10 +244,11 @@ fn run_module>(vm: &mut Machine, path: P) -> Result<(), Error> { fn main() -> ExitCode { let args = Args::parse(); let mut vm = Machine::default(); - prelude::load(&mut vm); + let mut env = Environment::default(); + prelude::load(&mut env); let result = match args.module.as_ref() { - Some(module) => run_module(&mut vm, module), - None => run_interactive(&mut vm), + Some(module) => run_module(&mut vm, &mut env, module), + None => run_interactive(&mut vm, &mut env), }; match result { Ok(()) => ExitCode::SUCCESS, diff --git a/src/vm/env.rs b/src/vm/env.rs new file mode 100644 index 0000000..d89d7a3 --- /dev/null +++ b/src/vm/env.rs @@ -0,0 +1,32 @@ +use std::{collections::HashMap, rc::Rc}; + +use crate::vm::{ + machine::{Machine, MachineError}, + native::NativeFunction, + value::Value, +}; + +#[derive(Default)] +pub struct Environment { + globals: HashMap, Value>, +} + +impl Environment { + pub fn defun_native(&mut self, identifier: S, function: F) + where + S: Into>, + F: Fn(&mut Machine, &mut Environment, &[Value]) -> Result + 'static, + { + let identifier = identifier.into(); + let native = NativeFunction::new(identifier.clone(), function); + self.set_global_value(identifier, Value::NativeFunction(native)); + } + + pub fn global_value(&self, identifier: &str) -> Option { + self.globals.get(identifier).cloned() + } + + pub fn set_global_value>, V: Into>(&mut self, identifier: S, value: V) { + self.globals.insert(identifier.into(), value.into()); + } +} diff --git a/src/vm/machine.rs b/src/vm/machine.rs index 2bdbc67..573942a 100644 --- a/src/vm/machine.rs +++ b/src/vm/machine.rs @@ -8,6 +8,7 @@ use std::{ use crate::{ error::EvalError, vm::{ + env::Environment, instruction::{ConstantId, Instruction, InstructionError, MathInstruction}, module::{Module, ModuleConstant, ModuleRef}, native::NativeFunction, @@ -63,7 +64,6 @@ pub struct CallFrame { } pub struct Machine { - globals: HashMap, Value>, ip: Option, value_stack: Stack, call_stack: Stack, @@ -81,7 +81,6 @@ pub enum ExecutionEvent { impl Default for Machine { fn default() -> Self { Self { - globals: Default::default(), ip: None, value_stack: Stack::new(1024), call_stack: Stack::new(32), @@ -95,9 +94,9 @@ impl Machine { self.ip.clone() } - pub fn set_global>>(&mut self, identifier: S, value: Value) { - self.globals.insert(identifier.into(), value); - } + // pub fn set_global>>(&mut self, identifier: S, value: Value) { + // self.globals.insert(identifier.into(), value); + // } pub fn set_local(&mut self, index: u32, value: Value) { let locals = match self.call_stack.current_mut() { @@ -115,16 +114,6 @@ impl Machine { locals.get(&index) } - pub fn defun_native(&mut self, identifier: S, function: F) - where - S: Into>, - F: Fn(&mut Machine, &[Value]) -> Result + 'static, - { - let identifier = identifier.into(); - let native = NativeFunction::new(identifier.clone(), function); - self.set_global(identifier, Value::NativeFunction(native)); - } - fn pop(&mut self) -> Result { self.value_stack .pop() @@ -170,7 +159,11 @@ impl Machine { Ok(()) } - fn execute_call(&mut self, count: usize) -> Result<(), MachineError> { + fn execute_call( + &mut self, + environment: &mut Environment, + count: usize, + ) -> Result<(), MachineError> { enum Callee { Bytecode(BytecodeFunction), Native(NativeFunction), @@ -192,7 +185,7 @@ impl Machine { } Callee::Native(native) => { let source_ip = self.ip.clone().unwrap(); - let result = native.invoke(self, &arguments)?; + let result = native.invoke(self, environment, &arguments)?; self.push(result)?; self.ip = Some(InstructionPointer { module: source_ip.module, @@ -203,15 +196,20 @@ impl Machine { Ok(()) } - fn execute_builtin_native(&mut self, function: F, count: usize) -> Result<(), MachineError> + fn execute_builtin_native( + &mut self, + environment: &mut Environment, + function: F, + count: usize, + ) -> Result<(), MachineError> where - F: Fn(&mut Self, &[Value]) -> Result, + F: Fn(&mut Self, &mut Environment, &[Value]) -> Result, { let mut args = vec![]; for _ in 0..count { args.push(self.pop()?); } - let value = function(self, &args)?; + let value = function(self, environment, &args)?; self.push(value)?; Ok(()) } @@ -227,30 +225,12 @@ impl Machine { } } - //fn execute_add(&mut self, count: usize) -> Result<(), MachineError> { - //} - - // fn execute_sub(&mut self, _count: usize) -> Result<(), MachineError> { - // todo!() - // } - - // fn execute_compare( - // &mut self, - // not: bool, - // cmp: Comparison, - // count: usize, - // ) -> Result<(), MachineError> { - // let f = match (not, cmp) { - // (true, Comparison::Gt) => prelude::builtin_cmp_le, - // (false, Comparison::Gt) => prelude::builtin_cmp_gt, - // (true, Comparison::Eq) => prelude::builtin_cmp_eq, - // (false, Comparison::Eq) => prelude::builtin_cmp_ne, - // (true, Comparison::Lt) => prelude::builtin_cmp_ge, - // (false, Comparison::Lt) => prelude::builtin_cmp_lt, - // }; - // self.execute_builtin_native(f, count) - // } - fn execute_math(&mut self, math: MathInstruction, count: usize) -> Result<(), MachineError> { + fn execute_math( + &mut self, + environment: &mut Environment, + math: MathInstruction, + count: usize, + ) -> Result<(), MachineError> { let function = match math { MathInstruction::Add => prelude::builtin_add, MathInstruction::Sub => prelude::builtin_sub, @@ -269,7 +249,7 @@ impl Machine { MathInstruction::Ge => prelude::builtin_cmp_ge, MathInstruction::Le => prelude::builtin_cmp_le, }; - self.execute_builtin_native(function, count) + self.execute_builtin_native(environment, function, count) } fn execute_branch(&mut self, offset: usize) -> Result { @@ -323,14 +303,12 @@ impl Machine { } } - fn execute_get_global(&mut self) -> Result<(), MachineError> { + fn execute_get_global(&mut self, environment: &mut Environment) -> Result<(), MachineError> { let ident = self.pop()?; match ident { Value::Identifier(ident) => { - let value = self - .globals - .get(&ident) - .cloned() + let value = environment + .global_value(&ident) .ok_or(MachineError::UnboundIdentifier(ident))?; self.push(value) } @@ -338,13 +316,13 @@ impl Machine { } } - fn execute_set_global(&mut self) -> Result<(), MachineError> { + fn execute_set_global(&mut self, environment: &mut Environment) -> Result<(), MachineError> { let ident = self.pop()?; let value = self.pop()?; let Value::Identifier(ident) = ident else { todo!(); }; - self.globals.insert(ident, value); + environment.set_global_value(ident, value); self.push(Value::Nil)?; Ok(()) } @@ -366,7 +344,10 @@ impl Machine { Ok(()) } - pub fn execute_next(&mut self) -> Result { + pub fn execute_next( + &mut self, + environment: &mut Environment, + ) -> Result { let ip = self.ip.clone().unwrap(); let instruction = ip .module @@ -395,10 +376,10 @@ impl Machine { self.pop()?; } Instruction::GetGlobal => { - self.execute_get_global()?; + self.execute_get_global(environment)?; } Instruction::SetGlobal => { - self.execute_set_global()?; + self.execute_set_global(environment)?; } Instruction::SetLocal(index) => { self.execute_set_local(index.into())?; @@ -412,10 +393,10 @@ impl Machine { } Instruction::Call(count) => { advance = false; - self.execute_call(count.into())?; + self.execute_call(environment, count.into())?; } Instruction::Math(math, count) => { - self.execute_math(math, count.into())?; + self.execute_math(environment, math, count.into())?; } Instruction::Branch(offset) => { advance = self.execute_branch(offset.into())?; @@ -441,13 +422,14 @@ impl Machine { pub fn eval_bytecode_call( &mut self, + environment: &mut Environment, function: BytecodeFunction, args: &[Value], ) -> Result { let expect = ExecutionEvent::BytecodeFunctionExit(function.clone()); self.enter_bytecode_function(function, args.into())?; loop { - let event = match self.execute_next() { + let event = match self.execute_next(environment) { Ok(event) => event, // TODO rework error handling Err(_error) => todo!(), @@ -483,7 +465,11 @@ impl Machine { Ok(module) } - pub fn eval_module(&mut self, module: ModuleRef) -> EvalResult { + pub fn eval_module( + &mut self, + environment: &mut Environment, + module: ModuleRef, + ) -> EvalResult { let module = match self.load_module(module) { Ok(module) => module, Err(error) => return EvalResult::LoadErr(error), @@ -491,7 +477,7 @@ impl Machine { let expect = ExecutionEvent::ModuleExit(module.clone()); loop { let ip = self.ip.clone(); - let event = match self.execute_next() { + let event = match self.execute_next(environment) { Ok(event) => event, Err(error) => return EvalResult::Err(module, ip, error), }; @@ -506,14 +492,18 @@ impl Machine { } } - pub fn eval_value(&mut self, value: Value) -> EvalResult { + pub fn eval_value( + &mut self, + environment: &mut Environment, + value: Value, + ) -> EvalResult { let value = self.macro_expand(value)?; let module = match Module::compile_value(&value) { Ok(module) => module, Err(error) => return EvalResult::LoadErr(error.into()), }; let module = ModuleRef::from(module); - match self.eval_module(module) { + match self.eval_module(environment, module) { EvalResult::Ok(value) => EvalResult::Ok(value), EvalResult::Err(module, ip, error) => EvalResult::Err(module, ip, error.into()), EvalResult::LoadErr(error) => EvalResult::LoadErr(error.into()), @@ -572,13 +562,14 @@ mod tests { use std::sync::atomic::{AtomicI64, Ordering}; use crate::vm::{ + env::Environment, instruction::{Instruction, MathInstruction, U}, machine::{InstructionPointer, Machine}, module::{Module, ModuleBuilder, ModuleConstant, ModuleRef}, value::Value, }; - fn execute_all( + fn execute_all( count: usize, build: F, prepare: G, @@ -591,7 +582,8 @@ mod tests { }), ..Default::default() }; - prepare(&mut machine); + let mut env = Environment::default(); + prepare(&mut machine, &mut env); let mut values = vec![]; for i in 0..count { let mut builder = ModuleBuilder::new(); @@ -599,7 +591,7 @@ mod tests { build(i as u32, &mut builder); builder.add(Instruction::Return); let module = builder.build(); - values.push(machine.eval_module(module.into()).unwrap()); + values.push(machine.eval_module(&mut env, module.into()).unwrap()); } (machine, values) } @@ -618,7 +610,7 @@ mod tests { Instruction::Math(MathInstruction::Add, U::truncate(2)), ]); }, - |_| {}, + |_, _| {}, ); assert!(m.value_stack.is_empty()); assert!(m.call_stack.is_empty()); @@ -644,7 +636,7 @@ mod tests { Instruction::Return, ]); }, - |_| {}, + |_, _| {}, ); assert!(m.value_stack.is_empty()); assert!(m.call_stack.is_empty()); @@ -700,8 +692,8 @@ mod tests { } _ => unreachable!(), }, - |m| { - m.defun_native("native", |_vm, args| { + |_, env| { + env.defun_native("native", |_, _, args| { assert_eq!( &args, &[Value::Integer(3), Value::Integer(2), Value::Integer(1)] diff --git a/src/vm/mod.rs b/src/vm/mod.rs index fd0cc10..2817199 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -1,3 +1,4 @@ +pub mod env; pub mod instruction; pub mod loader; pub mod machine; diff --git a/src/vm/native.rs b/src/vm/native.rs index b3771c5..cda3e8b 100644 --- a/src/vm/native.rs +++ b/src/vm/native.rs @@ -1,12 +1,13 @@ use std::{fmt, rc::Rc}; use crate::vm::{ + env::Environment, machine::{Machine, MachineError}, value::Value, }; pub type NativeFunctionImpl = - Rc Result + 'static>; + Rc Result + 'static>; #[derive(Clone)] pub struct NativeFunction { @@ -18,7 +19,7 @@ impl NativeFunction { pub fn new(name: S, function: F) -> Self where S: Into>, - F: Fn(&mut Machine, &[Value]) -> Result + 'static, + F: Fn(&mut Machine, &mut Environment, &[Value]) -> Result + 'static, { Self { name: name.into(), @@ -29,9 +30,10 @@ impl NativeFunction { pub fn invoke( &self, machine: &mut Machine, + environment: &mut Environment, arguments: &[Value], ) -> Result { - (self.inner)(machine, arguments) + (self.inner)(machine, environment, arguments) } } diff --git a/src/vm/prelude/math.rs b/src/vm/prelude/math.rs index 97a85d8..6a162f1 100644 --- a/src/vm/prelude/math.rs +++ b/src/vm/prelude/math.rs @@ -6,6 +6,7 @@ use std::{ use crate::{ convert::TryFromValue, vm::{ + env::Environment, machine::{Machine, MachineError}, value::Value, }, @@ -68,10 +69,18 @@ where Ok(accumulator.into()) } -pub(crate) fn builtin_add(_vm: &mut Machine, args: &[Value]) -> Result { +pub(crate) fn builtin_add( + _vm: &mut Machine, + _env: &mut Environment, + args: &[Value], +) -> Result { builtin_fold(value_add, Value::Integer(0), args) } -pub(crate) fn builtin_sub(_vm: &mut Machine, args: &[Value]) -> Result { +pub(crate) fn builtin_sub( + _vm: &mut Machine, + _env: &mut Environment, + args: &[Value], +) -> Result { match args { [] => Err(MachineError::InvalidArgument), [x] if let &Value::Integer(x) = x => Ok(Value::Integer(-x)), @@ -93,10 +102,18 @@ pub(crate) fn builtin_sub(_vm: &mut Machine, args: &[Value]) -> Result Result { +pub(crate) fn builtin_mul( + _vm: &mut Machine, + _env: &mut Environment, + args: &[Value], +) -> Result { builtin_fold_t(i64::wrapping_mul, 1, args) } -pub(crate) fn builtin_mod(_vm: &mut Machine, args: &[Value]) -> Result { +pub(crate) fn builtin_mod( + _vm: &mut Machine, + _env: &mut Environment, + args: &[Value], +) -> Result { let [x, y] = args else { return Err(MachineError::InvalidArgument); }; @@ -105,7 +122,11 @@ pub(crate) fn builtin_mod(_vm: &mut Machine, args: &[Value]) -> Result Result { +pub(crate) fn builtin_div( + _vm: &mut Machine, + _env: &mut Environment, + args: &[Value], +) -> Result { match args { [] => Err(MachineError::InvalidArgument), [x] if let &Value::Integer(_x) = x => todo!("Fractionals"), @@ -128,23 +149,37 @@ pub(crate) fn builtin_div(_vm: &mut Machine, args: &[Value]) -> Result Result { +pub(crate) fn builtin_and( + _vm: &mut Machine, + _env: &mut Environment, + args: &[Value], +) -> Result { builtin_fold_t(BitAnd::bitand, true, args) } -pub(crate) fn builtin_or(_vm: &mut Machine, args: &[Value]) -> Result { +pub(crate) fn builtin_or( + _vm: &mut Machine, + _env: &mut Environment, + args: &[Value], +) -> Result { builtin_fold_t(BitOr::bitor, false, args) } pub(crate) fn builtin_bitwise_and( _vm: &mut Machine, + _env: &mut Environment, args: &[Value], ) -> Result { builtin_fold_t(BitAnd::bitand, 1, args) } -pub(crate) fn builtin_bitwise_or(_vm: &mut Machine, args: &[Value]) -> Result { +pub(crate) fn builtin_bitwise_or( + _vm: &mut Machine, + _env: &mut Environment, + args: &[Value], +) -> Result { builtin_fold_t(BitOr::bitor, 0, args) } pub(crate) fn builtin_bitwise_xor( _vm: &mut Machine, + _env: &mut Environment, args: &[Value], ) -> Result { builtin_fold_t(BitXor::bitxor, 0, args) @@ -184,21 +219,45 @@ pub(crate) fn builtin_cmp( } Ok(Value::Boolean(accumulator)) } -pub(crate) fn builtin_cmp_eq(vm: &mut Machine, args: &[Value]) -> Result { +pub(crate) fn builtin_cmp_eq( + vm: &mut Machine, + _env: &mut Environment, + args: &[Value], +) -> Result { builtin_cmp(vm, args, CompareOperation::Eq) } -pub(crate) fn builtin_cmp_ne(vm: &mut Machine, args: &[Value]) -> Result { +pub(crate) fn builtin_cmp_ne( + vm: &mut Machine, + _env: &mut Environment, + args: &[Value], +) -> Result { builtin_cmp(vm, args, CompareOperation::Ne) } -pub(crate) fn builtin_cmp_gt(vm: &mut Machine, args: &[Value]) -> Result { +pub(crate) fn builtin_cmp_gt( + vm: &mut Machine, + _env: &mut Environment, + args: &[Value], +) -> Result { builtin_cmp(vm, args, CompareOperation::Gt) } -pub(crate) fn builtin_cmp_lt(vm: &mut Machine, args: &[Value]) -> Result { +pub(crate) fn builtin_cmp_lt( + vm: &mut Machine, + _env: &mut Environment, + args: &[Value], +) -> Result { builtin_cmp(vm, args, CompareOperation::Lt) } -pub(crate) fn builtin_cmp_ge(vm: &mut Machine, args: &[Value]) -> Result { +pub(crate) fn builtin_cmp_ge( + vm: &mut Machine, + _env: &mut Environment, + args: &[Value], +) -> Result { builtin_cmp(vm, args, CompareOperation::Ge) } -pub(crate) fn builtin_cmp_le(vm: &mut Machine, args: &[Value]) -> Result { +pub(crate) fn builtin_cmp_le( + vm: &mut Machine, + _env: &mut Environment, + args: &[Value], +) -> Result { builtin_cmp(vm, args, CompareOperation::Le) } diff --git a/src/vm/prelude/mod.rs b/src/vm/prelude/mod.rs index 483ff35..d4009e0 100644 --- a/src/vm/prelude/mod.rs +++ b/src/vm/prelude/mod.rs @@ -4,7 +4,8 @@ use crate::{ convert::{AnyFunction, TryFromValue}, util::IteratorExt, vm::{ - machine::{Machine, MachineError}, + env::Environment, + machine::MachineError, value::{Value, ValueString}, }, }; @@ -12,29 +13,29 @@ use crate::{ mod math; pub(crate) use math::*; -pub fn load(vm: &mut Machine) { +pub fn load(env: &mut Environment) { // math - vm.defun_native("+", builtin_add); - vm.defun_native("-", builtin_sub); - vm.defun_native("*", builtin_mul); - vm.defun_native("%", builtin_mod); - vm.defun_native("/", builtin_div); + env.defun_native("+", builtin_add); + env.defun_native("-", builtin_sub); + env.defun_native("*", builtin_mul); + env.defun_native("%", builtin_mod); + env.defun_native("/", builtin_div); - vm.defun_native("&&", builtin_and); - vm.defun_native("||", builtin_or); - vm.defun_native("&", builtin_bitwise_and); - vm.defun_native("|", builtin_bitwise_or); - vm.defun_native("^", builtin_bitwise_xor); + env.defun_native("&&", builtin_and); + env.defun_native("||", builtin_or); + env.defun_native("&", builtin_bitwise_and); + env.defun_native("|", builtin_bitwise_or); + env.defun_native("^", builtin_bitwise_xor); - vm.defun_native(">", builtin_cmp_gt); - vm.defun_native("<", builtin_cmp_lt); - vm.defun_native("=", builtin_cmp_eq); - vm.defun_native("/=", builtin_cmp_ne); - vm.defun_native(">=", builtin_cmp_ge); - vm.defun_native("<=", builtin_cmp_le); + env.defun_native(">", builtin_cmp_gt); + env.defun_native("<", builtin_cmp_lt); + env.defun_native("=", builtin_cmp_eq); + env.defun_native("/=", builtin_cmp_ne); + env.defun_native(">=", builtin_cmp_ge); + env.defun_native("<=", builtin_cmp_le); // conversion - vm.defun_native("string->int", |_vm, args| { + env.defun_native("string->int", |_, _, args| { let [arg] = args else { return Err(MachineError::InvalidArgument); }; @@ -42,7 +43,7 @@ pub fn load(vm: &mut Machine) { let result = arg.parse::().map(Value::Integer).unwrap_or(Value::Nil); Ok(result) }); - vm.defun_native("int->string", |_vm, args| { + env.defun_native("int->string", |_, _, args| { let [arg] = args else { return Err(MachineError::InvalidArgument); }; @@ -52,16 +53,16 @@ pub fn load(vm: &mut Machine) { }); // lists - vm.defun_native("map", |vm, args| { + env.defun_native("map", |vm, env, args| { let [f, xs] = args else { return Err(MachineError::InvalidArgument); }; let f = AnyFunction::try_from_value(f)?; let xs = xs.proper_iter(MachineError::InvalidArgument); - let out = Value::try_list_or_nil(xs.map(|v| f.invoke(vm, slice::from_ref(v?))))?; + let out = Value::try_list_or_nil(xs.map(|v| f.invoke(vm, env, slice::from_ref(v?))))?; Ok(out) }); - vm.defun_native("filter", |vm, args| { + env.defun_native("filter", |vm, env, args| { let [f, xs] = args else { return Err(MachineError::InvalidArgument); }; @@ -70,18 +71,18 @@ pub fn load(vm: &mut Machine) { .proper_iter(MachineError::InvalidArgument) .map(|x| x.cloned()); let out = Value::try_list_or_nil(xs.try_filter(|v| { - let result = f.invoke(vm, slice::from_ref(v))?; + let result = f.invoke(vm, env, slice::from_ref(v))?; bool::try_from_value(&result) }))?; Ok(out) }); - vm.defun_native("list", |_, args| { + env.defun_native("list", |_, _, args| { let out = Value::list_or_nil(args.iter().cloned()); Ok(out) }); // functional - vm.defun_native("identity", |_, args| { + env.defun_native("identity", |_, _, args| { let [arg] = args else { return Err(MachineError::InvalidArgument); }; @@ -89,7 +90,7 @@ pub fn load(vm: &mut Machine) { }); // eval - vm.defun_native("apply", |vm, args| { + env.defun_native("apply", |vm, env, args| { let [f, xs] = args else { return Err(MachineError::InvalidArgument); }; @@ -98,9 +99,9 @@ pub fn load(vm: &mut Machine) { .proper_iter(MachineError::InvalidArgument) .map(|x| x.cloned()) .collect::, _>>()?; - f.invoke(vm, &args[..]) + f.invoke(vm, env, &args[..]) }); - vm.defun_native("assert", |vm, args| match args { + env.defun_native("assert", |vm, _, args| match args { [] => Err(MachineError::InvalidArgument), [cond] => { let cond = bool::try_from_value(cond)?; @@ -117,7 +118,7 @@ pub fn load(vm: &mut Machine) { } _ => todo!(), }); - vm.defun_native("assert-equal", |vm, args| match args { + env.defun_native("assert-equal", |vm, _, args| match args { [] | [_] => Err(MachineError::InvalidArgument), [a, b] => { if a != b { @@ -151,7 +152,7 @@ pub fn load(vm: &mut Machine) { }); // io - vm.defun_native("print", |_, args| { + env.defun_native("print", |_, _, args| { for (i, arg) in args.iter().enumerate() { if i != 0 { print!(" ");