added visitor protocols
| -rw-r--r-- | src/build/protocols.rs | 94 | ||||
| -rw-r--r-- | src/builtins.rs | 2 | ||||
| -rw-r--r-- | src/builtins/visitor.rs | 5 | ||||
| -rw-r--r-- | src/builtins/visitor/borrow.rs | 116 | ||||
| -rw-r--r-- | src/builtins/visitor/request_hint.rs | 23 | ||||
| -rw-r--r-- | src/builtins/visitor/sequence.rs | 40 | ||||
| -rw-r--r-- | src/builtins/visitor/tagged.rs | 37 | ||||
| -rw-r--r-- | src/builtins/visitor/value.rs | 41 | ||||
| -rw-r--r-- | src/builtins/walker.rs | 1 | ||||
| -rw-r--r-- | src/builtins/walker/hint.rs | 45 | ||||
| -rw-r--r-- | src/lib.rs | 1 | ||||
| -rw-r--r-- | src/walk/protocols.rs | 43 |
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>; +} @@ -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>; - } -} |