Added directfs

Added a very rudimentary file I/O system suitable for experimenting
with the language further. A better one will be designed when we have
sensible error management.
This commit is contained in:
2023-09-17 16:37:39 +01:00
parent 1078835e8b
commit 7396078304
84 changed files with 563 additions and 721 deletions

View File

@@ -5,9 +5,7 @@
mod monotype;
mod multitype;
mod token;
// mod traits;
pub use monotype::TypedInterner;
pub use multitype::Interner;
pub use token::Tok;
// pub use traits::{DisplayBundle, InternedDisplay, InternedInto};

View File

@@ -15,11 +15,13 @@ pub struct TypedInterner<T: 'static + Eq + Hash + Clone> {
}
impl<T: Eq + Hash + Clone> TypedInterner<T> {
/// Create a fresh interner instance
#[must_use]
pub fn new() -> Rc<Self> {
Rc::new(Self { tokens: RefCell::new(HashMap::new()) })
}
/// Intern an object, returning a token
#[must_use]
pub fn i<Q: ?Sized + Eq + Hash + ToOwned<Owned = T>>(
self: &Rc<Self>,
q: &Q,
@@ -42,6 +44,7 @@ impl<T: Eq + Hash + Clone> TypedInterner<T> {
}
/// Helper function to compute hashes outside a hashmap
#[must_use]
fn compute_hash(
hash_builder: &impl BuildHasher,
key: &(impl Hash + ?Sized),

View File

@@ -8,7 +8,6 @@ use hashbrown::HashMap;
use super::monotype::TypedInterner;
use super::token::Tok;
// use super::InternedDisplay;
/// A collection of interners based on their type. Allows to intern any object
/// that implements [ToOwned]. Objects of the same type are stored together in a
@@ -18,9 +17,11 @@ pub struct Interner {
}
impl Interner {
/// Create a new interner
#[must_use]
pub fn new() -> Self { Self { interners: RefCell::new(HashMap::new()) } }
/// Intern something
#[must_use]
pub fn i<Q: ?Sized + Eq + Hash + ToOwned>(&self, q: &Q) -> Tok<Q::Owned>
where
Q::Owned: 'static + Eq + Hash + Clone + Borrow<Q>,
@@ -31,32 +32,10 @@ impl Interner {
}
/// Fully resolve a list of interned things.
#[must_use]
pub fn extern_all<T: 'static + Eq + Hash + Clone>(s: &[Tok<T>]) -> Vec<T> {
s.iter().map(|t| (**t).clone()).collect()
}
// /// A variant of `unwrap` using [InternedDisplay] to circumvent `unwrap`'s
// /// dependencyon [Debug]. For clarity, [expect] should be preferred.
// pub fn unwrap<T, E: InternedDisplay>(&self, result: Result<T, E>) -> T {
// result.unwrap_or_else(|e| {
// println!("Unwrapped Error: {}", e.bundle(self));
// panic!("Unwrapped an error");
// })
// }
// /// A variant of `expect` using [InternedDisplay] to circumvent `expect`'s
// /// depeendency on [Debug].
// pub fn expect<T, E: InternedDisplay>(
// &self,
// result: Result<T, E>,
// msg: &str,
// ) -> T {
// result.unwrap_or_else(|e| {
// println!("Expectation failed: {msg}");
// println!("Error: {}", e.bundle(self));
// panic!("Expected an error");
// })
// }
}
impl Default for Interner {
@@ -64,6 +43,7 @@ impl Default for Interner {
}
/// Get or create an interner for a given type.
#[must_use]
fn get_interner<T: 'static + Eq + Hash + Clone>(
interners: &mut RefMut<HashMap<TypeId, Rc<dyn Any>>>,
) -> Rc<TypedInterner<T>> {

View File

@@ -18,15 +18,18 @@ pub struct Tok<T: Eq + Hash + Clone + 'static> {
}
impl<T: Eq + Hash + Clone + 'static> Tok<T> {
/// Create a new token. Used exclusively by the interner
#[must_use]
pub(crate) fn new(data: Rc<T>, interner: Weak<TypedInterner<T>>) -> Self {
Self { data, interner }
}
/// Take the ID number out of a token
#[must_use]
pub fn id(&self) -> NonZeroUsize {
((self.data.as_ref() as *const T as usize).try_into())
.expect("Pointer can always be cast to nonzero")
}
/// Cast into usize
#[must_use]
pub fn usize(&self) -> usize { self.id().into() }
///
pub fn assert_comparable(&self, other: &Self) {

View File

@@ -1,69 +0,0 @@
use core::fmt::{self, Display, Formatter};
use core::ops::Deref;
use std::rc::Rc;
use crate::interner::Interner;
/// A variant of [std::fmt::Display] for objects that contain interned
/// strings and therefore can only be stringified in the presence of a
/// string interner
///
/// The functions defined here are suffixed to distinguish them from
/// the ones in Display and ToString respectively, because Rust can't
/// identify functions based on arity
pub trait InternedDisplay {
/// formats the value using the given formatter and string interner
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result;
/// Converts the value to a string to be displayed
fn to_string_i(&self, i: &Interner) -> String {
self.bundle(i).to_string()
}
/// Combine with an interner to implement [Display]
fn bundle<'a>(&'a self, interner: &'a Interner) -> DisplayBundle<'a, Self> {
DisplayBundle { interner, data: self }
}
}
// Special loophole for Rc<dyn ProjectError>
impl<T: ?Sized> InternedDisplay for Rc<T>
where
T: InternedDisplay,
{
fn fmt_i(&self, f: &mut Formatter<'_>, i: &Interner) -> fmt::Result {
self.deref().fmt_i(f, i)
}
}
/// A reference to an [InternedDisplay] type and an [Interner] tied together
/// to implement [Display]
pub struct DisplayBundle<'a, T: InternedDisplay + ?Sized> {
interner: &'a Interner,
data: &'a T,
}
impl<'a, T: InternedDisplay + ?Sized> Display for DisplayBundle<'a, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.data.fmt_i(f, self.interner)
}
}
/// Conversions that are possible in the presence of an interner
///
/// Essentially, this allows to define abstractions over interned and
/// non-interned versions of a type and convert between them
pub trait InternedInto<U> {
/// Execute the conversion
fn into_i(self, i: &Interner) -> U;
}
impl<T: Into<U>, U> InternedInto<U> for T {
fn into_i(self, _i: &Interner) -> U {
self.into()
}
}