From efe4b340bebaa7ef8bce6e69194959b126c5fade Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 10 Apr 2020 12:10:53 +0100 Subject: Deserialize `Prelude.Map` and `toMap` to a map instead of a list --- README.md | 4 +++ dhall/src/operations/normalization.rs | 4 +-- dhall/src/operations/typecheck.rs | 6 ++-- dhall/src/syntax/ast/label.rs | 6 ++++ serde_dhall/src/static_type.rs | 1 + serde_dhall/src/value.rs | 58 ++++++++++++++++++++++++++++++++--- serde_dhall/tests/de.rs | 4 +++ tests_buffer | 1 + 8 files changed, 74 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 6d9372b..e4411d3 100644 --- a/README.md +++ b/README.md @@ -169,8 +169,12 @@ same name as the corresponding test. #### [Unreleased] +- Deserialize `Prelude.Map` and `toMap` to a map instead of a list. + #### [0.5.1] - 2020-04-09 +- Small fixes + #### [0.5.0] - 2020-04-05 - Add `serde_dhall::from_file` to read a Dhall file directly. diff --git a/dhall/src/operations/normalization.rs b/dhall/src/operations/normalization.rs index e3a9415..86fed13 100644 --- a/dhall/src/operations/normalization.rs +++ b/dhall/src/operations/normalization.rs @@ -226,11 +226,11 @@ pub fn normalize_operation(opkind: &OpKind) -> Ret { Some(h) => ret_kind(h.app_to_kind(v.clone())), None => nothing_to_do(), }, - EmptyOptionalLit(_) => match kvs.get(&"None".into()) { + EmptyOptionalLit(_) => match kvs.get("None") { Some(h) => ret_ref(h), None => nothing_to_do(), }, - NEOptionalLit(v) => match kvs.get(&"Some".into()) { + NEOptionalLit(v) => match kvs.get("Some") { Some(h) => ret_kind(h.app_to_kind(v.clone())), None => nothing_to_do(), }, diff --git a/dhall/src/operations/typecheck.rs b/dhall/src/operations/typecheck.rs index 91d5059..314c587 100644 --- a/dhall/src/operations/typecheck.rs +++ b/dhall/src/operations/typecheck.rs @@ -398,11 +398,11 @@ pub fn typecheck_operation( if kts.len() != 2 { return span_err(err_msg); } - match kts.get(&"mapKey".into()) { + match kts.get("mapKey") { Some(t) if *t == Nir::from_builtin(Builtin::Text) => {} _ => return span_err(err_msg), } - match kts.get(&"mapValue".into()) { + match kts.get("mapValue") { Some(_) => {} None => return span_err(err_msg), } @@ -434,7 +434,7 @@ pub fn typecheck_operation( } Field(scrut, x) => { match scrut.ty().kind() { - RecordType(kts) => match kts.get(&x) { + RecordType(kts) => match kts.get(x) { Some(val) => Type::new_infer_universe(env, val.clone())?, None => return span_err("MissingRecordField"), }, diff --git a/dhall/src/syntax/ast/label.rs b/dhall/src/syntax/ast/label.rs index 43c3f53..2abde80 100644 --- a/dhall/src/syntax/ast/label.rs +++ b/dhall/src/syntax/ast/label.rs @@ -24,6 +24,12 @@ impl From<&Label> for String { } } +impl std::borrow::Borrow for Label { + fn borrow(&self) -> &str { + self.0.as_ref() + } +} + impl Label { pub fn from_str(s: &str) -> Label { Label(s.into()) diff --git a/serde_dhall/src/static_type.rs b/serde_dhall/src/static_type.rs index 26c70cd..3c5da18 100644 --- a/serde_dhall/src/static_type.rs +++ b/serde_dhall/src/static_type.rs @@ -47,6 +47,7 @@ use crate::SimpleType; /// `{ _1: T, _2: U }` | `(T, U)`, structs /// `{ x: T, y: T }` | `HashMap`, structs /// `< x: T \| y: U >` | enums +/// `Prelude.Map.Type Text T` | `HashMap`, structs /// `T -> U` | unsupported /// `Prelude.JSON.Type` | unsupported /// `Prelude.Map.Type T U` | unsupported diff --git a/serde_dhall/src/value.rs b/serde_dhall/src/value.rs index 03cfdba..0f0b256 100644 --- a/serde_dhall/src/value.rs +++ b/serde_dhall/src/value.rs @@ -144,13 +144,61 @@ impl SimpleValue { NirKind::NEOptionalLit(x) => { SimpleValue::Optional(Some(Box::new(Self::from_nir(x)?))) } - NirKind::EmptyListLit(_) => SimpleValue::List(vec![]), - NirKind::NEListLit(xs) => SimpleValue::List( - xs.iter().map(Self::from_nir).collect::>()?, - ), + NirKind::EmptyListLit(t) => { + // Detect and handle the special records that make assoc maps + if let NirKind::RecordType(kts) = t.kind() { + if kts.len() == 2 + && kts.contains_key("mapKey") + && kts.contains_key("mapValue") + { + return Some(SimpleValue::Record(Default::default())); + } + } + SimpleValue::List(vec![]) + } + NirKind::NEListLit(xs) => { + // Detect and handle the special records that make assoc maps + if let NirKind::RecordLit(kvs) = xs[0].kind() { + if kvs.len() == 2 + && kvs.contains_key("mapKey") + && kvs.contains_key("mapValue") + { + let convert_entry = |x: &Nir| match x.kind() { + NirKind::RecordLit(kvs) => { + let k = match kvs.get("mapKey").unwrap().kind() + { + NirKind::TextLit(t) + if t.as_text().is_some() => + { + t.as_text().unwrap() + } + // TODO + _ => panic!( + "Expected `mapKey` to be a text \ + literal" + ), + }; + let v = Self::from_nir( + kvs.get("mapValue").unwrap(), + )?; + Some((k, v)) + } + _ => unreachable!("Internal type error"), + }; + return Some(SimpleValue::Record( + xs.iter() + .map(convert_entry) + .collect::>()?, + )); + } + } + SimpleValue::List( + xs.iter().map(Self::from_nir).collect::>()?, + ) + } NirKind::RecordLit(kvs) => SimpleValue::Record( kvs.iter() - .map(|(k, v)| Some((k.into(), Self::from_nir(v)?))) + .map(|(k, v)| Some((k.to_string(), Self::from_nir(v)?))) .collect::>()?, ), NirKind::UnionLit(field, x, _) => SimpleValue::Union( diff --git a/serde_dhall/tests/de.rs b/serde_dhall/tests/de.rs index 41b4080..1932e26 100644 --- a/serde_dhall/tests/de.rs +++ b/serde_dhall/tests/de.rs @@ -80,6 +80,10 @@ fn test_de_untyped() { parse::>("{ x = 1, y = 2 }"), expected_map ); + assert_eq!( + parse::>("toMap { x = 1, y = 2 }"), + expected_map + ); let mut expected_map = HashMap::new(); expected_map.insert("if".to_string(), 1); diff --git a/tests_buffer b/tests_buffer index bd76d36..3240b41 100644 --- a/tests_buffer +++ b/tests_buffer @@ -24,6 +24,7 @@ normalization: move builtins and operators in their own folder ? RecordSortFields { b = 1, a = 0 } RecordTypeSortFields { b : Bool, a : Natural } +\(foo: { x: Bool, y: Bool }) -> \(bar: { x: Bool }) -> (foo.{x, y} // bar).{ x } type-inference: something that involves destructuring a recordtype after merge -- cgit v1.2.3