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/visitor.rs | 292 +++++++++++++++++++++++++++++++++-------------
1 file changed, 213 insertions(+), 79 deletions(-)
(limited to 'dhall_core/src/visitor.rs')
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