diff options
| author | Nadrieril | 2019-05-04 12:38:36 +0200 | 
|---|---|---|
| committer | Nadrieril | 2019-05-04 12:38:36 +0200 | 
| commit | 45be2ff1f5bb3d6e0faa098402adf985b3d5e7ca (patch) | |
| tree | a7b15b0bf4b5b211eb42a559bc3cfde9a14b7749 /dhall_core | |
| parent | ca4e2b39c838cde6da835470699579e8eddc1535 (diff) | |
Rename dhall_core to dhall_syntax
Diffstat (limited to 'dhall_core')
| -rw-r--r-- | dhall_core/Cargo.toml | 16 | ||||
| -rw-r--r-- | dhall_core/src/context.rs | 80 | ||||
| -rw-r--r-- | dhall_core/src/core.rs | 563 | ||||
| -rw-r--r-- | dhall_core/src/import.rs | 64 | ||||
| -rw-r--r-- | dhall_core/src/label.rs | 34 | ||||
| -rw-r--r-- | dhall_core/src/lib.rs | 28 | ||||
| -rw-r--r-- | dhall_core/src/parser.rs | 984 | ||||
| -rw-r--r-- | dhall_core/src/printer.rs | 498 | ||||
| -rw-r--r-- | dhall_core/src/text.rs | 116 | ||||
| -rw-r--r-- | dhall_core/src/visitor.rs | 667 | 
10 files changed, 0 insertions, 3050 deletions
diff --git a/dhall_core/Cargo.toml b/dhall_core/Cargo.toml deleted file mode 100644 index 476b9fa..0000000 --- a/dhall_core/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "dhall_core" -version = "0.1.0" -authors = ["NanoTech <nanotech@nanotechcorp.net>", "Nadrieril <nadrieril@users.noreply.github.com>"] -license = "BSD-2-Clause" -edition = "2018" - -[lib] -doctest = false - -[dependencies] -itertools = "0.8.0" -percent-encoding = "1.0.1" -pest = "2.1" -dhall_generated_parser = { path = "../dhall_generated_parser" } -improved_slice_patterns = { version = "2.0.0", path = "../improved_slice_patterns" } diff --git a/dhall_core/src/context.rs b/dhall_core/src/context.rs deleted file mode 100644 index 55bfff5..0000000 --- a/dhall_core/src/context.rs +++ /dev/null @@ -1,80 +0,0 @@ -use std::cmp::Eq; -use std::collections::HashMap; -use std::hash::Hash; - -/// A `(Context a)` associates `Text` labels with values of type `a` -/// -/// The `Context` is used for type-checking when `(a = Expr X)` -/// -/// * You create a `Context` using `empty` and `insert` -/// * You transform a `Context` using `fmap` -/// * You consume a `Context` using `lookup` and `toList` -/// -/// The difference between a `Context` and a `Map` is that a `Context` lets you -/// have multiple ordered occurrences of the same key and you can query for the -/// `n`th occurrence of a given key. -/// -#[derive(Debug, Clone)] -pub struct Context<K: Eq + Hash, T>(HashMap<K, Vec<T>>); - -impl<K: Hash + Eq + Clone, T> Context<K, T> { -    /// An empty context with no key-value pairs -    pub fn new() -> Self { -        Context(HashMap::new()) -    } - -    /// Look up a key by name and index -    /// -    /// ```c -    /// lookup _ _         empty  = Nothing -    /// lookup k 0 (insert k v c) = Just v -    /// lookup k n (insert k v c) = lookup k (n - 1) c  -- 1 <= n -    /// lookup k n (insert j v c) = lookup k  n      c  -- k /= j -    /// ``` -    pub fn lookup<'a>(&'a self, k: &K, n: usize) -> Option<&'a T> { -        self.0.get(k).and_then(|v| { -            if n < v.len() { -                v.get(v.len() - 1 - n) -            } else { -                None -            } -        }) -    } - -    pub fn map<U, F: Fn(&K, &T) -> U>(&self, f: F) -> Context<K, U> { -        Context( -            self.0 -                .iter() -                .map(|(k, vs)| { -                    ((*k).clone(), vs.iter().map(|v| f(k, v)).collect()) -                }) -                .collect(), -        ) -    } - -    pub fn lookup_all<'a>(&'a self, k: &K) -> impl Iterator<Item = &T> { -        self.0.get(k).into_iter().flat_map(|v| v.iter()) -    } - -    pub fn iter<'a>(&'a self) -> impl Iterator<Item = (&K, &T)> { -        self.0 -            .iter() -            .flat_map(|(k, vs)| vs.iter().map(move |v| (k, v))) -    } - -    pub fn iter_keys<'a>(&'a self) -> impl Iterator<Item = (&K, &Vec<T>)> { -        self.0.iter() -    } -} - -impl<K: Hash + Eq + Clone, T: Clone> Context<K, T> { -    /// Add a key-value pair to the `Context` -    pub fn insert(&self, k: K, v: T) -> Self { -        let mut ctx = (*self).clone(); -        { -            let m = ctx.0.entry(k).or_insert_with(Vec::new); -            m.push(v); -        } -        ctx -    } -} diff --git a/dhall_core/src/core.rs b/dhall_core/src/core.rs deleted file mode 100644 index 3db07dd..0000000 --- a/dhall_core/src/core.rs +++ /dev/null @@ -1,563 +0,0 @@ -#![allow(non_snake_case)] -use std::collections::BTreeMap; -use std::collections::HashMap; -use std::rc::Rc; - -use crate::context::Context; -use crate::visitor; -use crate::*; - -pub type Integer = isize; -pub type Natural = usize; -pub type Double = NaiveDouble; - -/// An empty type -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum X {} - -pub fn trivial_result<T>(x: Result<T, X>) -> T { -    match x { -        Ok(x) => x, -        Err(e) => match e {}, -    } -} - -/// Double with bitwise equality -#[derive(Debug, Copy, Clone)] -pub struct NaiveDouble(f64); - -impl PartialEq for NaiveDouble { -    fn eq(&self, other: &Self) -> bool { -        self.0.to_bits() == other.0.to_bits() -    } -} - -impl Eq for NaiveDouble {} - -impl From<f64> for NaiveDouble { -    fn from(x: f64) -> Self { -        NaiveDouble(x) -    } -} - -impl From<NaiveDouble> for f64 { -    fn from(x: NaiveDouble) -> f64 { -        x.0 -    } -} - -/// Constants for a pure type system -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum Const { -    Type, -    Kind, -    Sort, -} - -/// Bound variable -/// -/// The `Label` field is the variable's name (i.e. \"`x`\"). -/// The `Int` field is a DeBruijn index. -/// See dhall-lang/standard/semantics.md for details -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct V<Label>(pub Label, pub usize); - -// This is only for the specific `Label` type, not generic -impl From<Label> for V<Label> { -    fn from(x: Label) -> V<Label> { -        V(x, 0) -    } -} -impl<'a> From<&'a Label> for V<Label> { -    fn from(x: &'a Label) -> V<Label> { -        V(x.clone(), 0) -    } -} - -// Definition order must match precedence order for -// pretty-printing to work correctly -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub enum BinOp { -    /// x ? y -    ImportAlt, -    /// x || y` -    BoolOr, -    /// x + y` -    NaturalPlus, -    /// x ++ y` -    TextAppend, -    /// x # y -    ListAppend, -    /// x && y` -    BoolAnd, -    /// x ∧ y` -    Combine, -    /// x // y -    Prefer, -    /// x //\\ y -    CombineTypes, -    /// x * y` -    NaturalTimes, -    /// x == y` -    BoolEQ, -    /// x != y` -    BoolNE, -} - -/// Built-ins -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum Builtin { -    Bool, -    Natural, -    Integer, -    Double, -    Text, -    List, -    Optional, -    OptionalNone, -    NaturalBuild, -    NaturalFold, -    NaturalIsZero, -    NaturalEven, -    NaturalOdd, -    NaturalToInteger, -    NaturalShow, -    IntegerToDouble, -    IntegerShow, -    DoubleShow, -    ListBuild, -    ListFold, -    ListLength, -    ListHead, -    ListLast, -    ListIndexed, -    ListReverse, -    OptionalFold, -    OptionalBuild, -    TextShow, -} - -pub type ParsedExpr = SubExpr<X, Import>; -pub type ResolvedExpr = SubExpr<X, X>; -pub type DhallExpr = ResolvedExpr; - -#[derive(Debug, PartialEq, Eq)] -pub struct SubExpr<Note, Embed>(pub Rc<Expr<Note, Embed>>); - -pub type Expr<Note, Embed> = ExprF<SubExpr<Note, Embed>, Label, Note, Embed>; - -/// Syntax tree for expressions -// Having the recursion out of the enum definition enables writing -// much more generic code and improves pattern-matching behind -// smart pointers. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ExprF<SubExpr, Label, Note, Embed> { -    Const(Const), -    ///  `x` -    ///  `x@n` -    Var(V<Label>), -    ///  `λ(x : A) -> b` -    Lam(Label, SubExpr, SubExpr), -    ///  `A -> B` -    ///  `∀(x : A) -> B` -    Pi(Label, SubExpr, SubExpr), -    ///  `f a` -    App(SubExpr, SubExpr), -    ///  `let x     = r in e` -    ///  `let x : t = r in e` -    Let(Label, Option<SubExpr>, SubExpr, SubExpr), -    ///  `x : t` -    Annot(SubExpr, SubExpr), -    /// Built-in values -    Builtin(Builtin), -    // Binary operations -    BinOp(BinOp, SubExpr, SubExpr), -    ///  `True` -    BoolLit(bool), -    ///  `if x then y else z` -    BoolIf(SubExpr, SubExpr, SubExpr), -    ///  `1` -    NaturalLit(Natural), -    ///  `+2` -    IntegerLit(Integer), -    ///  `3.24` -    DoubleLit(Double), -    ///  `"Some ${interpolated} text"` -    TextLit(InterpolatedText<SubExpr>), -    ///  `[] : List t` -    EmptyListLit(SubExpr), -    ///  `[x, y, z]` -    NEListLit(Vec<SubExpr>), -    /// Deprecated Optional literal form -    ///  `[] : Optional a` -    ///  `[x] : Optional a` -    OldOptionalLit(Option<SubExpr>, SubExpr), -    ///  `Some e` -    SomeLit(SubExpr), -    ///  `{ k1 : t1, k2 : t1 }` -    RecordType(BTreeMap<Label, SubExpr>), -    ///  `{ k1 = v1, k2 = v2 }` -    RecordLit(BTreeMap<Label, SubExpr>), -    ///  `< k1 : t1, k2 >` -    UnionType(BTreeMap<Label, Option<SubExpr>>), -    ///  `< k1 = t1, k2 : t2, k3 >` -    UnionLit(Label, SubExpr, BTreeMap<Label, Option<SubExpr>>), -    ///  `merge x y : t` -    Merge(SubExpr, SubExpr, Option<SubExpr>), -    ///  `e.x` -    Field(SubExpr, Label), -    ///  `e.{ x, y, z }` -    Projection(SubExpr, Vec<Label>), -    /// Annotation on the AST. Unused for now but could hold e.g. file location information -    Note(Note, SubExpr), -    /// Embeds an import or the result of resolving the import -    Embed(Embed), -} - -impl<SE, L, N, E> ExprF<SE, L, N, E> { -    pub(crate) fn visit<'a, V, Return>(&'a self, v: V) -> Return -    where -        V: visitor::GenericVisitor<&'a ExprF<SE, L, N, E>, Return>, -    { -        v.visit(self) -    } - -    fn traverse_ref_with_special_handling_of_binders<'a, SE2, L2, N2, E2, Err>( -        &'a self, -        visit_subexpr: impl FnMut(&'a SE) -> Result<SE2, Err>, -        visit_under_binder: impl FnOnce(&'a L, &'a SE) -> Result<SE2, Err>, -        visit_note: impl FnOnce(&'a N) -> Result<N2, Err>, -        visit_embed: impl FnOnce(&'a E) -> Result<E2, Err>, -        visit_label: impl FnMut(&'a L) -> Result<L2, Err>, -    ) -> Result<ExprF<SE2, L2, N2, E2>, Err> -    where -        L: Ord, -        L2: Ord, -    { -        self.visit(visitor::TraverseRefWithBindersVisitor { -            visit_subexpr, -            visit_under_binder, -            visit_note, -            visit_embed, -            visit_label, -        }) -    } - -    fn traverse_ref<'a, SE2, L2, N2, E2, Err>( -        &'a self, -        visit_subexpr: impl FnMut(&'a SE) -> Result<SE2, Err>, -        visit_note: impl FnOnce(&'a N) -> Result<N2, Err>, -        visit_embed: impl FnOnce(&'a E) -> Result<E2, Err>, -        visit_label: impl FnMut(&'a L) -> Result<L2, Err>, -    ) -> Result<ExprF<SE2, L2, N2, E2>, Err> -    where -        L: Ord, -        L2: Ord, -    { -        self.visit(visitor::TraverseRefVisitor { -            visit_subexpr, -            visit_note, -            visit_embed, -            visit_label, -        }) -    } - -    pub fn map_ref_with_special_handling_of_binders<'a, SE2, L2, N2, E2>( -        &'a self, -        mut map_subexpr: impl FnMut(&'a SE) -> SE2, -        mut map_under_binder: impl FnMut(&'a L, &'a SE) -> SE2, -        map_note: impl FnOnce(&'a N) -> N2, -        map_embed: impl FnOnce(&'a E) -> E2, -        mut map_label: impl FnMut(&'a L) -> L2, -    ) -> ExprF<SE2, L2, N2, E2> -    where -        L: Ord, -        L2: Ord, -    { -        trivial_result(self.traverse_ref_with_special_handling_of_binders( -            |x| Ok(map_subexpr(x)), -            |l, x| Ok(map_under_binder(l, x)), -            |x| Ok(map_note(x)), -            |x| Ok(map_embed(x)), -            |x| Ok(map_label(x)), -        )) -    } - -    pub fn map_ref<'a, SE2, L2, N2, E2>( -        &'a self, -        mut map_subexpr: impl FnMut(&'a SE) -> SE2, -        map_note: impl FnOnce(&'a N) -> N2, -        map_embed: impl FnOnce(&'a E) -> E2, -        mut map_label: impl FnMut(&'a L) -> L2, -    ) -> ExprF<SE2, L2, N2, E2> -    where -        L: Ord, -        L2: Ord, -    { -        trivial_result(self.traverse_ref( -            |x| Ok(map_subexpr(x)), -            |x| Ok(map_note(x)), -            |x| Ok(map_embed(x)), -            |x| Ok(map_label(x)), -        )) -    } - -    pub fn traverse_ref_simple<'a, SE2, Err>( -        &'a self, -        visit_subexpr: impl FnMut(&'a SE) -> Result<SE2, Err>, -    ) -> Result<ExprF<SE2, L, N, E>, Err> -    where -        L: Ord + Clone, -        N: Clone, -        E: Clone, -    { -        self.traverse_ref( -            visit_subexpr, -            |x| Ok(N::clone(x)), -            |x| Ok(E::clone(x)), -            |x| Ok(L::clone(x)), -        ) -    } - -    pub fn map_ref_simple<'a, SE2>( -        &'a self, -        map_subexpr: impl Fn(&'a SE) -> SE2, -    ) -> ExprF<SE2, L, N, E> -    where -        L: Ord + Clone, -        N: Clone, -        E: Clone, -    { -        self.map_ref(map_subexpr, N::clone, E::clone, L::clone) -    } -} - -impl<N, E> Expr<N, E> { -    fn traverse_embed<E2, Err>( -        &self, -        visit_embed: impl FnMut(&E) -> Result<E2, Err>, -    ) -> Result<Expr<N, E2>, Err> -    where -        N: Clone, -    { -        self.visit(&mut visitor::TraverseEmbedVisitor(visit_embed)) -    } - -    fn map_embed<E2>(&self, mut map_embed: impl FnMut(&E) -> E2) -> Expr<N, E2> -    where -        N: Clone, -    { -        trivial_result(self.traverse_embed(|x| Ok(map_embed(x)))) -    } - -    pub fn roll(&self) -> SubExpr<N, E> -    where -        N: Clone, -        E: Clone, -    { -        rc(ExprF::clone(self)) -    } - -    pub fn squash_embed<E2>( -        &self, -        f: impl FnMut(&E) -> SubExpr<N, E2>, -    ) -> SubExpr<N, E2> -    where -        N: Clone, -    { -        trivial_result(self.visit(&mut visitor::SquashEmbedVisitor(f))) -    } -} - -impl<E: Clone> Expr<X, E> { -    pub fn note_absurd<N>(&self) -> Expr<N, E> { -        self.visit(&mut visitor::NoteAbsurdVisitor) -    } -} - -impl<N: Clone> Expr<N, X> { -    pub fn embed_absurd<E>(&self) -> Expr<N, E> { -        self.visit(&mut visitor::EmbedAbsurdVisitor) -    } -} - -impl<N, E> SubExpr<N, E> { -    pub fn as_ref(&self) -> &Expr<N, E> { -        self.0.as_ref() -    } - -    pub fn traverse_embed<E2, Err>( -        &self, -        visit_embed: impl FnMut(&E) -> Result<E2, Err>, -    ) -> Result<SubExpr<N, E2>, Err> -    where -        N: Clone, -    { -        Ok(rc(self.as_ref().traverse_embed(visit_embed)?)) -    } - -    pub fn map_embed<E2>( -        &self, -        map_embed: impl FnMut(&E) -> E2, -    ) -> SubExpr<N, E2> -    where -        N: Clone, -    { -        rc(self.as_ref().map_embed(map_embed)) -    } - -    pub fn map_subexprs_with_special_handling_of_binders<'a>( -        &'a self, -        map_expr: impl FnMut(&'a Self) -> Self, -        map_under_binder: impl FnMut(&'a Label, &'a Self) -> Self, -    ) -> Self { -        match self.as_ref() { -            ExprF::Embed(_) => SubExpr::clone(self), -            // Recursive call -            // TODO: don't discard the note ! -            ExprF::Note(_, e) => e -                .map_subexprs_with_special_handling_of_binders( -                    map_expr, -                    map_under_binder, -                ), -            // Call ExprF::map_ref -            e => rc(e.map_ref_with_special_handling_of_binders( -                map_expr, -                map_under_binder, -                |_| unreachable!(), -                |_| unreachable!(), -                Label::clone, -            )), -        } -    } - -    pub fn unroll(&self) -> Expr<N, E> -    where -        N: Clone, -        E: Clone, -    { -        ExprF::clone(self.as_ref()) -    } - -    pub fn unnote(&self) -> SubExpr<X, E> -    where -        E: Clone, -    { -        rc(self.as_ref().visit(&mut visitor::UnNoteVisitor)) -    } - -    /// `shift` is used by both normalization and type-checking to avoid variable -    /// capture by shifting variable indices -    /// See https://github.com/dhall-lang/dhall-lang/blob/master/standard/semantics.md#shift -    /// for details -    pub fn shift(&self, delta: isize, var: &V<Label>) -> Self { -        match self.as_ref() { -            ExprF::Var(v) => rc(ExprF::Var(v.shift(delta, var))), -            _ => self.map_subexprs_with_special_handling_of_binders( -                |e| e.shift(delta, var), -                |x: &Label, e| e.shift(delta, &var.shift(1, &x.into())), -            ), -        } -    } - -    pub fn subst_shift(&self, var: &V<Label>, val: &Self) -> Self { -        match self.as_ref() { -            ExprF::Var(v) if v == var => val.clone(), -            ExprF::Var(v) => rc(ExprF::Var(v.shift(-1, var))), -            _ => self.map_subexprs_with_special_handling_of_binders( -                |e| e.subst_shift(var, val), -                |x: &Label, e| { -                    e.subst_shift( -                        &var.shift(1, &x.into()), -                        &val.shift(1, &x.into()), -                    ) -                }, -            ), -        } -    } -} - -impl<N: Clone> SubExpr<N, X> { -    pub fn embed_absurd<T>(&self) -> SubExpr<N, T> { -        rc(self.as_ref().embed_absurd()) -    } -} - -impl<E: Clone> SubExpr<X, E> { -    pub fn note_absurd<N>(&self) -> SubExpr<N, E> { -        rc(self.as_ref().note_absurd()) -    } -} - -impl<N, E> Clone for SubExpr<N, E> { -    fn clone(&self) -> Self { -        SubExpr(Rc::clone(&self.0)) -    } -} - -// Should probably rename this -pub fn rc<N, E>(x: Expr<N, E>) -> SubExpr<N, E> { -    SubExpr(Rc::new(x)) -} - -/// Add an isize to an usize -/// Panics on over/underflow -fn add_ui(u: usize, i: isize) -> usize { -    if i < 0 { -        u.checked_sub(i.checked_neg().unwrap() as usize).unwrap() -    } else { -        u.checked_add(i as usize).unwrap() -    } -} - -impl<Label: PartialEq + Clone> V<Label> { -    pub fn shift(&self, delta: isize, var: &V<Label>) -> Self { -        let V(x, n) = var; -        let V(y, m) = self; -        if x == y && n <= m { -            V(y.clone(), add_ui(*m, delta)) -        } else { -            V(y.clone(), *m) -        } -    } -} - -/// `shift` is used by both normalization and type-checking to avoid variable -/// capture by shifting variable indices -/// See https://github.com/dhall-lang/dhall-lang/blob/master/standard/semantics.md#shift -/// for details -/// -pub fn shift<N, E>( -    delta: isize, -    var: &V<Label>, -    in_expr: &SubExpr<N, E>, -) -> SubExpr<N, E> { -    in_expr.shift(delta, var) -} - -pub fn shift0_multiple<N, E>( -    deltas: &HashMap<Label, isize>, -    in_expr: &SubExpr<N, E>, -) -> SubExpr<N, E> { -    shift0_multiple_inner(&Context::new(), deltas, in_expr) -} - -fn shift0_multiple_inner<N, E>( -    ctx: &Context<Label, ()>, -    deltas: &HashMap<Label, isize>, -    in_expr: &SubExpr<N, E>, -) -> SubExpr<N, E> { -    use crate::ExprF::*; -    match in_expr.as_ref() { -        Var(V(y, m)) if ctx.lookup(y, *m).is_none() => { -            let delta = deltas.get(y).unwrap_or(&0); -            rc(Var(V(y.clone(), add_ui(*m, *delta)))) -        } -        _ => in_expr.map_subexprs_with_special_handling_of_binders( -            |e| shift0_multiple_inner(ctx, deltas, e), -            |x: &Label, e| { -                shift0_multiple_inner(&ctx.insert(x.clone(), ()), deltas, e) -            }, -        ), -    } -} diff --git a/dhall_core/src/import.rs b/dhall_core/src/import.rs deleted file mode 100644 index 00f293c..0000000 --- a/dhall_core/src/import.rs +++ /dev/null @@ -1,64 +0,0 @@ -use std::path::PathBuf; - -/// The beginning of a file path which anchors subsequent path components -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum FilePrefix { -    /// Absolute path -    Absolute, -    /// Path relative to . -    Here, -    /// Path relative to .. -    Parent, -    /// Path relative to ~ -    Home, -} - -/// The location of import (i.e. local vs. remote vs. environment) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ImportLocation { -    Local(FilePrefix, PathBuf), -    Remote(URL), -    Env(String), -    Missing, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct URL { -    pub scheme: Scheme, -    pub authority: String, -    pub path: PathBuf, -    pub query: Option<String>, -    pub headers: Option<Box<ImportHashed>>, -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum Scheme { -    HTTP, -    HTTPS, -} - -/// How to interpret the import's contents (i.e. as Dhall code or raw text) -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum ImportMode { -    Code, -    RawText, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Hash { -    pub protocol: String, -    pub hash: String, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ImportHashed { -    pub location: ImportLocation, -    pub hash: Option<Hash>, -} - -/// Reference to an external resource -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Import { -    pub mode: ImportMode, -    pub location_hashed: ImportHashed, -} diff --git a/dhall_core/src/label.rs b/dhall_core/src/label.rs deleted file mode 100644 index 43c3f53..0000000 --- a/dhall_core/src/label.rs +++ /dev/null @@ -1,34 +0,0 @@ -use std::rc::Rc; - -// The type for labels throughout the AST -// It owns the data because otherwise lifetimes would make recursive imports impossible -#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct Label(Rc<str>); - -impl From<String> for Label { -    fn from(s: String) -> Self { -        let s: &str = &s; -        Label(s.into()) -    } -} - -impl<'a> From<&'a str> for Label { -    fn from(s: &'a str) -> Self { -        Label(Rc::from(s)) -    } -} - -impl From<&Label> for String { -    fn from(x: &Label) -> String { -        x.0.as_ref().to_owned() -    } -} - -impl Label { -    pub fn from_str(s: &str) -> Label { -        Label(s.into()) -    } -    pub fn as_ref(&self) -> &str { -        self.0.as_ref() -    } -} diff --git a/dhall_core/src/lib.rs b/dhall_core/src/lib.rs deleted file mode 100644 index 3db8222..0000000 --- a/dhall_core/src/lib.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![feature(trace_macros)] -#![feature(slice_patterns)] -#![allow( -    clippy::many_single_char_names, -    clippy::should_implement_trait, -    clippy::new_without_default, -    clippy::type_complexity -)] - -//! This crate contains the core AST-handling primitives for the [dhall-rust][dhall-rust] crate. -//! This is highly unstable and breaks regularly; use at your own risk. -//! -//! [dhall-rust]: https://github.com/Nadrieril/dhall-rust - -mod core; -pub use crate::core::*; -mod import; -pub use crate::import::*; -mod label; -pub use crate::label::*; -mod text; -pub use crate::text::*; -mod printer; -pub use crate::printer::*; -mod parser; -pub use crate::parser::*; -pub mod context; -pub mod visitor; diff --git a/dhall_core/src/parser.rs b/dhall_core/src/parser.rs deleted file mode 100644 index 12383d4..0000000 --- a/dhall_core/src/parser.rs +++ /dev/null @@ -1,984 +0,0 @@ -use itertools::Itertools; -use pest::iterators::Pair; -use pest::Parser; -pub use pest::Span; -use std::borrow::Cow; -use std::collections::BTreeMap; -use std::path::PathBuf; - -use dhall_generated_parser::{DhallParser, Rule}; - -use crate::*; - -// This file consumes the parse tree generated by pest and turns it into -// our own AST. All those custom macros should eventually moved into -// their own crate because they are quite general and useful. For now they -// are here and hopefully you can figure out how they work. - -use crate::ExprF::*; - -type ParsedExpr<'a> = Expr<Span<'a>, Import>; -type ParsedSubExpr<'a> = SubExpr<Span<'a>, Import>; -type ParsedText<'a> = InterpolatedText<SubExpr<Span<'a>, Import>>; -type ParsedTextContents<'a> = -    InterpolatedTextContents<SubExpr<Span<'a>, Import>>; - -pub type ParseError = pest::error::Error<Rule>; - -pub type ParseResult<T> = Result<T, ParseError>; - -fn rc(x: ParsedExpr<'_>) -> ParsedSubExpr<'_> { -    crate::rc(x) -} - -fn spanned<'a>(_span: Span<'a>, x: ParsedExpr<'a>) -> ParsedExpr<'a> { -    x -    // This breaks equality testing; I need to fix that first -    // Note(span, rc(x)) -} - -#[derive(Debug)] -enum Either<A, B> { -    Left(A), -    Right(B), -} - -impl crate::Builtin { -    pub fn parse(s: &str) -> Option<Self> { -        use crate::Builtin::*; -        match s { -            "Bool" => Some(Bool), -            "Natural" => Some(Natural), -            "Integer" => Some(Integer), -            "Double" => Some(Double), -            "Text" => Some(Text), -            "List" => Some(List), -            "Optional" => Some(Optional), -            "None" => Some(OptionalNone), -            "Natural/build" => Some(NaturalBuild), -            "Natural/fold" => Some(NaturalFold), -            "Natural/isZero" => Some(NaturalIsZero), -            "Natural/even" => Some(NaturalEven), -            "Natural/odd" => Some(NaturalOdd), -            "Natural/toInteger" => Some(NaturalToInteger), -            "Natural/show" => Some(NaturalShow), -            "Integer/toDouble" => Some(IntegerToDouble), -            "Integer/show" => Some(IntegerShow), -            "Double/show" => Some(DoubleShow), -            "List/build" => Some(ListBuild), -            "List/fold" => Some(ListFold), -            "List/length" => Some(ListLength), -            "List/head" => Some(ListHead), -            "List/last" => Some(ListLast), -            "List/indexed" => Some(ListIndexed), -            "List/reverse" => Some(ListReverse), -            "Optional/fold" => Some(OptionalFold), -            "Optional/build" => Some(OptionalBuild), -            "Text/show" => Some(TextShow), -            _ => None, -        } -    } -} - -pub fn custom_parse_error(pair: &Pair<Rule>, msg: String) -> ParseError { -    let msg = -        format!("{} while matching on:\n{}", msg, debug_pair(pair.clone())); -    let e = pest::error::ErrorVariant::CustomError { message: msg }; -    pest::error::Error::new_from_span(e, pair.as_span()) -} - -fn debug_pair(pair: Pair<Rule>) -> String { -    use std::fmt::Write; -    let mut s = String::new(); -    fn aux(s: &mut String, indent: usize, prefix: String, pair: Pair<Rule>) { -        let indent_str = "| ".repeat(indent); -        let rule = pair.as_rule(); -        let contents = pair.as_str(); -        let mut inner = pair.into_inner(); -        let mut first = true; -        while let Some(p) = inner.next() { -            if first { -                first = false; -                let last = inner.peek().is_none(); -                if last && p.as_str() == contents { -                    let prefix = format!("{}{:?} > ", prefix, rule); -                    aux(s, indent, prefix, p); -                    continue; -                } else { -                    writeln!( -                        s, -                        r#"{}{}{:?}: "{}""#, -                        indent_str, prefix, rule, contents -                    ) -                    .unwrap(); -                } -            } -            aux(s, indent + 1, "".into(), p); -        } -        if first { -            writeln!( -                s, -                r#"{}{}{:?}: "{}""#, -                indent_str, prefix, rule, contents -            ) -            .unwrap(); -        } -    } -    aux(&mut s, 0, "".into(), pair); -    s -} - -macro_rules! make_parser { -    (@pattern, rule, $name:ident) => (Rule::$name); -    (@pattern, token_rule, $name:ident) => (Rule::$name); -    (@pattern, rule_group, $name:ident) => (_); -    (@filter, rule) => (true); -    (@filter, token_rule) => (true); -    (@filter, rule_group) => (false); - -    (@body, -        $pair:expr, -        $children:expr, -        rule!( $name:ident<$o:ty>; $($args:tt)* ) -    ) => ( -        make_parser!(@body, -            $pair, -            $children, -            rule!( $name<$o> as $name; $($args)* ) -        ) -    ); -    (@body, -        $pair:expr, -        $children:expr, -        rule!( -            $name:ident<$o:ty> -            as $group:ident; -            captured_str!($x:pat) => $body:expr -        ) -    ) => ({ -        let $x = $pair.as_str(); -        let res: $o = $body; -        Ok(ParsedValue::$group(res)) -    }); -    (@body, -        $pair:expr, -        $children:expr, -        rule!( -            $name:ident<$o:ty> -            as $group:ident; -            children!( $( [$($args:tt)*] => $body:expr ),* $(,)* ) -        ) -    ) => ({ -        #[allow(unused_imports)] -        use ParsedValue::*; -        #[allow(unreachable_code)] -        let res: $o = improved_slice_patterns::match_vec!($children; -            $( [$($args)*] => $body, )* -            [x..] => Err( -                format!("Unexpected children: {:?}", x.collect::<Vec<_>>()) -            )?, -        ).map_err(|_| -> String { unreachable!() })?; -        Ok(ParsedValue::$group(res)) -    }); -    (@body, -        $pair:expr, -        $children:expr, -        rule!( -            $name:ident<$o:ty> -            as $group:ident; -            $span:ident; -            $($args:tt)* -        ) -    ) => ({ -        let $span = $pair.as_span(); -        make_parser!(@body, -            $pair, -            $children, -            rule!( -                $name<$o> -                as $group; -                $($args)* -            ) -        ) -    }); -    (@body, -        $pair:expr, -        $children:expr, -        token_rule!($name:ident<$o:ty>) -    ) => ({ -        Ok(ParsedValue::$name(())) -    }); -    (@body, $pair:expr, $children:expr, rule_group!( $name:ident<$o:ty> )) => ( -        unreachable!() -    ); - -    ($( $submac:ident!( $name:ident<$o:ty> $($args:tt)* ); )*) => ( -        #[allow(non_camel_case_types, dead_code, clippy::large_enum_variant)] -        #[derive(Debug)] -        enum ParsedValue<'a> { -            $( $name($o), )* -        } - -        fn parse_any<'a>(pair: Pair<'a, Rule>, children: Vec<ParsedValue<'a>>) -                -> Result<ParsedValue<'a>, String> { -            match pair.as_rule() { -                $( -                    make_parser!(@pattern, $submac, $name) -                    if make_parser!(@filter, $submac) -                    => make_parser!(@body, pair, children, -                                           $submac!( $name<$o> $($args)* )) -                    , -                )* -                r => Err(format!("Unexpected {:?}", r)), -            } -        } -    ); -} - -// Non-recursive implementation to avoid stack overflows -fn do_parse<'a>(initial_pair: Pair<'a, Rule>) -> ParseResult<ParsedValue<'a>> { -    enum StackFrame<'a> { -        Unprocessed(Pair<'a, Rule>), -        Processed(Pair<'a, Rule>, usize), -    } -    use StackFrame::*; -    let mut pairs_stack: Vec<StackFrame> = -        vec![Unprocessed(initial_pair.clone())]; -    let mut values_stack: Vec<ParsedValue> = vec![]; -    while let Some(p) = pairs_stack.pop() { -        match p { -            Unprocessed(mut pair) => loop { -                let mut pairs: Vec<_> = pair.clone().into_inner().collect(); -                let n_children = pairs.len(); -                if n_children == 1 && can_be_shortcutted(pair.as_rule()) { -                    pair = pairs.pop().unwrap(); -                    continue; -                } else { -                    pairs_stack.push(Processed(pair, n_children)); -                    pairs_stack -                        .extend(pairs.into_iter().map(StackFrame::Unprocessed)); -                    break; -                } -            }, -            Processed(pair, n) => { -                let mut children: Vec<_> = -                    values_stack.split_off(values_stack.len() - n); -                children.reverse(); -                let val = match parse_any(pair.clone(), children) { -                    Ok(v) => v, -                    Err(msg) => Err(custom_parse_error(&pair, msg))?, -                }; -                values_stack.push(val); -            } -        } -    } -    Ok(values_stack.pop().unwrap()) -} - -// List of rules that can be shortcutted if they have a single child -fn can_be_shortcutted(rule: Rule) -> bool { -    use Rule::*; -    match rule { -        expression -        | import_alt_expression -        | or_expression -        | plus_expression -        | text_append_expression -        | list_append_expression -        | and_expression -        | combine_expression -        | prefer_expression -        | combine_types_expression -        | times_expression -        | equal_expression -        | not_equal_expression -        | application_expression -        | first_application_expression -        | selector_expression -        | annotated_expression => true, -        _ => false, -    } -} - -make_parser! { -    token_rule!(EOI<()>); - -    rule!(simple_label<Label>; -        captured_str!(s) => Label::from(s.trim().to_owned()) -    ); -    rule!(quoted_label<Label>; -        captured_str!(s) => Label::from(s.trim().to_owned()) -    ); -    rule!(label<Label>; children!( -        [simple_label(l)] => l, -        [quoted_label(l)] => l, -    )); - -    rule!(double_quote_literal<ParsedText<'a>>; children!( -        [double_quote_chunk(chunks)..] => { -            chunks.collect() -        } -    )); - -    rule!(double_quote_chunk<ParsedTextContents<'a>>; children!( -        [interpolation(e)] => { -            InterpolatedTextContents::Expr(rc(e)) -        }, -        [double_quote_escaped(s)] => { -            InterpolatedTextContents::Text(s) -        }, -        [double_quote_char(s)] => { -            InterpolatedTextContents::Text(s.to_owned()) -        }, -    )); -    rule!(double_quote_escaped<String>; -        captured_str!(s) => { -            match s { -                "\"" => "\"".to_owned(), -                "$" => "$".to_owned(), -                "\\" => "\\".to_owned(), -                "/" => "/".to_owned(), -                "b" => "\u{0008}".to_owned(), -                "f" => "\u{000C}".to_owned(), -                "n" => "\n".to_owned(), -                "r" => "\r".to_owned(), -                "t" => "\t".to_owned(), -                _ => { -                    // "uXXXX" -                    use std::convert::TryFrom; -                    let c = u16::from_str_radix(&s[1..5], 16).unwrap(); -                    let c = char::try_from(u32::from(c)).unwrap(); -                    std::iter::once(c).collect() -                } -            } -        } -    ); -    rule!(double_quote_char<&'a str>; -        captured_str!(s) => s -    ); - -    rule!(single_quote_literal<ParsedText<'a>>; children!( -        [single_quote_continue(lines)] => { -            let space = InterpolatedTextContents::Text(" ".to_owned()); -            let newline = InterpolatedTextContents::Text("\n".to_owned()); -            let min_indent = lines -                .iter() -                .map(|l| { -                    l.iter().rev().take_while(|c| **c == space).count() -                }) -                .min() -                .unwrap(); - -            lines -                .into_iter() -                .rev() -                .map(|mut l| { l.split_off(l.len() - min_indent); l }) -                .intersperse(vec![newline]) -                .flat_map(|x| x.into_iter().rev()) -                .collect::<ParsedText>() -        } -    )); -    rule!(single_quote_char<&'a str>; -        captured_str!(s) => s -    ); -    rule!(escaped_quote_pair<&'a str>; -        captured_str!(_) => "''" -    ); -    rule!(escaped_interpolation<&'a str>; -        captured_str!(_) => "${" -    ); -    rule!(interpolation<ParsedExpr<'a>>; children!( -        [expression(e)] => e -    )); - -    rule!(single_quote_continue<Vec<Vec<ParsedTextContents<'a>>>>; children!( -        [interpolation(c), single_quote_continue(lines)] => { -            let c = InterpolatedTextContents::Expr(rc(c)); -            let mut lines = lines; -            lines.last_mut().unwrap().push(c); -            lines -        }, -        [escaped_quote_pair(c), single_quote_continue(lines)] => { -            let c = InterpolatedTextContents::Text(c.to_owned()); -            let mut lines = lines; -            lines.last_mut().unwrap().push(c); -            lines -        }, -        [escaped_interpolation(c), single_quote_continue(lines)] => { -            let c = InterpolatedTextContents::Text(c.to_owned()); -            let mut lines = lines; -            lines.last_mut().unwrap().push(c); -            lines -        }, -        [single_quote_char("\n"), single_quote_continue(lines)] => { -            let mut lines = lines; -            lines.push(vec![]); -            lines -        }, -        [single_quote_char(c), single_quote_continue(lines)] => { -            let c = InterpolatedTextContents::Text(c.to_owned()); -            let mut lines = lines; -            lines.last_mut().unwrap().push(c); -            lines -        }, -        [] => { -            vec![vec![]] -        }, -    )); - -    rule!(builtin<ParsedExpr<'a>>; span; -        captured_str!(s) => { -            spanned(span, match crate::Builtin::parse(s) { -                Some(b) => Builtin(b), -                None => match s { -                    "True" => BoolLit(true), -                    "False" => BoolLit(false), -                    "Type" => Const(crate::Const::Type), -                    "Kind" => Const(crate::Const::Kind), -                    "Sort" => Const(crate::Const::Sort), -                    _ => Err( -                        format!("Unrecognized builtin: '{}'", s) -                    )?, -                } -            }) -        } -    ); - -    token_rule!(NaN<()>); -    token_rule!(minus_infinity_literal<()>); -    token_rule!(plus_infinity_literal<()>); - -    rule!(numeric_double_literal<core::Double>; -        captured_str!(s) => { -            let s = s.trim(); -            match s.parse::<f64>() { -                Ok(x) if x.is_infinite() => -                    Err(format!("Overflow while parsing double literal '{}'", s))?, -                Ok(x) => NaiveDouble::from(x), -                Err(e) => Err(format!("{}", e))?, -            } -        } -    ); - -    rule!(double_literal<core::Double>; children!( -        [numeric_double_literal(n)] => n, -        [minus_infinity_literal(n)] => std::f64::NEG_INFINITY.into(), -        [plus_infinity_literal(n)] => std::f64::INFINITY.into(), -        [NaN(n)] => std::f64::NAN.into(), -    )); - -    rule!(natural_literal<core::Natural>; -        captured_str!(s) => { -            s.trim() -                .parse() -                .map_err(|e| format!("{}", e))? -        } -    ); - -    rule!(integer_literal<core::Integer>; -        captured_str!(s) => { -            s.trim() -                .parse() -                .map_err(|e| format!("{}", e))? -        } -    ); - -    rule!(identifier<ParsedExpr<'a>> as expression; span; children!( -        [variable(v)] => { -            spanned(span, Var(v)) -        }, -        [builtin(e)] => e, -    )); - -    rule!(variable<V<Label>>; children!( -        [label(l), natural_literal(idx)] => { -            V(l, idx) -        }, -        [label(l)] => { -            V(l, 0) -        }, -    )); - -    rule!(unquoted_path_component<&'a str>; captured_str!(s) => s); -    rule!(quoted_path_component<&'a str>; captured_str!(s) => s); -    rule!(path_component<String>; children!( -        [unquoted_path_component(s)] => { -            percent_encoding::percent_decode(s.as_bytes()) -                .decode_utf8_lossy() -                .into_owned() -        }, -        [quoted_path_component(s)] => s.to_string(), -    )); -    rule!(path<PathBuf>; children!( -        [path_component(components)..] => { -            components.collect() -        } -    )); - -    rule_group!(local<(FilePrefix, PathBuf)>); - -    rule!(parent_path<(FilePrefix, PathBuf)> as local; children!( -        [path(p)] => (FilePrefix::Parent, p) -    )); -    rule!(here_path<(FilePrefix, PathBuf)> as local; children!( -        [path(p)] => (FilePrefix::Here, p) -    )); -    rule!(home_path<(FilePrefix, PathBuf)> as local; children!( -        [path(p)] => (FilePrefix::Home, p) -    )); -    rule!(absolute_path<(FilePrefix, PathBuf)> as local; children!( -        [path(p)] => (FilePrefix::Absolute, p) -    )); - -    rule!(scheme<Scheme>; captured_str!(s) => match s { -        "http" => Scheme::HTTP, -        "https" => Scheme::HTTPS, -        _ => unreachable!(), -    }); - -    rule!(http_raw<URL>; children!( -        [scheme(sch), authority(auth), path(p)] => URL { -            scheme: sch, -            authority: auth, -            path: p, -            query: None, -            headers: None, -        }, -        [scheme(sch), authority(auth), path(p), query(q)] => URL { -            scheme: sch, -            authority: auth, -            path: p, -            query: Some(q), -            headers: None, -        }, -    )); - -    rule!(authority<String>; captured_str!(s) => s.to_owned()); - -    rule!(query<String>; captured_str!(s) => s.to_owned()); - -    rule!(http<URL>; children!( -        [http_raw(url)] => url, -        [http_raw(url), import_hashed(ih)] => -            URL { headers: Some(Box::new(ih)), ..url }, -    )); - -    rule!(env<String>; children!( -        [bash_environment_variable(s)] => s, -        [posix_environment_variable(s)] => s, -    )); -    rule!(bash_environment_variable<String>; captured_str!(s) => s.to_owned()); -    rule!(posix_environment_variable<String>; children!( -        [posix_environment_variable_character(chars)..] => { -            chars.collect() -        }, -    )); -    rule!(posix_environment_variable_character<Cow<'a, str>>; -        captured_str!(s) => { -            match s { -                "\\\"" => Cow::Owned("\"".to_owned()), -                "\\\\" => Cow::Owned("\\".to_owned()), -                "\\a" =>  Cow::Owned("\u{0007}".to_owned()), -                "\\b" =>  Cow::Owned("\u{0008}".to_owned()), -                "\\f" =>  Cow::Owned("\u{000C}".to_owned()), -                "\\n" =>  Cow::Owned("\n".to_owned()), -                "\\r" =>  Cow::Owned("\r".to_owned()), -                "\\t" =>  Cow::Owned("\t".to_owned()), -                "\\v" =>  Cow::Owned("\u{000B}".to_owned()), -                _ => Cow::Borrowed(s) -            } -        } -    ); - -    token_rule!(missing<()>); - -    rule!(import_type<ImportLocation>; children!( -        [missing(_)] => { -            ImportLocation::Missing -        }, -        [env(e)] => { -            ImportLocation::Env(e) -        }, -        [http(url)] => { -            ImportLocation::Remote(url) -        }, -        [local((prefix, p))] => { -            ImportLocation::Local(prefix, p) -        }, -    )); - -    rule!(hash<Hash>; captured_str!(s) => -        Hash { -            protocol: s.trim()[..6].to_owned(), -            hash: s.trim()[7..].to_owned(), -        } -    ); - -    rule!(import_hashed<ImportHashed>; children!( -        [import_type(location)] => -            ImportHashed { location, hash: None }, -        [import_type(location), hash(h)] => -            ImportHashed { location, hash: Some(h) }, -    )); - -    token_rule!(Text<()>); - -    rule!(import<ParsedExpr<'a>> as expression; span; children!( -        [import_hashed(location_hashed)] => { -            spanned(span, Embed(Import { -                mode: ImportMode::Code, -                location_hashed -            })) -        }, -        [import_hashed(location_hashed), Text(_)] => { -            spanned(span, Embed(Import { -                mode: ImportMode::RawText, -                location_hashed -            })) -        }, -    )); - -    token_rule!(lambda<()>); -    token_rule!(forall<()>); -    token_rule!(arrow<()>); -    token_rule!(merge<()>); -    token_rule!(if_<()>); -    token_rule!(in_<()>); - -    rule!(expression<ParsedExpr<'a>> as expression; span; children!( -        [lambda(()), label(l), expression(typ), -                arrow(()), expression(body)] => { -            spanned(span, Lam(l, rc(typ), rc(body))) -        }, -        [if_(()), expression(cond), expression(left), expression(right)] => { -            spanned(span, BoolIf(rc(cond), rc(left), rc(right))) -        }, -        [let_binding(bindings).., in_(()), expression(final_expr)] => { -            bindings.rev().fold( -                final_expr, -                |acc, x| Let(x.0, x.1, x.2, rc(acc)) -            ) -        }, -        [forall(()), label(l), expression(typ), -                arrow(()), expression(body)] => { -            spanned(span, Pi(l, rc(typ), rc(body))) -        }, -        [expression(typ), arrow(()), expression(body)] => { -            spanned(span, Pi("_".into(), rc(typ), rc(body))) -        }, -        [merge(()), expression(x), expression(y), expression(z)] => { -            spanned(span, Merge(rc(x), rc(y), Some(rc(z)))) -        }, -        [expression(e)] => e, -    )); - -    rule!(let_binding<(Label, Option<ParsedSubExpr<'a>>, ParsedSubExpr<'a>)>; -            children!( -        [label(name), expression(annot), expression(expr)] => -            (name, Some(rc(annot)), rc(expr)), -        [label(name), expression(expr)] => -            (name, None, rc(expr)), -    )); - -    token_rule!(List<()>); -    token_rule!(Optional<()>); - -    rule!(empty_collection<ParsedExpr<'a>> as expression; span; children!( -        [List(_), expression(t)] => { -            spanned(span, EmptyListLit(rc(t))) -        }, -        [Optional(_), expression(t)] => { -            spanned(span, OldOptionalLit(None, rc(t))) -        }, -    )); - -    rule!(non_empty_optional<ParsedExpr<'a>> as expression; span; children!( -        [expression(x), Optional(_), expression(t)] => { -            spanned(span, OldOptionalLit(Some(rc(x)), rc(t))) -        } -    )); - -    rule!(import_alt_expression<ParsedExpr<'a>> as expression; children!( -        [expression(e)] => e, -        [expression(first), expression(rest)..] => { -            let o = crate::BinOp::ImportAlt; -            rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) -        }, -    )); -    rule!(or_expression<ParsedExpr<'a>> as expression; children!( -        [expression(e)] => e, -        [expression(first), expression(rest)..] => { -            let o = crate::BinOp::BoolOr; -            rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) -        }, -    )); -    rule!(plus_expression<ParsedExpr<'a>> as expression; children!( -        [expression(e)] => e, -        [expression(first), expression(rest)..] => { -            let o = crate::BinOp::NaturalPlus; -            rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) -        }, -    )); -    rule!(text_append_expression<ParsedExpr<'a>> as expression; children!( -        [expression(e)] => e, -        [expression(first), expression(rest)..] => { -            let o = crate::BinOp::TextAppend; -            rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) -        }, -    )); -    rule!(list_append_expression<ParsedExpr<'a>> as expression; children!( -        [expression(e)] => e, -        [expression(first), expression(rest)..] => { -            let o = crate::BinOp::ListAppend; -            rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) -        }, -    )); -    rule!(and_expression<ParsedExpr<'a>> as expression; children!( -        [expression(e)] => e, -        [expression(first), expression(rest)..] => { -            let o = crate::BinOp::BoolAnd; -            rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) -        }, -    )); -    rule!(combine_expression<ParsedExpr<'a>> as expression; children!( -        [expression(e)] => e, -        [expression(first), expression(rest)..] => { -            let o = crate::BinOp::Combine; -            rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) -        }, -    )); -    rule!(prefer_expression<ParsedExpr<'a>> as expression; children!( -        [expression(e)] => e, -        [expression(first), expression(rest)..] => { -            let o = crate::BinOp::Prefer; -            rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) -        }, -    )); -    rule!(combine_types_expression<ParsedExpr<'a>> as expression; children!( -        [expression(e)] => e, -        [expression(first), expression(rest)..] => { -            let o = crate::BinOp::CombineTypes; -            rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) -        }, -    )); -    rule!(times_expression<ParsedExpr<'a>> as expression; children!( -        [expression(e)] => e, -        [expression(first), expression(rest)..] => { -            let o = crate::BinOp::NaturalTimes; -            rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) -        }, -    )); -    rule!(equal_expression<ParsedExpr<'a>> as expression; children!( -        [expression(e)] => e, -        [expression(first), expression(rest)..] => { -            let o = crate::BinOp::BoolEQ; -            rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) -        }, -    )); -    rule!(not_equal_expression<ParsedExpr<'a>> as expression; children!( -        [expression(e)] => e, -        [expression(first), expression(rest)..] => { -            let o = crate::BinOp::BoolNE; -            rest.fold(first, |acc, e| BinOp(o, rc(acc), rc(e))) -        }, -    )); - -    rule!(annotated_expression<ParsedExpr<'a>> as expression; span; children!( -        [expression(e)] => e, -        [expression(e), expression(annot)] => { -            spanned(span, Annot(rc(e), rc(annot))) -        }, -    )); - -    token_rule!(Some_<()>); - -    rule!(application_expression<ParsedExpr<'a>> as expression; children!( -        [expression(e)] => e, -        [expression(first), expression(rest)..] => { -            rest.fold(first, |acc, e| App(rc(acc), rc(e))) -        }, -    )); - -    rule!(first_application_expression<ParsedExpr<'a>> as expression; span; -            children!( -        [expression(e)] => e, -        [Some_(()), expression(e)] => { -            spanned(span, SomeLit(rc(e))) -        }, -        [merge(()), expression(x), expression(y)] => { -            spanned(span, Merge(rc(x), rc(y), None)) -        }, -    )); - -    rule!(selector_expression<ParsedExpr<'a>> as expression; children!( -        [expression(e)] => e, -        [expression(first), selector(rest)..] => { -            rest.fold(first, |acc, e| match e { -                Either::Left(l) => Field(rc(acc), l), -                Either::Right(ls) => Projection(rc(acc), ls), -            }) -        } -    )); - -    rule!(selector<Either<Label, Vec<Label>>>; children!( -        [label(l)] => Either::Left(l), -        [labels(ls)] => Either::Right(ls), -    )); - -    rule!(labels<Vec<Label>>; children!( -        [label(ls)..] => ls.collect(), -    )); - -    rule!(primitive_expression<ParsedExpr<'a>> as expression; span; children!( -        [double_literal(n)] => spanned(span, DoubleLit(n)), -        [natural_literal(n)] => spanned(span, NaturalLit(n)), -        [integer_literal(n)] => spanned(span, IntegerLit(n)), -        [double_quote_literal(s)] => spanned(span, TextLit(s)), -        [single_quote_literal(s)] => spanned(span, TextLit(s)), -        [expression(e)] => e, -    )); - -    rule!(empty_record_literal<ParsedExpr<'a>> as expression; span; -        captured_str!(_) => spanned(span, RecordLit(BTreeMap::new())) -    ); - -    rule!(empty_record_type<ParsedExpr<'a>> as expression; span; -        captured_str!(_) => spanned(span, RecordType(BTreeMap::new())) -    ); - -    rule!(non_empty_record_type_or_literal<ParsedExpr<'a>> as expression; span; -          children!( -        [label(first_label), non_empty_record_type(rest)] => { -            let (first_expr, mut map) = rest; -            map.insert(first_label, rc(first_expr)); -            spanned(span, RecordType(map)) -        }, -        [label(first_label), non_empty_record_literal(rest)] => { -            let (first_expr, mut map) = rest; -            map.insert(first_label, rc(first_expr)); -            spanned(span, RecordLit(map)) -        }, -    )); - -    rule!(non_empty_record_type -          <(ParsedExpr<'a>, BTreeMap<Label, ParsedSubExpr<'a>>)>; children!( -        [expression(expr), record_type_entry(entries)..] => { -            (expr, entries.collect()) -        } -    )); - -    rule!(record_type_entry<(Label, ParsedSubExpr<'a>)>; children!( -        [label(name), expression(expr)] => (name, rc(expr)) -    )); - -    rule!(non_empty_record_literal -          <(ParsedExpr<'a>, BTreeMap<Label, ParsedSubExpr<'a>>)>; children!( -        [expression(expr), record_literal_entry(entries)..] => { -            (expr, entries.collect()) -        } -    )); - -    rule!(record_literal_entry<(Label, ParsedSubExpr<'a>)>; children!( -        [label(name), expression(expr)] => (name, rc(expr)) -    )); - -    rule!(union_type_or_literal<ParsedExpr<'a>> as expression; span; children!( -        [empty_union_type(_)] => { -            spanned(span, UnionType(BTreeMap::new())) -        }, -        [non_empty_union_type_or_literal((Some((l, e)), entries))] => { -            spanned(span, UnionLit(l, e, entries)) -        }, -        [non_empty_union_type_or_literal((None, entries))] => { -            spanned(span, UnionType(entries)) -        }, -    )); - -    token_rule!(empty_union_type<()>); - -    rule!(non_empty_union_type_or_literal -          <(Option<(Label, ParsedSubExpr<'a>)>, -            BTreeMap<Label, Option<ParsedSubExpr<'a>>>)>; -            children!( -        [label(l), union_literal_variant_value((e, entries))] => { -            (Some((l, e)), entries) -        }, -        [label(l), union_type_or_literal_variant_type((e, rest))] => { -            let (x, mut entries) = rest; -            entries.insert(l, e); -            (x, entries) -        }, -    )); - -    rule!(union_literal_variant_value -          <(ParsedSubExpr<'a>, BTreeMap<Label, Option<ParsedSubExpr<'a>>>)>; -            children!( -        [expression(e), union_type_entry(entries)..] => { -            (rc(e), entries.collect()) -        }, -    )); - -    rule!(union_type_entry<(Label, Option<ParsedSubExpr<'a>>)>; children!( -        [label(name), expression(expr)] => (name, Some(rc(expr))), -        [label(name)] => (name, None), -    )); - -    // TODO: unary union variants -    rule!(union_type_or_literal_variant_type -          <(Option<ParsedSubExpr<'a>>, -            (Option<(Label, ParsedSubExpr<'a>)>, -             BTreeMap<Label, Option<ParsedSubExpr<'a>>>))>; -                children!( -        [expression(e), non_empty_union_type_or_literal(rest)] => { -            (Some(rc(e)), rest) -        }, -        [expression(e)] => { -            (Some(rc(e)), (None, BTreeMap::new())) -        }, -        [non_empty_union_type_or_literal(rest)] => { -            (None, rest) -        }, -        [] => { -            (None, (None, BTreeMap::new())) -        }, -    )); - -    rule!(non_empty_list_literal<ParsedExpr<'a>> as expression; span; -          children!( -        [expression(items)..] => spanned( -            span, -            NEListLit(items.map(rc).collect()) -        ) -    )); - -    rule!(final_expression<ParsedExpr<'a>> as expression; children!( -        [expression(e), EOI(_eoi)] => e -    )); -} - -pub fn parse_expr<'a>(s: &'a str) -> ParseResult<ParsedSubExpr<'a>> { -    let mut pairs = DhallParser::parse(Rule::final_expression, s)?; -    let expr = do_parse(pairs.next().unwrap())?; -    assert_eq!(pairs.next(), None); -    match expr { -        ParsedValue::expression(e) => Ok(rc(e)), -        _ => unreachable!(), -    } -    // Ok(rc(BoolLit(false))) -} - -#[test] -fn test_parse() { -    // let expr = r#"{ x = "foo", y = 4 }.x"#; -    // let expr = r#"(1 + 2) * 3"#; -    let expr = r#"(1) + 3 * 5"#; -    println!("{:?}", parse_expr(expr)); -    match parse_expr(expr) { -        Err(e) => { -            println!("{:?}", e); -            println!("{}", e); -        } -        ok => println!("{:?}", ok), -    }; -    // assert!(false); -} diff --git a/dhall_core/src/printer.rs b/dhall_core/src/printer.rs deleted file mode 100644 index 704000a..0000000 --- a/dhall_core/src/printer.rs +++ /dev/null @@ -1,498 +0,0 @@ -use crate::*; -use itertools::Itertools; -use std::fmt::{self, Display}; - -/// Generic instance that delegates to subexpressions -impl<SE: Display + Clone, N, E: Display> Display for ExprF<SE, Label, N, E> { -    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { -        use crate::ExprF::*; -        match self { -            Lam(a, b, c) => { -                write!(f, "λ({} : {}) → {}", a, b, c)?; -            } -            BoolIf(a, b, c) => { -                write!(f, "if {} then {} else {}", a, b, c)?; -            } -            Pi(a, b, c) if &String::from(a) == "_" => { -                write!(f, "{} → {}", b, c)?; -            } -            Pi(a, b, c) => { -                write!(f, "∀({} : {}) → {}", a, b, c)?; -            } -            Let(a, b, c, d) => { -                write!(f, "let {}", a)?; -                if let Some(b) = b { -                    write!(f, " : {}", b)?; -                } -                write!(f, " = {} in {}", c, d)?; -            } -            EmptyListLit(t) => { -                write!(f, "[] : List {}", t)?; -            } -            NEListLit(es) => { -                fmt_list("[", ", ", "]", es, f, Display::fmt)?; -            } -            OldOptionalLit(None, t) => { -                write!(f, "[] : Optional {}", t)?; -            } -            OldOptionalLit(Some(x), t) => { -                write!(f, "[{}] : Optional {}", x, t)?; -            } -            SomeLit(e) => { -                write!(f, "Some {}", e)?; -            } -            Merge(a, b, c) => { -                write!(f, "merge {} {}", a, b)?; -                if let Some(c) = c { -                    write!(f, " : {}", c)?; -                } -            } -            Annot(a, b) => { -                write!(f, "{} : {}", a, b)?; -            } -            ExprF::BinOp(op, a, b) => { -                write!(f, "{} {} {}", a, op, b)?; -            } -            ExprF::App(a, b) => { -                write!(f, "{} {}", a, b)?; -            } -            Field(a, b) => { -                write!(f, "{}.{}", a, b)?; -            } -            Projection(e, ls) => { -                write!(f, "{}.", e)?; -                fmt_list("{ ", ", ", " }", ls, f, Display::fmt)?; -            } -            Var(a) => a.fmt(f)?, -            Const(k) => k.fmt(f)?, -            Builtin(v) => v.fmt(f)?, -            BoolLit(true) => f.write_str("True")?, -            BoolLit(false) => f.write_str("False")?, -            NaturalLit(a) => a.fmt(f)?, -            IntegerLit(a) if *a >= 0 => { -                f.write_str("+")?; -                a.fmt(f)?; -            } -            IntegerLit(a) => a.fmt(f)?, -            DoubleLit(a) => a.fmt(f)?, -            TextLit(a) => a.fmt(f)?, -            RecordType(a) if a.is_empty() => f.write_str("{}")?, -            RecordType(a) => fmt_list("{ ", ", ", " }", a, f, |(k, t), f| { -                write!(f, "{} : {}", k, t) -            })?, -            RecordLit(a) if a.is_empty() => f.write_str("{=}")?, -            RecordLit(a) => fmt_list("{ ", ", ", " }", a, f, |(k, v), f| { -                write!(f, "{} = {}", k, v) -            })?, -            UnionType(a) => fmt_list("< ", " | ", " >", a, f, |(k, v), f| { -                write!(f, "{}", k)?; -                if let Some(v) = v { -                    write!(f, ": {}", v)?; -                } -                Ok(()) -            })?, -            UnionLit(a, b, c) => { -                write!(f, "< {} = {}", a, b)?; -                for (k, v) in c { -                    write!(f, " | {}", k)?; -                    if let Some(v) = v { -                        write!(f, ": {}", v)?; -                    } -                } -                f.write_str(" >")? -            } -            Embed(a) => a.fmt(f)?, -            Note(_, b) => b.fmt(f)?, -        } -        Ok(()) -    } -} - -// There is a one-to-one correspondence between the formatter and the grammar. Each phase is -// named after a corresponding grammar group, and the structure of the formatter reflects -// the relationship between the corresponding grammar rules. This leads to the nice property -// of automatically getting all the parentheses and precedences right. -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] -enum PrintPhase { -    Base, -    Operator, -    BinOp(core::BinOp), -    App, -    Import, -    Primitive, -} - -// Wraps an Expr with a phase, so that phase selsction can be done -// separate from the actual printing -#[derive(Clone)] -struct PhasedExpr<'a, S, A>(&'a SubExpr<S, A>, PrintPhase); - -impl<'a, S: Clone, A: Display + Clone> Display for PhasedExpr<'a, S, A> { -    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { -        self.0.as_ref().fmt_phase(f, self.1) -    } -} - -impl<'a, S: Clone, A: Display + Clone> PhasedExpr<'a, S, A> { -    fn phase(self, phase: PrintPhase) -> PhasedExpr<'a, S, A> { -        PhasedExpr(self.0, phase) -    } -} - -impl<S: Clone, A: Display + Clone> Expr<S, A> { -    fn fmt_phase( -        &self, -        f: &mut fmt::Formatter, -        mut phase: PrintPhase, -    ) -> Result<(), fmt::Error> { -        use crate::ExprF::*; -        use PrintPhase::*; - -        let needs_paren = match self { -            Lam(_, _, _) -            | BoolIf(_, _, _) -            | Pi(_, _, _) -            | Let(_, _, _, _) -            | EmptyListLit(_) -            | NEListLit(_) -            | OldOptionalLit(_, _) -            | SomeLit(_) -            | Merge(_, _, _) -            | Annot(_, _) -                if phase > Base => -            { -                true -            } -            // Precedence is magically handled by the ordering of BinOps. -            ExprF::BinOp(op, _, _) if phase > PrintPhase::BinOp(*op) => true, -            ExprF::App(_, _) if phase > PrintPhase::App => true, -            Field(_, _) | Projection(_, _) if phase > Import => true, -            _ => false, -        }; - -        if needs_paren { -            phase = Base; -        } - -        // Annotate subexpressions with the appropriate phase, defaulting to Base -        let phased_self = match self.map_ref_simple(|e| PhasedExpr(e, Base)) { -            Pi(a, b, c) => { -                if &String::from(&a) == "_" { -                    Pi(a, b.phase(Operator), c) -                } else { -                    Pi(a, b, c) -                } -            } -            Merge(a, b, c) => Merge( -                a.phase(Import), -                b.phase(Import), -                c.map(|x| x.phase(PrintPhase::App)), -            ), -            Annot(a, b) => Annot(a.phase(Operator), b), -            ExprF::BinOp(op, a, b) => ExprF::BinOp( -                op, -                a.phase(PrintPhase::BinOp(op)), -                b.phase(PrintPhase::BinOp(op)), -            ), -            EmptyListLit(t) => EmptyListLit(t.phase(Import)), -            OldOptionalLit(x, t) => OldOptionalLit(x, t.phase(Import)), -            SomeLit(e) => SomeLit(e.phase(Import)), -            ExprF::App(f, a) => ExprF::App(f.phase(Import), a.phase(Import)), -            Field(a, b) => Field(a.phase(Primitive), b), -            Projection(e, ls) => Projection(e.phase(Primitive), ls), -            Note(n, b) => Note(n, b.phase(phase)), -            e => e, -        }; - -        if needs_paren { -            f.write_str("(")?; -        } - -        // Uses the ExprF<PhasedExpr<_>, _, _, _> instance -        phased_self.fmt(f)?; - -        if needs_paren { -            f.write_str(")")?; -        } -        Ok(()) -    } -} - -impl<S: Clone, A: Display + Clone> Display for SubExpr<S, A> { -    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { -        self.as_ref().fmt_phase(f, PrintPhase::Base) -    } -} - -fn fmt_list<T, I, F>( -    open: &str, -    sep: &str, -    close: &str, -    it: I, -    f: &mut fmt::Formatter, -    func: F, -) -> Result<(), fmt::Error> -where -    I: IntoIterator<Item = T>, -    F: Fn(T, &mut fmt::Formatter) -> Result<(), fmt::Error>, -{ -    f.write_str(open)?; -    for (i, x) in it.into_iter().enumerate() { -        if i > 0 { -            f.write_str(sep)?; -        } -        func(x, f)?; -    } -    f.write_str(close) -} - -impl<SubExpr: Display + Clone> Display for InterpolatedText<SubExpr> { -    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { -        f.write_str("\"")?; -        for x in self.iter() { -            match x { -                InterpolatedTextContents::Text(a) => { -                    for c in a.chars() { -                        match c { -                            '\\' => f.write_str("\\\\"), -                            '"' => f.write_str("\\\""), -                            '$' => f.write_str("\\$"), -                            '\u{0008}' => f.write_str("\\b"), -                            '\u{000C}' => f.write_str("\\f"), -                            '\n' => f.write_str("\\n"), -                            '\r' => f.write_str("\\r"), -                            '\t' => f.write_str("\\t"), -                            c => write!(f, "{}", c), -                        }?; -                    } -                } -                InterpolatedTextContents::Expr(e) => { -                    f.write_str("${ ")?; -                    e.fmt(f)?; -                    f.write_str(" }")?; -                } -            } -        } -        f.write_str("\"")?; -        Ok(()) -    } -} - -impl Display for Const { -    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { -        <Self as fmt::Debug>::fmt(self, f) -    } -} - -impl Display for BinOp { -    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { -        use crate::BinOp::*; -        f.write_str(match self { -            BoolOr => "||", -            TextAppend => "++", -            NaturalPlus => "+", -            BoolAnd => "&&", -            Combine => "/\\", -            NaturalTimes => "*", -            BoolEQ => "==", -            BoolNE => "!=", -            CombineTypes => "//\\\\", -            ImportAlt => "?", -            Prefer => "//", -            ListAppend => "#", -        }) -    } -} - -impl Display for NaiveDouble { -    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { -        let v = f64::from(*self); -        if v == std::f64::INFINITY { -            f.write_str("Infinity") -        } else if v == std::f64::NEG_INFINITY { -            f.write_str("-Infinity") -        } else if v.is_nan() { -            f.write_str("NaN") -        } else { -            let s = format!("{}", v); -            if s.contains('e') || s.contains('.') { -                f.write_str(&s) -            } else { -                write!(f, "{}.0", s) -            } -        } -    } -} - -impl Display for Label { -    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { -        // TODO: distinguish between reserved and nonreserved locations for quoting builtins -        let s = String::from(self); -        let is_reserved = match s.as_str() { -            "let" | "in" | "if" | "then" | "else" | "Type" | "Kind" -            | "Sort" | "True" | "False" => true, -            _ => crate::Builtin::parse(&s).is_some(), -        }; -        if !is_reserved && s.chars().all(|c| c.is_ascii_alphanumeric()) { -            write!(f, "{}", s) -        } else { -            write!(f, "`{}`", s) -        } -    } -} - -impl Display for Hash { -    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { -        write!(f, "{}:{}", self.protocol, self.hash) -    } -} -impl Display for ImportHashed { -    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { -        use std::path::PathBuf; -        use FilePrefix::*; -        use ImportLocation::*; -        let quoted_path_component = |s: &str| -> String { -            if s.chars().all(|c| c.is_ascii_alphanumeric()) { -                s.to_owned() -            } else { -                format!("\"{}\"", s) -            } -        }; -        let fmt_path = |f: &mut fmt::Formatter, p: &PathBuf| { -            let res: String = p -                .iter() -                .map(|c| quoted_path_component(c.to_string_lossy().as_ref())) -                .join("/"); -            f.write_str(&res) -        }; - -        match &self.location { -            Local(prefix, path) => { -                let prefix = match prefix { -                    Here => ".", -                    Parent => "..", -                    Home => "~", -                    Absolute => "", -                }; -                write!(f, "{}/", prefix)?; -                fmt_path(f, path)?; -            } -            Remote(url) => { -                write!(f, "{}://{}/", url.scheme, url.authority,)?; -                fmt_path(f, &url.path)?; -                if let Some(q) = &url.query { -                    write!(f, "?{}", q)? -                } -                if let Some(h) = &url.headers { -                    write!(f, " using ({})", h)? -                } -            } -            Env(s) => { -                write!(f, "env:")?; -                if s.chars().all(|c| c.is_ascii_alphanumeric()) { -                    write!(f, "{}", s)?; -                } else { -                    write!(f, "\"")?; -                    for c in s.chars() { -                        match c { -                            '"' => f.write_str("\\\"")?, -                            '\\' => f.write_str("\\\\")?, -                            '\u{0007}' => f.write_str("\\a")?, -                            '\u{0008}' => f.write_str("\\b")?, -                            '\u{000C}' => f.write_str("\\f")?, -                            '\n' => f.write_str("\\n")?, -                            '\r' => f.write_str("\\r")?, -                            '\t' => f.write_str("\\t")?, -                            '\u{000B}' => f.write_str("\\v")?, -                            _ => write!(f, "{}", c)?, -                        } -                    } -                    write!(f, "\"")?; -                } -            } -            Missing => { -                write!(f, "missing")?; -            } -        } -        if let Some(hash) = &self.hash { -            write!(f, " ")?; -            hash.fmt(f)?; -        } -        Ok(()) -    } -} - -impl Display for Import { -    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { -        self.location_hashed.fmt(f)?; -        use ImportMode::*; -        match self.mode { -            Code => {} -            RawText => write!(f, " as Text")?, -        } -        Ok(()) -    } -} - -impl Display for Builtin { -    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { -        use crate::Builtin::*; -        f.write_str(match *self { -            Bool => "Bool", -            Natural => "Natural", -            Integer => "Integer", -            Double => "Double", -            Text => "Text", -            List => "List", -            Optional => "Optional", -            OptionalNone => "None", -            NaturalBuild => "Natural/build", -            NaturalFold => "Natural/fold", -            NaturalIsZero => "Natural/isZero", -            NaturalEven => "Natural/even", -            NaturalOdd => "Natural/odd", -            NaturalToInteger => "Natural/toInteger", -            NaturalShow => "Natural/show", -            IntegerToDouble => "Integer/toDouble", -            IntegerShow => "Integer/show", -            DoubleShow => "Double/show", -            ListBuild => "List/build", -            ListFold => "List/fold", -            ListLength => "List/length", -            ListHead => "List/head", -            ListLast => "List/last", -            ListIndexed => "List/indexed", -            ListReverse => "List/reverse", -            OptionalFold => "Optional/fold", -            OptionalBuild => "Optional/build", -            TextShow => "Text/show", -        }) -    } -} - -impl Display for Scheme { -    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { -        use crate::Scheme::*; -        f.write_str(match *self { -            HTTP => "http", -            HTTPS => "https", -        }) -    } -} - -impl<Label: Display> Display for V<Label> { -    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { -        let V(x, n) = self; -        x.fmt(f)?; -        if *n != 0 { -            write!(f, "@{}", n)?; -        } -        Ok(()) -    } -} - -impl Display for X { -    fn fmt(&self, _: &mut fmt::Formatter) -> Result<(), fmt::Error> { -        match *self {} -    } -} diff --git a/dhall_core/src/text.rs b/dhall_core/src/text.rs deleted file mode 100644 index 83643d9..0000000 --- a/dhall_core/src/text.rs +++ /dev/null @@ -1,116 +0,0 @@ -use std::iter::FromIterator; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct InterpolatedText<SubExpr> { -    head: String, -    tail: Vec<(SubExpr, String)>, -} - -impl<SubExpr> From<(String, Vec<(SubExpr, String)>)> -    for InterpolatedText<SubExpr> -{ -    fn from(x: (String, Vec<(SubExpr, String)>)) -> Self { -        InterpolatedText { -            head: x.0, -            tail: x.1, -        } -    } -} - -impl<SubExpr> From<String> for InterpolatedText<SubExpr> { -    fn from(s: String) -> Self { -        InterpolatedText { -            head: s, -            tail: vec![], -        } -    } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum InterpolatedTextContents<SubExpr> { -    Text(String), -    Expr(SubExpr), -} - -impl<SubExpr> InterpolatedTextContents<SubExpr> { -    pub fn is_empty(&self) -> bool { -        use InterpolatedTextContents::{Expr, Text}; -        match self { -            Expr(_) => false, -            Text(s) => s.is_empty(), -        } -    } -} - -impl<SubExpr> InterpolatedText<SubExpr> { -    pub fn traverse_ref<'a, SubExpr2, E, F>( -        &'a self, -        mut f: F, -    ) -> Result<InterpolatedText<SubExpr2>, E> -    where -        F: FnMut(&'a SubExpr) -> Result<SubExpr2, E>, -    { -        Ok(InterpolatedText { -            head: self.head.clone(), -            tail: self -                .tail -                .iter() -                .map(|(e, s)| Ok((f(e)?, s.clone()))) -                .collect::<Result<_, _>>()?, -        }) -    } - -    pub fn iter<'a>( -        &'a self, -    ) -> impl Iterator<Item = InterpolatedTextContents<SubExpr>> + 'a -    where -        SubExpr: Clone, -    { -        use std::iter::once; -        use InterpolatedTextContents::{Expr, Text}; -        once(Text(self.head.clone())) -            .chain(self.tail.iter().flat_map(|(e, s)| { -                once(Expr(SubExpr::clone(e))).chain(once(Text(s.clone()))) -            })) -            .filter(|c| !c.is_empty()) -    } - -    pub fn into_iter( -        self, -    ) -> impl Iterator<Item = InterpolatedTextContents<SubExpr>> { -        use std::iter::once; -        use InterpolatedTextContents::{Expr, Text}; -        once(Text(self.head)) -            .chain( -                self.tail -                    .into_iter() -                    .flat_map(|(e, s)| once(Expr(e)).chain(once(Text(s)))), -            ) -            .filter(|c| !c.is_empty()) -    } -} - -impl<SubExpr> FromIterator<InterpolatedTextContents<SubExpr>> -    for InterpolatedText<SubExpr> -{ -    fn from_iter<T>(iter: T) -> Self -    where -        T: IntoIterator<Item = InterpolatedTextContents<SubExpr>>, -    { -        let mut res = InterpolatedText { -            head: String::new(), -            tail: Vec::new(), -        }; -        let mut crnt_str = &mut res.head; -        for x in iter.into_iter() { -            match x { -                InterpolatedTextContents::Text(s) => crnt_str.push_str(&s), -                InterpolatedTextContents::Expr(e) => { -                    res.tail.push((e, String::new())); -                    crnt_str = &mut res.tail.last_mut().unwrap().1; -                } -            } -        } -        res -    } -} diff --git a/dhall_core/src/visitor.rs b/dhall_core/src/visitor.rs deleted file mode 100644 index caaefce..0000000 --- a/dhall_core/src/visitor.rs +++ /dev/null @@ -1,667 +0,0 @@ -use std::collections::BTreeMap; - -use crate::*; - -/// A way too generic Visitor trait. -pub trait GenericVisitor<Input, Return>: Sized { -    fn visit(self, input: Input) -> Return; -} - -/// A visitor trait that can be used to traverse `ExprF`s. We need this pattern -/// so that Rust lets us have as much mutability as we can. -/// For example, `traverse_embed` cannot be made using only `traverse_ref`, because -/// `traverse_ref` takes a `FnMut` so we would need to pass multiple mutable -/// reverences to this argument to `traverse_ref`. But Rust's ownership system -/// is all about preventing exactly this ! So we have to be more clever. -/// The visitor pattern allows us to have only one mutable thing the whole -/// 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. -/// 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<Self::SE2, Self::Error>; -    fn visit_label(&mut self, label: &'a L1) -> Result<Self::L2, Self::Error>; - -    fn visit_binder( -        self, -        label: &'a L1, -        subexpr: &'a SE1, -    ) -> Result<(Self::L2, Self::SE2), Self::Error>; - -    fn visit_embed_squash(self, embed: &'a E1) -> Result<Ret, Self::Error>; - -    fn visit_note_squash( -        self, -        note: &'a N1, -        subexpr: &'a SE1, -    ) -> Result<Ret, Self::Error>; - -    // 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<Self::SE2, Self::L2, Self::N2, Self::E2>, -    ) -> Result<Ret, Self::Error>; -} - -impl<'a, T, Ret, SE1, L1, N1, E1> -    GenericVisitor<&'a ExprF<SE1, L1, N1, E1>, Result<Ret, T::Error>> for T -where -    L1: Ord, -    T::L2: Ord, -    T: ExprFVeryGenericVisitor<'a, Ret, SE1, L1, N1, E1>, -{ -    fn visit(self, input: &'a ExprF<SE1, L1, N1, E1>) -> Result<Ret, T::Error> { -        fn vec<'a, T, U, Err, F: FnMut(&'a T) -> Result<U, Err>>( -            x: &'a [T], -            f: F, -        ) -> Result<Vec<U>, Err> { -            x.iter().map(f).collect() -        } -        fn opt<'a, T, U, Err, F: FnOnce(&'a T) -> Result<U, Err>>( -            x: &'a Option<T>, -            f: F, -        ) -> Result<Option<U>, Err> { -            Ok(match x { -                Some(x) => Some(f(x)?), -                None => None, -            }) -        } -        fn btmap<'a, V, Ret, SE, L, N, E>( -            x: &'a BTreeMap<L, SE>, -            mut v: V, -        ) -> Result<BTreeMap<V::L2, V::SE2>, V::Error> -        where -            L: Ord, -            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, Ret, SE, L, N, E>( -            x: &'a BTreeMap<L, Option<SE>>, -            mut v: V, -        ) -> Result<BTreeMap<V::L2, Option<V::SE2>>, V::Error> -        where -            L: Ord, -            V::L2: Ord, -            V: ExprFVeryGenericVisitor<'a, Ret, SE, L, N, E>, -        { -            x.iter() -                .map(|(k, x)| { -                    Ok(( -                        v.visit_label(k)?, -                        match x { -                            Some(x) => Some(v.visit_subexpr(x)?), -                            None => None, -                        }, -                    )) -                }) -                .collect() -        } - -        let mut v = self; -        use crate::ExprF::*; -        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)?; -                let (l, e) = v.visit_binder(l, e)?; -                Lam(l, t, e) -            } -            Pi(l, t, e) => { -                let t = v.visit_subexpr(t)?; -                let (l, e) = v.visit_binder(l, e)?; -                Pi(l, t, e) -            } -            Let(l, t, a, e) => { -                let t = opt(t, &mut |e| v.visit_subexpr(e))?; -                let a = v.visit_subexpr(a)?; -                let (l, e) = v.visit_binder(l, e)?; -                Let(l, t, a, e) -            } -            App(f, a) => App(v.visit_subexpr(f)?, v.visit_subexpr(a)?), -            Annot(x, t) => Annot(v.visit_subexpr(x)?, v.visit_subexpr(t)?), -            Const(k) => Const(*k), -            Builtin(v) => Builtin(*v), -            BoolLit(b) => BoolLit(*b), -            NaturalLit(n) => NaturalLit(*n), -            IntegerLit(n) => IntegerLit(*n), -            DoubleLit(n) => DoubleLit(*n), -            TextLit(t) => TextLit(t.traverse_ref(|e| v.visit_subexpr(e))?), -            BinOp(o, x, y) => { -                BinOp(*o, v.visit_subexpr(x)?, v.visit_subexpr(y)?) -            } -            BoolIf(b, t, f) => BoolIf( -                v.visit_subexpr(b)?, -                v.visit_subexpr(t)?, -                v.visit_subexpr(f)?, -            ), -            EmptyListLit(t) => EmptyListLit(v.visit_subexpr(t)?), -            NEListLit(es) => NEListLit(vec(es, |e| v.visit_subexpr(e))?), -            OldOptionalLit(x, t) => OldOptionalLit( -                opt(x, |e| v.visit_subexpr(e))?, -                v.visit_subexpr(t)?, -            ), -            SomeLit(e) => SomeLit(v.visit_subexpr(e)?), -            RecordType(kts) => RecordType(btmap(kts, v)?), -            RecordLit(kvs) => RecordLit(btmap(kvs, v)?), -            UnionType(kts) => UnionType(btoptmap(kts, v)?), -            UnionLit(k, x, kts) => UnionLit( -                v.visit_label(k)?, -                v.visit_subexpr(x)?, -                btoptmap(kts, v)?, -            ), -            Merge(x, y, t) => Merge( -                v.visit_subexpr(x)?, -                v.visit_subexpr(y)?, -                opt(t, |e| v.visit_subexpr(e))?, -            ), -            Field(e, l) => Field(v.visit_subexpr(e)?, v.visit_label(l)?), -            Projection(e, ls) => { -                Projection(v.visit_subexpr(e)?, vec(ls, |l| v.visit_label(l))?) -            } -            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<SE2, Self::Error>; -    fn visit_label(&mut self, label: &'a L1) -> Result<L2, Self::Error>; -    fn visit_note(self, note: &'a N1) -> Result<N2, Self::Error>; -    fn visit_embed(self, embed: &'a E1) -> Result<E2, Self::Error>; - -    fn visit_subexpr_under_binder( -        mut self, -        _label: &'a L1, -        subexpr: &'a SE1, -    ) -> Result<SE2, Self::Error> { -        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<ExprF<SE2, L2, N2, E2>, Self::Error> { -        Ok(ExprF::Embed(self.visit_embed(embed)?)) -    } - -    fn visit_note_squash( -        mut self, -        note: &'a N1, -        subexpr: &'a SE1, -    ) -> Result<ExprF<SE2, L2, N2, E2>, 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<SE2, L2, N2, E2>, 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::SE2, Self::Error> { -        self.visit_subexpr(subexpr) -    } - -    fn visit_label(&mut self, label: &'a L1) -> Result<Self::L2, Self::Error> { -        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<ExprF<SE2, L2, N2, E2>, Self::Error> { -        self.visit_embed_squash(embed) -    } - -    fn visit_note_squash( -        self, -        note: &'a N1, -        subexpr: &'a SE1, -    ) -> Result<ExprF<SE2, L2, N2, E2>, 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<Self::SE2, Self::L2, Self::N2, Self::E2>, -    ) -> Result<ExprF<SE2, L2, N2, E2>, Self::Error> { -        Ok(result) -    } -} - -/// Like ExprFFallibleVisitor, but without the error handling. -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<SE2, L2, N2, E2> { -        ExprF::Embed(self.visit_embed(embed)) -    } - -    fn visit_note_squash( -        mut self, -        note: &'a N1, -        subexpr: &'a SE1, -    ) -> ExprF<SE2, L2, N2, E2> { -        let subexpr = self.visit_subexpr(subexpr); -        let note = self.visit_note(note); -        ExprF::Note(note, subexpr) -    } -} - -struct InfallibleWrapper<T>(T); - -impl<'a, T, SE1, SE2, L1, L2, N1, N2, E1, E2> -    ExprFFallibleVisitor<'a, SE1, SE2, L1, L2, N1, N2, E1, E2> -    for InfallibleWrapper<T> -where -    T: ExprFInFallibleVisitor<'a, SE1, SE2, L1, L2, N1, N2, E1, E2>, -{ -    type Error = X; - -    fn visit_subexpr(&mut self, subexpr: &'a SE1) -> Result<SE2, Self::Error> { -        Ok(self.0.visit_subexpr(subexpr)) -    } -    fn visit_label(&mut self, label: &'a L1) -> Result<L2, Self::Error> { -        Ok(self.0.visit_label(label)) -    } -    fn visit_note(self, note: &'a N1) -> Result<N2, Self::Error> { -        Ok(self.0.visit_note(note)) -    } -    fn visit_embed(self, embed: &'a E1) -> Result<E2, Self::Error> { -        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<ExprF<SE2, L2, N2, E2>, Self::Error> { -        Ok(self.0.visit_embed_squash(embed)) -    } - -    fn visit_note_squash( -        self, -        note: &'a N1, -        subexpr: &'a SE1, -    ) -> Result<ExprF<SE2, L2, N2, E2>, Self::Error> { -        Ok(self.0.visit_note_squash(note, subexpr)) -    } -} - -impl<'a, T, SE1, SE2, L1, L2, N1, N2, E1, E2> -    GenericVisitor<&'a ExprF<SE1, L1, N1, E1>, ExprF<SE2, L2, N2, E2>> for T -where -    L1: Ord, -    L2: Ord, -    T: ExprFInFallibleVisitor<'a, SE1, SE2, L1, L2, N1, N2, E1, E2>, -{ -    fn visit( -        self, -        input: &'a ExprF<SE1, L1, N1, E1>, -    ) -> ExprF<SE2, L2, N2, E2> { -        trivial_result(InfallibleWrapper(self).visit(input)) -    } -} - -pub struct TraverseRefWithBindersVisitor<F1, F2, F3, F4, F5> { -    pub visit_subexpr: F1, -    pub visit_under_binder: F2, -    pub visit_note: F3, -    pub visit_embed: F4, -    pub visit_label: F5, -} - -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 TraverseRefWithBindersVisitor<F1, F2, F3, F4, F5> -where -    SE: 'a, -    L: 'a, -    N: 'a, -    E: 'a, -    L: Ord, -    L2: Ord, -    F1: FnMut(&'a SE) -> Result<SE2, Err>, -    F2: FnOnce(&'a L, &'a SE) -> Result<SE2, Err>, -    F3: FnOnce(&'a N) -> Result<N2, Err>, -    F4: FnOnce(&'a E) -> Result<E2, Err>, -    F5: FnMut(&'a L) -> Result<L2, Err>, -{ -    type Error = Err; - -    fn visit_subexpr(&mut self, subexpr: &'a SE) -> Result<SE2, Self::Error> { -        (self.visit_subexpr)(subexpr) -    } -    fn visit_subexpr_under_binder( -        self, -        label: &'a L, -        subexpr: &'a SE, -    ) -> Result<SE2, Self::Error> { -        (self.visit_under_binder)(label, subexpr) -    } -    fn visit_note(self, note: &'a N) -> Result<N2, Self::Error> { -        (self.visit_note)(note) -    } -    fn visit_embed(self, embed: &'a E) -> Result<E2, Self::Error> { -        (self.visit_embed)(embed) -    } -    fn visit_label(&mut self, label: &'a L) -> Result<L2, Self::Error> { -        (self.visit_label)(label) -    } -} - -pub struct TraverseRefVisitor<F1, F2, F3, F4> { -    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<F1, F2, F3, F4> -where -    SE: 'a, -    L: 'a, -    N: 'a, -    E: 'a, -    L: Ord, -    L2: Ord, -    F1: FnMut(&'a SE) -> Result<SE2, Err>, -    F2: FnOnce(&'a N) -> Result<N2, Err>, -    F3: FnOnce(&'a E) -> Result<E2, Err>, -    F4: FnMut(&'a L) -> Result<L2, Err>, -{ -    type Error = Err; - -    fn visit_subexpr(&mut self, subexpr: &'a SE) -> Result<SE2, Self::Error> { -        (self.visit_subexpr)(subexpr) -    } -    fn visit_note(self, note: &'a N) -> Result<N2, Self::Error> { -        (self.visit_note)(note) -    } -    fn visit_embed(self, embed: &'a E) -> Result<E2, Self::Error> { -        (self.visit_embed)(embed) -    } -    fn visit_label(&mut self, label: &'a L) -> Result<L2, Self::Error> { -        (self.visit_label)(label) -    } -} - -pub struct TraverseEmbedVisitor<F1>(pub F1); - -impl<'a, 'b, N, E, E2, Err, F1> -    ExprFFallibleVisitor< -        'a, -        SubExpr<N, E>, -        SubExpr<N, E2>, -        Label, -        Label, -        N, -        N, -        E, -        E2, -    > for &'b mut TraverseEmbedVisitor<F1> -where -    N: Clone + 'a, -    F1: FnMut(&E) -> Result<E2, Err>, -{ -    type Error = Err; - -    fn visit_subexpr( -        &mut self, -        subexpr: &'a SubExpr<N, E>, -    ) -> Result<SubExpr<N, E2>, Self::Error> { -        Ok(rc(subexpr.as_ref().visit(&mut **self)?)) -    } -    fn visit_note(self, note: &'a N) -> Result<N, Self::Error> { -        Ok(N::clone(note)) -    } -    fn visit_embed(self, embed: &'a E) -> Result<E2, Self::Error> { -        (self.0)(embed) -    } -    fn visit_label(&mut self, label: &'a Label) -> Result<Label, Self::Error> { -        Ok(Label::clone(label)) -    } -} - -pub struct SquashEmbedVisitor<F1>(pub F1); - -impl<'a, 'b, N, E1, E2, F1> -    ExprFVeryGenericVisitor<'a, SubExpr<N, E2>, SubExpr<N, E1>, Label, N, E1> -    for &'b mut SquashEmbedVisitor<F1> -where -    N: Clone + 'a, -    F1: FnMut(&E1) -> SubExpr<N, E2>, -{ -    type Error = X; -    type SE2 = SubExpr<N, E2>; -    type L2 = Label; -    type N2 = N; -    type E2 = E2; - -    fn visit_subexpr( -        &mut self, -        subexpr: &'a SubExpr<N, E1>, -    ) -> Result<Self::SE2, Self::Error> { -        Ok(subexpr.as_ref().visit(&mut **self)?) -    } - -    fn visit_label( -        &mut self, -        label: &'a Label, -    ) -> Result<Self::L2, Self::Error> { -        Ok(Label::clone(label)) -    } - -    fn visit_binder( -        mut self, -        label: &'a Label, -        subexpr: &'a SubExpr<N, E1>, -    ) -> Result<(Self::L2, Self::SE2), Self::Error> { -        Ok((self.visit_label(label)?, self.visit_subexpr(subexpr)?)) -    } - -    fn visit_embed_squash( -        self, -        embed: &'a E1, -    ) -> Result<SubExpr<N, E2>, Self::Error> { -        Ok((self.0)(embed)) -    } - -    fn visit_note_squash( -        mut self, -        note: &'a N, -        subexpr: &'a SubExpr<N, E1>, -    ) -> Result<SubExpr<N, E2>, 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<Self::SE2, Self::L2, Self::N2, Self::E2>, -    ) -> Result<SubExpr<N, E2>, Self::Error> { -        Ok(rc(result)) -    } -} - -pub struct UnNoteVisitor; - -impl<'a, 'b, N, E> -    ExprFInFallibleVisitor< -        'a, -        SubExpr<N, E>, -        SubExpr<X, E>, -        Label, -        Label, -        N, -        X, -        E, -        E, -    > for &'b mut UnNoteVisitor -where -    E: Clone + 'a, -{ -    fn visit_subexpr(&mut self, subexpr: &'a SubExpr<N, E>) -> SubExpr<X, E> { -        rc(subexpr.as_ref().visit(&mut **self)) -    } -    fn visit_note(self, _: &'a N) -> X { -        unreachable!() -    } -    fn visit_note_squash( -        self, -        _: &'a N, -        subexpr: &'a SubExpr<N, E>, -    ) -> Expr<X, E> { -        subexpr.as_ref().visit(self) -    } -    fn visit_embed(self, embed: &'a E) -> E { -        E::clone(embed) -    } -    fn visit_label(&mut self, label: &'a Label) -> Label { -        Label::clone(label) -    } -} - -pub struct NoteAbsurdVisitor; - -impl<'a, 'b, N, E> -    ExprFInFallibleVisitor< -        'a, -        SubExpr<X, E>, -        SubExpr<N, E>, -        Label, -        Label, -        X, -        N, -        E, -        E, -    > for &'b mut NoteAbsurdVisitor -where -    E: Clone + 'a, -{ -    fn visit_subexpr(&mut self, subexpr: &'a SubExpr<X, E>) -> SubExpr<N, E> { -        rc(subexpr.as_ref().visit(&mut **self)) -    } -    fn visit_note(self, note: &'a X) -> N { -        match *note {} -    } -    fn visit_embed(self, embed: &'a E) -> E { -        E::clone(embed) -    } -    fn visit_label(&mut self, label: &'a Label) -> Label { -        Label::clone(label) -    } -} - -pub struct EmbedAbsurdVisitor; - -impl<'a, 'b, N, E> -    ExprFInFallibleVisitor< -        'a, -        SubExpr<N, X>, -        SubExpr<N, E>, -        Label, -        Label, -        N, -        N, -        X, -        E, -    > for &'b mut EmbedAbsurdVisitor -where -    N: Clone + 'a, -{ -    fn visit_subexpr(&mut self, subexpr: &'a SubExpr<N, X>) -> SubExpr<N, E> { -        rc(subexpr.as_ref().visit(&mut **self)) -    } -    fn visit_note(self, note: &'a N) -> N { -        N::clone(note) -    } -    fn visit_embed(self, embed: &'a X) -> E { -        match *embed {} -    } -    fn visit_label(&mut self, label: &'a Label) -> Label { -        Label::clone(label) -    } -}  | 
