summaryrefslogtreecommitdiff
path: root/dhall
diff options
context:
space:
mode:
Diffstat (limited to 'dhall')
-rw-r--r--dhall/src/api/mod.rs85
-rw-r--r--dhall/src/api/static_type.rs93
-rw-r--r--dhall/src/api/traits/dynamic_type.rs32
-rw-r--r--dhall/src/api/traits/mod.rs4
-rw-r--r--dhall/src/api/traits/static_type.rs149
-rw-r--r--dhall/src/lib.rs10
-rw-r--r--dhall/src/phase/mod.rs57
-rw-r--r--dhall/src/phase/typecheck.rs2
-rw-r--r--dhall/tests/traits.rs67
9 files changed, 223 insertions, 276 deletions
diff --git a/dhall/src/api/mod.rs b/dhall/src/api/mod.rs
index 0a0ef93..72789d9 100644
--- a/dhall/src/api/mod.rs
+++ b/dhall/src/api/mod.rs
@@ -1,13 +1,88 @@
mod serde;
+pub(crate) mod static_type;
pub(crate) mod traits;
+// pub struct Value(crate::phase::Normalized);
+
+pub use typ::Type;
+
+mod typ {
+ use crate::core::thunk::{Thunk, TypeThunk};
+ use crate::core::value::Value;
+ use crate::phase::{NormalizedSubExpr, Typed};
+ use dhall_syntax::Builtin;
+
+ /// A Dhall expression representing a type.
+ ///
+ /// This captures what is usually simply called a "type", like
+ /// `Bool`, `{ x: Integer }` or `Natural -> Text`.
+ #[derive(Debug, Clone, PartialEq, Eq)]
+ pub struct Type(Typed);
+
+ impl Type {
+ pub(crate) fn from_value(v: Value) -> Self {
+ Type(Typed::from_value_untyped(v))
+ }
+ pub(crate) fn make_builtin_type(b: Builtin) -> Self {
+ Self::from_value(Value::from_builtin(b))
+ }
+ pub(crate) fn make_optional_type(t: Type) -> Self {
+ Self::from_value(Value::AppliedBuiltin(
+ Builtin::Optional,
+ vec![t.to_thunk()],
+ ))
+ }
+ pub(crate) fn make_list_type(t: Type) -> Self {
+ Self::from_value(Value::AppliedBuiltin(
+ Builtin::List,
+ vec![t.to_thunk()],
+ ))
+ }
+ #[doc(hidden)]
+ pub fn from_normalized_expr(e: NormalizedSubExpr) -> Self {
+ Type(Typed::from_normalized_expr_untyped(e))
+ }
+ #[doc(hidden)]
+ pub fn make_record_type(
+ kts: impl Iterator<Item = (String, Type)>,
+ ) -> Self {
+ Self::from_value(Value::RecordType(
+ kts.map(|(k, t)| {
+ (k.into(), TypeThunk::from_thunk(t.to_thunk()))
+ })
+ .collect(),
+ ))
+ }
+ #[doc(hidden)]
+ pub fn make_union_type(
+ kts: impl Iterator<Item = (String, Option<Type>)>,
+ ) -> Self {
+ Self::from_value(Value::UnionType(
+ kts.map(|(k, t)| {
+ (k.into(), t.map(|t| TypeThunk::from_thunk(t.to_thunk())))
+ })
+ .collect(),
+ ))
+ }
+
+ pub(crate) fn to_thunk(&self) -> Thunk {
+ self.0.to_thunk()
+ }
+ #[allow(dead_code)]
+ pub(crate) fn to_expr(&self) -> NormalizedSubExpr {
+ self.0.to_expr()
+ }
+ }
+}
+
/// Deserialization of Dhall expressions into Rust
pub mod de {
+ pub use super::static_type::StaticType;
+ pub use super::Type;
#[doc(hidden)]
- pub use crate::phase::SimpleType;
- pub use crate::traits::{Deserialize, SimpleStaticType, StaticType};
+ pub use crate::traits::Deserialize;
#[doc(hidden)]
- pub use dhall_proc_macros::SimpleStaticType;
+ pub use dhall_proc_macros::StaticType;
/// Deserialize an instance of type T from a string of Dhall text.
///
@@ -35,6 +110,8 @@ pub mod de {
pub fn from_str_auto_type<'a, T: Deserialize<'a> + StaticType>(
s: &'a str,
) -> crate::error::Result<T> {
- from_str(s, Some(&<T as StaticType>::get_static_type()))
+ // from_str(s, Some(&<T as StaticType>::static_type()))
+ // TODO
+ from_str(s, None)
}
}
diff --git a/dhall/src/api/static_type.rs b/dhall/src/api/static_type.rs
new file mode 100644
index 0000000..906bcef
--- /dev/null
+++ b/dhall/src/api/static_type.rs
@@ -0,0 +1,93 @@
+use dhall_syntax::{Builtin, Integer, Natural};
+
+use crate::api::Type;
+
+/// A Rust type that can be represented as a Dhall type.
+///
+/// A typical example is `Option<bool>`,
+/// represented by the dhall expression `Optional Bool`.
+///
+/// This trait can and should be automatically derived.
+///
+/// The representation needs to be independent of the value.
+/// For this reason, something like `HashMap<String, bool>` cannot implement
+/// [StaticType] because each different value would
+/// have a different Dhall record type.
+pub trait StaticType {
+ fn static_type() -> Type;
+}
+
+macro_rules! derive_builtin {
+ ($ty:ty, $builtin:ident) => {
+ impl StaticType for $ty {
+ fn static_type() -> Type {
+ Type::make_builtin_type(Builtin::$builtin)
+ }
+ }
+ };
+}
+
+derive_builtin!(bool, Bool);
+derive_builtin!(Natural, Natural);
+derive_builtin!(u64, Natural);
+derive_builtin!(Integer, Integer);
+derive_builtin!(String, Text);
+
+impl<A, B> StaticType for (A, B)
+where
+ A: StaticType,
+ B: StaticType,
+{
+ fn static_type() -> Type {
+ Type::make_record_type(
+ vec![
+ ("_1".to_owned(), A::static_type()),
+ ("_2".to_owned(), B::static_type()),
+ ]
+ .into_iter(),
+ )
+ }
+}
+
+impl<T, E> StaticType for std::result::Result<T, E>
+where
+ T: StaticType,
+ E: StaticType,
+{
+ fn static_type() -> Type {
+ Type::make_union_type(
+ vec![
+ ("Ok".to_owned(), Some(T::static_type())),
+ ("Err".to_owned(), Some(E::static_type())),
+ ]
+ .into_iter(),
+ )
+ }
+}
+
+impl<T> StaticType for Option<T>
+where
+ T: StaticType,
+{
+ fn static_type() -> Type {
+ Type::make_optional_type(T::static_type())
+ }
+}
+
+impl<T> StaticType for Vec<T>
+where
+ T: StaticType,
+{
+ fn static_type() -> Type {
+ Type::make_list_type(T::static_type())
+ }
+}
+
+impl<'a, T> StaticType for &'a T
+where
+ T: StaticType,
+{
+ fn static_type() -> Type {
+ T::static_type()
+ }
+}
diff --git a/dhall/src/api/traits/dynamic_type.rs b/dhall/src/api/traits/dynamic_type.rs
deleted file mode 100644
index 7763a28..0000000
--- a/dhall/src/api/traits/dynamic_type.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-use crate::error::TypeError;
-use crate::phase::{Normalized, Type, Typed};
-use crate::traits::StaticType;
-use std::borrow::Cow;
-
-pub trait DynamicType {
- fn get_type<'a>(&'a self) -> Result<Cow<'a, Type>, TypeError>;
-}
-
-impl<T: StaticType> DynamicType for T {
- fn get_type<'a>(&'a self) -> Result<Cow<'a, Type>, TypeError> {
- Ok(Cow::Owned(T::get_static_type()))
- }
-}
-
-impl DynamicType for Type {
- fn get_type(&self) -> Result<Cow<'_, Type>, TypeError> {
- self.get_type()
- }
-}
-
-impl DynamicType for Normalized {
- fn get_type(&self) -> Result<Cow<'_, Type>, TypeError> {
- self.0.get_type()
- }
-}
-
-impl DynamicType for Typed {
- fn get_type(&self) -> Result<Cow<'_, Type>, TypeError> {
- self.get_type()
- }
-}
diff --git a/dhall/src/api/traits/mod.rs b/dhall/src/api/traits/mod.rs
index 315e17a..3fd21e4 100644
--- a/dhall/src/api/traits/mod.rs
+++ b/dhall/src/api/traits/mod.rs
@@ -1,6 +1,2 @@
mod deserialize;
-mod dynamic_type;
-mod static_type;
pub use deserialize::Deserialize;
-pub use dynamic_type::DynamicType;
-pub use static_type::{SimpleStaticType, StaticType};
diff --git a/dhall/src/api/traits/static_type.rs b/dhall/src/api/traits/static_type.rs
deleted file mode 100644
index e05dfff..0000000
--- a/dhall/src/api/traits/static_type.rs
+++ /dev/null
@@ -1,149 +0,0 @@
-use crate::phase::*;
-use dhall_proc_macros as dhall;
-use dhall_syntax::*;
-
-/// A value that has a statically-known Dhall type.
-///
-/// This trait is strictly more general than [SimpleStaticType].
-/// The reason is that it allows an arbitrary [Type] to be returned
-/// instead of just a [SimpleType].
-///
-/// For now the only interesting impl is [SimpleType] itself, who
-/// has a statically-known type which is not itself a [SimpleType].
-pub trait StaticType {
- fn get_static_type() -> Type;
-}
-
-/// A Rust type that can be represented as a Dhall type.
-///
-/// A typical example is `Option<bool>`,
-/// represented by the dhall expression `Optional Bool`.
-///
-/// This trait can and should be automatically derived.
-///
-/// The representation needs to be independent of the value.
-/// For this reason, something like `HashMap<String, bool>` cannot implement
-/// [SimpleStaticType] because each different value would
-/// have a different Dhall record type.
-///
-/// The `Simple` in `SimpleStaticType` indicates that the returned type is
-/// a [SimpleType].
-pub trait SimpleStaticType {
- fn get_simple_static_type() -> SimpleType;
-}
-
-fn mktype(x: SubExpr<X, X>) -> SimpleType {
- x.into()
-}
-
-impl<T: SimpleStaticType> StaticType for T {
- fn get_static_type() -> Type {
- crate::phase::Normalized::from_thunk_and_type(
- crate::core::thunk::Thunk::from_normalized_expr(
- T::get_simple_static_type().into(),
- ),
- Type::const_type(),
- )
- .to_type()
- }
-}
-
-impl StaticType for SimpleType {
- /// By definition, a [SimpleType] has type `Type`.
- /// This returns the Dhall expression `Type`
- fn get_static_type() -> Type {
- Type::const_type()
- }
-}
-
-impl SimpleStaticType for bool {
- fn get_simple_static_type() -> SimpleType {
- mktype(dhall::subexpr!(Bool))
- }
-}
-
-impl SimpleStaticType for Natural {
- fn get_simple_static_type() -> SimpleType {
- mktype(dhall::subexpr!(Natural))
- }
-}
-
-impl SimpleStaticType for u32 {
- fn get_simple_static_type() -> SimpleType {
- mktype(dhall::subexpr!(Natural))
- }
-}
-
-impl SimpleStaticType for u64 {
- fn get_simple_static_type() -> SimpleType {
- mktype(dhall::subexpr!(Natural))
- }
-}
-
-impl SimpleStaticType for Integer {
- fn get_simple_static_type() -> SimpleType {
- mktype(dhall::subexpr!(Integer))
- }
-}
-
-impl SimpleStaticType for i32 {
- fn get_simple_static_type() -> SimpleType {
- mktype(dhall::subexpr!(Integer))
- }
-}
-
-impl SimpleStaticType for i64 {
- fn get_simple_static_type() -> SimpleType {
- mktype(dhall::subexpr!(Integer))
- }
-}
-
-impl SimpleStaticType for String {
- fn get_simple_static_type() -> SimpleType {
- mktype(dhall::subexpr!(Text))
- }
-}
-
-impl<A: SimpleStaticType, B: SimpleStaticType> SimpleStaticType for (A, B) {
- fn get_simple_static_type() -> SimpleType {
- let ta: SubExpr<_, _> = A::get_simple_static_type().into();
- let tb: SubExpr<_, _> = B::get_simple_static_type().into();
- mktype(dhall::subexpr!({ _1: ta, _2: tb }))
- }
-}
-
-impl<T: SimpleStaticType> SimpleStaticType for Option<T> {
- fn get_simple_static_type() -> SimpleType {
- let t: SubExpr<_, _> = T::get_simple_static_type().into();
- mktype(dhall::subexpr!(Optional t))
- }
-}
-
-impl<T: SimpleStaticType> SimpleStaticType for Vec<T> {
- fn get_simple_static_type() -> SimpleType {
- let t: SubExpr<_, _> = T::get_simple_static_type().into();
- mktype(dhall::subexpr!(List t))
- }
-}
-
-impl<'a, T: SimpleStaticType> SimpleStaticType for &'a T {
- fn get_simple_static_type() -> SimpleType {
- T::get_simple_static_type()
- }
-}
-
-impl<T> SimpleStaticType for std::marker::PhantomData<T> {
- fn get_simple_static_type() -> SimpleType {
- mktype(dhall::subexpr!({}))
- }
-}
-
-impl<T: SimpleStaticType, E: SimpleStaticType> SimpleStaticType
- for std::result::Result<T, E>
-{
- fn get_simple_static_type() -> SimpleType {
- let tt: SubExpr<_, _> = T::get_simple_static_type().into();
- let te: SubExpr<_, _> = E::get_simple_static_type().into();
- mktype(dhall::subexpr!(< Ok: tt | Err: te>))
- }
-}
diff --git a/dhall/src/lib.rs b/dhall/src/lib.rs
index b35b2ae..c25fc82 100644
--- a/dhall/src/lib.rs
+++ b/dhall/src/lib.rs
@@ -35,15 +35,15 @@
//! ### Custom datatype
//!
//! If you have a custom datatype for which you derived [serde::Deserialize], chances are
-//! you will be able to derive [SimpleStaticType][de::SimpleStaticType] for it as well.
+//! you will be able to derive [StaticType][de::StaticType] for it as well.
//! This gives you access to a dhall representation of your datatype that can be outputted
//! to users, and allows easy type-safe deserializing.
//!
//! ```edition2018
//! use serde::Deserialize;
-//! use dhall::de::SimpleStaticType;
+//! use dhall::de::StaticType;
//!
-//! #[derive(Debug, Deserialize, SimpleStaticType)]
+//! #[derive(Debug, Deserialize, StaticType)]
//! struct Point {
//! x: u64,
//! y: u64,
@@ -68,7 +68,7 @@
//! If you used to consume JSON or YAML in a loosely typed way, you can continue to do so
//! with dhall. You only need to replace [serde_json::from_str] or [serde_yaml::from_str]
//! with [dhall::de::from_str][de::from_str].
-//! More generally, if the [SimpleStaticType][de::SimpleStaticType] derive doesn't suit your
+//! More generally, if the [StaticType][de::StaticType] derive doesn't suit your
//! needs, you can still deserialize any valid dhall file that serde can handle.
//!
//! [serde_json::from_str]: https://docs.serde.rs/serde_json/de/fn.from_str.html
@@ -130,4 +130,4 @@ pub mod error;
pub(crate) mod phase;
pub(crate) use api::traits;
-pub use api::de;
+pub use api::*;
diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs
index af39eb6..5262a27 100644
--- a/dhall/src/phase/mod.rs
+++ b/dhall/src/phase/mod.rs
@@ -49,19 +49,6 @@ pub(crate) enum Typed {
#[derive(Debug, Clone)]
pub(crate) struct Normalized(pub(crate) Typed);
-/// A Dhall expression representing a simple type.
-///
-/// This captures what is usually simply called a "type", like
-/// `Bool`, `{ x: Integer }` or `Natural -> Text`.
-///
-/// For a more general notion of "type", see [Type].
-#[derive(Debug, Clone)]
-pub struct SimpleType(pub(crate) NormalizedSubExpr);
-
-/// A Dhall expression representing a (possibly higher-kinded) type.
-///
-/// This includes [SimpleType]s but also higher-kinded expressions like
-/// `Type`, `Kind` and `{ x: Type }`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Type(pub(crate) Typed);
@@ -131,6 +118,12 @@ impl Typed {
pub(crate) fn from_const(c: Const) -> Self {
Typed::Const(c)
}
+ pub(crate) fn from_value_untyped(v: Value) -> Self {
+ Typed::Untyped(Thunk::from_value(v))
+ }
+ pub(crate) fn from_normalized_expr_untyped(e: NormalizedSubExpr) -> Self {
+ Typed::from_thunk_untyped(Thunk::from_normalized_expr(e))
+ }
// TODO: Avoid cloning if possible
pub(crate) fn to_value(&self) -> Value {
@@ -179,6 +172,7 @@ impl Typed {
}
impl Type {
+ // Deprecated
pub(crate) fn to_normalized(&self) -> Normalized {
self.0.clone().normalize()
}
@@ -202,19 +196,12 @@ impl Type {
self.0.get_type()
}
- pub(crate) fn const_type() -> Self {
- Type::from_const(Const::Type)
- }
pub(crate) fn from_const(c: Const) -> Self {
Type(Typed::from_const(c))
}
}
impl Normalized {
- pub(crate) fn from_thunk_and_type(th: Thunk, t: Type) -> Self {
- Normalized(Typed::from_thunk_and_type(th, t))
- }
-
pub(crate) fn to_expr(&self) -> NormalizedSubExpr {
self.0.to_expr()
}
@@ -225,9 +212,12 @@ impl Normalized {
pub(crate) fn to_value(&self) -> Value {
self.0.to_value()
}
- pub(crate) fn to_type(self) -> Type {
+ pub(crate) fn to_type(&self) -> Type {
self.0.to_type()
}
+ pub(crate) fn into_typed(self) -> Typed {
+ self.0
+ }
pub(crate) fn get_type(&self) -> Result<Cow<'_, Type>, TypeError> {
self.0.get_type()
}
@@ -301,7 +291,6 @@ macro_rules! derive_traits_for_wrapper_struct {
derive_traits_for_wrapper_struct!(Parsed);
derive_traits_for_wrapper_struct!(Resolved);
derive_traits_for_wrapper_struct!(Normalized);
-derive_traits_for_wrapper_struct!(SimpleType);
impl Eq for Typed {}
impl PartialEq for Typed {
@@ -321,27 +310,3 @@ impl Display for Type {
self.to_normalized().fmt(f)
}
}
-
-// Exposed for the macros
-#[doc(hidden)]
-impl From<SimpleType> for NormalizedSubExpr {
- fn from(x: SimpleType) -> NormalizedSubExpr {
- x.0
- }
-}
-
-// Exposed for the macros
-#[doc(hidden)]
-impl From<NormalizedSubExpr> for SimpleType {
- fn from(x: NormalizedSubExpr) -> SimpleType {
- SimpleType(x)
- }
-}
-
-// Exposed for the macros
-#[doc(hidden)]
-impl From<Normalized> for Typed {
- fn from(x: Normalized) -> Typed {
- x.0
- }
-}
diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs
index e1dffb0..7f988c8 100644
--- a/dhall/src/phase/typecheck.rs
+++ b/dhall/src/phase/typecheck.rs
@@ -391,7 +391,7 @@ fn type_with(
let e = e.rewrap(Annot(x, t));
return type_with(ctx, e);
}
- Embed(p) => p.clone().into(),
+ Embed(p) => p.clone().into_typed(),
Var(var) => match ctx.lookup(&var) {
Some(typed) => typed,
None => {
diff --git a/dhall/tests/traits.rs b/dhall/tests/traits.rs
index 65220dc..75eaf75 100644
--- a/dhall/tests/traits.rs
+++ b/dhall/tests/traits.rs
@@ -1,79 +1,76 @@
#![feature(proc_macro_hygiene)]
-use dhall::de::SimpleStaticType;
-use dhall_proc_macros;
+use dhall::de::{StaticType, Type};
+use dhall_proc_macros::subexpr;
use dhall_syntax::{SubExpr, X};
#[test]
fn test_static_type() {
- fn mktype(x: SubExpr<X, X>) -> dhall::de::SimpleType {
- x.into()
+ fn mktype(x: SubExpr<X, X>) -> Type {
+ Type::from_normalized_expr(x)
}
+ assert_eq!(bool::static_type(), mktype(subexpr!(Bool)));
+ assert_eq!(String::static_type(), mktype(subexpr!(Text)));
assert_eq!(
- bool::get_simple_static_type(),
- mktype(dhall_proc_macros::subexpr!(Bool))
+ <Option<bool>>::static_type(),
+ mktype(subexpr!(Optional Bool))
);
assert_eq!(
- String::get_simple_static_type(),
- mktype(dhall_proc_macros::subexpr!(Text))
- );
- assert_eq!(
- <Option<bool>>::get_simple_static_type(),
- mktype(dhall_proc_macros::subexpr!(Optional Bool))
- );
- assert_eq!(
- <(bool, Option<String>)>::get_simple_static_type(),
- mktype(dhall_proc_macros::subexpr!({ _1: Bool, _2: Optional Text }))
+ <(bool, Vec<String>)>::static_type(),
+ mktype(subexpr!({ _1: Bool, _2: List Text }))
);
- #[derive(dhall::de::SimpleStaticType)]
+ #[derive(dhall::de::StaticType)]
#[allow(dead_code)]
struct A {
field1: bool,
field2: Option<bool>,
}
assert_eq!(
- <A as dhall::de::SimpleStaticType>::get_simple_static_type(),
- mktype(
- dhall_proc_macros::subexpr!({ field1: Bool, field2: Optional Bool })
- )
+ <A as dhall::de::StaticType>::static_type(),
+ mktype(subexpr!({ field1: Bool, field2: Optional Bool }))
);
- #[derive(SimpleStaticType)]
+ #[derive(StaticType)]
#[allow(dead_code)]
struct B<'a, T: 'a> {
field1: &'a T,
field2: Option<T>,
}
- assert_eq!(
- <B<'static, bool>>::get_simple_static_type(),
- A::get_simple_static_type()
- );
+ assert_eq!(<B<'static, bool>>::static_type(), A::static_type());
- #[derive(SimpleStaticType)]
+ #[derive(StaticType)]
#[allow(dead_code)]
struct C<T>(T, Option<String>);
assert_eq!(
- <C<bool>>::get_simple_static_type(),
- <(bool, Option<String>)>::get_simple_static_type()
+ <C<bool>>::static_type(),
+ <(bool, Option<String>)>::static_type()
);
- #[derive(SimpleStaticType)]
+ #[derive(StaticType)]
#[allow(dead_code)]
struct D();
assert_eq!(
- <C<D>>::get_simple_static_type(),
- mktype(dhall_proc_macros::subexpr!({ _1: {}, _2: Optional Text }))
+ <C<D>>::static_type(),
+ mktype(subexpr!({ _1: {}, _2: Optional Text }))
);
- #[derive(SimpleStaticType)]
+ #[derive(StaticType)]
#[allow(dead_code)]
enum E<T> {
A(T),
B(String),
};
assert_eq!(
- <E<bool>>::get_simple_static_type(),
- mktype(dhall_proc_macros::subexpr!(< A: Bool | B: Text >))
+ <E<bool>>::static_type(),
+ mktype(subexpr!(< A: Bool | B: Text >))
);
+
+ #[derive(StaticType)]
+ #[allow(dead_code)]
+ enum F {
+ A,
+ B(bool),
+ };
+ assert_eq!(F::static_type(), mktype(subexpr!(< A | B: Bool >)));
}