From bb1f698c23a83f60020a72bb5be1f9a386c60d44 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 18 Apr 2019 11:58:21 +0200 Subject: Start cleaning up the mess of mapping functions --- dhall_core/src/visitor.rs | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) (limited to 'dhall_core/src/visitor.rs') diff --git a/dhall_core/src/visitor.rs b/dhall_core/src/visitor.rs index c123275..c6b7321 100644 --- a/dhall_core/src/visitor.rs +++ b/dhall_core/src/visitor.rs @@ -302,7 +302,7 @@ where } } -pub struct TraverseRefVisitor { +pub struct TraverseRefWithBindersVisitor { pub visit_subexpr: F1, pub visit_under_binder: F2, pub visit_note: F3, @@ -312,7 +312,7 @@ pub struct TraverseRefVisitor { impl<'a, SE, L, N, E, SE2, L2, N2, E2, Err, F1, F2, F3, F4, F5> ExprFFallibleVisitor<'a, SE, SE2, L, L2, N, N2, E, E2> - for TraverseRefVisitor + for TraverseRefWithBindersVisitor where SE: 'a, L: 'a, @@ -349,6 +349,44 @@ where } } +pub struct TraverseRefVisitor { + pub visit_subexpr: F1, + pub visit_note: F2, + pub visit_embed: F3, + pub visit_label: F4, +} + +impl<'a, SE, L, N, E, SE2, L2, N2, E2, Err, F1, F2, F3, F4> + ExprFFallibleVisitor<'a, SE, SE2, L, L2, N, N2, E, E2> + for TraverseRefVisitor +where + SE: 'a, + L: 'a, + N: 'a, + E: 'a, + L: Ord, + L2: Ord, + F1: FnMut(&'a SE) -> Result, + F2: FnOnce(&'a N) -> Result, + F3: FnOnce(&'a E) -> Result, + F4: FnMut(&'a L) -> Result, +{ + type Error = Err; + + fn visit_subexpr(&mut self, subexpr: &'a SE) -> Result { + (self.visit_subexpr)(subexpr) + } + fn visit_note(self, note: &'a N) -> Result { + (self.visit_note)(note) + } + fn visit_embed(self, embed: &'a E) -> Result { + (self.visit_embed)(embed) + } + fn visit_label(&mut self, label: &'a L) -> Result { + (self.visit_label)(label) + } +} + pub struct TraverseRefSimpleVisitor { pub visit_subexpr: F1, } -- cgit v1.2.3 From e68e34f361a29e0661201ac3c93a711a9884833f Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 18 Apr 2019 13:15:42 +0200 Subject: Reduce duplication between mapping functions --- dhall_core/src/visitor.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'dhall_core/src/visitor.rs') diff --git a/dhall_core/src/visitor.rs b/dhall_core/src/visitor.rs index c6b7321..053932d 100644 --- a/dhall_core/src/visitor.rs +++ b/dhall_core/src/visitor.rs @@ -433,7 +433,6 @@ impl<'a, 'b, N, E, E2, Err, F1> > for &'b mut TraverseEmbedVisitor where N: Clone + 'a, - E2: Clone, F1: FnMut(&E) -> Result, { type Error = Err; -- cgit v1.2.3 From bce1538a6b80702ef71749215dce339c9f22f09c Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 18 Apr 2019 13:42:40 +0200 Subject: Add even more general visitor trait --- dhall_core/src/visitor.rs | 195 +++++++++++++++++++++++++++++++++------------- 1 file changed, 140 insertions(+), 55 deletions(-) (limited to 'dhall_core/src/visitor.rs') diff --git a/dhall_core/src/visitor.rs b/dhall_core/src/visitor.rs index 053932d..dcd860e 100644 --- a/dhall_core/src/visitor.rs +++ b/dhall_core/src/visitor.rs @@ -17,67 +17,49 @@ pub trait GenericVisitor: Sized { /// time: the visitor itself. The visitor can then carry around multiple closures /// or just one, and Rust is ok with either. See for example TraverseRefVisitor /// and TraverseEmbedVisitor. -pub trait ExprFFallibleVisitor<'a, SE1, SE2, L1, L2, N1, N2, E1, E2>: - Sized -{ +/// This is very generic. For a more legible trait, see ExprFInFallibleVisitor +pub trait ExprFVeryGenericVisitor<'a, Ret, SE1, L1, N1, E1>: Sized { type Error; + type SE2; + type L2; + type N2; + type E2; - fn visit_subexpr(&mut self, subexpr: &'a SE1) -> Result; - fn visit_label(&mut self, label: &'a L1) -> Result; - fn visit_note(self, note: &'a N1) -> Result; - fn visit_embed(self, embed: &'a E1) -> Result; - - fn visit_subexpr_under_binder( - mut self, - _label: &'a L1, + fn visit_subexpr( + &mut self, subexpr: &'a SE1, - ) -> Result { - self.visit_subexpr(subexpr) - } + ) -> Result; + fn visit_label(&mut self, label: &'a L1) -> Result; fn visit_binder( - mut self, + self, label: &'a L1, subexpr: &'a SE1, - ) -> Result<(L2, SE2), Self::Error> { - Ok(( - self.visit_label(label)?, - self.visit_subexpr_under_binder(label, subexpr)?, - )) - } + ) -> Result<(Self::L2, Self::SE2), Self::Error>; - fn visit_embed_squash( - self, - embed: &'a E1, - ) -> Result, Self::Error> { - Ok(ExprF::Embed(self.visit_embed(embed)?)) - } + fn visit_embed_squash(self, embed: &'a E1) -> Result; fn visit_note_squash( - mut self, + self, note: &'a N1, subexpr: &'a SE1, - ) -> Result, Self::Error> { - let subexpr = self.visit_subexpr(subexpr)?; - let note = self.visit_note(note)?; - Ok(ExprF::Note(note, subexpr)) - } + ) -> Result; + + // Called with the result of the map, in the non-embed/note case. + // Useful to change the result type, and/or avoid some loss of info + fn visit_resulting_exprf( + result: ExprF, + ) -> Result; } -impl<'a, T, SE1, SE2, L1, L2, N1, N2, E1, E2> - GenericVisitor< - &'a ExprF, - Result, T::Error>, - > for T +impl<'a, T, Ret, SE1, L1, N1, E1> + GenericVisitor<&'a ExprF, Result> for T where L1: Ord, - L2: Ord, - T: ExprFFallibleVisitor<'a, SE1, SE2, L1, L2, N1, N2, E1, E2>, + T::L2: Ord, + T: ExprFVeryGenericVisitor<'a, Ret, SE1, L1, N1, E1>, { - fn visit( - self, - input: &'a ExprF, - ) -> Result, T::Error> { + fn visit(self, input: &'a ExprF) -> Result { fn vec<'a, T, U, Err, F: FnMut(&'a T) -> Result>( x: &'a [T], f: F, @@ -93,27 +75,27 @@ where None => None, }) } - fn btmap<'a, V, SE, L, N, E, SE2, L2, N2, E2>( + fn btmap<'a, V, Ret, SE, L, N, E>( x: &'a BTreeMap, mut v: V, - ) -> Result, V::Error> + ) -> Result, V::Error> where L: Ord, - L2: Ord, - V: ExprFFallibleVisitor<'a, SE, SE2, L, L2, N, N2, E, E2>, + V::L2: Ord, + V: ExprFVeryGenericVisitor<'a, Ret, SE, L, N, E>, { x.iter() .map(|(k, x)| Ok((v.visit_label(k)?, v.visit_subexpr(x)?))) .collect() } - fn btoptmap<'a, V, SE, L, N, E, SE2, L2, N2, E2>( + fn btoptmap<'a, V, Ret, SE, L, N, E>( x: &'a BTreeMap>, mut v: V, - ) -> Result>, V::Error> + ) -> Result>, V::Error> where L: Ord, - L2: Ord, - V: ExprFFallibleVisitor<'a, SE, SE2, L, L2, N, N2, E, E2>, + V::L2: Ord, + V: ExprFVeryGenericVisitor<'a, Ret, SE, L, N, E>, { x.iter() .map(|(k, x)| { @@ -130,7 +112,7 @@ where let mut v = self; use crate::ExprF::*; - Ok(match input { + T::visit_resulting_exprf(match input { Var(V(l, n)) => Var(V(v.visit_label(l)?, *n)), Lam(l, t, e) => { let t = v.visit_subexpr(t)?; @@ -195,12 +177,115 @@ where Projection(e, ls) => { Projection(v.visit_subexpr(e)?, vec(ls, |l| v.visit_label(l))?) } - Note(n, e) => v.visit_note_squash(n, e)?, - Embed(a) => v.visit_embed_squash(a)?, + Note(n, e) => return v.visit_note_squash(n, e), + Embed(a) => return v.visit_embed_squash(a), }) } } +/// Like ExprFVeryGenericVisitor, but sets the return +/// type to ExprF<_> +pub trait ExprFFallibleVisitor<'a, SE1, SE2, L1, L2, N1, N2, E1, E2>: + Sized +{ + type Error; + + fn visit_subexpr(&mut self, subexpr: &'a SE1) -> Result; + fn visit_label(&mut self, label: &'a L1) -> Result; + fn visit_note(self, note: &'a N1) -> Result; + fn visit_embed(self, embed: &'a E1) -> Result; + + fn visit_subexpr_under_binder( + mut self, + _label: &'a L1, + subexpr: &'a SE1, + ) -> Result { + self.visit_subexpr(subexpr) + } + + fn visit_binder( + mut self, + label: &'a L1, + subexpr: &'a SE1, + ) -> Result<(L2, SE2), Self::Error> { + Ok(( + self.visit_label(label)?, + self.visit_subexpr_under_binder(label, subexpr)?, + )) + } + + fn visit_embed_squash( + self, + embed: &'a E1, + ) -> Result, Self::Error> { + Ok(ExprF::Embed(self.visit_embed(embed)?)) + } + + fn visit_note_squash( + mut self, + note: &'a N1, + subexpr: &'a SE1, + ) -> Result, Self::Error> { + let subexpr = self.visit_subexpr(subexpr)?; + let note = self.visit_note(note)?; + Ok(ExprF::Note(note, subexpr)) + } +} + +impl<'a, T, SE1, SE2, L1, L2, N1, N2, E1, E2> + ExprFVeryGenericVisitor<'a, ExprF, SE1, L1, N1, E1> for T +where + T: ExprFFallibleVisitor<'a, SE1, SE2, L1, L2, N1, N2, E1, E2>, +{ + type Error = T::Error; + type SE2 = SE2; + type L2 = L2; + type N2 = N2; + type E2 = E2; + + fn visit_subexpr( + &mut self, + subexpr: &'a SE1, + ) -> Result { + self.visit_subexpr(subexpr) + } + + fn visit_label(&mut self, label: &'a L1) -> Result { + self.visit_label(label) + } + + fn visit_binder( + self, + label: &'a L1, + subexpr: &'a SE1, + ) -> Result<(Self::L2, Self::SE2), Self::Error> { + self.visit_binder(label, subexpr) + } + + fn visit_embed_squash( + self, + embed: &'a E1, + ) -> Result, Self::Error> { + self.visit_embed_squash(embed) + } + + fn visit_note_squash( + self, + note: &'a N1, + subexpr: &'a SE1, + ) -> Result, Self::Error> { + self.visit_note_squash(note, subexpr) + } + + // Called with the result of the map, in the non-embed/note case. + // Useful to change the result type, and/or avoid some loss of info + fn visit_resulting_exprf( + result: ExprF, + ) -> Result, Self::Error> { + Ok(result) + } +} + /// Like ExprFFallibleVisitor, but without the error handling. pub trait ExprFInFallibleVisitor<'a, SE1, SE2, L1, L2, N1, N2, E1, E2>: Sized -- cgit v1.2.3 From 69267c7cc108a2f5db35c52a71afaa5be7be7355 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 18 Apr 2019 14:10:03 +0200 Subject: Avoid an unnecessary unroll() --- dhall_core/src/visitor.rs | 75 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 24 deletions(-) (limited to 'dhall_core/src/visitor.rs') diff --git a/dhall_core/src/visitor.rs b/dhall_core/src/visitor.rs index dcd860e..c2b0d06 100644 --- a/dhall_core/src/visitor.rs +++ b/dhall_core/src/visitor.rs @@ -541,37 +541,64 @@ where pub struct SquashEmbedVisitor(pub F1); -impl<'a, 'b, N, E, E2, F1> - ExprFInFallibleVisitor< - 'a, - SubExpr, - SubExpr, - Label, - Label, - N, - N, - E, - E2, - > for &'b mut SquashEmbedVisitor +impl<'a, 'b, N, E1, E2, F1> + ExprFVeryGenericVisitor<'a, SubExpr, SubExpr, Label, N, E1> + for &'b mut SquashEmbedVisitor where N: Clone + 'a, - E2: Clone, - F1: FnMut(&E) -> SubExpr, + F1: FnMut(&E1) -> SubExpr, { - fn visit_subexpr(&mut self, subexpr: &'a SubExpr) -> SubExpr { - rc(subexpr.as_ref().visit(&mut **self)) + type Error = X; + type SE2 = SubExpr; + type L2 = Label; + type N2 = N; + type E2 = E2; + + fn visit_subexpr( + &mut self, + subexpr: &'a SubExpr, + ) -> Result { + Ok(subexpr.as_ref().visit(&mut **self)?) } - fn visit_note(self, note: &'a N) -> N { - N::clone(note) + + fn visit_label( + &mut self, + label: &'a Label, + ) -> Result { + Ok(Label::clone(label)) } - fn visit_embed(self, _: &'a E) -> E2 { - unreachable!() + + fn visit_binder( + mut self, + label: &'a Label, + subexpr: &'a SubExpr, + ) -> Result<(Self::L2, Self::SE2), Self::Error> { + Ok((self.visit_label(label)?, self.visit_subexpr(subexpr)?)) } - fn visit_embed_squash(self, embed: &'a E) -> Expr { - (self.0)(embed).unroll() + + fn visit_embed_squash( + self, + embed: &'a E1, + ) -> Result, Self::Error> { + Ok((self.0)(embed)) } - fn visit_label(&mut self, label: &'a Label) -> Label { - Label::clone(label) + + fn visit_note_squash( + mut self, + note: &'a N, + subexpr: &'a SubExpr, + ) -> Result, Self::Error> { + let subexpr = self.visit_subexpr(subexpr)?; + let note = N::clone(note); + Ok(rc(ExprF::Note(note, subexpr))) + } + + // Called with the result of the map, in the non-embed/note case. + // Useful to change the result type, and/or avoid some loss of info + fn visit_resulting_exprf( + result: ExprF, + ) -> Result, Self::Error> { + Ok(rc(result)) } } -- cgit v1.2.3 From 9474d4939db6f844285182fc15aad74f6aa18e21 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 18 Apr 2019 14:39:56 +0200 Subject: Remove more duplication --- dhall_core/src/visitor.rs | 30 ------------------------------ 1 file changed, 30 deletions(-) (limited to 'dhall_core/src/visitor.rs') diff --git a/dhall_core/src/visitor.rs b/dhall_core/src/visitor.rs index c2b0d06..16ad418 100644 --- a/dhall_core/src/visitor.rs +++ b/dhall_core/src/visitor.rs @@ -472,36 +472,6 @@ where } } -pub struct TraverseRefSimpleVisitor { - pub visit_subexpr: F1, -} - -impl<'a, SE, L, N, E, SE2, Err, F1> - ExprFFallibleVisitor<'a, SE, SE2, L, L, N, N, E, E> - for TraverseRefSimpleVisitor -where - SE: 'a, - L: Ord + Clone + 'a, - N: Clone + 'a, - E: Clone + 'a, - F1: FnMut(&'a SE) -> Result, -{ - type Error = Err; - - fn visit_subexpr(&mut self, subexpr: &'a SE) -> Result { - (self.visit_subexpr)(subexpr) - } - fn visit_note(self, note: &'a N) -> Result { - Ok(N::clone(note)) - } - fn visit_embed(self, embed: &'a E) -> Result { - Ok(E::clone(embed)) - } - fn visit_label(&mut self, label: &'a L) -> Result { - Ok(L::clone(label)) - } -} - pub struct TraverseEmbedVisitor(pub F1); impl<'a, 'b, N, E, E2, Err, F1> -- cgit v1.2.3