diff options
Diffstat (limited to '')
-rw-r--r-- | dhall_core/src/core.rs | 682 |
1 files changed, 49 insertions, 633 deletions
diff --git a/dhall_core/src/core.rs b/dhall_core/src/core.rs index e7c9f2a..68e781d 100644 --- a/dhall_core/src/core.rs +++ b/dhall_core/src/core.rs @@ -1,11 +1,17 @@ #![allow(non_snake_case)] +use crate::*; use std::collections::BTreeMap; -use std::fmt::{self, Display}; -use std::iter::FromIterator; -use std::ops::Add; -use std::path::PathBuf; use std::rc::Rc; +pub type Double = f64; +pub type Int = isize; +pub type Integer = isize; +pub type Natural = usize; + +/// An empty type +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum X {} + /// Constants for a pure type system /// /// The only axiom is: @@ -33,82 +39,9 @@ pub enum Const { Kind, } -/// The beginning of a file path which anchors subsequent path components -#[derive(Debug, Clone, PartialEq, Eq)] -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)] -pub enum ImportLocation { - Local(FilePrefix, PathBuf), - // TODO: other import types -} - -/// How to interpret the import's contents (i.e. as Dhall code or raw text) -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ImportMode { - Code, - // TODO - // RawText, -} - -/// Reference to an external resource -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Import { - pub mode: ImportMode, - pub location: ImportLocation, - // TODO - pub hash: Option<()>, -} - -// 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 Display for Label { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - self.0.as_ref().fmt(f) - } -} - -impl Label { - pub fn from_str(s: &str) -> Label { - Label(s.into()) - } -} - -/// Label for a bound variable +/// Bound variable /// -/// The `String` field is the variable's name (i.e. \"`x`\"). +/// The `Label` field is the variable's name (i.e. \"`x`\"). /// /// The `Int` field disambiguates variables with the same name if there are /// multiple bound variables of the same name in scope. Zero refers to the @@ -173,93 +106,43 @@ pub enum BinOp { ListAppend, } -#[derive(Debug, Clone, PartialEq)] -pub struct InterpolatedText<Note, Embed> { - head: String, - tail: Vec<(Rc<Expr<Note, Embed>>, String)>, -} - -impl<N, E> From<(String, Vec<(Rc<Expr<N, E>>, String)>)> - for InterpolatedText<N, E> -{ - fn from(x: (String, Vec<(Rc<Expr<N, E>>, String)>)) -> Self { - InterpolatedText { - head: x.0, - tail: x.1, - } - } -} - -impl<N, E> From<String> for InterpolatedText<N, E> { - fn from(s: String) -> Self { - InterpolatedText { - head: s, - tail: vec![], - } - } -} - -#[derive(Debug, Clone)] -pub enum InterpolatedTextContents<'a, Note, Embed> { - Text(&'a str), - Expr(SubExpr<Note, Embed>), -} - -impl<N, E> InterpolatedText<N, E> { - pub fn map<N2, E2, F>(&self, mut f: F) -> InterpolatedText<N2, E2> - where - F: FnMut(&Rc<Expr<N, E>>) -> Rc<Expr<N2, E2>>, - { - InterpolatedText { - head: self.head.clone(), - tail: self.tail.iter().map(|(e, s)| (f(e), s.clone())).collect(), - } - } - - pub fn iter(&self) -> impl Iterator<Item = InterpolatedTextContents<N, E>> { - use std::iter::once; - once(InterpolatedTextContents::Text(self.head.as_ref())).chain( - self.tail.iter().flat_map(|(e, s)| { - once(InterpolatedTextContents::Expr(Rc::clone(e))) - .chain(once(InterpolatedTextContents::Text(s))) - }), - ) - } -} - -impl<'a, N: 'a, E: 'a> FromIterator<InterpolatedTextContents<'a, N, E>> - for InterpolatedText<N, E> -{ - fn from_iter<T>(iter: T) -> Self - where - T: IntoIterator<Item = InterpolatedTextContents<'a, N, E>>, - { - let mut res = InterpolatedText { - head: "".to_owned(), - tail: vec![], - }; - // let mut empty_string = "".to_owned(); - 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) => { - // crnt_str = &mut empty_string; - res.tail.push((e.clone(), "".to_owned())); - crnt_str = &mut res.tail.last_mut().unwrap().1; - } - } - } - res - } +/// Built-ins +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum Builtin { + Bool, + Natural, + Integer, + Double, + Text, + List, + Optional, + OptionalSome, + OptionalNone, + NaturalBuild, + NaturalFold, + NaturalIsZero, + NaturalEven, + NaturalOdd, + NaturalToInteger, + NaturalShow, + IntegerToDouble, + IntegerShow, + DoubleShow, + ListBuild, + ListFold, + ListLength, + ListHead, + ListLast, + ListIndexed, + ListReverse, + OptionalFold, + OptionalBuild, + TextShow, } -impl<N, E> Add for &InterpolatedText<N, E> { - type Output = InterpolatedText<N, E>; - fn add(self, rhs: &InterpolatedText<N, E>) -> Self::Output { - self.iter().chain(rhs.iter()).collect() - } -} +pub type ParsedExpr<S> = SubExpr<S, Import>; +pub type ResolvedExpr<S> = SubExpr<S, X>; +pub type DhallExpr = ResolvedExpr<X>; pub type SubExpr<Note, Embed> = Rc<Expr<Note, Embed>>; @@ -341,64 +224,6 @@ pub enum Expr<Note, Embed> { Embed(Embed), } -/// Built-ins -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum Builtin { - Bool, - Natural, - Integer, - Double, - Text, - List, - Optional, - OptionalSome, - OptionalNone, - NaturalBuild, - NaturalFold, - NaturalIsZero, - NaturalEven, - NaturalOdd, - NaturalToInteger, - NaturalShow, - IntegerToDouble, - IntegerShow, - DoubleShow, - ListBuild, - ListFold, - ListLength, - ListHead, - ListLast, - ListIndexed, - ListReverse, - OptionalFold, - OptionalBuild, - TextShow, -} - -impl From<Label> for V { - fn from(s: Label) -> Self { - V(s, 0) - } -} - -impl From<&'static str> for V { - fn from(s: &'static str) -> Self { - V(s.into(), 0) - } -} - -impl<S, A> From<&'static str> for Expr<S, A> { - fn from(s: &'static str) -> Self { - Expr::Var(V(s.into(), 0)) - } -} - -impl<S, A> From<Builtin> for Expr<S, A> { - fn from(t: Builtin) -> Self { - Expr::Builtin(t) - } -} - impl<S, A> Expr<S, A> { pub fn map_shallow<T, B, F1, F2, F3, F4>( &self, @@ -445,20 +270,6 @@ impl<S, A> Expr<S, A> { let recurse = |e: &Self| -> Self { e.map_label(map_label) }; self.map_shallow(recurse, |x| x.clone(), |x| x.clone(), map_label) } - - pub fn bool_lit(&self) -> Option<bool> { - match *self { - Expr::BoolLit(v) => Some(v), - _ => None, - } - } - - pub fn natural_lit(&self) -> Option<usize> { - match *self { - Expr::NaturalLit(v) => Some(v), - _ => None, - } - } } impl<S: Clone, A: Clone> Expr<S, Expr<S, A>> { @@ -475,406 +286,11 @@ impl<S: Clone, A: Clone> Expr<S, Expr<S, A>> { } } -// There is a one-to-one correspondence between the formatters in this section -// and the grammar in grammar.lalrpop. Each formatter is named after the -// corresponding grammar rule and the relationship between formatters exactly matches -// the relationship between grammar rules. This leads to the nice emergent property -// of automatically getting all the parentheses and precedences right. -// -// This approach has one major disadvantage: you can get an infinite loop if -// you add a new constructor to the syntax tree without adding a matching -// case the corresponding builder. - -impl<S, A: Display> Display for Expr<S, A> { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - // buildExprA - use crate::Expr::*; - match self { - &Annot(ref a, ref b) => { - a.fmt_b(f)?; - write!(f, " : ")?; - b.fmt(f) - } - &Note(_, ref b) => b.fmt(f), - a => a.fmt_b(f), - } - } -} - -// WARNING: this may cause stack overflows when adding new variants -impl<S, A: Display> Expr<S, A> { - fn fmt_b(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - use crate::Expr::*; - match self { - &Lam(ref a, ref b, ref c) => { - write!(f, "λ({} : ", a)?; - b.fmt(f)?; - write!(f, ") → ")?; - c.fmt_b(f) - } - &BoolIf(ref a, ref b, ref c) => { - write!(f, "if ")?; - a.fmt(f)?; - write!(f, " then ")?; - b.fmt_b(f)?; - write!(f, " else ")?; - c.fmt_c(f) - } - // TODO: wait for decision on label types - // &Pi("_", ref b, ref c) => { - // b.fmt_c(f)?; - // write!(f, " → ")?; - // c.fmt_b(f) - // } - &Pi(ref a, ref b, ref c) => { - write!(f, "∀({} : ", a)?; - b.fmt(f)?; - write!(f, ") → ")?; - c.fmt_b(f) - } - &Let(ref a, None, ref c, ref d) => { - write!(f, "let {} = ", a)?; - c.fmt(f)?; - write!(f, " in ")?; - d.fmt_b(f) - } - &Let(ref a, Some(ref b), ref c, ref d) => { - write!(f, "let {} : ", a)?; - b.fmt(f)?; - write!(f, " = ")?; - c.fmt(f)?; - write!(f, " in ")?; - d.fmt_b(f) - } - &EmptyListLit(ref t) => { - write!(f, "[] : List ")?; - t.fmt_e(f) - } - &NEListLit(ref es) => { - fmt_list("[", ", ", "]", es, f, |e, f| e.fmt(f)) - } - &OptionalLit(ref t, ref es) => { - match es { - None => { - // TODO: use None when parsing fixed - write!(f, "[] : Optional ")?; - t.as_ref().unwrap().fmt_e(f)?; - } - Some(e) => { - // TODO: use Some when parsing fixed - write!(f, "[ ")?; - e.fmt_e(f)?; - write!(f, " ]")?; - if let Some(t) = t { - write!(f, " : Optional ")?; - t.fmt_e(f)?; - } - } - } - Ok(()) - } - &Merge(ref a, ref b, ref c) => { - write!(f, "merge ")?; - a.fmt_e(f)?; - write!(f, " ")?; - b.fmt_e(f)?; - match c { - Some(c) => { - write!(f, " : ")?; - c.fmt_d(f)? - } - None => {} - } - Ok(()) - } - &Note(_, ref b) => b.fmt_b(f), - a => a.fmt_c(f), - } - } - - fn fmt_c(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - use crate::BinOp::*; - use crate::Expr::*; - match self { - // FIXME precedence - &BinOp(op, ref a, ref b) => { - write!(f, "(")?; - a.fmt_d(f)?; - write!( - f, - " {} ", - match op { - BoolOr => "||", - TextAppend => "++", - NaturalPlus => "+", - BoolAnd => "&&", - Combine => "/\\", - NaturalTimes => "*", - BoolEQ => "==", - BoolNE => "!=", - CombineTypes => "//\\\\", - ImportAlt => "?", - Prefer => "//", - ListAppend => "#", - } - )?; - b.fmt_c(f)?; - write!(f, ")") - } - &Note(_, ref b) => b.fmt_c(f), - a => a.fmt_d(f), - } - } - - fn fmt_d(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - use crate::Expr::*; - match self { - &App(ref a, ref args) => { - a.fmt_d(f)?; - for x in args { - f.write_str(" ")?; - x.fmt_e(f)?; - } - Ok(()) - } - &Note(_, ref b) => b.fmt_d(f), - a => a.fmt_e(f), - } - } - - fn fmt_e(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - use crate::Expr::*; - match self { - &Field(ref a, ref b) => { - a.fmt_e(f)?; - write!(f, ".{}", b) - } - &Note(_, ref b) => b.fmt_e(f), - a => a.fmt_f(f), - } - } - - fn fmt_f(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - use crate::Expr::*; - match &self { - &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(ref a) => { - f.write_str("\"")?; - for x in a.iter() { - match x { - InterpolatedTextContents::Text(a) => { - // TODO Format all escapes properly - f.write_str( - &a.replace("\n", "\\n") - .replace("\t", "\\t") - .replace("\r", "\\r") - .replace("\"", "\\\""), - )?; - } - InterpolatedTextContents::Expr(e) => { - f.write_str("${ ")?; - e.fmt(f)?; - f.write_str(" }")?; - } - } - } - f.write_str("\"")?; - Ok(()) - } - &Record(ref a) if a.is_empty() => f.write_str("{}"), - &Record(ref a) => fmt_list("{ ", ", ", " }", a, f, |(k, t), f| { - write!(f, "{} : {}", k, t) - }), - &RecordLit(ref a) if a.is_empty() => f.write_str("{=}"), - &RecordLit(ref a) => { - fmt_list("{ ", ", ", " }", a, f, |(k, v), f| { - write!(f, "{} = {}", k, v) - }) - } - &Union(ref a) => fmt_list("< ", " | ", " >", a, f, |(k, v), f| { - write!(f, "{} : {}", k, v) - }), - &UnionLit(ref a, ref b, ref c) => { - f.write_str("< ")?; - write!(f, "{} = {}", a, b)?; - for (k, v) in c { - f.write_str(" | ")?; - write!(f, "{} : {}", k, v)?; - } - f.write_str(" >") - } - &Embed(ref a) => a.fmt(f), - &Note(_, ref b) => b.fmt_f(f), - a => write!(f, "({})", a), - } - } -} - -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 Display for Const { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - <Self as fmt::Debug>::fmt(self, f) - } -} - -impl Display for Import { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - <Self as fmt::Debug>::fmt(self, f) - } -} - -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", - OptionalSome => "Some", - 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 Builtin { - pub fn parse(s: &str) -> Option<Self> { - use self::Builtin::*; - match s { - "Bool" => Some(Bool), - "Natural" => Some(Natural), - "Integer" => Some(Integer), - "Double" => Some(Double), - "Text" => Some(Text), - "List" => Some(List), - "Optional" => Some(Optional), - "Some" => Some(OptionalSome), - "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, - } - } -} - -impl Display for V { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - let V(ref x, ref n) = *self; - x.fmt(f)?; - if *n != 0 { - write!(f, "@{}", n)?; - } - Ok(()) - } -} - -pub fn pi<S, A, Name, Et, Ev>(var: Name, ty: Et, value: Ev) -> Expr<S, A> -where - Name: Into<Label>, - Et: Into<Expr<S, A>>, - Ev: Into<Expr<S, A>>, -{ - Expr::Pi(var.into(), bx(ty.into()), bx(value.into())) -} - -pub fn app<S, A, Ef>(f: Ef, x: Vec<Rc<Expr<S, A>>>) -> Expr<S, A> -where - Ef: Into<Expr<S, A>>, -{ - Expr::App(bx(f.into()), x) -} - -pub type Double = f64; -pub type Int = isize; -pub type Integer = isize; -pub type Natural = usize; - -/// A void type -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum X {} - -impl Display for X { - fn fmt(&self, _: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match *self {} - } -} - +// Remains of a previous life, where everything was in Boxes pub fn bx<T>(x: T) -> Rc<T> { Rc::new(x) } + pub fn rc<T>(x: T) -> Rc<T> { Rc::new(x) } |