Split Environment and Machine

This commit is contained in:
2026-05-06 16:31:19 +03:00
parent 0c2d6c85bb
commit 3a88d7a9b3
9 changed files with 228 additions and 144 deletions
-17
View File
@@ -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 {
+11 -3
View File
@@ -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<Value, MachineError> {
pub fn invoke(
&self,
vm: &mut Machine,
env: &mut Environment,
args: &[Value],
) -> Result<Value, MachineError> {
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),
}
}
}
+13 -7
View File
@@ -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<PathBuf>,
}
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<P: AsRef<Path>>(vm: &mut Machine, path: P) -> Result<(), Error> {
fn run_module<P: AsRef<Path>>(
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<P: AsRef<Path>>(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<P: AsRef<Path>>(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,
+32
View File
@@ -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<Rc<str>, Value>,
}
impl Environment {
pub fn defun_native<S, F>(&mut self, identifier: S, function: F)
where
S: Into<Rc<str>>,
F: Fn(&mut Machine, &mut Environment, &[Value]) -> Result<Value, MachineError> + '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<Value> {
self.globals.get(identifier).cloned()
}
pub fn set_global_value<S: Into<Rc<str>>, V: Into<Value>>(&mut self, identifier: S, value: V) {
self.globals.insert(identifier.into(), value.into());
}
}
+61 -69
View File
@@ -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<Rc<str>, Value>,
ip: Option<InstructionPointer>,
value_stack: Stack<Value>,
call_stack: Stack<CallFrame>,
@@ -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<S: Into<Rc<str>>>(&mut self, identifier: S, value: Value) {
self.globals.insert(identifier.into(), value);
}
// pub fn set_global<S: Into<Rc<str>>>(&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<S, F>(&mut self, identifier: S, function: F)
where
S: Into<Rc<str>>,
F: Fn(&mut Machine, &[Value]) -> Result<Value, MachineError> + 'static,
{
let identifier = identifier.into();
let native = NativeFunction::new(identifier.clone(), function);
self.set_global(identifier, Value::NativeFunction(native));
}
fn pop(&mut self) -> Result<Value, MachineError> {
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<F>(&mut self, function: F, count: usize) -> Result<(), MachineError>
fn execute_builtin_native<F>(
&mut self,
environment: &mut Environment,
function: F,
count: usize,
) -> Result<(), MachineError>
where
F: Fn(&mut Self, &[Value]) -> Result<Value, MachineError>,
F: Fn(&mut Self, &mut Environment, &[Value]) -> Result<Value, MachineError>,
{
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<bool, MachineError> {
@@ -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<ExecutionEvent, MachineError> {
pub fn execute_next(
&mut self,
environment: &mut Environment,
) -> Result<ExecutionEvent, MachineError> {
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<Value, MachineError> {
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<Value, MachineError> {
pub fn eval_module(
&mut self,
environment: &mut Environment,
module: ModuleRef,
) -> EvalResult<Value, MachineError> {
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<Value, EvalError> {
pub fn eval_value(
&mut self,
environment: &mut Environment,
value: Value,
) -> EvalResult<Value, EvalError> {
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<F: Fn(u32, &mut ModuleBuilder), G: FnOnce(&mut Machine)>(
fn execute_all<F: Fn(u32, &mut ModuleBuilder), G: FnOnce(&mut Machine, &mut Environment)>(
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)]
+1
View File
@@ -1,3 +1,4 @@
pub mod env;
pub mod instruction;
pub mod loader;
pub mod machine;
+5 -3
View File
@@ -1,12 +1,13 @@
use std::{fmt, rc::Rc};
use crate::vm::{
env::Environment,
machine::{Machine, MachineError},
value::Value,
};
pub type NativeFunctionImpl =
Rc<dyn Fn(&mut Machine, &[Value]) -> Result<Value, MachineError> + 'static>;
Rc<dyn Fn(&mut Machine, &mut Environment, &[Value]) -> Result<Value, MachineError> + 'static>;
#[derive(Clone)]
pub struct NativeFunction {
@@ -18,7 +19,7 @@ impl NativeFunction {
pub fn new<S, F>(name: S, function: F) -> Self
where
S: Into<Rc<str>>,
F: Fn(&mut Machine, &[Value]) -> Result<Value, MachineError> + 'static,
F: Fn(&mut Machine, &mut Environment, &[Value]) -> Result<Value, MachineError> + 'static,
{
Self {
name: name.into(),
@@ -29,9 +30,10 @@ impl NativeFunction {
pub fn invoke(
&self,
machine: &mut Machine,
environment: &mut Environment,
arguments: &[Value],
) -> Result<Value, MachineError> {
(self.inner)(machine, arguments)
(self.inner)(machine, environment, arguments)
}
}
+73 -14
View File
@@ -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<Value, MachineError> {
pub(crate) fn builtin_add(
_vm: &mut Machine,
_env: &mut Environment,
args: &[Value],
) -> Result<Value, MachineError> {
builtin_fold(value_add, Value::Integer(0), args)
}
pub(crate) fn builtin_sub(_vm: &mut Machine, args: &[Value]) -> Result<Value, MachineError> {
pub(crate) fn builtin_sub(
_vm: &mut Machine,
_env: &mut Environment,
args: &[Value],
) -> Result<Value, MachineError> {
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<Value, Ma
}
}
}
pub(crate) fn builtin_mul(_vm: &mut Machine, args: &[Value]) -> Result<Value, MachineError> {
pub(crate) fn builtin_mul(
_vm: &mut Machine,
_env: &mut Environment,
args: &[Value],
) -> Result<Value, MachineError> {
builtin_fold_t(i64::wrapping_mul, 1, args)
}
pub(crate) fn builtin_mod(_vm: &mut Machine, args: &[Value]) -> Result<Value, MachineError> {
pub(crate) fn builtin_mod(
_vm: &mut Machine,
_env: &mut Environment,
args: &[Value],
) -> Result<Value, MachineError> {
let [x, y] = args else {
return Err(MachineError::InvalidArgument);
};
@@ -105,7 +122,11 @@ pub(crate) fn builtin_mod(_vm: &mut Machine, args: &[Value]) -> Result<Value, Ma
};
Ok(Value::Integer(x % y))
}
pub(crate) fn builtin_div(_vm: &mut Machine, args: &[Value]) -> Result<Value, MachineError> {
pub(crate) fn builtin_div(
_vm: &mut Machine,
_env: &mut Environment,
args: &[Value],
) -> Result<Value, MachineError> {
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<Value, Ma
}
}
pub(crate) fn builtin_and(_vm: &mut Machine, args: &[Value]) -> Result<Value, MachineError> {
pub(crate) fn builtin_and(
_vm: &mut Machine,
_env: &mut Environment,
args: &[Value],
) -> Result<Value, MachineError> {
builtin_fold_t(BitAnd::bitand, true, args)
}
pub(crate) fn builtin_or(_vm: &mut Machine, args: &[Value]) -> Result<Value, MachineError> {
pub(crate) fn builtin_or(
_vm: &mut Machine,
_env: &mut Environment,
args: &[Value],
) -> Result<Value, MachineError> {
builtin_fold_t(BitOr::bitor, false, args)
}
pub(crate) fn builtin_bitwise_and(
_vm: &mut Machine,
_env: &mut Environment,
args: &[Value],
) -> Result<Value, MachineError> {
builtin_fold_t(BitAnd::bitand, 1, args)
}
pub(crate) fn builtin_bitwise_or(_vm: &mut Machine, args: &[Value]) -> Result<Value, MachineError> {
pub(crate) fn builtin_bitwise_or(
_vm: &mut Machine,
_env: &mut Environment,
args: &[Value],
) -> Result<Value, MachineError> {
builtin_fold_t(BitOr::bitor, 0, args)
}
pub(crate) fn builtin_bitwise_xor(
_vm: &mut Machine,
_env: &mut Environment,
args: &[Value],
) -> Result<Value, MachineError> {
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<Value, MachineError> {
pub(crate) fn builtin_cmp_eq(
vm: &mut Machine,
_env: &mut Environment,
args: &[Value],
) -> Result<Value, MachineError> {
builtin_cmp(vm, args, CompareOperation::Eq)
}
pub(crate) fn builtin_cmp_ne(vm: &mut Machine, args: &[Value]) -> Result<Value, MachineError> {
pub(crate) fn builtin_cmp_ne(
vm: &mut Machine,
_env: &mut Environment,
args: &[Value],
) -> Result<Value, MachineError> {
builtin_cmp(vm, args, CompareOperation::Ne)
}
pub(crate) fn builtin_cmp_gt(vm: &mut Machine, args: &[Value]) -> Result<Value, MachineError> {
pub(crate) fn builtin_cmp_gt(
vm: &mut Machine,
_env: &mut Environment,
args: &[Value],
) -> Result<Value, MachineError> {
builtin_cmp(vm, args, CompareOperation::Gt)
}
pub(crate) fn builtin_cmp_lt(vm: &mut Machine, args: &[Value]) -> Result<Value, MachineError> {
pub(crate) fn builtin_cmp_lt(
vm: &mut Machine,
_env: &mut Environment,
args: &[Value],
) -> Result<Value, MachineError> {
builtin_cmp(vm, args, CompareOperation::Lt)
}
pub(crate) fn builtin_cmp_ge(vm: &mut Machine, args: &[Value]) -> Result<Value, MachineError> {
pub(crate) fn builtin_cmp_ge(
vm: &mut Machine,
_env: &mut Environment,
args: &[Value],
) -> Result<Value, MachineError> {
builtin_cmp(vm, args, CompareOperation::Ge)
}
pub(crate) fn builtin_cmp_le(vm: &mut Machine, args: &[Value]) -> Result<Value, MachineError> {
pub(crate) fn builtin_cmp_le(
vm: &mut Machine,
_env: &mut Environment,
args: &[Value],
) -> Result<Value, MachineError> {
builtin_cmp(vm, args, CompareOperation::Le)
}
+32 -31
View File
@@ -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::<i64>().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::<Result<Vec<_>, _>>()?;
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!(" ");