summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dhall_core/src/lib.rs1
-rw-r--r--dhall_core/src/parser.rs168
-rw-r--r--iter_patterns/src/lib.rs95
3 files changed, 129 insertions, 135 deletions
diff --git a/dhall_core/src/lib.rs b/dhall_core/src/lib.rs
index 0874b09..2042b04 100644
--- a/dhall_core/src/lib.rs
+++ b/dhall_core/src/lib.rs
@@ -1,5 +1,6 @@
#![feature(trace_macros)]
#![feature(slice_patterns)]
+#![feature(bind_by_move_pattern_guards)]
#![allow(
clippy::many_single_char_names,
clippy::should_implement_trait,
diff --git a/dhall_core/src/parser.rs b/dhall_core/src/parser.rs
index 560d177..b7ac3f6 100644
--- a/dhall_core/src/parser.rs
+++ b/dhall_core/src/parser.rs
@@ -112,106 +112,6 @@ fn debug_pair(pair: Pair<Rule>) -> String {
s
}
-macro_rules! match_children {
- (@make_child_match,
- ($pair:expr, $($vars:tt)*),
- ($($outer_acc:tt)*),
- ($($acc:tt)*),
- ($(,)* $ty:ident ($x:ident..) $($rest_of_match:tt)*) => $body:expr,
- $($rest:tt)*
- ) => {
- match_children!(@make_child_match,
- ($pair, $($vars)*),
- ($($outer_acc)*),
- ($($acc)*, xs..),
- ($($rest_of_match)*) => {
- let xs = xs.map(|x| match x {
- ParsedValue::$ty(y) => Ok(y),
- x => Err(format!("Unexpected child: {:?}", x)),
- }).collect::<Result<Vec<_>, _>>()?;
- let $x = xs.into_iter();
- $body
- },
- $($rest)*
- )
- };
- (@make_child_match,
- ($($vars:tt)*),
- ($($outer_acc:tt)*),
- ($($acc:tt)*),
- ($(,)* $ty:ident ($x:pat) $($rest_of_match:tt)*) => $body:expr,
- $($rest:tt)*
- ) => {
- match_children!(@make_child_match,
- ($($vars)*),
- ($($outer_acc)*),
- ($($acc)*, ParsedValue::$ty($x)),
- ($($rest_of_match)*) => $body,
- $($rest)*
- )
- };
- (@make_child_match,
- ($($vars:tt)*),
- ($($outer_acc:tt)*),
- (, $($acc:tt)*),
- ($(,)*) => $body:expr,
- $($rest:tt)*
- ) => {
- match_children!(@make_matches,
- ($($vars)*),
- ($($outer_acc)* [$($acc)*] => { $body },),
- $($rest)*
- )
- };
- (@make_child_match,
- ($($vars:tt)*),
- ($($outer_acc:tt)*),
- (),
- ($(,)*) => $body:expr,
- $($rest:tt)*
- ) => {
- match_children!(@make_matches,
- ($($vars)*),
- ($($outer_acc)* [] => { $body },),
- $($rest)*
- )
- };
-
- (@make_matches,
- ($($vars:tt)*),
- ($($acc:tt)*),
- [$($args:tt)*] => $body:expr,
- $($rest:tt)*
- ) => {
- match_children!(@make_child_match,
- ($($vars)*),
- ($($acc)*),
- (),
- ($($args)*) => $body,
- $($rest)*
- )
- };
- (@make_matches, ($pair:expr, $children:expr), ($($acc:tt)*) $(,)*) => {
- {
- #[allow(unreachable_code)]
- iter_patterns::match_vec!($children;
- $($acc)*
- [x..] => Err(
- format!("Unexpected children: {:?}", x.collect::<Vec<_>>())
- )?,
- ).ok_or_else(|| -> String { unreachable!() })
- }
- };
-
- (($($vars:tt)*); $( [$($args:tt)*] => $body:expr ),* $(,)*) => {
- match_children!(@make_matches,
- ($($vars)*),
- (),
- $( [$($args)*] => $body ),* ,
- )
- };
-}
-
macro_rules! make_parser {
(@pattern, rule, $name:ident) => (Rule::$name);
(@pattern, rule_group, $name:ident) => (_);
@@ -248,10 +148,18 @@ macro_rules! make_parser {
rule!(
$name:ident<$o:ty>
as $group:ident;
- children!( $($args:tt)* )
+ children!( $( [$($args:tt)*] => $body:expr ),* $(,)* )
)
) => ({
- let res: $o = match_children!(($pair, $children); $($args)*)?;
+ #[allow(unused_imports)]
+ use ParsedValue::*;
+ #[allow(unreachable_code)]
+ let res: $o = iter_patterns::match_vec!($children;
+ $( [$($args)*] => $body, )*
+ [x..] => Err(
+ format!("Unexpected children: {:?}", x.collect::<Vec<_>>())
+ )?,
+ ).ok_or_else(|| -> String { unreachable!() })?;
Ok(ParsedValue::$group(res))
});
(@body, $pair:expr, $children:expr, rule_group!( $name:ident<$o:ty> )) => (
@@ -369,7 +277,7 @@ make_parser! {
));
rule!(double_quote_literal<ParsedText>; children!(
- [double_quote_chunk(chunks..)] => {
+ [double_quote_chunk(chunks)..] => {
chunks.collect()
}
));
@@ -521,7 +429,7 @@ make_parser! {
[quoted_path_component(s)] => s,
));
rule!(path<PathBuf>; children!(
- [path_component(components..)] => {
+ [path_component(components)..] => {
components.collect()
}
));
@@ -570,8 +478,8 @@ make_parser! {
rule!(http<URL>; children!(
[http_raw(url)] => url,
- [http_raw(url), import_hashed(import_hashed)] =>
- URL { headers: Some(Box::new(import_hashed)), ..url },
+ [http_raw(url), import_hashed(ih)] =>
+ URL { headers: Some(Box::new(ih)), ..url },
));
rule!(env<String>; children!(
@@ -593,8 +501,8 @@ make_parser! {
[http(url)] => {
ImportLocation::Remote(url)
},
- [local((prefix, path))] => {
- ImportLocation::Local(prefix, path)
+ [local((prefix, p))] => {
+ ImportLocation::Local(prefix, p)
},
));
@@ -608,8 +516,8 @@ make_parser! {
rule!(import_hashed<ImportHashed>; children!(
[import_type(location)] =>
ImportHashed { location, hash: None },
- [import_type(location), hash(hash)] =>
- ImportHashed { location, hash: Some(hash) },
+ [import_type(location), hash(h)] =>
+ ImportHashed { location, hash: Some(h) },
));
rule_group!(expression<ParsedExpr>);
@@ -644,7 +552,7 @@ make_parser! {
));
rule!(let_expression<ParsedExpr> as expression; children!(
- [let_binding(bindings..), expression(final_expr)] => {
+ [let_binding(bindings).., expression(final_expr)] => {
bindings.fold(
final_expr,
|acc, x| bx(Expr::Let(x.0, x.1, x.2, acc))
@@ -698,84 +606,84 @@ make_parser! {
rule!(import_alt_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
- [expression(first), expression(rest..)] => {
+ [expression(first), expression(rest)..] => {
let o = BinOp::ImportAlt;
rest.fold(first, |acc, e| bx(Expr::BinOp(o, acc, e)))
},
));
rule!(or_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
- [expression(first), expression(rest..)] => {
+ [expression(first), expression(rest)..] => {
let o = BinOp::BoolOr;
rest.fold(first, |acc, e| bx(Expr::BinOp(o, acc, e)))
},
));
rule!(plus_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
- [expression(first), expression(rest..)] => {
+ [expression(first), expression(rest)..] => {
let o = BinOp::NaturalPlus;
rest.fold(first, |acc, e| bx(Expr::BinOp(o, acc, e)))
},
));
rule!(text_append_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
- [expression(first), expression(rest..)] => {
+ [expression(first), expression(rest)..] => {
let o = BinOp::TextAppend;
rest.fold(first, |acc, e| bx(Expr::BinOp(o, acc, e)))
},
));
rule!(list_append_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
- [expression(first), expression(rest..)] => {
+ [expression(first), expression(rest)..] => {
let o = BinOp::ListAppend;
rest.fold(first, |acc, e| bx(Expr::BinOp(o, acc, e)))
},
));
rule!(and_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
- [expression(first), expression(rest..)] => {
+ [expression(first), expression(rest)..] => {
let o = BinOp::BoolAnd;
rest.fold(first, |acc, e| bx(Expr::BinOp(o, acc, e)))
},
));
rule!(combine_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
- [expression(first), expression(rest..)] => {
+ [expression(first), expression(rest)..] => {
let o = BinOp::Combine;
rest.fold(first, |acc, e| bx(Expr::BinOp(o, acc, e)))
},
));
rule!(prefer_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
- [expression(first), expression(rest..)] => {
+ [expression(first), expression(rest)..] => {
let o = BinOp::Prefer;
rest.fold(first, |acc, e| bx(Expr::BinOp(o, acc, e)))
},
));
rule!(combine_types_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
- [expression(first), expression(rest..)] => {
+ [expression(first), expression(rest)..] => {
let o = BinOp::CombineTypes;
rest.fold(first, |acc, e| bx(Expr::BinOp(o, acc, e)))
},
));
rule!(times_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
- [expression(first), expression(rest..)] => {
+ [expression(first), expression(rest)..] => {
let o = BinOp::NaturalTimes;
rest.fold(first, |acc, e| bx(Expr::BinOp(o, acc, e)))
},
));
rule!(equal_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
- [expression(first), expression(rest..)] => {
+ [expression(first), expression(rest)..] => {
let o = BinOp::BoolEQ;
rest.fold(first, |acc, e| bx(Expr::BinOp(o, acc, e)))
},
));
rule!(not_equal_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
- [expression(first), expression(rest..)] => {
+ [expression(first), expression(rest)..] => {
let o = BinOp::BoolNE;
rest.fold(first, |acc, e| bx(Expr::BinOp(o, acc, e)))
},
@@ -799,7 +707,7 @@ make_parser! {
_ => bx(Expr::App(first, vec![second])),
}
},
- [expression(first), expression(second), expression(rest..)] => {
+ [expression(first), expression(second), expression(rest)..] => {
match first.as_ref() {
Expr::Builtin(Builtin::OptionalNone) =>
bx(Expr::App(bx(Expr::EmptyOptionalLit(second)),
@@ -817,7 +725,7 @@ make_parser! {
rule!(selector_expression<ParsedExpr> as expression; children!(
[expression(e)] => e,
- [expression(first), selector(rest..)] => {
+ [expression(first), selector(rest)..] => {
rest.fold(first, |acc, e| match e {
Either::Left(l) => bx(Expr::Field(acc, l)),
Either::Right(ls) => bx(Expr::Projection(acc, ls)),
@@ -831,7 +739,7 @@ make_parser! {
));
rule!(labels<Vec<Label>>; children!(
- [label(ls..)] => ls.collect(),
+ [label(ls)..] => ls.collect(),
));
rule!(literal_expression<ParsedExpr> as expression; children!(
@@ -900,7 +808,7 @@ make_parser! {
rule!(non_empty_record_type
<(ParsedExpr, BTreeMap<Label, ParsedExpr>)>; children!(
- [expression(expr), record_type_entry(entries..)] => {
+ [expression(expr), record_type_entry(entries)..] => {
(expr, entries.collect())
}
));
@@ -911,7 +819,7 @@ make_parser! {
rule!(non_empty_record_literal
<(ParsedExpr, BTreeMap<Label, ParsedExpr>)>; children!(
- [expression(expr), record_literal_entry(entries..)] => {
+ [expression(expr), record_literal_entry(entries)..] => {
(expr, entries.collect())
}
));
@@ -953,7 +861,7 @@ make_parser! {
));
rule!(union_type_entries<BTreeMap<Label, ParsedExpr>>; children!(
- [union_type_entry(entries..)] => entries.collect()
+ [union_type_entry(entries)..] => entries.collect()
));
rule!(union_type_entry<(Label, ParsedExpr)>; children!(
@@ -961,7 +869,7 @@ make_parser! {
));
rule!(non_empty_list_literal<ParsedExpr> as expression; children!(
- [expression(items..)] => bx(Expr::NEListLit(items.collect()))
+ [expression(items)..] => bx(Expr::NEListLit(items.collect()))
));
rule!(final_expression<ParsedExpr> as expression; children!(
diff --git a/iter_patterns/src/lib.rs b/iter_patterns/src/lib.rs
index 10679aa..a4be783 100644
--- a/iter_patterns/src/lib.rs
+++ b/iter_patterns/src/lib.rs
@@ -1,4 +1,4 @@
-#![feature(slice_patterns)]
+#![feature(slice_patterns, bind_by_move_pattern_guards)]
/* Destructure an iterator using the syntax of slice_patterns.
* Wraps the match body in `Some` if there was a match; returns
@@ -35,6 +35,21 @@ macro_rules! destructure_iter {
$($rest)*
)
};
+ // Special variable length pattern with a common unary variant
+ (@match_forwards, $iter:expr, ($body:expr), $variant:ident ($x:ident).., $($rest:tt)*) => {
+ $crate::destructure_iter!(@match_backwards,
+ $iter,
+ ({
+ let $x = $iter
+ .map(|x| match x {
+ $variant(y) => y,
+ _ => unreachable!(),
+ });
+ $body
+ }),
+ $($rest)*
+ )
+ };
// Variable length pattern without a binder
(@match_forwards, $iter:expr, ($body:expr), .., $($rest:tt)*) => {
$crate::destructure_iter!(@match_backwards,
@@ -117,6 +132,71 @@ macro_rules! destructure_iter {
*/
#[macro_export]
macro_rules! match_vec {
+ // Variable length pattern
+ (@make_pat; ($($acc:tt)*), $x:ident.., $($rest:tt)*) => {
+ $crate::match_vec!(@make_pat;
+ ($($acc)*, $x..),
+ $($rest)*
+ )
+ };
+ // Special variable length pattern with a common unary variant
+ (@make_pat; ($($acc:tt)*), $variant:ident ($x:ident).., $($rest:tt)*) => {
+ $crate::match_vec!(@make_pat;
+ ($($acc)*, $x..),
+ $($rest)*
+ )
+ };
+ // Variable length pattern without a binder
+ (@make_pat; ($($acc:tt)*), .., $($rest:tt)*) => {
+ $crate::match_vec!(@make_pat;
+ ($($acc)*, ..),
+ $($rest)*
+ )
+ };
+ // Single item pattern
+ (@make_pat; ($($acc:tt)*), $x:pat, $($rest:tt)*) => {
+ $crate::match_vec!(@make_pat;
+ ($($acc)*, $x),
+ $($rest)*
+ )
+ };
+ (@make_pat; (, $($acc:tt)*), $(,)*) => {
+ [$($acc)*]
+ };
+ (@make_pat; ($($acc:tt)*), $(,)*) => {
+ [$($acc)*]
+ };
+
+ (@make_filter; $x:ident.., $($rest:tt)*) => {
+ $crate::match_vec!(@make_filter;
+ $($rest)*
+ )
+ };
+ (@make_filter; $variant:ident ($x:ident).., $($rest:tt)*) => {
+ $x.iter()
+ .all(|x| match x {
+ $variant(_) => true,
+ _ => false,
+ })
+ &&
+ $crate::match_vec!(@make_filter;
+ $($rest)*
+ )
+ };
+ (@make_filter; .., $($rest:tt)*) => {
+ $crate::match_vec!(@make_filter;
+ $($rest)*
+ )
+ };
+ (@make_filter; $x:pat, $($rest:tt)*) => {
+ $crate::match_vec!(@make_filter;
+ $($rest)*
+ )
+ };
+ (@make_filter; $(,)*) => {
+ true
+ };
+
($arg:expr; $( [$($args:tt)*] => $body:expr ),* $(,)*) => {
{
let vec = $arg;
@@ -126,7 +206,10 @@ macro_rules! match_vec {
#[allow(unused_variables, unreachable_patterns)]
match vec.as_slice() {
$(
- [$($args)*] => {
+ $crate::match_vec!(@make_pat; (), $($args)*,)
+ if
+ $crate::match_vec!(@make_filter; $($args)*,)
+ => {
// Actually consume the values
#[allow(unused_mut)]
let mut iter = vec.into_iter();
@@ -179,7 +262,8 @@ fn test() {
[Some(_x), None] => 2,
[None, Some(y)] => 1,
[None, _y..] => 3,
- [_x.., Some(y), Some(z)] => y - z,
+ [_x.., Some(y), Some(z), None] => y - z,
+ [Some(ys)..] => ys.sum(),
[] => 0,
[..] => -1,
)
@@ -189,10 +273,11 @@ fn test() {
assert_eq!(test(vec![Some(0), None, None]), 4);
assert_eq!(test(vec![Some(0), None]), 2);
assert_eq!(test(vec![None, Some(0)]), 1);
- assert_eq!(test(vec![Some(1), Some(2), Some(5), Some(14)]), -9);
+ assert_eq!(test(vec![Some(1), Some(2), Some(5), Some(14), None]), -9);
+ assert_eq!(test(vec![Some(1), Some(2), Some(3), Some(4)]), 10);
assert_eq!(test(vec![None]), 3);
assert_eq!(test(vec![]), 0);
- assert_eq!(test(vec![Some(0)]), -1);
+ assert_eq!(test(vec![Some(0), None, Some(1)]), -1);
// Test move out of pattern
struct Foo;