diff --git a/src/compile/block.rs b/src/compile/block.rs index 56d956d..8793730 100644 --- a/src/compile/block.rs +++ b/src/compile/block.rs @@ -15,7 +15,7 @@ use crate::{ }, vm::{ instruction::{Instruction, LocalId, MathInstruction, U}, - value::Value, + value::{Value, Vector}, }, }; @@ -625,6 +625,10 @@ impl<'a> LocalBlock<'a> { Ok(CompileValue::Nil) } + fn compile_vector(&mut self, vector: &Rc) -> Result { + Ok(CompileValue::Quote(Rc::new(Value::Vector(vector.clone())))) + } + pub fn compile_expression( &mut self, expression: &Rc, @@ -648,6 +652,7 @@ impl<'a> LocalBlock<'a> { Expression::While(cloop) => self.compile_while(cloop, break_label), Expression::Loop(cloop) => self.compile_loop(cloop), Expression::Progn(progn) => self.compile_progn(progn, break_label), + Expression::Vector(vector) => self.compile_vector(vector), Expression::Return => self.compile_call_return(break_label), Expression::SyntaxError(_) => unreachable!(), diff --git a/src/compile/syntax/mod.rs b/src/compile/syntax/mod.rs index 8d31b33..686b009 100644 --- a/src/compile/syntax/mod.rs +++ b/src/compile/syntax/mod.rs @@ -1,6 +1,6 @@ use std::rc::Rc; -use crate::vm::value::{ConsCell, Keyword, Value, ValueString}; +use crate::vm::value::{ConsCell, Keyword, Value, ValueString, Vector}; mod binding; mod call; @@ -40,6 +40,7 @@ pub enum Expression { While(WhileExpression), Loop(LoopExpression), Progn(PrognExpression), + Vector(Rc), Return, } @@ -67,7 +68,7 @@ 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::Vector(vector) => Rc::new(Self::Vector(vector.clone())), Value::Identifier(value) => Rc::new(Self::Identifier(value.clone())), Value::Quasi(_value) => todo!("{value}"), Value::Unquote(_value) => todo!("Unquote {_value}"), @@ -143,6 +144,7 @@ impl CollectErrors for Expression { Self::Loop(cloop) => cloop.collect_errors(errors), Self::Progn(progn) => progn.collect_errors(errors), Self::Nil + | Self::Vector(_) | Self::Return | Self::IntegerLiteral(_) | Self::Identifier(_) diff --git a/src/compile/syntax/vector.rs b/src/compile/syntax/vector.rs new file mode 100644 index 0000000..cb64cd0 --- /dev/null +++ b/src/compile/syntax/vector.rs @@ -0,0 +1,6 @@ +use crate::vm::value::Value; + +#[derive(Debug, PartialEq)] +pub struct VectorExpression { + pub elements: Vec, +} diff --git a/src/parse.rs b/src/parse.rs index bf8e527..592c0cd 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; @@ -295,9 +295,22 @@ fn parse_quote(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_iter) + .map(Into::into) + .map(Value::Vector) + .parse(input) +} + 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..74818b3 100644 --- a/src/vm/macros.rs +++ b/src/vm/macros.rs @@ -75,7 +75,7 @@ impl MacroExpand for Value { let value = expand_quasiquote(value); value.macro_expand(vm, env, false) } - Self::Vector(_) => todo!(), + Self::Vector(vector) => Ok(Self::Vector(vector.clone())), } } } diff --git a/src/vm/prelude/mod.rs b/src/vm/prelude/mod.rs index f68faa7..5911060 100644 --- a/src/vm/prelude/mod.rs +++ b/src/vm/prelude/mod.rs @@ -51,6 +51,44 @@ pub fn load(env: &mut Environment) { let result = Value::String(format!("{arg}").into()); Ok(result) }); + env.defun_native("type", |vm, _, args| { + let [arg] = args else { + return Err(vm.error_at_ip(MachineErrorKind::InvalidArgument)); + }; + Ok(arg.typeid()) + }); + + // vectors + env.defun_native("getv", |vm, _, args| { + let [vec, index] = args else { + return Err(vm.error_at_ip(MachineErrorKind::InvalidArgument)); + }; + let Value::Vector(vec) = vec else { + return Err(vm.error_at_ip(MachineErrorKind::InvalidArgument)); + }; + let index = i64::try_from_value(index).map_err(|e| vm.error_at_ip(e))? as isize; + let value = if index < 0 { + todo!() + } else { + vec.value_at(index as usize).unwrap_or(Value::Nil) + }; + Ok(value) + }); + env.defun_native("setv", |vm, _, args| { + let [vec, index, value] = args else { + return Err(vm.error_at_ip(MachineErrorKind::InvalidArgument)); + }; + let Value::Vector(vec) = vec else { + return Err(vm.error_at_ip(MachineErrorKind::InvalidArgument)); + }; + let index = i64::try_from_value(index).map_err(|e| vm.error_at_ip(e))? as isize; + if index < 0 { + todo!() + } else { + vec.set_value_at(index as usize, value.clone()); + } + Ok(Value::Nil) + }); // lists env.defun_native("car", |vm, _env, args| { diff --git a/src/vm/value/mod.rs b/src/vm/value/mod.rs index 6978e8d..6706fa8 100644 --- a/src/vm/value/mod.rs +++ b/src/vm/value/mod.rs @@ -21,7 +21,7 @@ pub use cons::ConsCell; pub use keyword::Keyword; pub use native::{NativeFunction, NativeFunctionImpl, OpaqueValue}; pub use string::ValueString; -pub use vector::Vector; +pub use vector::{Vector, VectorStorage}; pub use convert::{AnyFunction, TryFromValue}; @@ -85,6 +85,46 @@ impl Value { } } + pub fn typeid(&self) -> Value { + match self { + Value::Nil | Value::Cons(_) => Value::list_or_nil([Value::Identifier("list".into())]), + Value::Integer(_) => Value::list_or_nil([Value::Identifier("integer".into())]), + Value::Vector(vector) => Value::list_or_nil([ + Value::Identifier("vector".into()), + match &*vector.borrow() { + VectorStorage::I8(_) => Value::Identifier("i8".into()), + VectorStorage::I16(_) => Value::Identifier("i16".into()), + VectorStorage::I32(_) => Value::Identifier("i32".into()), + VectorStorage::I64(_) => Value::Identifier("i64".into()), + VectorStorage::Any(_) => Value::Identifier("*".into()), + }, + ]), + Value::Boolean(_) => Value::list_or_nil([Value::Identifier("boolean".into())]), + Value::String(_) => Value::list_or_nil([Value::Identifier("string".into())]), + Value::Quasi(value) => { + Value::list_or_nil([Value::Identifier("quasi".into()), value.typeid()]) + } + Value::Quote(value) => { + Value::list_or_nil([Value::Identifier("quote".into()), value.typeid()]) + } + Value::Unquote(value) => { + Value::list_or_nil([Value::Identifier("unquote".into()), value.typeid()]) + } + Value::NativeFunction(_) => { + Value::list_or_nil([Value::Identifier("native-function".into())]) + } + Value::BytecodeFunction(_) => { + Value::list_or_nil([Value::Identifier("bytecode-function".into())]) + } + Value::OpaqueValue(_) => Value::list_or_nil([Value::Identifier("opaque".into())]), + Value::Keyword(keyword) => Value::list_or_nil([ + Value::Identifier("keyword".into()), + Value::Identifier(format!("{keyword}").into()), + ]), + Value::Identifier(_) => Value::list_or_nil([Value::Identifier("identifier".into())]), + } + } + pub fn stringify(&self) -> Result { match self { Self::Integer(value) => Ok(format!("{value}")), diff --git a/src/vm/value/vector.rs b/src/vm/value/vector.rs index fc3de68..cdfe866 100644 --- a/src/vm/value/vector.rs +++ b/src/vm/value/vector.rs @@ -1,21 +1,23 @@ use std::{ - cell::RefCell, + cell::{Ref, RefCell}, fmt, hash::{Hash, Hasher}, - ops::Deref, }; use crate::vm::value::Value; -#[derive(Debug, PartialEq, Eq)] -pub struct Vector(RefCell>); - -impl Hash for Vector { - fn hash(&self, state: &mut H) { - self.0.borrow().hash(state); - } +#[derive(Debug, PartialEq, Eq, Hash)] +pub enum VectorStorage { + I8(Vec), + I16(Vec), + I32(Vec), + I64(Vec), + Any(Vec), } +#[derive(Debug, PartialEq, Eq)] +pub struct Vector(RefCell); + impl Vector { pub fn is_empty(&self) -> bool { self.0.borrow().is_empty() @@ -24,31 +26,333 @@ impl Vector { pub fn len(&self) -> usize { self.0.borrow().len() } -} -impl FromIterator for Vector { - fn from_iter>(iter: T) -> Self { - Self(RefCell::new(Vec::from_iter(iter))) + pub fn borrow(&self) -> Ref<'_, VectorStorage> { + self.0.borrow() + } + + pub fn value_at(&self, index: usize) -> Option { + self.0.borrow().value_at(index) + } + pub fn set_value_at(&self, index: usize, value: Value) { + self.0.borrow_mut().set_value_at(index, value); } } -impl Deref for Vector { - type Target = RefCell>; - - fn deref(&self) -> &Self::Target { - &self.0 +impl Hash for Vector { + fn hash(&self, state: &mut H) { + self.0.borrow().hash(state); } } impl fmt::Display for Vector { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "[")?; - for (i, element) in self.0.borrow().iter().enumerate() { - if i != 0 { - write!(f, " ")?; - } - write!(f, "{element}")?; + fmt::Display::fmt(&*self.0.borrow(), f) + } +} + +impl FromIterator for Vector +where + VectorStorage: FromIterator, +{ + fn from_iter>(iter: T) -> Self { + Self(RefCell::new(VectorStorage::from_iter(iter))) + } +} + +macro_rules! static_dispatch { + ([$input:expr] $value:ident => $body:expr) => { + match $input { + Self::I8($value) => $body, + Self::I16($value) => $body, + Self::I32($value) => $body, + Self::I64($value) => $body, + Self::Any($value) => $body, } + }; +} + +macro_rules! dispatch_integer_convert { + ($self:ident ($storage:ident, $value:ident) => $f:expr) => { + match $self { + Self::I8($storage) if let Ok($value) = i8::try_from($value) => { + $f; + } + Self::I8($storage) if let Ok($value) = i16::try_from($value) => { + let mut $storage = $storage.iter().copied().map(Into::into).collect::>(); + $f; + *$self = Self::I16($storage); + } + Self::I8($storage) if let Ok($value) = i32::try_from($value) => { + let mut $storage = $storage.iter().copied().map(Into::into).collect::>(); + $f; + *$self = Self::I32($storage); + } + Self::I8($storage) => { + let mut $storage = $storage.iter().copied().map(Into::into).collect::>(); + $f; + *$self = Self::I64($storage); + } + Self::I16($storage) if let Ok($value) = i16::try_from($value) => { + $f; + } + Self::I16($storage) if let Ok($value) = i32::try_from($value) => { + let mut $storage = $storage.iter().copied().map(Into::into).collect::>(); + $f; + *$self = Self::I32($storage); + } + Self::I16($storage) => { + let mut $storage = $storage.iter().copied().map(Into::into).collect::>(); + $f; + *$self = Self::I64($storage); + } + Self::I32($storage) if let Ok($value) = i32::try_from($value) => { + $f; + } + Self::I32($storage) => { + let mut $storage = $storage.iter().copied().map(Into::into).collect::>(); + $f; + *$self = Self::I64($storage); + } + Self::I64($storage) => { + $f; + } + Self::Any($storage) => { + let $value = Value::Integer($value); + $f; + } + } + }; +} + +macro_rules! dispatch_any_convert { + ($self:ident ($storage:ident) => $f:expr) => { + match $self { + Self::I8($storage) => { + let mut $storage = $storage + .iter() + .copied() + .map(Into::into) + .map(Value::Integer) + .collect::>(); + $f; + *$self = Self::Any($storage); + } + Self::I16($storage) => { + let mut $storage = $storage + .iter() + .copied() + .map(Into::into) + .map(Value::Integer) + .collect::>(); + $f; + *$self = Self::Any($storage); + } + Self::I32($storage) => { + let mut $storage = $storage + .iter() + .copied() + .map(Into::into) + .map(Value::Integer) + .collect::>(); + $f; + *$self = Self::Any($storage); + } + Self::I64($storage) => { + let mut $storage = $storage + .iter() + .copied() + .map(Value::Integer) + .collect::>(); + $f; + *$self = Self::Any($storage); + } + Self::Any($storage) => { + $f; + } + } + }; +} + +impl VectorStorage { + fn value_at(&self, index: usize) -> Option { + match self { + Self::I8(values) if let Some(value) = values.get(index).copied() => { + Some(Value::Integer(value.into())) + } + Self::I16(values) if let Some(value) = values.get(index).copied() => { + Some(Value::Integer(value.into())) + } + Self::I32(values) if let Some(value) = values.get(index).copied() => { + Some(Value::Integer(value.into())) + } + Self::I64(values) if let Some(value) = values.get(index).copied() => { + Some(Value::Integer(value)) + } + Self::Any(values) if let Some(value) = values.get(index).cloned() => Some(value), + _ => None, + } + } + + fn len(&self) -> usize { + static_dispatch!([self] vec => vec.len()) + } + + fn is_empty(&self) -> bool { + self.len() == 0 + } + + fn push(&mut self, value: Value) { + match value { + Value::Integer(value) => self.push_integer(value), + value => match self { + Self::Any(vec) => vec.push(value), + _ => self.push_any(value), + }, + } + } + + fn set_value_at(&mut self, index: usize, value: Value) { + if index >= self.len() { + return; + } + match value { + Value::Integer(value) => self.set_integer(index, value), + value => match self { + Self::Any(vec) => vec[index] = value, + _ => self.set_any(index, value), + }, + } + } + + fn push_any(&mut self, value: Value) { + dispatch_any_convert!(self (w) => { + w.push(value); + }); + } + + fn set_any(&mut self, index: usize, value: Value) { + dispatch_any_convert!(self (w) => { + w[index] = value; + }); + } + + fn push_integer(&mut self, value: i64) { + dispatch_integer_convert!(self (w, value) => { + w.push(value); + }); + } + + fn set_integer(&mut self, index: usize, value: i64) { + dispatch_integer_convert!(self (w, value) => { + w[index] = value; + }); + } +} + +impl FromIterator for VectorStorage { + fn from_iter>(iter: T) -> Self { + let mut accumulator = Self::I8(vec![]); + for item in iter { + accumulator.push(item); + } + accumulator + } +} + +fn display_vector(value: &[T], f: &mut fmt::Formatter) -> fmt::Result { + for (i, value) in value.iter().enumerate() { + if i != 0 { + write!(f, " ")?; + } + write!(f, "{value}")?; + } + Ok(()) +} + +impl fmt::Display for VectorStorage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[")?; + match self { + Self::I8(vec) => display_vector(vec, f), + Self::I16(vec) => display_vector(vec, f), + Self::I32(vec) => display_vector(vec, f), + Self::I64(vec) => display_vector(vec, f), + Self::Any(vec) => display_vector(vec, f), + }?; write!(f, "]") } } + +macro_rules! impl_primitive_from_iter { + ($signed_ty:ty, $unsigned_ty:ty => $variant:ident) => { + impl FromIterator<$signed_ty> for VectorStorage { + fn from_iter>(iter: T) -> Self { + Self::$variant(iter.into_iter().collect()) + } + } + impl FromIterator<$unsigned_ty> for VectorStorage { + fn from_iter>(iter: T) -> Self { + Self::$variant(iter.into_iter().map(|x| x as $signed_ty).collect()) + } + } + }; +} + +impl_primitive_from_iter!(i8, u8 => I8); +impl_primitive_from_iter!(i16, u16 => I16); +impl_primitive_from_iter!(i32, u32 => I32); +impl_primitive_from_iter!(i64, u64 => I64); + +#[cfg(test)] +mod tests { + use crate::vm::value::{Value, vector::VectorStorage}; + + #[test] + fn test_vector_storage_from_iter() { + let v = VectorStorage::from_iter([1i8, 2, 3, 4, 5, 6, 7]); + assert_eq!(VectorStorage::I8(vec![1, 2, 3, 4, 5, 6, 7]), v); + let v = VectorStorage::from_iter([1u8, 2, 3, 4, 5, 6, 7]); + assert_eq!(VectorStorage::I8(vec![1, 2, 3, 4, 5, 6, 7]), v); + let v = VectorStorage::from_iter([1i16, 2, 3, 4, 5, 6, 7]); + assert_eq!(VectorStorage::I16(vec![1, 2, 3, 4, 5, 6, 7]), v); + let v = VectorStorage::from_iter([1u16, 2, 3, 4, 5, 6, 7]); + assert_eq!(VectorStorage::I16(vec![1, 2, 3, 4, 5, 6, 7]), v); + let v = VectorStorage::from_iter([1i32, 2, 3, 4, 5, 6, 7]); + assert_eq!(VectorStorage::I32(vec![1, 2, 3, 4, 5, 6, 7]), v); + let v = VectorStorage::from_iter([1u32, 2, 3, 4, 5, 6, 7]); + assert_eq!(VectorStorage::I32(vec![1, 2, 3, 4, 5, 6, 7]), v); + let v = VectorStorage::from_iter([1i64, 2, 3, 4, 5, 6, 7]); + assert_eq!(VectorStorage::I64(vec![1, 2, 3, 4, 5, 6, 7]), v); + let v = VectorStorage::from_iter([1u64, 2, 3, 4, 5, 6, 7]); + assert_eq!(VectorStorage::I64(vec![1, 2, 3, 4, 5, 6, 7]), v); + } + + #[test] + fn test_vector_unspecialize() { + let mut v = VectorStorage::from_iter([1i8, 2, 3]); + assert_eq!(VectorStorage::I8(vec![1, 2, 3]), v); + v.push(Value::Integer(1234)); + assert_eq!(VectorStorage::I16(vec![1, 2, 3, 1234]), v); + v.push(Value::Integer(12341234)); + assert_eq!(VectorStorage::I32(vec![1, 2, 3, 1234, 12341234]), v); + v.push(Value::Integer(1234123412341234)); + assert_eq!( + VectorStorage::I64(vec![1, 2, 3, 1234, 12341234, 1234123412341234]), + v + ); + v.push(Value::String("a".into())); + assert_eq!( + VectorStorage::Any(vec![ + Value::Integer(1), + Value::Integer(2), + Value::Integer(3), + Value::Integer(1234), + Value::Integer(12341234), + Value::Integer(1234123412341234), + Value::String("a".into()) + ]), + v + ); + } +}