summaryrefslogtreecommitdiff
path: root/serde_dhall
diff options
context:
space:
mode:
authorNadrieril2020-12-08 18:47:41 +0000
committerGitHub2020-12-08 18:47:41 +0000
commit109dcf894e759bce1c28f9ae94f3fdaa6e08feb5 (patch)
tree9ce374d02ea15966c7bb2dfb39d5d81720a63687 /serde_dhall
parent35ed301e8de5a2b1102e370e638564d3c3d204a8 (diff)
parentd0a61179addf838d33e7e7a4c6a13f06e871e9c5 (diff)
Merge pull request #204 from Nadrieril/source-id
Diffstat (limited to 'serde_dhall')
-rw-r--r--serde_dhall/src/options/de.rs42
-rw-r--r--serde_dhall/src/value.rs114
-rw-r--r--serde_dhall/tests/serde.rs19
-rw-r--r--serde_dhall/tests/simple_value.rs14
4 files changed, 133 insertions, 56 deletions
diff --git a/serde_dhall/src/options/de.rs b/serde_dhall/src/options/de.rs
index 22fa7ba..30846a2 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;
@@ -229,26 +229,32 @@ impl<'a, A> Deserializer<'a, A> {
// self
// }
- fn _parse<T>(&self) -> dhall::error::Result<Value>
+ fn _parse<T>(&self) -> dhall::error::Result<Result<Value>>
where
A: TypeAnnot,
T: HasAnnot<A>,
{
- 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_value().as_hir())?,
- };
- Ok(Value::from_nir(typed.normalize().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(cx)?
+ };
+ 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(
+ cx,
+ typed.normalize(cx).as_nir(),
+ typed.ty().as_nir(),
+ ))
+ })
}
/// Parses the chosen dhall value with the options provided.
@@ -274,7 +280,7 @@ impl<'a, A> Deserializer<'a, A> {
let val = self
._parse::<T>()
.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..b259c4b 100644
--- a/serde_dhall/src/value.rs
+++ b/serde_dhall/src/value.rs
@@ -5,19 +5,22 @@ 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};
+#[derive(Debug, Clone)]
+enum ValueKind {
+ /// Invariant: the value must be printable with the given type.
+ Val(SimpleValue, Option<SimpleType>),
+ 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<SimpleValue>,
- as_simple_ty: Option<SimpleType>,
+ kind: ValueKind,
}
/// A value of the kind that can be decoded by `serde_dhall`, e.g. `{ x = True, y = [1, 2, 3] }`.
@@ -204,31 +207,52 @@ 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<'cx>(
+ cx: Ctxt<'cx>,
+ x: &Nir<'cx>,
+ ty: &Nir<'cx>,
+ ) -> Result<Self> {
+ 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(cx, 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<SimpleValue> {
- 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<SimpleType> {
- 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(),
+ }
}
}
@@ -316,14 +340,14 @@ 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<Hir> {
+ fn to_hir<'cx>(&self, ty: Option<&SimpleType>) -> Result<Hir<'cx>> {
use SimpleType as T;
use SimpleValue as V;
let hir = |k| Hir::new(HirKind::Expr(k), Span::Artificial);
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
)))
};
@@ -411,10 +435,17 @@ impl SimpleValue {
Ok(hir(kind))
}
pub(crate) fn into_value(self, ty: Option<&SimpleType>) -> Result<Value> {
+ // 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<Expr> {
+ Ctxt::with_new(|cx| {
+ Ok(self.to_hir(ty)?.to_expr(cx, Default::default()))
})
}
}
@@ -457,14 +488,7 @@ 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 {
+ 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),
@@ -497,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()))
}
}
@@ -526,10 +550,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 +585,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/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::<bool>()
+ .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
}
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<T>(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::<Value>()
+ .map_err(|e| e.to_string()),
+ Err(format!(
+ "this is neither a simple type nor a simple value: {}",
+ not_simple
+ ))
+ );
}
}