From 697e93e0f56e3c063ce253983f703be88d468b47 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 7 Dec 2020 11:56:00 +0000 Subject: Don't store internal structures of `dhall` in `serde_dhall` --- serde_dhall/src/options/de.rs | 11 +++-- serde_dhall/src/value.rs | 99 ++++++++++++++++++++++++++------------- serde_dhall/tests/simple_value.rs | 14 +++++- 3 files changed, 86 insertions(+), 38 deletions(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/options/de.rs b/serde_dhall/src/options/de.rs index 22fa7ba..39ab5ca 100644 --- a/serde_dhall/src/options/de.rs +++ b/serde_dhall/src/options/de.rs @@ -229,7 +229,7 @@ impl<'a, A> Deserializer<'a, A> { // self // } - fn _parse(&self) -> dhall::error::Result + fn _parse(&self) -> dhall::error::Result> where A: TypeAnnot, T: HasAnnot, @@ -246,9 +246,12 @@ impl<'a, A> Deserializer<'a, A> { }; let typed = match &T::get_annot(self.annot) { None => resolved.typecheck()?, - Some(ty) => resolved.typecheck_with(ty.to_value().as_hir())?, + Some(ty) => resolved.typecheck_with(&ty.to_hir())?, }; - Ok(Value::from_nir(typed.normalize().as_nir())) + Ok(Value::from_nir_and_ty( + typed.normalize().as_nir(), + typed.ty().as_nir(), + )) } /// Parses the chosen dhall value with the options provided. @@ -274,7 +277,7 @@ impl<'a, A> Deserializer<'a, A> { let val = self ._parse::() .map_err(ErrorKind::Dhall) - .map_err(Error)?; + .map_err(Error)??; T::from_dhall(&val) } } diff --git a/serde_dhall/src/value.rs b/serde_dhall/src/value.rs index b8ad199..4b22158 100644 --- a/serde_dhall/src/value.rs +++ b/serde_dhall/src/value.rs @@ -8,16 +8,18 @@ use dhall::syntax::{Expr, ExprKind, Span}; use crate::{Error, ErrorKind, FromDhall, Result, ToDhall}; +#[derive(Debug, Clone)] +enum ValueKind { + /// Invariant: the value must be printable with the given type. + Val(SimpleValue, Option), + Ty(SimpleType), +} + #[doc(hidden)] /// An arbitrary Dhall value. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Value { - /// Invariant: in normal form - hir: Hir, - /// Cached conversions because they are annoying to construct from Hir. - /// At most one of them will be `Some`. - as_simple_val: Option, - as_simple_ty: Option, + kind: ValueKind, } /// A value of the kind that can be decoded by `serde_dhall`, e.g. `{ x = True, y = [1, 2, 3] }`. @@ -204,31 +206,48 @@ pub enum SimpleType { } impl Value { - pub(crate) fn from_nir(x: &Nir) -> Self { - Value { - hir: x.to_hir_noenv(), - as_simple_val: SimpleValue::from_nir(x), - as_simple_ty: SimpleType::from_nir(x), - } - } - - pub(crate) fn as_hir(&self) -> &Hir { - &self.hir + pub(crate) fn from_nir_and_ty(x: &Nir, ty: &Nir) -> Result { + Ok(if let Some(val) = SimpleValue::from_nir(x) { + // The type must be simple if the value is simple. + let ty = SimpleType::from_nir(ty).unwrap(); + Value { + kind: ValueKind::Val(val, Some(ty)), + } + } else if let Some(ty) = SimpleType::from_nir(x) { + Value { + kind: ValueKind::Ty(ty), + } + } else { + let expr = x.to_hir_noenv().to_expr(Default::default()); + return Err(Error(ErrorKind::Deserialize(format!( + "this is neither a simple type nor a simple value: {}", + expr + )))); + }) } /// Converts a Value into a SimpleValue. pub(crate) fn to_simple_value(&self) -> Option { - self.as_simple_val.clone() + match &self.kind { + ValueKind::Val(val, _) => Some(val.clone()), + _ => None, + } } /// Converts a Value into a SimpleType. pub(crate) fn to_simple_type(&self) -> Option { - self.as_simple_ty.clone() + match &self.kind { + ValueKind::Ty(ty) => Some(ty.clone()), + _ => None, + } } /// Converts a value back to the corresponding AST expression. pub(crate) fn to_expr(&self) -> Expr { - self.hir.to_expr(Default::default()) + match &self.kind { + ValueKind::Val(val, ty) => val.to_expr(ty.as_ref()).unwrap(), + ValueKind::Ty(ty) => ty.to_expr(), + } } } @@ -411,12 +430,17 @@ impl SimpleValue { Ok(hir(kind)) } pub(crate) fn into_value(self, ty: Option<&SimpleType>) -> Result { + // Check that the value is printable with the given type. + self.to_hir(ty)?; Ok(Value { - hir: self.to_hir(ty)?, - as_simple_val: Some(self), - as_simple_ty: None, + kind: ValueKind::Val(self, ty.cloned()), }) } + + /// Converts back to the corresponding AST expression. + pub(crate) fn to_expr(&self, ty: Option<&SimpleType>) -> Result { + Ok(self.to_hir(ty)?.to_expr(Default::default())) + } } impl SimpleType { @@ -457,13 +481,6 @@ impl SimpleType { }) } - pub(crate) fn to_value(&self) -> Value { - Value { - hir: self.to_hir(), - as_simple_val: None, - as_simple_ty: Some(self.clone()), - } - } pub(crate) fn to_hir(&self) -> Hir { let hir = |k| Hir::new(HirKind::Expr(k), Span::Artificial); hir(match self { @@ -526,10 +543,15 @@ impl ToDhall for Value { } } -impl Eq for Value {} -impl PartialEq for Value { +impl Eq for ValueKind {} +impl PartialEq for ValueKind { fn eq(&self, other: &Self) -> bool { - self.hir == other.hir + use ValueKind::*; + match (self, other) { + (Val(a, _), Val(b, _)) => a == b, + (Ty(a), Ty(b)) => a == b, + _ => false, + } } } impl std::fmt::Display for Value { @@ -556,3 +578,14 @@ fn test_display_simpletype() { let ty = List(Box::new(Optional(Box::new(Natural)))); assert_eq!(ty.to_string(), "List (Optional Natural)".to_string()) } + +#[test] +fn test_display_value() { + use SimpleType::*; + let ty = List(Box::new(Optional(Box::new(Natural)))); + let val = SimpleValue::List(vec![]); + let val = Value { + kind: ValueKind::Val(val, Some(ty)), + }; + assert_eq!(val.to_string(), "[] : List (Optional Natural)".to_string()) +} diff --git a/serde_dhall/tests/simple_value.rs b/serde_dhall/tests/simple_value.rs index 3bd9d64..3d40da1 100644 --- a/serde_dhall/tests/simple_value.rs +++ b/serde_dhall/tests/simple_value.rs @@ -1,7 +1,7 @@ mod simple_value { use serde::{Deserialize, Serialize}; use serde_dhall::{ - from_str, serialize, FromDhall, NumKind, SimpleValue, ToDhall, + from_str, serialize, FromDhall, NumKind, SimpleValue, ToDhall, Value, }; fn assert_de(s: &str, x: T) @@ -54,5 +54,17 @@ mod simple_value { foo: bool_true.clone(), }, ); + + // Neither a simple value or a simple type. + let not_simple = "Type → Type"; + assert_eq!( + from_str(not_simple) + .parse::() + .map_err(|e| e.to_string()), + Err(format!( + "this is neither a simple type nor a simple value: {}", + not_simple + )) + ); } } -- cgit v1.2.3 From c785b7c0c6cd8b3b1cc15eb79caf982a757020ba Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 6 Dec 2020 23:55:21 +0000 Subject: Thread cx through normalization --- serde_dhall/src/options/de.rs | 40 +++++++++++++++++++++------------------- serde_dhall/src/value.rs | 4 ++-- 2 files changed, 23 insertions(+), 21 deletions(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/options/de.rs b/serde_dhall/src/options/de.rs index 39ab5ca..d57759a 100644 --- a/serde_dhall/src/options/de.rs +++ b/serde_dhall/src/options/de.rs @@ -1,6 +1,6 @@ use std::path::{Path, PathBuf}; -use dhall::Parsed; +use dhall::{Ctxt, Parsed}; use crate::options::{HasAnnot, ManualAnnot, NoAnnot, StaticAnnot, TypeAnnot}; use crate::SimpleType; @@ -234,24 +234,26 @@ impl<'a, A> Deserializer<'a, A> { A: TypeAnnot, T: HasAnnot, { - let parsed = match &self.source { - Source::Str(s) => Parsed::parse_str(s)?, - Source::File(p) => Parsed::parse_file(p.as_ref())?, - Source::BinaryFile(p) => Parsed::parse_binary_file(p.as_ref())?, - }; - let resolved = if self.allow_imports { - parsed.resolve()? - } else { - parsed.skip_resolve()? - }; - let typed = match &T::get_annot(self.annot) { - None => resolved.typecheck()?, - Some(ty) => resolved.typecheck_with(&ty.to_hir())?, - }; - Ok(Value::from_nir_and_ty( - typed.normalize().as_nir(), - typed.ty().as_nir(), - )) + Ctxt::with_new(|cx| { + let parsed = match &self.source { + Source::Str(s) => Parsed::parse_str(s)?, + Source::File(p) => Parsed::parse_file(p.as_ref())?, + Source::BinaryFile(p) => Parsed::parse_binary_file(p.as_ref())?, + }; + let resolved = if self.allow_imports { + parsed.resolve(cx)? + } else { + parsed.skip_resolve()? + }; + let typed = match &T::get_annot(self.annot) { + None => resolved.typecheck(cx)?, + Some(ty) => resolved.typecheck_with(cx, &ty.to_hir())?, + }; + Ok(Value::from_nir_and_ty( + typed.normalize(cx).as_nir(), + typed.ty().as_nir(), + )) + }) } /// Parses the chosen dhall value with the options provided. diff --git a/serde_dhall/src/value.rs b/serde_dhall/src/value.rs index 4b22158..e5f5acd 100644 --- a/serde_dhall/src/value.rs +++ b/serde_dhall/src/value.rs @@ -335,7 +335,7 @@ impl SimpleValue { // Converts this to `Hir`, using the optional type annotation. Without the type, things like // empty lists and unions will fail to convert. - fn to_hir(&self, ty: Option<&SimpleType>) -> Result { + fn to_hir<'cx>(&self, ty: Option<&SimpleType>) -> Result> { use SimpleType as T; use SimpleValue as V; let hir = |k| Hir::new(HirKind::Expr(k), Span::Artificial); @@ -481,7 +481,7 @@ impl SimpleType { }) } - pub(crate) fn to_hir(&self) -> Hir { + pub(crate) fn to_hir<'cx>(&self) -> Hir<'cx> { let hir = |k| Hir::new(HirKind::Expr(k), Span::Artificial); hir(match self { SimpleType::Bool => ExprKind::Builtin(Builtin::Bool), -- cgit v1.2.3 From 8c5b3ff15f2125e9d731fc199e194e1993c36b37 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 7 Dec 2020 14:15:43 +0000 Subject: Thread cx everywhere else imports are read --- serde_dhall/src/options/de.rs | 1 + serde_dhall/src/value.rs | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/options/de.rs b/serde_dhall/src/options/de.rs index d57759a..fc8c6dc 100644 --- a/serde_dhall/src/options/de.rs +++ b/serde_dhall/src/options/de.rs @@ -250,6 +250,7 @@ impl<'a, A> Deserializer<'a, A> { Some(ty) => resolved.typecheck_with(cx, &ty.to_hir())?, }; Ok(Value::from_nir_and_ty( + cx, typed.normalize(cx).as_nir(), typed.ty().as_nir(), )) diff --git a/serde_dhall/src/value.rs b/serde_dhall/src/value.rs index e5f5acd..b259c4b 100644 --- a/serde_dhall/src/value.rs +++ b/serde_dhall/src/value.rs @@ -5,6 +5,7 @@ use dhall::operations::OpKind; use dhall::semantics::{Hir, HirKind, Nir, NirKind}; pub use dhall::syntax::NumKind; use dhall::syntax::{Expr, ExprKind, Span}; +use dhall::Ctxt; use crate::{Error, ErrorKind, FromDhall, Result, ToDhall}; @@ -206,7 +207,11 @@ pub enum SimpleType { } impl Value { - pub(crate) fn from_nir_and_ty(x: &Nir, ty: &Nir) -> Result { + pub(crate) fn from_nir_and_ty<'cx>( + cx: Ctxt<'cx>, + x: &Nir<'cx>, + ty: &Nir<'cx>, + ) -> Result { Ok(if let Some(val) = SimpleValue::from_nir(x) { // The type must be simple if the value is simple. let ty = SimpleType::from_nir(ty).unwrap(); @@ -218,7 +223,7 @@ impl Value { kind: ValueKind::Ty(ty), } } else { - let expr = x.to_hir_noenv().to_expr(Default::default()); + let expr = x.to_hir_noenv().to_expr(cx, Default::default()); return Err(Error(ErrorKind::Deserialize(format!( "this is neither a simple type nor a simple value: {}", expr @@ -342,7 +347,7 @@ impl SimpleValue { let type_error = || { Error(ErrorKind::Serialize(format!( "expected a value of type {}, found {:?}", - ty.unwrap().to_hir().to_expr(Default::default()), + ty.unwrap().to_expr(), self ))) }; @@ -439,7 +444,9 @@ impl SimpleValue { /// Converts back to the corresponding AST expression. pub(crate) fn to_expr(&self, ty: Option<&SimpleType>) -> Result { - Ok(self.to_hir(ty)?.to_expr(Default::default())) + Ctxt::with_new(|cx| { + Ok(self.to_hir(ty)?.to_expr(cx, Default::default())) + }) } } @@ -514,7 +521,7 @@ impl SimpleType { /// Converts back to the corresponding AST expression. pub(crate) fn to_expr(&self) -> Expr { - self.to_hir().to_expr(Default::default()) + Ctxt::with_new(|cx| self.to_hir().to_expr(cx, Default::default())) } } -- cgit v1.2.3 From 922199ab322efa7b62bf4698cf5ed9e2d7a378c0 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 7 Dec 2020 15:24:36 +0000 Subject: Unify `skip_resolve_expr` with normal resolution --- serde_dhall/src/options/de.rs | 2 +- serde_dhall/tests/serde.rs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/options/de.rs b/serde_dhall/src/options/de.rs index fc8c6dc..30846a2 100644 --- a/serde_dhall/src/options/de.rs +++ b/serde_dhall/src/options/de.rs @@ -243,7 +243,7 @@ impl<'a, A> Deserializer<'a, A> { let resolved = if self.allow_imports { parsed.resolve(cx)? } else { - parsed.skip_resolve()? + parsed.skip_resolve(cx)? }; let typed = match &T::get_annot(self.annot) { None => resolved.typecheck(cx)?, diff --git a/serde_dhall/tests/serde.rs b/serde_dhall/tests/serde.rs index 1181f72..fe0bffb 100644 --- a/serde_dhall/tests/serde.rs +++ b/serde_dhall/tests/serde.rs @@ -226,6 +226,25 @@ mod serde { Ok(true) ); } + + #[test] + fn test_import() { + assert_de( + "../dhall-lang/tests/parser/success/unit/BoolLitTrueA.dhall", + true, + ); + assert_eq!( + serde_dhall::from_str( + "../dhall-lang/tests/parser/success/unit/BoolLitTrueA.dhall" + ) + .imports(false) + .static_type_annotation() + .parse::() + .map_err(|e| e.to_string()), + Err("UnexpectedImport(Import { mode: Code, location: Local(Parent, FilePath { file_path: [\"dhall-lang\", \"tests\", \"parser\", \"success\", \"unit\", \"BoolLitTrueA.dhall\"] }), hash: None })".to_string()) + ); + } + // TODO: test various builder configurations // In particular test cloning and reusing builder } -- cgit v1.2.3