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.rs682
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)
}