From 049f1f12bcf3013e31b179fd469a4ff0f61bf831 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 19 Mar 2019 02:18:52 +0100 Subject: [PATCH 01/13] rustfmt --- dhall/src/normalize.rs | 34 ++++++++++++++++++++-------------- dhall/tests/common/mod.rs | 2 +- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/dhall/src/normalize.rs b/dhall/src/normalize.rs index e335fbbd..6257faf2 100644 --- a/dhall/src/normalize.rs +++ b/dhall/src/normalize.rs @@ -4,7 +4,10 @@ use dhall_generator::dhall_expr; use std::fmt; use std::rc::Rc; -fn apply_builtin(b: Builtin, mut args: Vec>) -> SubExpr +fn apply_builtin( + b: Builtin, + mut args: Vec>, +) -> SubExpr where S: fmt::Debug, A: fmt::Debug, @@ -72,9 +75,7 @@ where (ListLast, Some(NEListLit(ys)), _) => { rc(OptionalLit(None, ys.iter().cloned().last())) } - (ListReverse, Some(EmptyListLit(t)), _) => { - rc(EmptyListLit(t.clone())) - } + (ListReverse, Some(EmptyListLit(t)), _) => rc(EmptyListLit(t.clone())), (ListReverse, Some(NEListLit(ys)), _) => { let ys = ys.iter().rev().cloned().collect(); rc(NEListLit(ys)) @@ -84,10 +85,15 @@ where dhall_expr!([] : List ({ index : Natural, value : t })) } (ListIndexed, Some(NEListLit(xs)), _) => { - let xs = xs.iter().cloned().enumerate().map(|(i, e)| { - let i = rc(NaturalLit(i)); - dhall_expr!({ index = i, value = e }) - }).collect(); + let xs = xs + .iter() + .cloned() + .enumerate() + .map(|(i, e)| { + let i = rc(NaturalLit(i)); + dhall_expr!({ index = i, value = e }) + }) + .collect(); rc(NEListLit(xs)) } (ListBuild, _, [a0, g, ..]) => { @@ -165,15 +171,13 @@ where } }; // TODO: use Embed to avoid reevaluating g - break dhall_expr!(g Natural (λ(x : Natural) -> x + 1) 0) + break dhall_expr!(g Natural (λ(x : Natural) -> x + 1) 0); } } - (NaturalFold, Some(NaturalLit(0)), [_, _, _, zero]) => { - Rc::clone(zero) - } + (NaturalFold, Some(NaturalLit(0)), [_, _, _, zero]) => Rc::clone(zero), (NaturalFold, Some(NaturalLit(n)), [_, t, succ, zero]) => { let fold = rc(Builtin(NaturalFold)); - let n = rc(NaturalLit(n-1)); + let n = rc(NaturalLit(n - 1)); let t = Rc::clone(t); let succ = Rc::clone(succ); let zero = Rc::clone(zero); @@ -274,7 +278,9 @@ where NaturalLit(x * y) } (TextAppend, TextLit(x), TextLit(y)) => TextLit(x + y), - (ListAppend, EmptyListLit(t), EmptyListLit(_)) => EmptyListLit(Rc::clone(t)), + (ListAppend, EmptyListLit(t), EmptyListLit(_)) => { + EmptyListLit(Rc::clone(t)) + } (ListAppend, EmptyListLit(_), _) => return y, (ListAppend, _, EmptyListLit(_)) => return x, (ListAppend, NEListLit(xs), NEListLit(ys)) => { diff --git a/dhall/tests/common/mod.rs b/dhall/tests/common/mod.rs index a24125ed..7ba64b0f 100644 --- a/dhall/tests/common/mod.rs +++ b/dhall/tests/common/mod.rs @@ -25,7 +25,7 @@ macro_rules! make_spec_test { fn $name() { use crate::common::*; - if cfg!(feature="nothreads") { + if cfg!(feature = "nothreads") { run_test($path, Feature::$type); } else { use std::thread; From 3ce64f46a79855913a7cc8626c45781cb6b16300 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 19 Mar 2019 21:59:41 +0100 Subject: [PATCH 02/13] Extract the core of parser macros into a separate crate --- Cargo.lock | 5 ++ Cargo.toml | 3 + dhall_core/Cargo.toml | 1 + dhall_core/src/parser.rs | 176 ++++++++++-------------------------- iter_patterns/Cargo.toml | 8 ++ iter_patterns/src/lib.rs | 190 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 252 insertions(+), 131 deletions(-) create mode 100644 iter_patterns/Cargo.toml create mode 100644 iter_patterns/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 6e218fb1..fa37a5e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -82,6 +82,7 @@ name = "dhall_core" version = "0.1.0" dependencies = [ "dhall_parser 0.1.0", + "iter_patterns 0.1.0", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "pest 2.1.0 (git+https://github.com/pest-parser/pest)", "term-painter 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -143,6 +144,10 @@ name = "half" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "iter_patterns" +version = "0.1.0" + [[package]] name = "itertools" version = "0.8.0" diff --git a/Cargo.toml b/Cargo.toml index 74388cb7..c2c0fae8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,9 @@ members = [ "abnf_to_pest", "dhall", "dhall_parser", + "dhall_core", + "dhall_generator", + "iter_patterns", ] # # Parser is super slow when not optimized diff --git a/dhall_core/Cargo.toml b/dhall_core/Cargo.toml index 4010f4a7..c3c417a3 100644 --- a/dhall_core/Cargo.toml +++ b/dhall_core/Cargo.toml @@ -12,3 +12,4 @@ itertools = "0.8.0" term-painter = "0.2.3" pest = { git = "https://github.com/pest-parser/pest" } dhall_parser = { path = "../dhall_parser" } +iter_patterns = { path = "../iter_patterns" } diff --git a/dhall_core/src/parser.rs b/dhall_core/src/parser.rs index 6f84abe0..45930d43 100644 --- a/dhall_core/src/parser.rs +++ b/dhall_core/src/parser.rs @@ -71,102 +71,11 @@ fn debug_pair(pair: Pair) -> String { s } -/* Macro to pattern-match iterators. - * Returns `Result<_, IterMatchError<_>>`. - * - * Example: - * ``` - * let vec = vec![1, 2, 3]; - * - * match_iter!(vec.into_iter(); (x, y?, z) => { - * // x: T - * // y: Option - * // z: T - * }) - * - * // or - * match_iter!(vec.into_iter(); (x, y, z*) => { - * // x, y: T - * // z: impl Iterator - * }) - * ``` - * -*/ #[derive(Debug)] enum IterMatchError { - NotEnoughItems, - TooManyItems, NoMatchFound, Other(T), // Allow other macros to inject their own errors } -macro_rules! match_iter { - // Everything else pattern - (@match 0, $iter:expr, $x:ident* $($rest:tt)*) => { - match_iter!(@match 2, $iter $($rest)*); - #[allow(unused_mut)] - let mut $x = $iter; - }; - // Alias to use in macros - (@match 0, $iter:expr, $x:ident?? $($rest:tt)*) => { - match_iter!(@match 2, $iter $($rest)*); - #[allow(unused_mut)] - let mut $x = $iter; - }; - // Optional pattern - (@match 0, $iter:expr, $x:ident? $($rest:tt)*) => { - match_iter!(@match 1, $iter $($rest)*); - #[allow(unused_mut)] - let mut $x = $iter.next(); - if $iter.next().is_some() { - break Err(IterMatchError::TooManyItems); - } - }; - // Normal pattern - (@match 0, $iter:expr, $x:ident $($rest:tt)*) => { - #[allow(unused_mut)] - let mut $x = match $iter.next() { - Some(x) => x, - None => break Err(IterMatchError::NotEnoughItems), - }; - match_iter!(@match 0, $iter $($rest)*); - }; - // Normal pattern after a variable length one: declare reversed and take from the end - (@match $w:expr, $iter:expr, $x:ident $($rest:tt)*) => { - match_iter!(@match $w, $iter $($rest)*); - #[allow(unused_mut)] - let mut $x = match $iter.next_back() { - Some(x) => x, - None => break Err(IterMatchError::NotEnoughItems), - }; - }; - - // Check no elements remain - (@match 0, $iter:expr $(,)*) => { - if $iter.next().is_some() { - break Err(IterMatchError::TooManyItems); - } - }; - (@match $_:expr, $iter:expr) => {}; - - (@panic; $($args:tt)*) => { - { - let ret: Result<_, IterMatchError<()>> = match_iter!($($args)*); - ret.unwrap() - } - }; - ($iter:expr; ($($args:tt)*) => $body:expr) => { - { - #[allow(unused_mut)] - let mut iter = $iter; - // Not a real loop; used for error handling - let ret: Result<_, IterMatchError<_>> = loop { - match_iter!(@match 0, iter, $($args)*); - break Ok($body); - }; - ret - } - }; -} /* Extends match_iter with typed matches. Takes a callback that determines * when a capture matches. @@ -200,21 +109,21 @@ macro_rules! match_iter_typed { (@collect, ($($vars:tt)*), ($($args:tt)*), ($($acc:tt)*), ($x:ident : $ty:ident, $($rest:tt)*)) => { match_iter_typed!(@collect, ($($vars)*), ($($args)*), ($($acc)*, $x), ($($rest)*)) }; - (@collect, ($($vars:tt)*), ($($args:tt)*), ($($acc:tt)*), ($x:ident? : $ty:ident, $($rest:tt)*)) => { - match_iter_typed!(@collect, ($($vars)*), ($($args)*), ($($acc)*, $x?), ($($rest)*)) - }; - (@collect, ($($vars:tt)*), ($($args:tt)*), ($($acc:tt)*), ($x:ident* : $ty:ident, $($rest:tt)*)) => { - match_iter_typed!(@collect, ($($vars)*), ($($args)*), ($($acc)*, $x??), ($($rest)*)) + (@collect, ($($vars:tt)*), ($($args:tt)*), ($($acc:tt)*), ($x:ident.. : $ty:ident, $($rest:tt)*)) => { + match_iter_typed!(@collect, ($($vars)*), ($($args)*), ($($acc)*, $x..), ($($rest)*)) }; // Catch extra comma if exists (@collect, ($($vars:tt)*), ($($args:tt)*), (,$($acc:tt)*), ($(,)*)) => { match_iter_typed!(@collect, ($($vars)*), ($($args)*), ($($acc)*), ()) }; (@collect, ($iter:expr, $body:expr, $callback:ident, $error:ident), ($($args:tt)*), ($($acc:tt)*), ($(,)*)) => { - match_iter!($iter; ($($acc)*) => { - match_iter_typed!(@callback, $callback, $iter, $($args)*); - $body - }) + { + let res = iter_patterns::destructure_iter!($iter; [$($acc)*] => { + match_iter_typed!(@callback, $callback, $iter, $($args)*); + $body + }); + res.ok_or(IterMatchError::NoMatchFound) + } }; // Pass the matches through the callback @@ -227,17 +136,7 @@ macro_rules! match_iter_typed { }; match_iter_typed!(@callback, $callback, $iter $($rest)*); }; - (@callback, $callback: ident, $iter:expr, $x:ident? : $ty:ident $($rest:tt)*) => { - let $x = $x.map(|x| $callback!(@type_callback, $ty, x)); - #[allow(unused_mut)] - let mut $x = match $x { - Some(Ok(x)) => Some(x), - Some(Err(e)) => break Err(IterMatchError::Other(e)), - None => None, - }; - match_iter_typed!(@callback, $callback, $iter $($rest)*); - }; - (@callback, $callback: ident, $iter:expr, $x:ident* : $ty:ident $($rest:tt)*) => { + (@callback, $callback: ident, $iter:expr, $x:ident.. : $ty:ident $($rest:tt)*) => { let $x = $x.map(|x| $callback!(@type_callback, $ty, x)).collect(); let $x: Vec<_> = match $x { Ok(x) => x, @@ -253,10 +152,13 @@ macro_rules! match_iter_typed { { #[allow(unused_mut)] let mut iter = $iter; - match_iter_typed!(@collect, - (iter, $body, $callback, last_error), - ($($args)*), (), ($($args)*,) - ) + let res: Result<_, IterMatchError<_>> = loop { + break match_iter_typed!(@collect, + (iter, $body, $callback, last_error), + ($($args)*), (), ($($args)*,) + ) + }; + res } }; } @@ -430,7 +332,7 @@ named!(raw_str<&'a str>; captured_str!(s) => s); named!(label