summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNadrieril2019-05-10 19:49:38 +0200
committerNadrieril2019-05-10 19:49:38 +0200
commita8e696f62f14296b94964adb1946d7e2b5ef5ebd (patch)
tree8ac9c17c4e0cf7470b047c46ac7042d1db1bb1e9
parent36bcec6c91d3192b5c84c96af96961ff6b79f0f0 (diff)
Write a custom map type that allows duplicates
-rw-r--r--Cargo.lock8
-rw-r--r--dhall/src/phase/binary.rs67
-rw-r--r--dhall_proc_macros/src/quote.rs13
-rw-r--r--dhall_syntax/Cargo.toml2
-rw-r--r--dhall_syntax/src/core/expr.rs9
-rw-r--r--dhall_syntax/src/core/map.rs178
-rw-r--r--dhall_syntax/src/core/mod.rs1
-rw-r--r--dhall_syntax/src/core/visitor.rs29
-rw-r--r--dhall_syntax/src/parser.rs37
9 files changed, 269 insertions, 75 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 53e019b..e837a27 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -106,10 +106,12 @@ name = "dhall_syntax"
version = "0.1.0"
dependencies = [
"dhall_generated_parser 0.1.0",
+ "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"improved_slice_patterns 2.0.0",
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pest 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -329,6 +331,11 @@ dependencies = [
]
[[package]]
+name = "take_mut"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "term"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -453,6 +460,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "58fc82bec244f168b23d1963b45c8bf5726e9a15a9d146a067f9081aeed2de79"
"checksum sha-1 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9d1f3b5de8a167ab06834a7c883bd197f2191e1dda1a22d9ccfeedbf9aded"
"checksum syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)" = "d2b4cfac95805274c6afdb12d8f770fa2d27c045953e7b630a81801953699a9a"
+"checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
"checksum term-painter 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "dcaa948f0e3e38470cd8dc8dcfe561a75c9e43f28075bb183845be2b9b3c08cf"
"checksum typed-arena 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c6c06a92aef38bb4dc5b0df00d68496fc31307c5344c867bb61678c6e1671ec5"
diff --git a/dhall/src/phase/binary.rs b/dhall/src/phase/binary.rs
index 5110241..7f72e80 100644
--- a/dhall/src/phase/binary.rs
+++ b/dhall/src/phase/binary.rs
@@ -1,5 +1,6 @@
use itertools::Itertools;
use serde_cbor::value::value as cbor;
+use std::iter::FromIterator;
use dhall_syntax::{
rc, ExprF, FilePrefix, Hash, Import, ImportHashed, ImportLocation,
@@ -131,11 +132,11 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result<ParsedExpr, DecodeError> {
Merge(x, y, Some(z))
}
[U64(7), Object(map)] => {
- let map = cbor_map_to_dhall_map(map.iter())?;
+ let map = cbor_map_to_dhall_map(map)?;
RecordType(map)
}
[U64(8), Object(map)] => {
- let map = cbor_map_to_dhall_map(map.iter())?;
+ let map = cbor_map_to_dhall_map(map)?;
RecordLit(map)
}
[U64(9), x, String(l)] => {
@@ -144,11 +145,11 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result<ParsedExpr, DecodeError> {
Field(x, l)
}
[U64(11), Object(map)] => {
- let map = cbor_map_to_dhall_opt_map(map.iter())?;
+ let map = cbor_map_to_dhall_opt_map(map)?;
UnionType(map)
}
[U64(12), String(l), x, Object(map)] => {
- let map = cbor_map_to_dhall_opt_map(map.iter())?;
+ let map = cbor_map_to_dhall_opt_map(map)?;
let x = cbor_value_to_dhall(&x)?;
let l = Label::from(l.as_str());
UnionLit(l, x, map)
@@ -331,31 +332,39 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result<ParsedExpr, DecodeError> {
}))
}
-fn cbor_map_to_dhall_map<'a>(
- map: impl Iterator<Item = (&'a cbor::ObjectKey, &'a cbor::Value)>,
-) -> Result<Vec<(Label, ParsedExpr)>, DecodeError> {
- map.map(|(k, v)| -> Result<(_, _), _> {
- let k = k.as_string().ok_or_else(|| {
- DecodeError::WrongFormatError("map/key".to_owned())
- })?;
- let v = cbor_value_to_dhall(v)?;
- Ok((Label::from(k.as_ref()), v))
- })
- .collect::<Result<_, _>>()
+fn cbor_map_to_dhall_map<'a, T>(
+ map: impl IntoIterator<Item = (&'a cbor::ObjectKey, &'a cbor::Value)>,
+) -> Result<T, DecodeError>
+where
+ T: FromIterator<(Label, ParsedExpr)>,
+{
+ map.into_iter()
+ .map(|(k, v)| -> Result<(_, _), _> {
+ let k = k.as_string().ok_or_else(|| {
+ DecodeError::WrongFormatError("map/key".to_owned())
+ })?;
+ let v = cbor_value_to_dhall(v)?;
+ Ok((Label::from(k.as_ref()), v))
+ })
+ .collect::<Result<_, _>>()
}
-fn cbor_map_to_dhall_opt_map<'a>(
- map: impl Iterator<Item = (&'a cbor::ObjectKey, &'a cbor::Value)>,
-) -> Result<Vec<(Label, Option<ParsedExpr>)>, DecodeError> {
- map.map(|(k, v)| -> Result<(_, _), _> {
- let k = k.as_string().ok_or_else(|| {
- DecodeError::WrongFormatError("map/key".to_owned())
- })?;
- let v = match v {
- cbor::Value::Null => None,
- _ => Some(cbor_value_to_dhall(v)?),
- };
- Ok((Label::from(k.as_ref()), v))
- })
- .collect::<Result<_, _>>()
+fn cbor_map_to_dhall_opt_map<'a, T>(
+ map: impl IntoIterator<Item = (&'a cbor::ObjectKey, &'a cbor::Value)>,
+) -> Result<T, DecodeError>
+where
+ T: FromIterator<(Label, Option<ParsedExpr>)>,
+{
+ map.into_iter()
+ .map(|(k, v)| -> Result<(_, _), _> {
+ let k = k.as_string().ok_or_else(|| {
+ DecodeError::WrongFormatError("map/key".to_owned())
+ })?;
+ let v = match v {
+ cbor::Value::Null => None,
+ _ => Some(cbor_value_to_dhall(v)?),
+ };
+ Ok((Label::from(k.as_ref()), v))
+ })
+ .collect::<Result<_, _>>()
}
diff --git a/dhall_proc_macros/src/quote.rs b/dhall_proc_macros/src/quote.rs
index 00bcd45..3dbfba9 100644
--- a/dhall_proc_macros/src/quote.rs
+++ b/dhall_proc_macros/src/quote.rs
@@ -161,15 +161,15 @@ fn quote_expr<N>(expr: &Expr<N, X>, ctx: &Context<Label, ()>) -> TokenStream {
}
fn quote_builtin(b: Builtin) -> TokenStream {
- format!("dhall_syntax::Builtin::{:?}", b).parse().unwrap()
+ format!("::dhall_syntax::Builtin::{:?}", b).parse().unwrap()
}
fn quote_const(c: Const) -> TokenStream {
- format!("dhall_syntax::Const::{:?}", c).parse().unwrap()
+ format!("::dhall_syntax::Const::{:?}", c).parse().unwrap()
}
fn quote_binop(b: BinOp) -> TokenStream {
- format!("dhall_syntax::BinOp::{:?}", b).parse().unwrap()
+ format!("::dhall_syntax::BinOp::{:?}", b).parse().unwrap()
}
fn quote_label(l: &Label) -> TokenStream {
@@ -178,7 +178,7 @@ fn quote_label(l: &Label) -> TokenStream {
}
fn rc(x: TokenStream) -> TokenStream {
- quote! { dhall_syntax::rc(#x) }
+ quote! { ::dhall_syntax::rc(#x) }
}
fn quote_opt<TS>(x: Option<TS>) -> TokenStream
@@ -204,11 +204,10 @@ where
{
let entries = m.into_iter().map(|(k, v)| {
let k = quote_label(&k);
- quote!(m.push((#k, #v));)
+ quote!(m.insert(#k, #v);)
});
quote! { {
- use std::vec::Vec;
- let mut m = Vec::new();
+ let mut m = ::dhall_syntax::map::DupTreeMap::new();
#( #entries )*
m
} }
diff --git a/dhall_syntax/Cargo.toml b/dhall_syntax/Cargo.toml
index 3e32930..b25a0fe 100644
--- a/dhall_syntax/Cargo.toml
+++ b/dhall_syntax/Cargo.toml
@@ -12,5 +12,7 @@ doctest = false
itertools = "0.8.0"
percent-encoding = "1.0.1"
pest = "2.1"
+either = "1.5.2"
+take_mut = "0.2.2"
dhall_generated_parser = { path = "../dhall_generated_parser" }
improved_slice_patterns = { version = "2.0.0", path = "../improved_slice_patterns" }
diff --git a/dhall_syntax/src/core/expr.rs b/dhall_syntax/src/core/expr.rs
index c509bae..f8b0215 100644
--- a/dhall_syntax/src/core/expr.rs
+++ b/dhall_syntax/src/core/expr.rs
@@ -1,6 +1,7 @@
#![allow(non_snake_case)]
use std::rc::Rc;
+use crate::map::DupTreeMap;
use crate::visitor;
use crate::*;
@@ -201,13 +202,13 @@ pub enum ExprF<SubExpr, Embed> {
/// `Some e`
SomeLit(SubExpr),
/// `{ k1 : t1, k2 : t1 }`
- RecordType(Vec<(Label, SubExpr)>),
+ RecordType(DupTreeMap<Label, SubExpr>),
/// `{ k1 = v1, k2 = v2 }`
- RecordLit(Vec<(Label, SubExpr)>),
+ RecordLit(DupTreeMap<Label, SubExpr>),
/// `< k1 : t1, k2 >`
- UnionType(Vec<(Label, Option<SubExpr>)>),
+ UnionType(DupTreeMap<Label, Option<SubExpr>>),
/// `< k1 = t1, k2 : t2, k3 >`
- UnionLit(Label, SubExpr, Vec<(Label, Option<SubExpr>)>),
+ UnionLit(Label, SubExpr, DupTreeMap<Label, Option<SubExpr>>),
/// `merge x y : t`
Merge(SubExpr, SubExpr, Option<SubExpr>),
/// `e.x`
diff --git a/dhall_syntax/src/core/map.rs b/dhall_syntax/src/core/map.rs
new file mode 100644
index 0000000..c76ac34
--- /dev/null
+++ b/dhall_syntax/src/core/map.rs
@@ -0,0 +1,178 @@
+/// A sorted map that allows multiple values for each key.
+pub use dup_tree_map::DupTreeMap;
+
+mod one_or_more {
+ use either::Either;
+ use std::{iter, slice, vec};
+
+ #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ pub enum OneOrMore<T> {
+ One(T),
+ More(Vec<T>),
+ }
+
+ pub type Iter<'a, T> = Either<slice::Iter<'a, T>, iter::Once<&'a T>>;
+ pub type IntoIter<T> = Either<vec::IntoIter<T>, iter::Once<T>>;
+
+ impl<T> OneOrMore<T> {
+ pub fn new(x: T) -> Self {
+ OneOrMore::One(x)
+ }
+
+ pub fn push(&mut self, x: T) {
+ take_mut::take(self, |sef| match sef {
+ OneOrMore::More(mut vec) => {
+ vec.push(x);
+ OneOrMore::More(vec)
+ }
+ OneOrMore::One(one) => OneOrMore::More(vec![one, x]),
+ })
+ }
+
+ pub fn iter(&self) -> Iter<'_, T> {
+ match self {
+ OneOrMore::More(vec) => Either::Left(vec.iter()),
+ OneOrMore::One(x) => Either::Right(iter::once(x)),
+ }
+ }
+ }
+
+ impl<T> IntoIterator for OneOrMore<T> {
+ type Item = T;
+ type IntoIter = IntoIter<T>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ match self {
+ OneOrMore::More(vec) => Either::Left(vec.into_iter()),
+ OneOrMore::One(x) => Either::Right(iter::once(x)),
+ }
+ }
+ }
+}
+
+mod dup_tree_map {
+ use super::one_or_more;
+ use super::one_or_more::OneOrMore;
+ use std::collections::{btree_map, BTreeMap};
+ use std::iter;
+
+ #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ pub struct DupTreeMap<K, V> {
+ map: BTreeMap<K, OneOrMore<V>>,
+ size: usize,
+ }
+
+ pub type IterInternal<'a, K, V> =
+ iter::Zip<iter::Repeat<&'a K>, one_or_more::Iter<'a, V>>;
+ pub type Iter<'a, K, V> = iter::FlatMap<
+ btree_map::Iter<'a, K, OneOrMore<V>>,
+ IterInternal<'a, K, V>,
+ for<'b> fn((&'b K, &'b OneOrMore<V>)) -> IterInternal<'b, K, V>,
+ >;
+ pub type IntoIterInternal<K, V> =
+ iter::Zip<iter::Repeat<K>, one_or_more::IntoIter<V>>;
+ pub type IntoIter<K, V> = iter::FlatMap<
+ btree_map::IntoIter<K, OneOrMore<V>>,
+ IntoIterInternal<K, V>,
+ fn((K, OneOrMore<V>)) -> IntoIterInternal<K, V>,
+ >;
+
+ impl<K, V> DupTreeMap<K, V> {
+ pub fn new() -> Self
+ where
+ K: Ord,
+ {
+ DupTreeMap {
+ map: BTreeMap::new(),
+ size: 0,
+ }
+ }
+
+ pub fn insert(&mut self, key: K, value: V)
+ where
+ K: Ord,
+ {
+ use std::collections::btree_map::Entry;
+ match self.map.entry(key) {
+ Entry::Vacant(e) => {
+ e.insert(OneOrMore::new(value));
+ }
+ Entry::Occupied(mut e) => e.get_mut().push(value),
+ }
+ }
+
+ pub fn len(&self) -> usize {
+ self.size
+ }
+ pub fn is_empty(&self) -> bool {
+ self.size == 0
+ }
+
+ pub fn iter(&self) -> Iter<'_, K, V>
+ where
+ K: Ord,
+ {
+ fn foo<'a, K, V>(
+ (k, oom): (&'a K, &'a OneOrMore<V>),
+ ) -> IterInternal<'a, K, V> {
+ iter::repeat(k).zip(oom.iter())
+ }
+ self.map.iter().flat_map(foo)
+ }
+ }
+
+ impl<K, V> Default for DupTreeMap<K, V>
+ where
+ K: Ord,
+ {
+ fn default() -> Self {
+ Self::new()
+ }
+ }
+
+ impl<K, V> IntoIterator for DupTreeMap<K, V>
+ where
+ K: Ord + Clone,
+ {
+ type Item = (K, V);
+ type IntoIter = IntoIter<K, V>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ fn foo<K, V>((k, oom): (K, OneOrMore<V>)) -> IntoIterInternal<K, V>
+ where
+ K: Clone,
+ {
+ iter::repeat(k).zip(oom.into_iter())
+ }
+ self.map.into_iter().flat_map(foo)
+ }
+ }
+
+ impl<'a, K, V> IntoIterator for &'a DupTreeMap<K, V>
+ where
+ K: Ord,
+ {
+ type Item = (&'a K, &'a V);
+ type IntoIter = Iter<'a, K, V>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter()
+ }
+ }
+
+ impl<K, V> iter::FromIterator<(K, V)> for DupTreeMap<K, V>
+ where
+ K: Ord,
+ {
+ fn from_iter<T>(iter: T) -> Self
+ where
+ T: IntoIterator<Item = (K, V)>,
+ {
+ let mut map = DupTreeMap::new();
+ for (k, v) in iter {
+ map.insert(k, v);
+ }
+ map
+ }
+ }
+}
diff --git a/dhall_syntax/src/core/mod.rs b/dhall_syntax/src/core/mod.rs
index 7762479..fe2c0be 100644
--- a/dhall_syntax/src/core/mod.rs
+++ b/dhall_syntax/src/core/mod.rs
@@ -7,4 +7,5 @@ pub use label::*;
mod text;
pub use text::*;
pub mod context;
+pub mod map;
pub mod visitor;
diff --git a/dhall_syntax/src/core/visitor.rs b/dhall_syntax/src/core/visitor.rs
index dd539e3..99a9c11 100644
--- a/dhall_syntax/src/core/visitor.rs
+++ b/dhall_syntax/src/core/visitor.rs
@@ -1,4 +1,5 @@
use crate::*;
+use std::iter::FromIterator;
/// A way too generic Visitor trait.
pub trait GenericVisitor<Input, Return>: Sized {
@@ -62,25 +63,29 @@ where
None => None,
})
}
- fn vecmap<'a, V, Ret, SE, E>(
- x: &'a Vec<(Label, SE)>,
+ fn dupmap<'a, V, Ret, SE, E, T>(
+ x: impl IntoIterator<Item = (&'a Label, &'a SE)>,
mut v: V,
- ) -> Result<Vec<(Label, V::SE2)>, V::Error>
+ ) -> Result<T, V::Error>
where
+ SE: 'a,
+ T: FromIterator<(Label, V::SE2)>,
V: ExprFVeryGenericVisitor<'a, Ret, SE, E>,
{
- x.iter()
+ x.into_iter()
.map(|(k, x)| Ok((k.clone(), v.visit_subexpr(x)?)))
.collect()
}
- fn vecoptmap<'a, V, Ret, SE, E>(
- x: &'a Vec<(Label, Option<SE>)>,
+ fn optdupmap<'a, V, Ret, SE, E, T>(
+ x: impl IntoIterator<Item = (&'a Label, &'a Option<SE>)>,
mut v: V,
- ) -> Result<Vec<(Label, Option<V::SE2>)>, V::Error>
+ ) -> Result<T, V::Error>
where
+ SE: 'a,
+ T: FromIterator<(Label, Option<V::SE2>)>,
V: ExprFVeryGenericVisitor<'a, Ret, SE, E>,
{
- x.iter()
+ x.into_iter()
.map(|(k, x)| {
Ok((
k.clone(),
@@ -137,11 +142,11 @@ where
v.visit_subexpr(t)?,
),
SomeLit(e) => SomeLit(v.visit_subexpr(e)?),
- RecordType(kts) => RecordType(vecmap(kts, v)?),
- RecordLit(kvs) => RecordLit(vecmap(kvs, v)?),
- UnionType(kts) => UnionType(vecoptmap(kts, v)?),
+ RecordType(kts) => RecordType(dupmap(kts, v)?),
+ RecordLit(kvs) => RecordLit(dupmap(kvs, v)?),
+ UnionType(kts) => UnionType(optdupmap(kts, v)?),
UnionLit(k, x, kts) => {
- UnionLit(k.clone(), v.visit_subexpr(x)?, vecoptmap(kts, v)?)
+ UnionLit(k.clone(), v.visit_subexpr(x)?, optdupmap(kts, v)?)
}
Merge(x, y, t) => Merge(
v.visit_subexpr(x)?,
diff --git a/dhall_syntax/src/parser.rs b/dhall_syntax/src/parser.rs
index 276510e..c847b29 100644
--- a/dhall_syntax/src/parser.rs
+++ b/dhall_syntax/src/parser.rs
@@ -7,6 +7,7 @@ use std::rc::Rc;
use dhall_generated_parser::{DhallParser, Rule};
+use crate::map::DupTreeMap;
use crate::ExprF::*;
use crate::*;
@@ -886,33 +887,29 @@ make_parser! {
));
rule!(empty_record_literal<ParsedSubExpr> as expression; span;
- captured_str!(_) => spanned(span, RecordLit(Vec::new()))
+ captured_str!(_) => spanned(span, RecordLit(Default::default()))
);
rule!(empty_record_type<ParsedSubExpr> as expression; span;
- captured_str!(_) => spanned(span, RecordType(Vec::new()))
+ captured_str!(_) => spanned(span, RecordType(Default::default()))
);
rule!(non_empty_record_type_or_literal<ParsedSubExpr> as expression; span;
children!(
[label(first_label), non_empty_record_type(rest)] => {
let (first_expr, mut map) = rest;
- map.push((first_label, first_expr));
- // Sort until we stop using binary decode for parser tests
- map.sort_by(|(l1, _), (l2, _)| l1.cmp(l2));
+ map.insert(first_label, first_expr);
spanned(span, RecordType(map))
},
[label(first_label), non_empty_record_literal(rest)] => {
let (first_expr, mut map) = rest;
- map.push((first_label, first_expr));
- // Sort until we stop using binary decode for parser tests
- map.sort_by(|(l1, _), (l2, _)| l1.cmp(l2));
+ map.insert(first_label, first_expr);
spanned(span, RecordLit(map))
},
));
rule!(non_empty_record_type
- <(ParsedSubExpr, Vec<(Label, ParsedSubExpr)>)>; children!(
+ <(ParsedSubExpr, DupTreeMap<Label, ParsedSubExpr>)>; children!(
[expression(expr), record_type_entry(entries)..] => {
(expr, entries.collect())
}
@@ -923,7 +920,7 @@ make_parser! {
));
rule!(non_empty_record_literal
- <(ParsedSubExpr, Vec<(Label, ParsedSubExpr)>)>; children!(
+ <(ParsedSubExpr, DupTreeMap<Label, ParsedSubExpr>)>; children!(
[expression(expr), record_literal_entry(entries)..] => {
(expr, entries.collect())
}
@@ -935,18 +932,12 @@ make_parser! {
rule!(union_type_or_literal<ParsedSubExpr> as expression; span; children!(
[empty_union_type(_)] => {
- spanned(span, UnionType(Vec::new()))
+ spanned(span, UnionType(Default::default()))
},
[non_empty_union_type_or_literal((Some((l, e)), entries))] => {
- let mut entries = entries;
- // Sort until we stop using binary decode for parser tests
- entries.sort_by(|(l1, _), (l2, _)| l1.cmp(l2));
spanned(span, UnionLit(l, e, entries))
},
[non_empty_union_type_or_literal((None, entries))] => {
- let mut entries = entries;
- // Sort until we stop using binary decode for parser tests
- entries.sort_by(|(l1, _), (l2, _)| l1.cmp(l2));
spanned(span, UnionType(entries))
},
));
@@ -955,20 +946,20 @@ make_parser! {
rule!(non_empty_union_type_or_literal
<(Option<(Label, ParsedSubExpr)>,
- Vec<(Label, Option<ParsedSubExpr>)>)>;
+ DupTreeMap<Label, Option<ParsedSubExpr>>)>;
children!(
[label(l), union_literal_variant_value((e, entries))] => {
(Some((l, e)), entries)
},
[label(l), union_type_or_literal_variant_type((e, rest))] => {
let (x, mut entries) = rest;
- entries.push((l, e));
+ entries.insert(l, e);
(x, entries)
},
));
rule!(union_literal_variant_value
- <(ParsedSubExpr, Vec<(Label, Option<ParsedSubExpr>)>)>;
+ <(ParsedSubExpr, DupTreeMap<Label, Option<ParsedSubExpr>>)>;
children!(
[expression(e), union_type_entry(entries)..] => {
(e, entries.collect())
@@ -984,19 +975,19 @@ make_parser! {
rule!(union_type_or_literal_variant_type
<(Option<ParsedSubExpr>,
(Option<(Label, ParsedSubExpr)>,
- Vec<(Label, Option<ParsedSubExpr>)>))>;
+ DupTreeMap<Label, Option<ParsedSubExpr>>))>;
children!(
[expression(e), non_empty_union_type_or_literal(rest)] => {
(Some(e), rest)
},
[expression(e)] => {
- (Some(e), (None, Vec::new()))
+ (Some(e), (None, Default::default()))
},
[non_empty_union_type_or_literal(rest)] => {
(None, rest)
},
[] => {
- (None, (None, Vec::new()))
+ (None, (None, Default::default()))
},
));