Compare commits
2 Commits
777c10d79c
...
d21f927a24
| Author | SHA1 | Date | |
|---|---|---|---|
| d21f927a24 | |||
| e956f7b68d |
Generated
+2
-57
@@ -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]]
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
+8
-7
@@ -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: &mut 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: &mut 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: &mut Environment,
|
||||
env: &Rc<Environment>,
|
||||
path: P,
|
||||
) -> Result<(), Error> {
|
||||
let path = path.as_ref();
|
||||
@@ -202,8 +203,8 @@ 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 mut env = Environment::default();
|
||||
prelude::load(&mut env);
|
||||
let env = Rc::new(Environment::default());
|
||||
prelude::load(&env);
|
||||
let mut arguments = vec![];
|
||||
if let Some(script) = args.module.as_ref() {
|
||||
arguments.push(format!("{}", script.display()));
|
||||
@@ -214,8 +215,8 @@ fn main() -> ExitCode {
|
||||
Value::list_or_nil(arguments.into_iter().map(|arg| Value::String(arg.into()))),
|
||||
);
|
||||
let result = match args.module.as_ref() {
|
||||
Some(module) => run_module(&compile_options, &mut vm, &mut env, module),
|
||||
None => run_interactive(&compile_options, &mut vm, &mut env),
|
||||
Some(module) => run_module(&compile_options, &mut vm, &env, module),
|
||||
None => run_interactive(&compile_options, &mut vm, &env),
|
||||
};
|
||||
match result {
|
||||
Ok(()) => ExitCode::SUCCESS,
|
||||
|
||||
+3
-3
@@ -104,7 +104,7 @@ impl<R: BufRead> ModuleReader<R> {
|
||||
pub fn read_expression(
|
||||
&mut self,
|
||||
options: &CompileOptions,
|
||||
env: &mut 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: &mut 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: &mut Environment,
|
||||
env: &Rc<Environment>,
|
||||
) -> Result<Option<Value>, MachineErrorAt> {
|
||||
let raw_value = reader.read().map_err(Into::into)?;
|
||||
let Some(raw_value) = raw_value else {
|
||||
|
||||
+51
-11
@@ -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 defun_native<S, D, F>(&mut self, identifier: S, docstring: D, function: F) -> Value
|
||||
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, &mut 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);
|
||||
@@ -35,11 +45,11 @@ impl Environment {
|
||||
value
|
||||
}
|
||||
|
||||
pub fn defmacro_native<S, D, F>(&mut self, identifier: S, docstring: D, function: F)
|
||||
pub fn defmacro_native<S, D, F>(&self, identifier: S, docstring: D, function: F)
|
||||
where
|
||||
S: Into<IdentifierValue>,
|
||||
D: Into<StringValue>,
|
||||
F: Fn(&mut Machine, &mut 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);
|
||||
@@ -49,7 +59,7 @@ impl Environment {
|
||||
}
|
||||
|
||||
pub fn defmacro_bytecode<S: Into<IdentifierValue>>(
|
||||
&mut self,
|
||||
&self,
|
||||
identifier: S,
|
||||
value: Rc<BytecodeFunction>,
|
||||
) {
|
||||
@@ -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
|
||||
@@ -73,7 +83,7 @@ impl Environment {
|
||||
}
|
||||
|
||||
pub fn set_global_value<S: Into<IdentifierValue>, V: Into<Value>>(
|
||||
&mut self,
|
||||
&self,
|
||||
identifier: S,
|
||||
value: V,
|
||||
) {
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+22
-20
@@ -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: &mut 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: &mut 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: &mut 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: &mut 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: &mut 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: &mut 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: &mut 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: &mut 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: &mut Environment,
|
||||
env: &Rc<Environment>,
|
||||
mut instructions: Vec<u8>,
|
||||
constants: Vec<Value>,
|
||||
) -> (Machine, Result<Value, MachineErrorAt>) {
|
||||
@@ -692,7 +694,7 @@ mod tests {
|
||||
}
|
||||
|
||||
fn eval0(
|
||||
env: &mut Environment,
|
||||
env: &Rc<Environment>,
|
||||
instructions: Vec<u8>,
|
||||
constants: Vec<Value>,
|
||||
) -> (Machine, Value) {
|
||||
@@ -703,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());
|
||||
@@ -720,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);
|
||||
@@ -732,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,
|
||||
@@ -760,7 +762,7 @@ mod tests {
|
||||
max_arity: 1,
|
||||
});
|
||||
let (m, r) = eval0(
|
||||
&mut env,
|
||||
&env,
|
||||
vec![
|
||||
Instruction::PushConstant.into(),
|
||||
0,
|
||||
@@ -780,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,
|
||||
@@ -801,7 +803,7 @@ mod tests {
|
||||
max_arity: 2,
|
||||
});
|
||||
let (m, r) = eval0(
|
||||
&mut env,
|
||||
&env,
|
||||
vec![
|
||||
Instruction::PushConstant.into(),
|
||||
0,
|
||||
|
||||
+2
-2
@@ -13,7 +13,7 @@ pub trait MacroExpand: Sized {
|
||||
fn macro_expand(
|
||||
&self,
|
||||
vm: &mut Machine,
|
||||
env: &mut 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: &mut Environment,
|
||||
env: &Rc<Environment>,
|
||||
tail: bool,
|
||||
) -> Result<Self, MachineErrorAt> {
|
||||
match self {
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
pub fn load(env: &mut Environment) {
|
||||
pub fn load(env: &Rc<Environment>) {
|
||||
// // vectors
|
||||
// env.defun_native("getv", |vm, _, args| {
|
||||
// let [vec, index] = args else {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::{
|
||||
error::MachineError,
|
||||
vm::{
|
||||
@@ -7,7 +9,7 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
pub fn load(env: &mut Environment) {
|
||||
pub fn load(env: &Rc<Environment>) {
|
||||
env.defun_native(
|
||||
"->string",
|
||||
"Converts a value to string representation",
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::{
|
||||
error::MachineError,
|
||||
vm::{Value, env::Environment, value::Keyword},
|
||||
};
|
||||
|
||||
pub fn load(env: &mut Environment) {
|
||||
pub fn load(env: &Rc<Environment>) {
|
||||
env.defun_native(
|
||||
"explain",
|
||||
"Provides an explanation for a given value",
|
||||
|
||||
+33
-9
@@ -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: &mut 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",
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::{
|
||||
error::{MachineError, ValueConversionError},
|
||||
vm::{
|
||||
@@ -6,7 +8,7 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
pub fn load(env: &mut 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));
|
||||
|
||||
@@ -76,7 +76,7 @@ impl Stream {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load(env: &mut 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
@@ -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, &mut 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: &mut 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: &mut 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: &mut 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: &mut 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: &mut 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: &mut 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: &mut 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: &mut 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: &mut 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: &mut 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: &mut 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: &mut 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: &mut 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: &mut 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: &mut 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: &mut 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: &mut 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: &mut Environment,
|
||||
_env: &Rc<Environment>,
|
||||
args: &[Value],
|
||||
) -> Result<Value, MachineError> {
|
||||
let [x] = args else {
|
||||
|
||||
@@ -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: &mut Environment) {
|
||||
pub fn load(env: &Rc<Environment>) {
|
||||
math::load(env);
|
||||
eval::load(env);
|
||||
functional::load(env);
|
||||
|
||||
@@ -144,7 +144,7 @@ impl AnyFunction {
|
||||
pub fn invoke(
|
||||
&self,
|
||||
vm: &mut Machine,
|
||||
env: &mut Environment,
|
||||
env: &Rc<Environment>,
|
||||
args: &[Value],
|
||||
) -> Result<Value, MachineError> {
|
||||
match self {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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, &mut 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, &mut 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: &mut 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
@@ -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: &mut 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: &mut Environment) -> Result<Value, MachineErrorA
|
||||
|
||||
#[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]
|
||||
|
||||
Reference in New Issue
Block a user