From fa89e9cb319b353332c9e835944e7f86a6604c42 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 18 Mar 2020 21:37:14 +0000 Subject: Move Value, SimpleValue and SimpleType to serde --- dhall/src/lib.rs | 66 +------------ dhall/src/semantics/tck/typecheck.rs | 5 +- dhall/src/simple.rs | 163 ------------------------------- serde_dhall/src/lib.rs | 9 +- serde_dhall/src/serde.rs | 6 +- serde_dhall/src/simple.rs | 180 +++++++++++++++++++++++++++++++++-- serde_dhall/src/static_type.rs | 3 +- serde_dhall/src/value.rs | 73 ++++++++++++++ 8 files changed, 257 insertions(+), 248 deletions(-) delete mode 100644 dhall/src/simple.rs create mode 100644 serde_dhall/src/value.rs diff --git a/dhall/src/lib.rs b/dhall/src/lib.rs index 34a9bac..0f4b623 100644 --- a/dhall/src/lib.rs +++ b/dhall/src/lib.rs @@ -9,7 +9,6 @@ mod tests; pub mod error; pub mod semantics; -pub mod simple; pub mod syntax; use std::fmt::Display; @@ -23,8 +22,6 @@ use crate::semantics::resolve::ImportLocation; use crate::semantics::{typecheck, typecheck_with, Hir, Nir, Tir, Type}; use crate::syntax::Expr; -pub use crate::simple::{STyKind, SValKind, SimpleType, SimpleValue}; - #[derive(Debug, Clone)] pub struct Parsed(Expr, ImportLocation); @@ -47,16 +44,6 @@ pub struct Typed { #[derive(Debug, Clone)] pub struct Normalized(Nir); -/// A Dhall value. -#[derive(Debug, Clone)] -pub struct Value { - /// Invariant: in normal form - pub hir: Hir, - /// Cached conversions because they are annoying to construct from Hir. - pub as_simple_val: Option, - pub as_simple_ty: Option, -} - /// Controls conversion from `Nir` to `Expr` #[derive(Copy, Clone, Default)] pub struct ToExprOptions { @@ -131,14 +118,6 @@ impl Typed { } impl Normalized { - pub fn to_value(&self) -> Value { - Value { - hir: self.to_hir(), - as_simple_val: SimpleValue::from_nir(&self.0), - as_simple_ty: SimpleType::from_nir(&self.0), - } - } - /// Converts a value back to the corresponding AST expression. pub fn to_expr(&self) -> Expr { self.0.to_expr(ToExprOptions::default()) @@ -147,42 +126,15 @@ impl Normalized { pub fn to_hir(&self) -> Hir { self.0.to_hir_noenv() } + pub fn as_nir(&self) -> &Nir { + &self.0 + } /// Converts a value back to the corresponding AST expression, alpha-normalizing in the process. pub fn to_expr_alpha(&self) -> Expr { self.0.to_expr(ToExprOptions { alpha: true }) } } -impl Value { - /// Parse a string into a Value, and optionally ensure that the value matches the provided type - /// annotation. - pub fn from_str_with_annot( - s: &str, - ty: Option<&Self>, - ) -> Result { - let resolved = Parsed::parse_str(s)?.resolve()?; - let typed = match ty { - None => resolved.typecheck()?, - Some(ty) => resolved.typecheck_with(&ty.hir)?, - }; - Ok(typed.normalize().to_value()) - } - - /// Converts a Value into a SimpleValue. - pub fn to_simple_value(&self) -> Option { - self.as_simple_val.clone() - } - /// Converts a Value into a SimpleType. - pub fn to_simple_type(&self) -> Option { - self.as_simple_ty.clone() - } - - /// Converts a value back to the corresponding AST expression. - pub fn to_expr(&self) -> Expr { - self.hir.to_expr(ToExprOptions::default()) - } -} - macro_rules! derive_traits_for_wrapper_struct { ($ty:ident) => { impl std::cmp::PartialEq for $ty { @@ -246,15 +198,3 @@ impl Display for Normalized { self.to_expr().fmt(f) } } - -impl Eq for Value {} -impl PartialEq for Value { - fn eq(&self, other: &Self) -> bool { - self.hir == other.hir - } -} -impl Display for Value { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - self.to_expr().fmt(f) - } -} diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index 205185f..c3334b5 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -57,10 +57,7 @@ pub fn mkerr(msg: S) -> Result { Err(TypeError::new(TypeMessage::Custom(msg.to_string()))) } -pub fn mk_span_err( - span: Span, - msg: S, -) -> Result { +pub fn mk_span_err(span: Span, msg: S) -> Result { mkerr( ErrorBuilder::new(msg.to_string()) .span_err(span, msg.to_string()) diff --git a/dhall/src/simple.rs b/dhall/src/simple.rs deleted file mode 100644 index c00380c..0000000 --- a/dhall/src/simple.rs +++ /dev/null @@ -1,163 +0,0 @@ -use std::collections::BTreeMap; - -use crate::semantics::{Hir, HirKind, Nir, NirKind}; -use crate::syntax::{Builtin, ExprKind, NumKind, Span}; -use crate::Value; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct SimpleValue { - kind: Box, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum SValKind { - Num(NumKind), - Text(String), - Optional(Option), - List(Vec), - Record(BTreeMap), - Union(String, Option), -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct SimpleType { - kind: Box, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum STyKind { - Bool, - Natural, - Integer, - Double, - Text, - Optional(SimpleType), - List(SimpleType), - Record(BTreeMap), - Union(BTreeMap>), -} - -impl SimpleValue { - pub fn new(kind: SValKind) -> Self { - SimpleValue { - kind: Box::new(kind), - } - } - pub fn from_nir(nir: &Nir) -> Option { - Some(SimpleValue::new(match nir.kind() { - NirKind::Num(lit) => SValKind::Num(lit.clone()), - NirKind::TextLit(x) => SValKind::Text( - x.as_text() - .expect("Normal form should ensure the text is a string"), - ), - NirKind::EmptyOptionalLit(_) => SValKind::Optional(None), - NirKind::NEOptionalLit(x) => { - SValKind::Optional(Some(Self::from_nir(x)?)) - } - NirKind::EmptyListLit(_) => SValKind::List(vec![]), - NirKind::NEListLit(xs) => SValKind::List( - xs.iter() - .map(|v| Self::from_nir(v)) - .collect::>()?, - ), - NirKind::RecordLit(kvs) => SValKind::Record( - kvs.iter() - .map(|(k, v)| Some((k.into(), Self::from_nir(v)?))) - .collect::>()?, - ), - NirKind::UnionLit(field, x, _) => { - SValKind::Union(field.into(), Some(Self::from_nir(x)?)) - } - NirKind::UnionConstructor(field, ty) - if ty.get(field).map(|f| f.is_some()) == Some(false) => - { - SValKind::Union(field.into(), None) - } - _ => return None, - })) - } - - pub fn kind(&self) -> &SValKind { - self.kind.as_ref() - } -} - -impl SimpleType { - pub fn new(kind: STyKind) -> Self { - SimpleType { - kind: Box::new(kind), - } - } - pub fn from_nir(nir: &Nir) -> Option { - Some(SimpleType::new(match nir.kind() { - NirKind::BuiltinType(b) => match b { - Builtin::Bool => STyKind::Bool, - Builtin::Natural => STyKind::Natural, - Builtin::Integer => STyKind::Integer, - Builtin::Double => STyKind::Double, - Builtin::Text => STyKind::Text, - _ => unreachable!(), - }, - NirKind::OptionalType(t) => STyKind::Optional(Self::from_nir(t)?), - NirKind::ListType(t) => STyKind::List(Self::from_nir(t)?), - NirKind::RecordType(kts) => STyKind::Record( - kts.iter() - .map(|(k, v)| Some((k.into(), Self::from_nir(v)?))) - .collect::>()?, - ), - NirKind::UnionType(kts) => STyKind::Union( - kts.iter() - .map(|(k, v)| { - Some(( - k.into(), - v.as_ref() - .map(|v| Ok(Self::from_nir(v)?)) - .transpose()?, - )) - }) - .collect::>()?, - ), - _ => return None, - })) - } - - pub fn kind(&self) -> &STyKind { - self.kind.as_ref() - } - pub fn to_value(&self) -> Value { - Value { - hir: self.to_hir(), - as_simple_val: None, - as_simple_ty: Some(self.clone()), - } - } - pub fn to_hir(&self) -> Hir { - let hir = |k| Hir::new(HirKind::Expr(k), Span::Artificial); - hir(match self.kind() { - STyKind::Bool => ExprKind::Builtin(Builtin::Bool), - STyKind::Natural => ExprKind::Builtin(Builtin::Natural), - STyKind::Integer => ExprKind::Builtin(Builtin::Integer), - STyKind::Double => ExprKind::Builtin(Builtin::Double), - STyKind::Text => ExprKind::Builtin(Builtin::Text), - STyKind::Optional(t) => ExprKind::App( - hir(ExprKind::Builtin(Builtin::Optional)), - t.to_hir(), - ), - STyKind::List(t) => { - ExprKind::App(hir(ExprKind::Builtin(Builtin::List)), t.to_hir()) - } - STyKind::Record(kts) => ExprKind::RecordType( - kts.into_iter() - .map(|(k, t)| (k.as_str().into(), t.to_hir())) - .collect(), - ), - STyKind::Union(kts) => ExprKind::UnionType( - kts.into_iter() - .map(|(k, t)| { - (k.as_str().into(), t.as_ref().map(|t| t.to_hir())) - }) - .collect(), - ), - }) - } -} diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 15f45ce..adc242f 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -171,11 +171,13 @@ mod error; mod serde; pub mod simple; mod static_type; +mod value; #[doc(hidden)] pub use dhall_proc_macros::StaticType; pub use error::{Error, Result}; pub use static_type::StaticType; +pub use value::Value; use simple::Type; @@ -191,16 +193,15 @@ pub(crate) mod sealed { /// This trait cannot be implemented manually. pub trait Deserialize: sealed::Sealed + Sized { /// See [serde_dhall::from_str][crate::from_str] - fn from_dhall(v: &dhall::Value) -> Result; + fn from_dhall(v: &Value) -> Result; } fn from_str_with_annot(s: &str, ty: Option<&Type>) -> Result where T: Deserialize, { - let ty = ty.map(|ty| ty.to_dhall_value()); - let val = dhall::Value::from_str_with_annot(s, ty.as_ref()) - .map_err(Error::Dhall)?; + let ty = ty.map(|ty| ty.to_value()); + let val = Value::from_str_with_annot(s, ty.as_ref())?; T::from_dhall(&val) } diff --git a/serde_dhall/src/serde.rs b/serde_dhall/src/serde.rs index d144abf..91ef5d7 100644 --- a/serde_dhall/src/serde.rs +++ b/serde_dhall/src/serde.rs @@ -5,9 +5,9 @@ use serde::de::value::{ }; use dhall::syntax::NumKind; -use dhall::{SValKind, SimpleValue}; -use crate::{Deserialize, Error, Result}; +use crate::simple::{SValKind, SimpleValue}; +use crate::{Deserialize, Error, Result, Value}; impl<'a, T> crate::sealed::Sealed for T where T: serde::Deserialize<'a> {} @@ -17,7 +17,7 @@ impl<'a, T> Deserialize for T where T: serde::Deserialize<'a>, { - fn from_dhall(v: &dhall::Value) -> Result { + fn from_dhall(v: &Value) -> Result { let sval = v.to_simple_value().ok_or_else(|| { Error::Deserialize(format!( "this cannot be deserialized into the serde data model: {}", diff --git a/serde_dhall/src/simple.rs b/serde_dhall/src/simple.rs index 93364a0..0b322ae 100644 --- a/serde_dhall/src/simple.rs +++ b/serde_dhall/src/simple.rs @@ -1,25 +1,62 @@ -use super::Error; -use dhall::{STyKind, SimpleType, SimpleValue}; +use std::collections::BTreeMap; + +use dhall::semantics::{Hir, HirKind, Nir, NirKind}; +use dhall::syntax::{Builtin, ExprKind, NumKind, Span}; + +use crate::Error; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SimpleValue { + kind: Box, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum SValKind { + Num(NumKind), + Text(String), + Optional(Option), + List(Vec), + Record(BTreeMap), + Union(String, Option), +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SimpleType { + kind: Box, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum STyKind { + Bool, + Natural, + Integer, + Double, + Text, + Optional(SimpleType), + List(SimpleType), + Record(BTreeMap), + Union(BTreeMap>), +} /// A Dhall value. This is a wrapper around [`dhall::SimpleValue`]. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Value(SimpleValue); +/// A Dhall type. This is a wrapper around [`dhall::SimpleType`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Type(SimpleType); + impl Value { pub fn into_simple_value(self) -> SimpleValue { self.0 } } -/// A Dhall type. This is a wrapper around [`dhall::SimpleType`]. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Type(SimpleType); - impl Type { pub fn into_simple_type(self) -> SimpleType { self.0 } - pub fn to_dhall_value(&self) -> dhall::Value { + pub fn to_value(&self) -> crate::Value { self.0.to_value() } @@ -52,10 +89,135 @@ impl Type { } } +impl SimpleValue { + pub fn new(kind: SValKind) -> Self { + SimpleValue { + kind: Box::new(kind), + } + } + pub fn from_nir(nir: &Nir) -> Option { + Some(SimpleValue::new(match nir.kind() { + NirKind::Num(lit) => SValKind::Num(lit.clone()), + NirKind::TextLit(x) => SValKind::Text( + x.as_text() + .expect("Normal form should ensure the text is a string"), + ), + NirKind::EmptyOptionalLit(_) => SValKind::Optional(None), + NirKind::NEOptionalLit(x) => { + SValKind::Optional(Some(Self::from_nir(x)?)) + } + NirKind::EmptyListLit(_) => SValKind::List(vec![]), + NirKind::NEListLit(xs) => SValKind::List( + xs.iter() + .map(|v| Self::from_nir(v)) + .collect::>()?, + ), + NirKind::RecordLit(kvs) => SValKind::Record( + kvs.iter() + .map(|(k, v)| Some((k.into(), Self::from_nir(v)?))) + .collect::>()?, + ), + NirKind::UnionLit(field, x, _) => { + SValKind::Union(field.into(), Some(Self::from_nir(x)?)) + } + NirKind::UnionConstructor(field, ty) + if ty.get(field).map(|f| f.is_some()) == Some(false) => + { + SValKind::Union(field.into(), None) + } + _ => return None, + })) + } + + pub fn kind(&self) -> &SValKind { + self.kind.as_ref() + } +} + +impl SimpleType { + pub fn new(kind: STyKind) -> Self { + SimpleType { + kind: Box::new(kind), + } + } + pub fn from_nir(nir: &Nir) -> Option { + Some(SimpleType::new(match nir.kind() { + NirKind::BuiltinType(b) => match b { + Builtin::Bool => STyKind::Bool, + Builtin::Natural => STyKind::Natural, + Builtin::Integer => STyKind::Integer, + Builtin::Double => STyKind::Double, + Builtin::Text => STyKind::Text, + _ => unreachable!(), + }, + NirKind::OptionalType(t) => STyKind::Optional(Self::from_nir(t)?), + NirKind::ListType(t) => STyKind::List(Self::from_nir(t)?), + NirKind::RecordType(kts) => STyKind::Record( + kts.iter() + .map(|(k, v)| Some((k.into(), Self::from_nir(v)?))) + .collect::>()?, + ), + NirKind::UnionType(kts) => STyKind::Union( + kts.iter() + .map(|(k, v)| { + Some(( + k.into(), + v.as_ref() + .map(|v| Ok(Self::from_nir(v)?)) + .transpose()?, + )) + }) + .collect::>()?, + ), + _ => return None, + })) + } + + pub fn kind(&self) -> &STyKind { + self.kind.as_ref() + } + pub fn to_value(&self) -> crate::Value { + crate::Value { + hir: self.to_hir(), + as_simple_val: None, + as_simple_ty: Some(self.clone()), + } + } + pub fn to_hir(&self) -> Hir { + let hir = |k| Hir::new(HirKind::Expr(k), Span::Artificial); + hir(match self.kind() { + STyKind::Bool => ExprKind::Builtin(Builtin::Bool), + STyKind::Natural => ExprKind::Builtin(Builtin::Natural), + STyKind::Integer => ExprKind::Builtin(Builtin::Integer), + STyKind::Double => ExprKind::Builtin(Builtin::Double), + STyKind::Text => ExprKind::Builtin(Builtin::Text), + STyKind::Optional(t) => ExprKind::App( + hir(ExprKind::Builtin(Builtin::Optional)), + t.to_hir(), + ), + STyKind::List(t) => { + ExprKind::App(hir(ExprKind::Builtin(Builtin::List)), t.to_hir()) + } + STyKind::Record(kts) => ExprKind::RecordType( + kts.into_iter() + .map(|(k, t)| (k.as_str().into(), t.to_hir())) + .collect(), + ), + STyKind::Union(kts) => ExprKind::UnionType( + kts.into_iter() + .map(|(k, t)| { + (k.as_str().into(), t.as_ref().map(|t| t.to_hir())) + }) + .collect(), + ), + }) + } +} + impl super::sealed::Sealed for Value {} impl super::Deserialize for Value { - fn from_dhall(v: &dhall::Value) -> super::Result { + fn from_dhall(v: &crate::Value) -> super::Result { let sval = v.to_simple_value().ok_or_else(|| { Error::Deserialize(format!( "this cannot be deserialized into a simple type: {}", @@ -69,7 +231,7 @@ impl super::Deserialize for Value { impl super::sealed::Sealed for Type {} impl super::Deserialize for Type { - fn from_dhall(v: &dhall::Value) -> super::Result { + fn from_dhall(v: &crate::Value) -> super::Result { let sty = v.to_simple_type().ok_or_else(|| { Error::Deserialize(format!( "this cannot be deserialized into a simple type: {}", diff --git a/serde_dhall/src/static_type.rs b/serde_dhall/src/static_type.rs index bc5f366..4e30f34 100644 --- a/serde_dhall/src/static_type.rs +++ b/serde_dhall/src/static_type.rs @@ -1,5 +1,4 @@ -use dhall::{STyKind, SimpleType}; - +use crate::simple::{STyKind, SimpleType}; use crate::Type; /// A Rust type that can be represented as a Dhall type. diff --git a/serde_dhall/src/value.rs b/serde_dhall/src/value.rs new file mode 100644 index 0000000..a24f211 --- /dev/null +++ b/serde_dhall/src/value.rs @@ -0,0 +1,73 @@ +use dhall::semantics::Hir; +use dhall::syntax::Expr; +use dhall::{Normalized, Parsed}; + +use crate::simple::{SimpleType, SimpleValue}; +use crate::Error; + +/// A Dhall value. +#[derive(Debug, Clone)] +pub struct Value { + /// Invariant: in normal form + pub(crate) hir: Hir, + /// Cached conversions because they are annoying to construct from Hir. + /// At most one of them will be `Some`. + pub(crate) as_simple_val: Option, + pub(crate) as_simple_ty: Option, +} + +impl Value { + /// Parse a string into a Value, and optionally ensure that the value matches the provided type + /// annotation. + pub fn from_str_with_annot( + s: &str, + ty: Option<&Self>, + ) -> Result { + Self::from_str_with_annot_dhall_error(s, ty).map_err(Error::Dhall) + } + fn from_normalized(x: &Normalized) -> Self { + Value { + hir: x.to_hir(), + as_simple_val: SimpleValue::from_nir(x.as_nir()), + as_simple_ty: SimpleType::from_nir(x.as_nir()), + } + } + + fn from_str_with_annot_dhall_error( + s: &str, + ty: Option<&Self>, + ) -> Result { + let resolved = Parsed::parse_str(s)?.resolve()?; + let typed = match ty { + None => resolved.typecheck()?, + Some(ty) => resolved.typecheck_with(&ty.hir)?, + }; + Ok(Self::from_normalized(&typed.normalize())) + } + + /// Converts a Value into a SimpleValue. + pub fn to_simple_value(&self) -> Option { + self.as_simple_val.clone() + } + /// Converts a Value into a SimpleType. + pub fn to_simple_type(&self) -> Option { + self.as_simple_ty.clone() + } + + /// Converts a value back to the corresponding AST expression. + pub fn to_expr(&self) -> Expr { + self.hir.to_expr(Default::default()) + } +} + +impl Eq for Value {} +impl PartialEq for Value { + fn eq(&self, other: &Self) -> bool { + self.hir == other.hir + } +} +impl std::fmt::Display for Value { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + self.to_expr().fmt(f) + } +} -- cgit v1.2.3