lerox: Consolidate traits

The auto-implementation scheme doesn't really fit the application
This commit is contained in:
John 2023-09-25 13:52:21 -05:00
parent 8bc32896c9
commit 71053f1992
2 changed files with 34 additions and 27 deletions

View File

@ -1,13 +1,22 @@
//! Lerox is a stupid, simple combinator library, part of the Conlang project //! Lerox is a stupid, simple combinator library, part of the Conlang project
pub trait Combinable { /// The core trait of Lerox, [Combinator], generically implements a handful of simple
/// Evaluates the [Combinable], and returns whether it is alright /// combinators for your type based on two required functions:
/// - [`is_alright(&self) -> bool`](Combinator::is_alright) performs some unspecified *evaluation*
/// on `self`, and returns true if `self` is valid for your problem domain.
/// - [`into_alright(self) -> Self`](Combinator::into_alright) performs some unspecified
/// *transformation* of `self` into an alright version of `self` (that is, one which satisfies
/// [`self.is_alright()`](Combinator::is_alright) == `true`)
pub trait Combinator: Sized {
/// Evaluates the [Combinator], and returns whether it is alright.
///
/// This is the basis for [Combinator]'s [and*](Combinator::and())/[or*](Combinator::or())
/// behaviors, and is like a generic form of [Option::is_some()] or [Result::is_ok()]
fn is_alright(&self) -> bool; fn is_alright(&self) -> bool;
/// Makes this [Combinable] alright, somehow
fn alright(self) -> Self;
}
pub trait Combinator: Combinable + Sized { /// Does something to make this [Combinator] [alright](Combinator::is_alright())
fn into_alright(self) -> Self;
/// If self is alright, runs f(self) /// If self is alright, runs f(self)
fn and(self, f: impl Fn(Self) -> Self) -> Self { fn and(self, f: impl Fn(Self) -> Self) -> Self {
match self.is_alright() { match self.is_alright() {
@ -16,14 +25,29 @@ pub trait Combinator: Combinable + Sized {
} }
} }
/// If self is not alright, runs f(self) /// If self is not alright, runs f(self) as if it were alright
fn or(self, f: impl FnOnce(Self) -> Self) -> Self { fn or(self, f: impl FnOnce(Self) -> Self) -> Self {
match self.is_alright() { match self.is_alright() {
true => self, true => self,
false => f(self), false => f(self.into_alright()),
} }
} }
/// Repeats the function f on self until it would fail
fn and_any(self, f: impl Fn(Self) -> Self) -> Self {
self.and(|mut this| {
while this.is_alright() {
this = this.and(&f)
}
this.into_alright()
})
}
/// Repeats the function f on self at least once, then until it fails.
fn and_many(self, f: impl Fn(Self) -> Self) -> Self {
self.and(&f).and_any(f)
}
/// Returns the result of running f on self, or if it fails, the original self /// Returns the result of running f on self, or if it fails, the original self
fn and_maybe(self, f: impl Fn(Self) -> Self) -> Self fn and_maybe(self, f: impl Fn(Self) -> Self) -> Self
where Self: Clone { where Self: Clone {
@ -35,21 +59,4 @@ pub trait Combinator: Combinable + Sized {
where Self: Clone { where Self: Clone {
self.clone().and(f).or(|_| g(self)) self.clone().and(f).or(|_| g(self))
} }
/// Repeats the function f on self until it fails
fn and_any(self, f: impl Fn(Self) -> Self) -> Self {
self.and(|mut this| {
while this.is_alright() {
this = this.and(&f)
}
this.alright()
})
}
/// Repeats the function f on self at least once, then until it fails.
fn and_many(self, f: impl Fn(Self) -> Self) -> Self {
self.and(&f).and_any(f)
}
} }
impl<C: Combinable> Combinator for C {}

View File

@ -133,11 +133,11 @@ pub mod lexer {
} }
} }
impl<'t> lerox::Combinable for Rule<'t> { impl<'t> lerox::Combinator for Rule<'t> {
fn is_alright(&self) -> bool { fn is_alright(&self) -> bool {
self.is_alright self.is_alright
} }
fn alright(self) -> Self { fn into_alright(self) -> Self {
Self { is_alright: true, ..self } Self { is_alright: true, ..self }
} }
} }