summaryrefslogtreecommitdiff
path: root/dhall_core/src/core.rs
diff options
context:
space:
mode:
Diffstat (limited to 'dhall_core/src/core.rs')
-rw-r--r--dhall_core/src/core.rs563
1 files changed, 0 insertions, 563 deletions
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)
- },
- ),
- }
-}