added visitor protocols
Konnor Andrews 2024-02-03
parent b6be0b9 · commit c076f01
-rw-r--r--src/build/protocols.rs94
-rw-r--r--src/builtins.rs2
-rw-r--r--src/builtins/visitor.rs5
-rw-r--r--src/builtins/visitor/borrow.rs116
-rw-r--r--src/builtins/visitor/request_hint.rs23
-rw-r--r--src/builtins/visitor/sequence.rs40
-rw-r--r--src/builtins/visitor/tagged.rs37
-rw-r--r--src/builtins/visitor/value.rs41
-rw-r--r--src/builtins/walker.rs1
-rw-r--r--src/builtins/walker/hint.rs45
-rw-r--r--src/lib.rs1
-rw-r--r--src/walk/protocols.rs43
12 files changed, 311 insertions, 137 deletions
diff --git a/src/build/protocols.rs b/src/build/protocols.rs
index 30dc074..fbd4fc0 100644
--- a/src/build/protocols.rs
+++ b/src/build/protocols.rs
@@ -1,33 +1,4 @@
pub mod hint {
- use crate::protocol::{Implementer, Protocol};
-
- /// Protocol for requesting a visitor give a hint.
- ///
- /// This protocol is implemented by visitors.
- ///
- /// Some walkers don't know what the data they are walking actually represents.
- /// This protocol allows such walkers to request the visitor to give a hint of what
- /// it is expecting.
- ///
- /// This can also be paired with the [`Recoverable`][super::recoverable::Recoverable]
- /// protocol to place the walker in a recoverable mode for the visitor to try multiple
- /// protocols.
- pub enum RequestHint {}
-
- /// Object implementing the [`RequestHint`] protocol.
- pub trait RequestHintObject<'ctx> {
- /// Call this to request a hint.
- ///
- /// `hints` is expected to be the walker. This is what the visitor (`Self`)
- /// will call to give a hint using the [`Hint`] protocol.
- ///
- /// `needs_hints` can be `false` if the walker can continue without a hint.
- fn request_hint(&mut self, hints: &mut dyn Implementer<'ctx>) -> Result<(), ()>;
- }
-
- impl Protocol for RequestHint {
- type Object<'a, 'ctx: 'a> = &'a mut dyn RequestHintObject<'ctx>;
- }
}
pub mod recoverable {
@@ -90,45 +61,6 @@ pub mod owned {
}
pub mod borrowed {
- use core::marker::PhantomData;
-
- use crate::{protocol::Protocol, walk::protocols::hint::Meta};
-
- pub struct Borrowed<T: 'static>(PhantomData<fn() -> T>);
-
- pub enum Value<'a, 'ctx, T: 'static> {
- Temp(&'a T),
- Context(&'ctx T),
- Static(&'static T),
- }
-
- pub trait Object<'ctx, T: 'static> {
- fn visit(&mut self, value: Value<'_, 'ctx, T>) -> Result<(), ()>;
- }
-
- impl<T: 'static> Protocol for Borrowed<T> {
- type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx, T>;
- }
-
- pub enum Kind {
- Temp,
- Context,
- Static,
- }
-
- pub struct Known {
- pub kind: Option<Kind>,
- }
-
- pub struct Hint {
- pub kind: Option<Kind>,
- }
-
- impl<T: 'static> Meta for Borrowed<T> {
- type Known<'a, 'ctx: 'a> = Known;
-
- type Hint<'a, 'ctx: 'a> = Hint;
- }
}
pub mod borrowed_mut {
@@ -174,32 +106,6 @@ pub mod borrowed_mut {
}
pub mod tagged {
- use crate::{
- protocol::{Implementer, Protocol},
- walk::protocols::hint::Meta,
- };
-
- pub enum Tagged {}
-
- pub trait TaggedWalker<'ctx> {
- fn walk_tag(&mut self, visitor: &mut dyn Implementer<'ctx>) -> Result<(), ()>;
-
- fn walk_value(&mut self, visitor: &mut dyn Implementer<'ctx>) -> Result<(), ()>;
- }
-
- pub trait Object<'ctx> {
- fn visit(&mut self, walker: &mut dyn TaggedWalker<'ctx>) -> Result<(), ()>;
- }
-
- impl Protocol for Tagged {
- type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx>;
- }
-
- impl Meta for Tagged {
- type Known<'a, 'ctx: 'a> = ();
-
- type Hint<'a, 'ctx: 'a> = ();
- }
}
pub mod sequence {
diff --git a/src/builtins.rs b/src/builtins.rs
new file mode 100644
index 0000000..3a5e50e
--- /dev/null
+++ b/src/builtins.rs
@@ -0,0 +1,2 @@
+pub mod visitor;
+pub mod walker;
diff --git a/src/builtins/visitor.rs b/src/builtins/visitor.rs
new file mode 100644
index 0000000..d36c3a6
--- /dev/null
+++ b/src/builtins/visitor.rs
@@ -0,0 +1,5 @@
+pub mod request_hint;
+pub mod sequence;
+pub mod tagged;
+pub mod value;
+pub mod borrow;
diff --git a/src/builtins/visitor/borrow.rs b/src/builtins/visitor/borrow.rs
new file mode 100644
index 0000000..511d429
--- /dev/null
+++ b/src/builtins/visitor/borrow.rs
@@ -0,0 +1,116 @@
+//! Protocol for giving a visitor a borrowed value.
+
+use core::marker::PhantomData;
+
+use crate::{builtins::walker::hint::Meta, protocol::Protocol};
+
+pub struct Value<T: ?Sized>(PhantomData<fn() -> *const T>);
+
+pub enum Kind<'a, 'ctx: 'a, T: ?Sized> {
+ Temp(&'a T),
+ Context(&'ctx T),
+ TempMut(&'a mut T),
+ ContextMut(&'ctx mut T),
+}
+
+impl<'a, 'ctx, T: ?Sized> Kind<'a, 'ctx, T> {
+ pub fn into_temp(self) -> &'a T {
+ use Kind as K;
+ match self {
+ K::Temp(v) | K::Context(v) => v,
+ K::TempMut(v) | K::ContextMut(v) => v,
+ }
+ }
+
+ pub fn into_context(self) -> Result<&'ctx T, Self> {
+ use Kind as K;
+ match self {
+ K::Context(v) => Ok(v),
+ K::ContextMut(v) => Ok(v),
+ this @ (K::Temp(_) | K::TempMut(_)) => Err(this),
+ }
+ }
+
+ pub fn into_temp_mut(self) -> Result<&'a mut T, Self> {
+ use Kind as K;
+ match self {
+ K::TempMut(v) | K::ContextMut(v) => Ok(v),
+ this @ (K::Temp(_) | K::Context(_)) => Err(this),
+ }
+ }
+
+ pub fn into_context_mut(self) -> Result<&'ctx mut T, Self> {
+ use Kind as K;
+ match self {
+ K::ContextMut(v) => Ok(v),
+ this @ (K::Temp(_) | K::Context(_) | K::TempMut(_)) => {
+ Err(this)
+ }
+ }
+ }
+
+ pub fn variant(&self) -> KindVariants {
+ use Kind as K;
+ use KindVariants as V;
+ match self {
+ K::Temp(_) => V::Temp,
+ K::Context(_) => V::Context,
+ K::TempMut(_) => V::TempMut,
+ K::ContextMut(_) => V::ContextMut,
+ }
+ }
+}
+
+pub trait Object<'ctx, T: 'static> {
+ fn visit(&mut self, value: Kind<'_, 'ctx, T>) -> Result<(), ()>;
+}
+
+impl<T: 'static> Protocol for Value<T> {
+ type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx, T>;
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+pub enum KindVariants {
+ Temp,
+ Context,
+ TempMut,
+ ContextMut,
+}
+
+impl KindVariants {
+ pub fn can_become(&self, wanted: Self) -> bool {
+ use KindVariants as V;
+ match (self, wanted) {
+ (V::Temp, V::Temp) => true,
+ (V::Temp, V::Context) => false,
+ (V::Temp, V::TempMut) => false,
+ (V::Temp, V::ContextMut) => false,
+ (V::Context, V::Temp) => true,
+ (V::Context, V::Context) => true,
+ (V::Context, V::TempMut) => false,
+ (V::Context, V::ContextMut) => false,
+ (V::TempMut, V::Temp) => true,
+ (V::TempMut, V::Context) => false,
+ (V::TempMut, V::TempMut) => true,
+ (V::TempMut, V::ContextMut) => false,
+ (V::ContextMut, V::Temp) => true,
+ (V::ContextMut, V::Context) => true,
+ (V::ContextMut, V::TempMut) => true,
+ (V::ContextMut, V::ContextMut) => true,
+ }
+ }
+}
+
+pub struct Known {
+ pub kind: Option<KindVariants>,
+}
+
+pub struct Hint {
+ pub kind: Option<KindVariants>,
+}
+
+impl<T: 'static> Meta for Value<T> {
+ type Known<'a, 'ctx: 'a> = Known;
+
+ type Hint<'a, 'ctx: 'a> = Hint;
+}
diff --git a/src/builtins/visitor/request_hint.rs b/src/builtins/visitor/request_hint.rs
new file mode 100644
index 0000000..6ab797a
--- /dev/null
+++ b/src/builtins/visitor/request_hint.rs
@@ -0,0 +1,23 @@
+//! Protocol for requesting a visitor give a hint to walker.
+///
+/// Some walkers don't know what the data they are walking actually represents.
+/// This protocol allows such walkers to request the visitor to give a hint of what
+/// it is expecting.
+use crate::protocol::{Implementer, Protocol};
+
+/// Protocol for requesting a visitor give a hint.
+pub enum RequestHint {}
+
+/// Object implementing the [`RequestHint`] protocol.
+pub trait RequestHintObject<'ctx> {
+ /// Call this to request a hint.
+ ///
+ /// `hints` is expected to be the walker. This is what the visitor (`Self`)
+ /// will call to give a hint using the
+ /// [`Hint`][crate::builtins::walker::hint::Hint] protocol.
+ fn request_hint(&mut self, hints: &mut dyn Implementer<'ctx>) -> Result<(), ()>;
+}
+
+impl Protocol for RequestHint {
+ type Object<'a, 'ctx: 'a> = &'a mut dyn RequestHintObject<'ctx>;
+}
diff --git a/src/builtins/visitor/sequence.rs b/src/builtins/visitor/sequence.rs
new file mode 100644
index 0000000..b143c12
--- /dev/null
+++ b/src/builtins/visitor/sequence.rs
@@ -0,0 +1,40 @@
+
+use crate::{
+ builtins::walker::hint::Meta,
+ protocol::{Implementer, Protocol},
+};
+
+pub enum Sequence {}
+
+#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)]
+pub enum Status {
+ Done,
+ Continue,
+}
+
+pub trait SequenceWalker<'ctx> {
+ fn next(&mut self, visitor: &mut dyn Implementer<'ctx>) -> Result<Status, ()>;
+}
+
+pub trait Object<'ctx> {
+ fn visit(&mut self, walker: &mut dyn SequenceWalker<'ctx>) -> Result<(), ()>;
+}
+
+impl Protocol for Sequence {
+ type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx>;
+}
+
+#[derive(Default)]
+pub struct Known {
+ pub len: (usize, Option<usize>),
+}
+
+pub struct Hint {
+ pub len: (usize, Option<usize>),
+}
+
+impl Meta for Sequence {
+ type Known<'a, 'ctx: 'a> = Known;
+
+ type Hint<'a, 'ctx: 'a> = Hint;
+}
diff --git a/src/builtins/visitor/tagged.rs b/src/builtins/visitor/tagged.rs
new file mode 100644
index 0000000..c447a5f
--- /dev/null
+++ b/src/builtins/visitor/tagged.rs
@@ -0,0 +1,37 @@
+use crate::{
+ builtins::walker::hint::Meta,
+ protocol::{Implementer, Protocol},
+ symbol::Symbol,
+};
+
+pub enum Tagged {}
+
+pub trait TaggedWalker<'ctx> {
+ fn kind(&mut self) -> Symbol;
+
+ fn walk_tag(&mut self, visitor: &mut dyn Implementer<'ctx>) -> Result<(), ()>;
+
+ fn walk_value(&mut self, visitor: &mut dyn Implementer<'ctx>) -> Result<(), ()>;
+}
+
+pub trait Object<'ctx> {
+ fn visit(&mut self, walker: &mut dyn TaggedWalker<'ctx>) -> Result<(), ()>;
+}
+
+impl Protocol for Tagged {
+ type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx>;
+}
+
+pub struct Known {
+ pub kind_available: Option<bool>,
+}
+
+pub struct Hint {
+ pub kind: Option<Symbol>,
+}
+
+impl Meta for Tagged {
+ type Known<'a, 'ctx: 'a> = Known;
+
+ type Hint<'a, 'ctx: 'a> = Hint;
+}
diff --git a/src/builtins/visitor/value.rs b/src/builtins/visitor/value.rs
new file mode 100644
index 0000000..6a1b450
--- /dev/null
+++ b/src/builtins/visitor/value.rs
@@ -0,0 +1,41 @@
+//! [`Protocol`] for giving a visitor an owned value.
+//!
+//! In some sense, this is the most basic protocol.
+
+use core::{marker::PhantomData, ops::ControlFlow};
+
+use crate::{builtins::walker::hint::Meta, protocol::Protocol};
+
+/// [`Protocol`] for giving a visitor an owned value.
+///
+/// A value of type `T` can be given to the visitor using
+/// [`Object::visit()`]. There is a restriction that `T: 'static`.
+pub struct Value<T>(PhantomData<fn() -> T>);
+
+/// Trait object for the [`Value`] protocol.
+///
+/// Types implementing the [`Value`] protocol will implement this trait.
+pub trait Object<'ctx, T> {
+ /// Visit a value of type `T`.
+ ///
+ /// Use this to give a value to a visitor. Its expected that a walker
+ /// only calls this once per usage of the trait object, but that is not
+ /// forced.
+ ///
+ /// If a [`ControlFlow::Break`] is returned then the walker
+ /// should stop walking as soon as possible as there has likely been
+ /// and error.
+ fn visit(&mut self, value: T) -> ControlFlow<()>;
+}
+
+// This is what makes Value a protocol.
+impl<T: 'static> Protocol for Value<T> {
+ type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx, T>;
+}
+
+// This enrolls the Value protocol into the walker hint system.
+impl<T: 'static> Meta for Value<T> {
+ type Known<'a, 'ctx: 'a> = ();
+
+ type Hint<'a, 'ctx: 'a> = ();
+}
diff --git a/src/builtins/walker.rs b/src/builtins/walker.rs
new file mode 100644
index 0000000..a0216be
--- /dev/null
+++ b/src/builtins/walker.rs
@@ -0,0 +1 @@
+pub mod hint;
diff --git a/src/builtins/walker/hint.rs b/src/builtins/walker/hint.rs
new file mode 100644
index 0000000..42234e9
--- /dev/null
+++ b/src/builtins/walker/hint.rs
@@ -0,0 +1,45 @@
+//! Protocol for giving a hint to a walker.
+//!
+//! Sometimes a walker has multiple protocols it could use,
+//! this module gives a protocol by which a visitor can give a hint
+//! to the walker about what it is expecting.
+
+use crate::protocol::{Implementer, Protocol};
+
+/// Protocol for giving a hint to a walker.
+///
+/// A hint is for a particular protocol `P`.
+pub struct Hint<P: Meta>(P);
+
+/// Meta information for the hint.
+///
+/// This gives the visitor more information to work from when selecting a hint.
+pub trait Meta: Protocol {
+ /// Information known by the walker.
+ ///
+ /// This should be information easy to get without changing the state of the walker
+ /// in an irreversable way.
+ type Known<'a, 'ctx: 'a>;
+
+ /// Extra information the visitor can give to the walker about what it is expecting.
+ type Hint<'a, 'ctx: 'a>;
+}
+
+/// Object implementing the [`Hint`] protocol.
+pub trait Object<'ctx, P: Meta> {
+ /// Hint to the walker to use the `P` protocol.
+ ///
+ /// This should only be called once per [`RequestHint`].
+ fn hint(
+ &mut self,
+ visitor: &mut dyn Implementer<'ctx>,
+ hint: P::Hint<'_, 'ctx>,
+ ) -> Result<(), ()>;
+
+ /// Ask the walker for information about it's support of the protocol.
+ fn known(&mut self, hint: &P::Hint<'_, 'ctx>) -> Result<P::Known<'_, 'ctx>, ()>;
+}
+
+impl<P: Meta> Protocol for Hint<P> {
+ type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx, P>;
+}
diff --git a/src/lib.rs b/src/lib.rs
index 6e564fc..3f7f59a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -7,6 +7,7 @@
extern crate alloc;
mod build;
+pub mod builtins;
pub mod protocol;
pub mod symbol;
mod walk;
diff --git a/src/walk/protocols.rs b/src/walk/protocols.rs
index 39e5faa..e69de29 100644
--- a/src/walk/protocols.rs
+++ b/src/walk/protocols.rs
@@ -1,43 +0,0 @@
-pub mod hint {
- use crate::protocol::{Implementer, Protocol};
-
- /// Protocol for giving a hint to a walker.
- ///
- /// This protocol is implemented by walkers.
- ///
- /// A hint is for a particular protocol `P`.
- pub struct Hint<P: Meta>(P);
-
- /// Meta information for the hint.
- ///
- /// This gives the visitor more information to work from when selecting a hint.
- pub trait Meta: Protocol {
- /// Information known by the walker.
- ///
- /// This should be information easy to get without changing the state of the walker
- /// in a irreversable way.
- type Known<'a, 'ctx: 'a>;
-
- /// Extra information the visitor can give to the walker about what it is expecting.
- type Hint<'a, 'ctx: 'a>;
- }
-
- /// Object implementing the [`Hint`] protocol.
- pub trait Object<'ctx, P: Meta> {
- /// Hint to the walker to use the `P` protocol.
- ///
- /// This should only be called once per [`RequestHint`].
- fn hint(
- &mut self,
- visitor: &mut dyn Implementer<'ctx>,
- hint: P::Hint<'_, 'ctx>,
- ) -> Result<(), ()>;
-
- /// Ask the walker for information about it's support of the protocol.
- fn known(&mut self, hint: &P::Hint<'_, 'ctx>) -> Result<P::Known<'_, 'ctx>, ()>;
- }
-
- impl<P: Meta> Protocol for Hint<P> {
- type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx, P>;
- }
-}