Vector specialization

This commit is contained in:
2026-05-11 13:06:55 +03:00
parent 01012ae211
commit 4131cb121b
8 changed files with 438 additions and 30 deletions
+6 -1
View File
@@ -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<Vector>) -> Result<CompileValue, CompileError> {
Ok(CompileValue::Quote(Rc::new(Value::Vector(vector.clone()))))
}
pub fn compile_expression(
&mut self,
expression: &Rc<Expression>,
@@ -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!(),
+4 -2
View File
@@ -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<Vector>),
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<ParseError> 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(_)
+6
View File
@@ -0,0 +1,6 @@
use crate::vm::value::Value;
#[derive(Debug, PartialEq)]
pub struct VectorExpression {
pub elements: Vec<Value>,
}
+14 -1
View File
@@ -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,
+1 -1
View File
@@ -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())),
}
}
}
+38
View File
@@ -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| {
+41 -1
View File
@@ -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<String, MachineErrorKind> {
match self {
Self::Integer(value) => Ok(format!("{value}")),
+328 -24
View File
@@ -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<Vec<Value>>);
impl Hash for Vector {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.borrow().hash(state);
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum VectorStorage {
I8(Vec<i8>),
I16(Vec<i16>),
I32(Vec<i32>),
I64(Vec<i64>),
Any(Vec<Value>),
}
#[derive(Debug, PartialEq, Eq)]
pub struct Vector(RefCell<VectorStorage>);
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<Value> for Vector {
fn from_iter<T: IntoIterator<Item = Value>>(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<Value> {
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<Vec<Value>>;
fn deref(&self) -> &Self::Target {
&self.0
impl Hash for Vector {
fn hash<H: Hasher>(&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<A> FromIterator<A> for Vector
where
VectorStorage: FromIterator<A>,
{
fn from_iter<T: IntoIterator<Item = A>>(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::<Vec<_>>();
$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::<Vec<_>>();
$f;
*$self = Self::I32($storage);
}
Self::I8($storage) => {
let mut $storage = $storage.iter().copied().map(Into::into).collect::<Vec<_>>();
$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::<Vec<_>>();
$f;
*$self = Self::I32($storage);
}
Self::I16($storage) => {
let mut $storage = $storage.iter().copied().map(Into::into).collect::<Vec<_>>();
$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::<Vec<_>>();
$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::<Vec<_>>();
$f;
*$self = Self::Any($storage);
}
Self::I16($storage) => {
let mut $storage = $storage
.iter()
.copied()
.map(Into::into)
.map(Value::Integer)
.collect::<Vec<_>>();
$f;
*$self = Self::Any($storage);
}
Self::I32($storage) => {
let mut $storage = $storage
.iter()
.copied()
.map(Into::into)
.map(Value::Integer)
.collect::<Vec<_>>();
$f;
*$self = Self::Any($storage);
}
Self::I64($storage) => {
let mut $storage = $storage
.iter()
.copied()
.map(Value::Integer)
.collect::<Vec<_>>();
$f;
*$self = Self::Any($storage);
}
Self::Any($storage) => {
$f;
}
}
};
}
impl VectorStorage {
fn value_at(&self, index: usize) -> Option<Value> {
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<Value> for VectorStorage {
fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
let mut accumulator = Self::I8(vec![]);
for item in iter {
accumulator.push(item);
}
accumulator
}
}
fn display_vector<T: fmt::Display>(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<T: IntoIterator<Item = $signed_ty>>(iter: T) -> Self {
Self::$variant(iter.into_iter().collect())
}
}
impl FromIterator<$unsigned_ty> for VectorStorage {
fn from_iter<T: IntoIterator<Item = $unsigned_ty>>(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
);
}
}