Split Environment and Machine
This commit is contained in:
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
@@ -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,3 +1,4 @@
|
||||
pub mod env;
|
||||
pub mod instruction;
|
||||
pub mod loader;
|
||||
pub mod machine;
|
||||
|
||||
+5
-3
@@ -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
@@ -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
@@ -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!(" ");
|
||||
|
||||
Reference in New Issue
Block a user