diff options
-rw-r--r-- | dhall_core/src/lib.rs | 1 | ||||
-rw-r--r-- | dhall_core/src/parser.rs | 152 |
2 files changed, 123 insertions, 30 deletions
diff --git a/dhall_core/src/lib.rs b/dhall_core/src/lib.rs index 86b0363..3d8fbe1 100644 --- a/dhall_core/src/lib.rs +++ b/dhall_core/src/lib.rs @@ -1,4 +1,5 @@ #![feature(box_patterns)] +#![feature(slice_patterns)] #![feature(trace_macros)] #![allow( clippy::many_single_char_names, diff --git a/dhall_core/src/parser.rs b/dhall_core/src/parser.rs index ddf3f8f..b5d4b1a 100644 --- a/dhall_core/src/parser.rs +++ b/dhall_core/src/parser.rs @@ -77,14 +77,14 @@ fn debug_pair(pair: Pair<Rule>) -> String { * ``` * let vec = vec![1, 2, 3]; * - * match_iter!(vec.into_iter(); (x, y?, z) => { + * match_iter!(vec.into_iter(); (x, y, z) => { * // x: T - * // y: Option<T> + * // y: T * // z: T * }) * * // or - * match_iter!(vec.into_iter(); (x, y, z*) => { + * match_iter!(vec.into_iter(); (x, y, z..) => { * // x, y: T * // z: impl Iterator<T> * }) @@ -98,28 +98,68 @@ enum IterMatchError<T> { NoMatchFound, Other(T), // Allow other macros to inject their own errors } +// macro_rules! match_iter { +// (@as_expr, $e:expr) => { +// $e +// }; +// // Everything else pattern +// (@match 0, $x:ident* $($rest:tt)*) => { +// match_iter!(@match 0, $iter $($rest)*); +// #[allow(unused_mut)] +// let mut $x = $x; +// }; +// // Alias to use in macros +// (@match 0, $x:ident.. $($rest:tt)*) => { +// match_iter!(@match 0, $iter $($rest)*); +// #[allow(unused_mut)] +// let mut $x = $x; +// }; +// // Normal pattern +// (@match 0, $x:ident $($rest:tt)*) => { +// #[allow(unused_mut)] +// let mut $x = match $x.next() { +// Some(x) => x, +// None => break Err(IterMatchError::NotEnoughItems), +// }; +// match_iter!(@match 0, $iter $($rest)*); +// }; + +// (@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 { +// let vec: Vec<_> = iter.collect(); +// break match_iter!(@as_expr, match *vec.into_boxed_slice() { +// [$($args)*] => { +// match_iter!(@match 0, $($args)*); +// Ok($body) +// }, +// _ => Err(IterMatchError::NotEnoughItems), +// }); +// // match_iter!(@match 0, iter, $($args)*); +// // break Ok($body); +// }; +// ret +// } +// }; +// } macro_rules! match_iter { // Everything else pattern - (@match 0, $iter:expr, $x:ident* $($rest:tt)*) => { + (@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)] @@ -189,7 +229,7 @@ macro_rules! match_iter { * let vec = vec![-1, 2, 3]; * * match_iter_typed!(callback; vec.into_iter(); - * (x: positive, y?: negative, z: any) => { ... }, + * (x: positive, y*: negative, z: any) => { ... }, * ) * ``` * @@ -199,11 +239,8 @@ 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)*)) + match_iter_typed!(@collect, ($($vars)*), ($($args)*), ($($acc)*, $x..), ($($rest)*)) }; // Catch extra comma if exists (@collect, ($($vars:tt)*), ($($args:tt)*), (,$($acc:tt)*), ($(,)*)) => { @@ -289,7 +326,7 @@ macro_rules! match_iter_typed { * let vec = vec![-1, 2, 3]; * * match_iter_branching!(branch_callback; vec.into_iter(); - * typed!(x: positive, y?: negative, z: any) => { ... }, + * typed!(x: positive, y*: negative, z: any) => { ... }, * untyped!(x, y, z) => { ... }, * ) * ``` @@ -420,6 +457,56 @@ macro_rules! match_rule { }; } +enum ParsedValue<'a> { + Expr(ParsedExpr), + Label(Label), + Str(&'a str), + RawStr(&'a str), + Text(ParsedText), + TextContents(ParsedTextContents<'a>), + VecTextContents(Vec<ParsedTextContents<'a>>), +} + +fn parse_pair(p: Pair<Rule>) -> ParseResult<ParsedValue> { + let rule = p.as_rule(); + let mut values: Vec<_> = p + .clone() + .into_inner() + .map(parse_pair) + .collect::<Result<_, _>>()?; + use crate::Expr::*; + use crate::Label; + use std::mem; + use ParsedValue::*; + match rule { + Rule::lambda_expression => match *values.as_mut_slice() { + [Label(ref mut l), Expr(ref mut typ), Expr(ref mut body)] => { + let l: Label = mem::replace(l, Label::from("")); + let typ: BoxExpr = bx(mem::replace(typ, BoolLit(false))); + let body: BoxExpr = bx(mem::replace(body, BoolLit(false))); + return Ok(ParsedValue::Expr(Lam(l, typ, body))); + } + _ => {} + }, + Rule::application_expression => match *values.as_mut_slice() { + [Expr(ref mut first), ref mut rest..] => { + let first: ParsedExpr = mem::replace(first, BoolLit(false)); + let rest: Vec<ParsedExpr> = rest.into_iter() + .map(|x| match *x { + Expr(ref mut e) => Ok(mem::replace(e, BoolLit(false))), + _ => Err(custom_parse_error(&p, "No match found".to_owned())), + }) + .collect::<Result<Vec<_>, _>>()?; + let rest = rest.into_iter(); + return Ok(ParsedValue::Expr(rest.fold(first, |acc, e| App(bx(acc), bx(e))))); + } + _ => {} + }, + _ => {} + } + Err(custom_parse_error(&p, "No match found".to_owned())) +} + rule!(EOI<()>; children!() => ()); named!(str<&'a str>; captured_str!(s) => s.trim()); @@ -624,7 +711,8 @@ rule!(let_expression<BoxExpr>; ); rule!(let_binding<(Label, Option<BoxExpr>, BoxExpr)>; - children!(name: label, annot?: expression, expr: expression) => (name, annot, expr) + children!(name: label, expr: expression) => (name, None, expr), + children!(name: label, annot: expression, expr: expression) => (name, Some(annot), expr), ); rule!(forall_expression<BoxExpr>; @@ -640,9 +728,12 @@ rule!(arrow_expression<BoxExpr>; ); rule!(merge_expression<BoxExpr>; - children!(x: expression, y: expression, z?: expression) => { - bx(Expr::Merge(x, y, z)) - } + children!(x: expression, y: expression) => { + bx(Expr::Merge(x, y, None)) + }, + children!(x: expression, y: expression, z: expression) => { + bx(Expr::Merge(x, y, Some(z))) + }, ); rule!(empty_collection<BoxExpr>; @@ -769,7 +860,8 @@ rule!(literal_expression_raw<BoxExpr>; ); rule!(identifier_raw<BoxExpr>; - children!(name: str, idx?: natural_literal_raw) => { + children!(name: str, idx*: natural_literal_raw) => { + let idx = idx.next(); match Builtin::parse(name) { Some(b) => bx(Expr::Builtin(b)), None => match name { |