From a72e00dc9193f82f93459a493d4f3167f9b2f6f1 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 14 Apr 2019 15:45:43 +0200 Subject: Improve visitor trait hierarchy --- dhall_core/src/core.rs | 21 ++-- dhall_core/src/visitor.rs | 292 +++++++++++++++++++++++++++++++++------------- 2 files changed, 226 insertions(+), 87 deletions(-) diff --git a/dhall_core/src/core.rs b/dhall_core/src/core.rs index f836294..b3f6b9c 100644 --- a/dhall_core/src/core.rs +++ b/dhall_core/src/core.rs @@ -198,6 +198,15 @@ pub enum ExprF { Embed(Embed), } +impl ExprF { + pub fn visit<'a, V, Return>(&'a self, v: V) -> Return + where + V: visitor::GenericVisitor<&'a ExprF, Return>, + { + v.visit(self) + } +} + impl Expr { pub fn map_shallow( &self, @@ -270,9 +279,7 @@ impl Expr { &self, f: impl FnMut(&E) -> SubExpr, ) -> SubExpr { - rc(trivial_result( - self.visit(&mut visitor::SquashEmbedVisitor(f)), - )) + rc(self.visit(&mut visitor::SquashEmbedVisitor(f))) } } @@ -463,15 +470,13 @@ impl SubExpr { impl Expr { pub fn note_absurd(&self) -> Expr { - trivial_result(self.visit(&mut visitor::NoteAbsurdVisitor)) + self.visit(&mut visitor::NoteAbsurdVisitor) } } impl SubExpr { pub fn unnote(&self) -> SubExpr { - rc(trivial_result( - self.as_ref().visit(&mut visitor::UnNoteVisitor), - )) + rc(self.as_ref().visit(&mut visitor::UnNoteVisitor)) } } @@ -481,7 +486,7 @@ impl Expr { self.embed_absurd() } pub fn embed_absurd(&self) -> Expr { - trivial_result(self.visit(&mut visitor::EmbedAbsurdVisitor)) + self.visit(&mut visitor::EmbedAbsurdVisitor) } } diff --git a/dhall_core/src/visitor.rs b/dhall_core/src/visitor.rs index 3a94c7b..5eb17f6 100644 --- a/dhall_core/src/visitor.rs +++ b/dhall_core/src/visitor.rs @@ -2,7 +2,13 @@ use std::collections::BTreeMap; use crate::*; -pub trait ExprVisitor<'a, SE1, SE2, L1, L2, N1, N2, E1, E2>: Sized { +pub trait GenericVisitor: Sized { + fn visit(self, input: Input) -> Return; +} + +pub trait ExprFFallibleVisitor<'a, SE1, SE2, L1, L2, N1, N2, E1, E2>: + Sized +{ type Error; fn visit_subexpr(&mut self, subexpr: &'a SE1) -> Result; @@ -47,16 +53,20 @@ pub trait ExprVisitor<'a, SE1, SE2, L1, L2, N1, N2, E1, E2>: Sized { } } -impl ExprF { - pub fn visit<'a, V, SE2, L2, N2, E2>( - &'a self, - mut v: V, - ) -> Result, V::Error> - where - L: Ord, - L2: Ord, - V: ExprVisitor<'a, SE, SE2, L, L2, N, N2, E, E2>, - { +impl<'a, T, SE1, SE2, L1, L2, N1, N2, E1, E2> + GenericVisitor< + &'a ExprF, + Result, T::Error>, + > for T +where + L1: Ord, + L2: Ord, + T: ExprFFallibleVisitor<'a, SE1, SE2, L1, L2, N1, N2, E1, E2>, +{ + fn visit( + self, + input: &'a ExprF, + ) -> Result, T::Error> { fn vec<'a, T, U, Err, F: FnMut(&'a T) -> Result>( x: &'a Vec, f: F, @@ -79,15 +89,16 @@ impl ExprF { where L: Ord, L2: Ord, - V: ExprVisitor<'a, SE, SE2, L, L2, N, N2, E, E2>, + V: ExprFFallibleVisitor<'a, SE, SE2, L, L2, N, N2, E, E2>, { x.into_iter() .map(|(k, x)| Ok((v.visit_label(k)?, v.visit_subexpr(x)?))) .collect() } + let mut v = self; use crate::ExprF::*; - Ok(match self { + Ok(match input { Var(V(l, n)) => Var(V(v.visit_label(l)?, *n)), Lam(l, t, e) => { let t = v.visit_subexpr(t)?; @@ -149,6 +160,106 @@ impl ExprF { } } +pub trait ExprFInFallibleVisitor<'a, SE1, SE2, L1, L2, N1, N2, E1, E2>: + Sized +{ + fn visit_subexpr(&mut self, subexpr: &'a SE1) -> SE2; + fn visit_label(&mut self, label: &'a L1) -> L2; + fn visit_note(self, note: &'a N1) -> N2; + fn visit_embed(self, embed: &'a E1) -> E2; + + fn visit_subexpr_under_binder( + mut self, + _label: &'a L1, + subexpr: &'a SE1, + ) -> SE2 { + self.visit_subexpr(subexpr) + } + + fn visit_binder(mut self, label: &'a L1, subexpr: &'a SE1) -> (L2, SE2) { + ( + self.visit_label(label), + self.visit_subexpr_under_binder(label, subexpr), + ) + } + + fn visit_embed_squash(self, embed: &'a E1) -> ExprF { + ExprF::Embed(self.visit_embed(embed)) + } + + fn visit_note_squash( + mut self, + note: &'a N1, + subexpr: &'a SE1, + ) -> ExprF { + let subexpr = self.visit_subexpr(subexpr); + let note = self.visit_note(note); + ExprF::Note(note, subexpr) + } +} + +struct InfallibleWrapper(T); + +impl<'a, T, SE1, SE2, L1, L2, N1, N2, E1, E2> + ExprFFallibleVisitor<'a, SE1, SE2, L1, L2, N1, N2, E1, E2> + for InfallibleWrapper +where + T: ExprFInFallibleVisitor<'a, SE1, SE2, L1, L2, N1, N2, E1, E2>, +{ + type Error = X; + + fn visit_subexpr(&mut self, subexpr: &'a SE1) -> Result { + Ok(self.0.visit_subexpr(subexpr)) + } + fn visit_label(&mut self, label: &'a L1) -> Result { + Ok(self.0.visit_label(label)) + } + fn visit_note(self, note: &'a N1) -> Result { + Ok(self.0.visit_note(note)) + } + fn visit_embed(self, embed: &'a E1) -> Result { + Ok(self.0.visit_embed(embed)) + } + + fn visit_binder( + self, + label: &'a L1, + subexpr: &'a SE1, + ) -> Result<(L2, SE2), Self::Error> { + Ok(self.0.visit_binder(label, subexpr)) + } + + fn visit_embed_squash( + self, + embed: &'a E1, + ) -> Result, Self::Error> { + Ok(self.0.visit_embed_squash(embed)) + } + + fn visit_note_squash( + self, + note: &'a N1, + subexpr: &'a SE1, + ) -> Result, Self::Error> { + Ok(self.0.visit_note_squash(note, subexpr)) + } +} + +impl<'a, T, SE1, SE2, L1, L2, N1, N2, E1, E2> + GenericVisitor<&'a ExprF, ExprF> for T +where + L1: Ord, + L2: Ord, + T: ExprFInFallibleVisitor<'a, SE1, SE2, L1, L2, N1, N2, E1, E2>, +{ + fn visit( + self, + input: &'a ExprF, + ) -> ExprF { + trivial_result(InfallibleWrapper(self).visit(input)) + } +} + pub struct TraverseRefVisitor { pub visit_subexpr: F1, pub visit_under_binder: F2, @@ -158,7 +269,7 @@ pub struct TraverseRefVisitor { } impl<'a, SE, L, N, E, SE2, L2, N2, E2, Err, F1, F2, F3, F4, F5> - ExprVisitor<'a, SE, SE2, L, L2, N, N2, E, E2> + ExprFFallibleVisitor<'a, SE, SE2, L, L2, N, N2, E, E2> for TraverseRefVisitor where SE: 'a, @@ -200,7 +311,8 @@ pub struct TraverseRefSimpleVisitor { pub visit_subexpr: F1, } -impl<'a, SE, L, N, E, SE2, Err, F1> ExprVisitor<'a, SE, SE2, L, L, N, N, E, E> +impl<'a, SE, L, N, E, SE2, Err, F1> + ExprFFallibleVisitor<'a, SE, SE2, L, L, N, N, E, E> for TraverseRefSimpleVisitor where SE: 'a, @@ -228,8 +340,17 @@ where pub struct TraverseEmbedVisitor(pub F1); impl<'a, 'b, N, E, E2, Err, F1> - ExprVisitor<'a, SubExpr, SubExpr, Label, Label, N, N, E, E2> - for &'b mut TraverseEmbedVisitor + ExprFFallibleVisitor< + 'a, + SubExpr, + SubExpr, + Label, + Label, + N, + N, + E, + E2, + > for &'b mut TraverseEmbedVisitor where N: Clone + 'a, E2: Clone, @@ -257,122 +378,135 @@ where pub struct SquashEmbedVisitor(pub F1); impl<'a, 'b, N, E, E2, F1> - ExprVisitor<'a, SubExpr, SubExpr, Label, Label, N, N, E, E2> - for &'b mut SquashEmbedVisitor + ExprFInFallibleVisitor< + 'a, + SubExpr, + SubExpr, + Label, + Label, + N, + N, + E, + E2, + > for &'b mut SquashEmbedVisitor where N: Clone + 'a, E2: Clone, F1: FnMut(&E) -> SubExpr, { - type Error = X; - - fn visit_subexpr( - &mut self, - subexpr: &'a SubExpr, - ) -> Result, Self::Error> { - Ok(rc(subexpr.as_ref().visit(&mut **self)?)) + fn visit_subexpr(&mut self, subexpr: &'a SubExpr) -> SubExpr { + rc(subexpr.as_ref().visit(&mut **self)) } - fn visit_note(self, note: &'a N) -> Result { - Ok(N::clone(note)) + fn visit_note(self, note: &'a N) -> N { + N::clone(note) } - fn visit_embed(self, _: &'a E) -> Result { + fn visit_embed(self, _: &'a E) -> E2 { unreachable!() } - fn visit_embed_squash( - self, - embed: &'a E, - ) -> Result, Self::Error> { - Ok((self.0)(embed).unroll()) + fn visit_embed_squash(self, embed: &'a E) -> Expr { + (self.0)(embed).unroll() } - fn visit_label(&mut self, label: &'a Label) -> Result { - Ok(Label::clone(label)) + fn visit_label(&mut self, label: &'a Label) -> Label { + Label::clone(label) } } pub struct UnNoteVisitor; impl<'a, 'b, N, E> - ExprVisitor<'a, SubExpr, SubExpr, Label, Label, N, X, E, E> - for &'b mut UnNoteVisitor + ExprFInFallibleVisitor< + 'a, + SubExpr, + SubExpr, + Label, + Label, + N, + X, + E, + E, + > for &'b mut UnNoteVisitor where E: Clone + 'a, { - type Error = X; - - fn visit_subexpr( - &mut self, - subexpr: &'a SubExpr, - ) -> Result, Self::Error> { - Ok(rc(subexpr.as_ref().visit(&mut **self)?)) + fn visit_subexpr(&mut self, subexpr: &'a SubExpr) -> SubExpr { + rc(subexpr.as_ref().visit(&mut **self)) } - fn visit_note(self, _: &'a N) -> Result { + fn visit_note(self, _: &'a N) -> X { unreachable!() } fn visit_note_squash( self, _: &'a N, subexpr: &'a SubExpr, - ) -> Result, Self::Error> { + ) -> Expr { subexpr.as_ref().visit(self) } - fn visit_embed(self, embed: &'a E) -> Result { - Ok(E::clone(embed)) + fn visit_embed(self, embed: &'a E) -> E { + E::clone(embed) } - fn visit_label(&mut self, label: &'a Label) -> Result { - Ok(Label::clone(label)) + fn visit_label(&mut self, label: &'a Label) -> Label { + Label::clone(label) } } pub struct NoteAbsurdVisitor; impl<'a, 'b, N, E> - ExprVisitor<'a, SubExpr, SubExpr, Label, Label, X, N, E, E> - for &'b mut NoteAbsurdVisitor + ExprFInFallibleVisitor< + 'a, + SubExpr, + SubExpr, + Label, + Label, + X, + N, + E, + E, + > for &'b mut NoteAbsurdVisitor where E: Clone + 'a, { - type Error = X; - - fn visit_subexpr( - &mut self, - subexpr: &'a SubExpr, - ) -> Result, Self::Error> { - Ok(rc(subexpr.as_ref().visit(&mut **self)?)) + fn visit_subexpr(&mut self, subexpr: &'a SubExpr) -> SubExpr { + rc(subexpr.as_ref().visit(&mut **self)) } - fn visit_note(self, note: &'a X) -> Result { + fn visit_note(self, note: &'a X) -> N { match *note {} } - fn visit_embed(self, embed: &'a E) -> Result { - Ok(E::clone(embed)) + fn visit_embed(self, embed: &'a E) -> E { + E::clone(embed) } - fn visit_label(&mut self, label: &'a Label) -> Result { - Ok(Label::clone(label)) + fn visit_label(&mut self, label: &'a Label) -> Label { + Label::clone(label) } } pub struct EmbedAbsurdVisitor; impl<'a, 'b, N, E> - ExprVisitor<'a, SubExpr, SubExpr, Label, Label, N, N, X, E> - for &'b mut EmbedAbsurdVisitor + ExprFInFallibleVisitor< + 'a, + SubExpr, + SubExpr, + Label, + Label, + N, + N, + X, + E, + > for &'b mut EmbedAbsurdVisitor where N: Clone + 'a, { - type Error = X; - - fn visit_subexpr( - &mut self, - subexpr: &'a SubExpr, - ) -> Result, Self::Error> { - Ok(rc(subexpr.as_ref().visit(&mut **self)?)) + fn visit_subexpr(&mut self, subexpr: &'a SubExpr) -> SubExpr { + rc(subexpr.as_ref().visit(&mut **self)) } - fn visit_note(self, note: &'a N) -> Result { - Ok(N::clone(note)) + fn visit_note(self, note: &'a N) -> N { + N::clone(note) } - fn visit_embed(self, embed: &'a X) -> Result { + fn visit_embed(self, embed: &'a X) -> E { match *embed {} } - fn visit_label(&mut self, label: &'a Label) -> Result { - Ok(Label::clone(label)) + fn visit_label(&mut self, label: &'a Label) -> Label { + Label::clone(label) } } -- cgit v1.2.3