diff --git a/examples/io.lysp b/examples/io.lysp new file mode 100644 index 0000000..5bb5bf2 --- /dev/null +++ b/examples/io.lysp @@ -0,0 +1,5 @@ +;; vi:ft=lisp:sw=2:ts=2 + +(let (f (fopen (car *args*))) + (fwrite (fread f)) + ) diff --git a/src/compile/block.rs b/src/compile/block.rs index 56d956d..b493ddd 100644 --- a/src/compile/block.rs +++ b/src/compile/block.rs @@ -9,7 +9,7 @@ use crate::{ syntax::{ CallExpression, CondExpression, DefmacroExpression, DefunExpression, Expression, FunctionBody, IfExpression, LambdaExpression, LetExpression, LoopExpression, - PrognExpression, SetqExpression, WhileExpression, + PrognExpression, SetqExpression, VectorExpression, WhileExpression, }, value::{BuiltinFunction, CompileConstant, CompileValue}, }, @@ -625,6 +625,23 @@ impl<'a> LocalBlock<'a> { Ok(CompileValue::Nil) } + fn compile_vector( + &mut self, + vector: &VectorExpression, + break_label: Option, + ) -> Result { + for expression in vector.elements.iter().rev() { + let value = self.compile_expression(expression, break_label)?; + self.compile_push(value)?; + } + self.compile_push(CompileValue::Global("vector".into()))?; + let Some(count) = U::new(vector.elements.len() as u32) else { + todo!() + }; + self.function.emit(Instruction::Call(count)); + Ok(CompileValue::Stack) + } + pub fn compile_expression( &mut self, expression: &Rc, @@ -638,6 +655,7 @@ impl<'a> LocalBlock<'a> { Expression::Identifier(identifier) => self.compile_identifier(identifier), Expression::Lambda(lambda) => self.compile_lambda(lambda), Expression::Defun(defun) => self.compile_defun(defun), + Expression::Vector(vector) => self.compile_vector(vector, break_label), Expression::Call(call) => self.compile_call(call, break_label), Expression::If(condition) => self.compile_if(condition, break_label), Expression::Cond(condition) => self.compile_cond(condition, break_label), diff --git a/src/compile/syntax/mod.rs b/src/compile/syntax/mod.rs index 8d31b33..a8b03ea 100644 --- a/src/compile/syntax/mod.rs +++ b/src/compile/syntax/mod.rs @@ -10,6 +10,7 @@ mod function; mod lambda; mod loops; mod macros; +mod vector; pub use binding::*; pub use call::*; @@ -19,6 +20,7 @@ pub use function::*; pub use lambda::*; pub use loops::*; pub use macros::*; +pub use vector::*; #[derive(Debug, PartialEq)] pub enum Expression { @@ -40,6 +42,7 @@ pub enum Expression { While(WhileExpression), Loop(LoopExpression), Progn(PrognExpression), + Vector(VectorExpression), Return, } @@ -67,7 +70,6 @@ impl Expression { Value::Boolean(value) => Rc::new(Self::BooleanLiteral(*value)), Value::Integer(value) => Rc::new(Self::IntegerLiteral(*value)), Value::String(value) => Rc::new(Self::StringLiteral(value.clone())), - Value::Vector(_vector) => todo!(), Value::Identifier(value) => Rc::new(Self::Identifier(value.clone())), Value::Quasi(_value) => todo!("{value}"), Value::Unquote(_value) => todo!("Unquote {_value}"), @@ -116,6 +118,9 @@ impl Expression { _ => Self::map_or(CallExpression::parse(cons, value), Expression::Call), } } + Value::Vector(vector) => { + Rc::new(Self::Vector(VectorExpression::parse(&vector.borrow()))) + } Value::Keyword(_) => todo!(), Value::NativeFunction(_) | Value::BytecodeFunction(_) | Value::OpaqueValue(_) => { todo!() @@ -142,6 +147,7 @@ impl CollectErrors for Expression { Self::While(cloop) => cloop.collect_errors(errors), Self::Loop(cloop) => cloop.collect_errors(errors), Self::Progn(progn) => progn.collect_errors(errors), + Self::Vector(vector) => vector.collect_errors(errors), Self::Nil | Self::Return | Self::IntegerLiteral(_) diff --git a/src/compile/syntax/vector.rs b/src/compile/syntax/vector.rs new file mode 100644 index 0000000..ed61f50 --- /dev/null +++ b/src/compile/syntax/vector.rs @@ -0,0 +1,29 @@ +use std::rc::Rc; + +use crate::{ + compile::{Expression, ParseError, syntax::CollectErrors}, + vm::value::Value, +}; + +#[derive(Debug, PartialEq)] +pub struct VectorExpression { + pub elements: Vec>, +} + +impl VectorExpression { + pub fn parse(values: &[Value]) -> Self { + Self { + elements: values.iter().map(Expression::parse_inner).collect(), + } + } +} + +impl CollectErrors for VectorExpression { + fn collect_errors(&self, errors: &mut Vec) -> bool { + let mut r = false; + for expr in self.elements.iter() { + r |= expr.collect_errors(errors); + } + r + } +} diff --git a/src/parse.rs b/src/parse.rs index bf8e527..4226720 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -14,7 +14,7 @@ use nom::{ sequence::{delimited, preceded}, }; -use crate::vm::value::{Keyword, Value}; +use crate::vm::value::{Keyword, Value, Vector}; struct IdentifierHead; struct IdentifierTail; @@ -179,6 +179,17 @@ fn parse_list_or_nil(input: &str) -> IResult<&str, Value> { .parse(input) } +fn parse_vector(input: &str) -> IResult<&str, Value> { + delimited( + char('['), + many0(preceded(skip_comment_and_whitespace, parse_value)), + preceded(skip_comment_and_whitespace, char(']')), + ) + .map(Vector::from) + .map(Value::from) + .parse(input) +} + fn parse_boolean(input: &str) -> IResult<&str, Value> { map( alt(( @@ -298,6 +309,7 @@ fn parse_quote(input: &str) -> IResult<&str, Value> { pub fn parse_value(input: &str) -> IResult<&str, Value> { alt(( parse_list_or_nil, + parse_vector, parse_boolean, parse_quote, parse_quasi, diff --git a/src/vm/macros.rs b/src/vm/macros.rs index c7fa0c8..70d7849 100644 --- a/src/vm/macros.rs +++ b/src/vm/macros.rs @@ -75,7 +75,11 @@ impl MacroExpand for Value { let value = expand_quasiquote(value); value.macro_expand(vm, env, false) } - Self::Vector(_) => todo!(), + Self::Vector(vector) => Ok(Value::Vector( + vector + .try_map(|value| value.macro_expand(vm, env, false))? + .into(), + )), } } } diff --git a/src/vm/prelude/io.rs b/src/vm/prelude/io.rs new file mode 100644 index 0000000..f4d360c --- /dev/null +++ b/src/vm/prelude/io.rs @@ -0,0 +1,119 @@ +use std::{ + cell::RefCell, + fs::File, + io::{Read, Write, stdin, stdout}, +}; + +use crate::vm::{ + env::Environment, + value::{Value, Vector}, +}; + +enum FileStream { + Closed, + File(File), +} + +enum Stream { + Stdin, + Stdout, + File(RefCell), +} + +impl Stream { + fn read_bytes(&self, data: &mut [u8]) -> Option { + let result = match self { + Self::Stdin => stdin().read(data), + Self::Stdout => return None, + Self::File(file) => match &mut *file.borrow_mut() { + FileStream::File(file) => file.read(data), + FileStream::Closed => return None, + }, + }; + result.ok() + } + + fn write_bytes(&self, data: &[u8]) -> Option { + match self { + Self::Stdin => None, + Self::Stdout => stdout().write(data).ok(), + Self::File(file) => match &mut *file.borrow_mut() { + FileStream::File(file) => file.write(data).ok(), + FileStream::Closed => None, + }, + } + } +} + +pub(super) fn load(env: &mut Environment) { + env.set_global_value("*stdin*", Value::opaque(Stream::Stdin)); + env.set_global_value("*stdout*", Value::opaque(Stream::Stdout)); + + env.defun_native("fopen", |_, _, args| { + let [path] = args else { + todo!(); + }; + let Value::String(path) = path else { todo!() }; + match File::open(&**path) { + Ok(file) => Ok(Value::opaque(Stream::File(RefCell::new(FileStream::File( + file, + ))))), + Err(_) => Ok(Value::Nil), + } + }); + env.defun_native("fclose", |vm, _, args| { + let [stream] = args else { todo!() }; + let stream = stream + .as_opaque::() + .map_err(|e| vm.error_at_ip(e))?; + if let Stream::File(file) = stream { + *file.borrow_mut() = FileStream::Closed; + } + Ok(Value::Nil) + }); + env.defun_native("fread", |vm, _, args| { + let stream = match args { + [] => &Stream::Stdin, + [stream] => stream + .as_opaque::() + .map_err(|e| vm.error_at_ip(e))?, + _ => todo!(), + }; + let mut buffer = [0; 256]; + let count = stream.read_bytes(&mut buffer); + match count { + Some(len) => { + let vector = Vector::from_iter(&buffer[..len]); + Ok(Value::Vector(vector.into())) + } + None => Ok(Value::Nil), + } + }); + env.defun_native("fwrite", |vm, _, args| { + let (stream, data) = match args { + [data] => (&Stream::Stdout, data), + [stream, data] => ( + stream + .as_opaque::() + .map_err(|e| vm.error_at_ip(e))?, + data, + ), + _ => todo!(), + }; + + match data { + Value::Vector(vector) => { + let bytes = vector.to_bytes().unwrap(); + match stream.write_bytes(&bytes) { + Some(count) => Ok(Value::Integer(count as i64)), + None => Ok(Value::Nil), + } + } + Value::String(value) => match stream.write_bytes(value.as_bytes()) { + Some(count) => Ok(Value::Integer(count as i64)), + None => Ok(Value::Nil), + }, + _ => todo!(), + } + }); +} diff --git a/src/vm/prelude/math.rs b/src/vm/prelude/math.rs index b3822ff..c1acda0 100644 --- a/src/vm/prelude/math.rs +++ b/src/vm/prelude/math.rs @@ -267,3 +267,25 @@ pub(crate) fn builtin_cmp_le( ) -> Result { builtin_cmp(vm, args, CompareOperation::Le) } + +pub(super) fn load(env: &mut Environment) { + // math + 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); + + 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); + + 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); +} diff --git a/src/vm/prelude/mod.rs b/src/vm/prelude/mod.rs index f68faa7..e02a667 100644 --- a/src/vm/prelude/mod.rs +++ b/src/vm/prelude/mod.rs @@ -6,33 +6,18 @@ use crate::{ util::IteratorExt, vm::{ env::Environment, - value::{AnyFunction, ConsCell, Keyword, TryFromValue, Value, ValueString}, + value::{AnyFunction, ConsCell, Keyword, TryFromValue, Value, ValueString, Vector}, }, }; +mod io; mod math; + pub(crate) use math::*; pub fn load(env: &mut Environment) { - // math - 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); - - 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); - - 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); + math::load(env); + io::load(env); // conversion env.defun_native("string->int", |vm, _, args| { @@ -51,6 +36,10 @@ pub fn load(env: &mut Environment) { let result = Value::String(format!("{arg}").into()); Ok(result) }); + env.defun_native("vector", |_, _, args| { + let vector = Vector::from_iter(args.iter().cloned()); + Ok(Value::Vector(vector.into())) + }); // lists env.defun_native("car", |vm, _env, args| { diff --git a/src/vm/value/convert.rs b/src/vm/value/convert.rs index f570626..7bb1fbf 100644 --- a/src/vm/value/convert.rs +++ b/src/vm/value/convert.rs @@ -39,6 +39,12 @@ macro_rules! impl_primitive_value { } } + impl From<&$t> for Value { + fn from(value: &$t) -> Self { + Self::Integer(*value as i64) + } + } + impl TryFromValue<'_> for $t { fn try_from_value(value: &Value) -> Result { match value { diff --git a/src/vm/value/mod.rs b/src/vm/value/mod.rs index 6978e8d..eb93a92 100644 --- a/src/vm/value/mod.rs +++ b/src/vm/value/mod.rs @@ -1,4 +1,4 @@ -use std::{fmt, hash::Hash, rc::Rc}; +use std::{any::Any, fmt, hash::Hash, rc::Rc}; use crate::{ compile::{ExpectedWhat, ExpectedWhere, ParseError, ParseErrorKind}, @@ -78,6 +78,12 @@ impl Value { matches!(self, Self::Nil) } + pub fn opaque(value: T) -> Self { + let value: Rc = Rc::new(value); + let opaque = OpaqueValue::from(value); + Self::OpaqueValue(opaque) + } + pub fn as_opaque(&self) -> Result<&T, MachineErrorKind> { match self { Self::OpaqueValue(opaque) => opaque.cast(), @@ -135,6 +141,12 @@ impl Value { } } +impl From for Value { + fn from(value: Vector) -> Self { + Self::Vector(Rc::new(value)) + } +} + impl fmt::Display for Value { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { diff --git a/src/vm/value/vector.rs b/src/vm/value/vector.rs index fc3de68..2c2e41a 100644 --- a/src/vm/value/vector.rs +++ b/src/vm/value/vector.rs @@ -5,7 +5,10 @@ use std::{ ops::Deref, }; -use crate::vm::value::Value; +use crate::{ + error::MachineErrorKind, + vm::value::{TryFromValue, Value}, +}; #[derive(Debug, PartialEq, Eq)] pub struct Vector(RefCell>); @@ -16,7 +19,21 @@ impl Hash for Vector { } } +impl From> for Vector { + fn from(value: Vec) -> Self { + Self(RefCell::new(value)) + } +} + impl Vector { + pub fn try_map Result>(&self, map: F) -> Result { + self.0.borrow().iter().map(map).collect() + } + + pub fn to_bytes(&self) -> Result, MachineErrorKind> { + self.0.borrow().iter().map(u8::try_from_value).collect() + } + pub fn is_empty(&self) -> bool { self.0.borrow().is_empty() } @@ -26,9 +43,17 @@ impl Vector { } } -impl FromIterator for Vector { - fn from_iter>(iter: T) -> Self { - Self(RefCell::new(Vec::from_iter(iter))) +// impl FromIterator for Vector { +// fn from_iter>(iter: T) -> Self { +// Self(RefCell::new(Vec::from_iter(iter))) +// } +// } + +impl> FromIterator for Vector { + fn from_iter>(iter: I) -> Self { + Self(RefCell::new(Vec::from_iter( + iter.into_iter().map(Into::into), + ))) } }