Skip to content

Commit

Permalink
A first impl of CharTable (#106)
Browse files Browse the repository at this point in the history
* A first implementation of CharTable

* Implement Trace, CloneIn, and IntoObject for CharTable

* Implement display_walk for LispChartable

* Create todo!() aset/aref for ObjectType::CharTable

* Implemented aref for LispCharTable

* Fix clippy elided lifetime

* Rename LispCharTable and CharTable

* Return NIL in data.rs instead of get in chartab

* defsym! CHAR_TABLE

* Implement Display for CharTable and remove display_walk

* Wrap data of CharTableInner with RefCell

---------

Co-authored-by: Troy Hinckley <[email protected]>
  • Loading branch information
hesampakdaman and CeleritasCelery authored Jan 31, 2025
1 parent 44aedd4 commit a97f4eb
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 4 deletions.
7 changes: 7 additions & 0 deletions src/chartab.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use crate::core::object::{CharTableInner, Object, Symbol};
use rune_macros::defun;

#[defun]
fn make_char_table<'ob>(_purpose: Symbol<'ob>, init: Option<Object<'ob>>) -> CharTableInner<'ob> {
CharTableInner::new(init)
}
1 change: 1 addition & 0 deletions src/core/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub(crate) enum Type {
Number,
List,
Buffer,
CharTable,
}

/// Error provided if object was the wrong type
Expand Down
8 changes: 8 additions & 0 deletions src/core/gc/trace.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::cell::RefCell;

use super::super::object::RawObj;
use crate::core::object::{Gc, Object};
use rune_core::hashmap::{HashMap, HashSet};
Expand Down Expand Up @@ -77,6 +79,12 @@ impl<T: Trace> Trace for Vec<T> {
}
}

impl<T: Trace> Trace for RefCell<T> {
fn trace(&self, state: &mut GcState) {
self.borrow().trace(state);
}
}

impl<T: Trace> Trace for std::collections::VecDeque<T> {
fn trace(&self, state: &mut GcState) {
for x in self {
Expand Down
2 changes: 2 additions & 0 deletions src/core/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
mod buffer;
mod cell;
mod chartab;
mod convert;
mod float;
mod func;
Expand All @@ -22,6 +23,7 @@ mod vector;

pub(crate) use buffer::*;
pub(super) use cell::*;
pub(crate) use chartab::*;
pub(crate) use convert::*;
pub(crate) use float::*;
pub(crate) use func::*;
Expand Down
83 changes: 83 additions & 0 deletions src/core/object/chartab.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
use super::{CloneIn, Gc, IntoObject, Object, WithLifetime};
use crate::{
core::gc::{Block, GcHeap, Slot},
derive_markable,
};
use rune_core::hashmap::HashMap;
use rune_macros::Trace;
use std::{cell::RefCell, fmt};

#[derive(Debug, Eq, Trace)]
pub struct CharTableInner<'ob> {
parent: Option<Slot<&'ob CharTable>>,
data: RefCell<HashMap<usize, Object<'ob>>>,
init: Option<Object<'ob>>,
}

impl<'ob> CharTableInner<'ob> {
pub fn new(init: Option<Object<'ob>>) -> Self {
CharTableInner { parent: None, data: RefCell::new(HashMap::default()), init }
}
}

#[derive(PartialEq, Eq, Trace, Debug)]
pub(crate) struct CharTable(GcHeap<CharTableInner<'static>>);

derive_markable!(CharTable);

impl PartialEq for CharTableInner<'_> {
fn eq(&self, other: &Self) -> bool {
std::ptr::eq(self, other)
}
}

impl<'new> CloneIn<'new, &'new Self> for CharTable {
fn clone_in<const C: bool>(&self, bk: &'new Block<C>) -> Gc<&'new Self> {
let parent = self.0.parent.as_ref().map(|p| Slot::new(p.clone_in(bk).untag()));

let mut data = HashMap::default();
for (key, value) in self.0.data.borrow().iter() {
let new_value = value.clone_in(bk);
data.insert(*key, new_value);
}
let data = RefCell::new(data);
let init = self.0.init.map(|i| i.clone_in(bk));
CharTableInner { parent, data, init }.into_obj(bk)
}
}

impl CharTable {
pub(in crate::core) unsafe fn new(table: CharTableInner<'_>, constant: bool) -> Self {
// transmute lifetime to static
let table =
unsafe { std::mem::transmute::<CharTableInner<'_>, CharTableInner<'static>>(table) };
Self(GcHeap::new(table, constant))
}

pub fn get(&self, idx: usize) -> Option<Object> {
self.0.data.borrow().get(&idx).copied().or(self.0.init)
}

pub fn set(&self, idx: usize, item: Object) {
unsafe { self.0.data.borrow_mut().insert(idx, item.with_lifetime()) };
}
}

impl fmt::Display for CharTable {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[")?;
let data = self.0.data.borrow();

let mut entries: Vec<_> = data.iter().collect();
entries.sort_by_key(|&(key, _)| key);

let mut iter = entries.into_iter();
if let Some((_, first)) = iter.next() {
write!(f, "{}", first)?;
for (_, value) in iter {
write!(f, " {}", value)?;
}
}
write!(f, "]")
}
}
54 changes: 50 additions & 4 deletions src/core/object/tagged.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ use super::{
error::{Type, TypeError},
gc::Block,
},
ByteFnPrototype, ByteString, GcString, LispBuffer,
ByteFnPrototype, ByteString, CharTableInner, GcString, LispBuffer,
};
use super::{
ByteFn, HashTable, LispFloat, LispHashTable, LispString, LispVec, Record, RecordBuilder,
SubrFn, Symbol, SymbolCell,
ByteFn, CharTable, HashTable, LispFloat, LispHashTable, LispString, LispVec, Record,
RecordBuilder, SubrFn, Symbol, SymbolCell,
};
use crate::core::{
env::sym,
Expand Down Expand Up @@ -292,6 +292,7 @@ object_trait_impls!(LispVec);
object_trait_impls!(Record);
object_trait_impls!(LispHashTable);
object_trait_impls!(LispBuffer);
object_trait_impls!(CharTable);

/// Trait for types that can be managed by the GC. This trait is implemented for
/// as many types as possible, even for types that are already Gc managed, Like
Expand Down Expand Up @@ -504,6 +505,17 @@ impl IntoObject for HashTable<'_> {
}
}

impl IntoObject for CharTableInner<'_> {
type Out<'ob> = &'ob CharTable;

fn into_obj<const C: bool>(self, block: &Block<C>) -> Gc<Self::Out<'_>> {
unsafe {
let ptr = block.objects.alloc(CharTable::new(self, C));
<Self::Out<'_>>::tag_ptr(ptr)
}
}
}

mod private {
use super::{Gc, WithLifetime};

Expand All @@ -522,6 +534,7 @@ mod private {
SubrFn,
ByteFn,
Buffer,
CharTable,
}

/// Trait for tagged pointers. Anything that can be stored and passed around
Expand Down Expand Up @@ -628,6 +641,7 @@ impl<'a> TaggedPtr for ObjectType<'a> {
Tag::Record => ObjectType::Record(<&Record>::from_obj_ptr(ptr)),
Tag::HashTable => ObjectType::HashTable(<&LispHashTable>::from_obj_ptr(ptr)),
Tag::Buffer => ObjectType::Buffer(<&LispBuffer>::from_obj_ptr(ptr)),
Tag::CharTable => ObjectType::CharTable(<&CharTable>::from_obj_ptr(ptr)),
}
}
}
Expand All @@ -646,6 +660,7 @@ impl<'a> TaggedPtr for ObjectType<'a> {
ObjectType::ByteFn(x) => TaggedPtr::tag(x).into(),
ObjectType::SubrFn(x) => TaggedPtr::tag(x).into(),
ObjectType::Buffer(x) => TaggedPtr::tag(x).into(),
ObjectType::CharTable(x) => TaggedPtr::tag(x).into(),
}
}
}
Expand Down Expand Up @@ -900,6 +915,19 @@ impl TaggedPtr for &LispBuffer {
}
}

impl TaggedPtr for &CharTable {
type Ptr = CharTable;
const TAG: Tag = Tag::CharTable;

unsafe fn from_obj_ptr(ptr: *const u8) -> Self {
&*ptr.cast::<Self::Ptr>()
}

fn get_ptr(self) -> *const Self::Ptr {
self as *const Self::Ptr
}
}

macro_rules! cast_gc {
($supertype:ty => $($subtype:ty),+ $(,)?) => {
$(
Expand Down Expand Up @@ -1012,6 +1040,7 @@ pub(crate) enum ObjectType<'ob> {
ByteFn(&'ob ByteFn) = Tag::ByteFn as u8,
SubrFn(&'static SubrFn) = Tag::SubrFn as u8,
Buffer(&'static LispBuffer) = Tag::Buffer as u8,
CharTable(&'static CharTable) = Tag::CharTable as u8,
}

/// The Object defintion that contains all other possible lisp objects. This
Expand All @@ -1032,7 +1061,8 @@ cast_gc!(ObjectType<'ob> => NumberType<'ob>,
&'ob ByteString,
&'ob ByteFn,
&'ob SubrFn,
&'ob LispBuffer
&'ob LispBuffer,
&'ob CharTable
);

impl ObjectType<'_> {
Expand All @@ -1052,6 +1082,7 @@ impl ObjectType<'_> {
ObjectType::ByteString(_) => Type::String,
ObjectType::ByteFn(_) | ObjectType::SubrFn(_) => Type::Func,
ObjectType::Buffer(_) => Type::Buffer,
ObjectType::CharTable(_) => Type::CharTable,
}
}
}
Expand Down Expand Up @@ -1301,6 +1332,17 @@ impl<'ob> TryFrom<Object<'ob>> for Gc<&'ob LispBuffer> {
}
}

impl<'ob> TryFrom<Object<'ob>> for Gc<&'ob CharTable> {
type Error = TypeError;

fn try_from(value: Object<'ob>) -> Result<Self, Self::Error> {
match value.get_tag() {
Tag::CharTable => unsafe { Ok(cast_gc(value)) },
_ => Err(TypeError::new(Type::String, value)),
}
}
}

impl<'ob> std::ops::Deref for Gc<&'ob Cons> {
type Target = Cons;

Expand Down Expand Up @@ -1336,6 +1378,7 @@ where
ObjectType::Record(x) => x.clone_in(bk).into(),
ObjectType::HashTable(x) => x.clone_in(bk).into(),
ObjectType::Buffer(x) => x.clone_in(bk).into(),
ObjectType::CharTable(x) => x.clone_in(bk).into(),
};
let Ok(x) = Gc::<U>::try_from(obj) else { unreachable!() };
x
Expand All @@ -1356,6 +1399,7 @@ impl<T> Trace for Gc<T> {
ObjectType::Symbol(x) => x.trace(state),
ObjectType::ByteFn(x) => x.trace(state),
ObjectType::Buffer(x) => x.trace(state),
ObjectType::CharTable(x) => x.trace(state),
}
}
}
Expand Down Expand Up @@ -1393,6 +1437,7 @@ impl Markable for Object<'_> {
let (sym, moved) = x.move_value(to_space)?;
(sym.as_ptr(), moved)
}
ObjectType::CharTable(x) => cast_pair(x.move_value(to_space)?),
};

let tag = self.get_tag();
Expand Down Expand Up @@ -1595,6 +1640,7 @@ impl ObjectType<'_> {
ObjectType::SubrFn(x) => D::fmt(x, f),
ObjectType::Float(x) => D::fmt(x, f),
ObjectType::Buffer(x) => D::fmt(x, f),
ObjectType::CharTable(x) => D::fmt(x, f),
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,10 @@ pub(crate) fn aset<'ob>(
Err(anyhow!("index {idx} is out of bounds. Length was {len}"))
}
}
ObjectType::CharTable(table) => {
table.set(idx, newlet);
Ok(newlet)
}
x => Err(TypeError::new(Type::Sequence, x).into()),
}
}
Expand Down Expand Up @@ -374,6 +378,10 @@ pub(crate) fn aref<'ob>(array: Object<'ob>, idx: usize, cx: &'ob Context) -> Res
Some(x) => Ok(x),
None => Err(anyhow!("index {idx} is out of bounds")),
},
ObjectType::CharTable(chartable) => match chartable.get(idx) {
Some(x) => Ok(x),
None => Ok(NIL),
},
x => Err(TypeError::new(Type::Sequence, x).into()),
}
}
Expand All @@ -392,6 +400,7 @@ fn type_of(object: Object) -> Object {
ObjectType::String(_) | ObjectType::ByteString(_) => sym::STRING.into(),
ObjectType::SubrFn(_) => sym::SUBR.into(),
ObjectType::Buffer(_) => sym::BUFFER.into(),
ObjectType::CharTable(_) => sym::CHAR_TABLE.into(),
}
}

Expand Down Expand Up @@ -543,3 +552,4 @@ defsym!(COMPILED_FUNCTION);
defsym!(HASH_TABLE);
defsym!(BUFFER);
defsym!(SUBR);
defsym!(CHAR_TABLE);
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ mod buffer;
mod bytecode;
mod casefiddle;
mod character;
mod chartab;
mod data;
mod dired;
mod editfns;
Expand Down

0 comments on commit a97f4eb

Please sign in to comment.