diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 32da594..bdf6f8c 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -109,7 +109,7 @@ pub struct NamedBlock<'a> { #[derive(Clone, Debug, PartialEq)] pub struct ParameterizedBlock<'a> { - pub name: &'a str, + pub path: Path<'a>, pub explicit_context: Option>, pub params: Vec>, pub contents: Option>, @@ -225,20 +225,29 @@ fn dust_tag(i: &str) -> IResult<&str, DustTag> { named_block("{<", DustTag::DTInlinePartial), partial("{>", DustTag::DTPartial), map( - parameterized_block("{@", "gte"), + parameterized_block("{@", &tag_to_path("gte")), DustTag::DTHelperGreaterThanOrEquals, ), map( - parameterized_block("{@", "lte"), + parameterized_block("{@", &tag_to_path("lte")), DustTag::DTHelperLessThanOrEquals, ), - map(parameterized_block("{@", "eq"), DustTag::DTHelperEquals), - map(parameterized_block("{@", "ne"), DustTag::DTHelperNotEquals), map( - parameterized_block("{@", "gt"), + parameterized_block("{@", &tag_to_path("eq")), + DustTag::DTHelperEquals, + ), + map( + parameterized_block("{@", &tag_to_path("ne")), + DustTag::DTHelperNotEquals, + ), + map( + parameterized_block("{@", &tag_to_path("gt")), DustTag::DTHelperGreaterThan, ), - map(parameterized_block("{@", "lt"), DustTag::DTHelperLessThan), + map( + parameterized_block("{@", &tag_to_path("lt")), + DustTag::DTHelperLessThan, + ), ))(i) } @@ -289,6 +298,14 @@ fn path(i: &str) -> IResult<&str, Path> { ))(i) } +fn tag_to_path<'a>(text: &'static str) -> impl Fn(&'a str) -> IResult<&str, Path<'a>> { + move |i: &'a str| map(tag(text), |t| Path { keys: vec![t] })(i) +} + +fn key_to_path<'a>(i: &'a str) -> IResult<&str, Path<'a>> { + map(key, |k| Path { keys: vec![k] })(i) +} + /// Just digits, no signs or decimals fn postitive_integer_literal(i: &str) -> IResult<&str, u64> { map( @@ -469,42 +486,51 @@ where } } -fn parameterized_block<'a>( +fn parameterized_block<'a, F>( open_matcher: &'static str, - tag_name: &'static str, -) -> impl FnMut(&'a str) -> IResult<&'a str, ParameterizedBlock<'a>> { + name_matcher: F, +) -> impl FnMut(&'a str) -> IResult<&'a str, ParameterizedBlock<'a>> +where + F: Copy + Fn(&'a str) -> IResult<&'a str, Path<'a>>, +{ alt(( - parameterized_block_with_body(open_matcher, tag_name), - parameterized_self_closing_block(open_matcher, tag_name), + parameterized_block_with_body(open_matcher, name_matcher), + parameterized_self_closing_block(open_matcher, name_matcher), )) } -fn parameterized_block_with_body<'a>( +fn parameterized_block_with_body<'a, F>( open_matcher: &'static str, - tag_name: &'static str, -) -> impl Fn(&'a str) -> IResult<&'a str, ParameterizedBlock<'a>> { + name_matcher: F, +) -> impl Fn(&'a str) -> IResult<&'a str, ParameterizedBlock<'a>> +where + F: Copy + Fn(&'a str) -> IResult<&'a str, Path<'a>>, +{ move |i: &'a str| { - let (i, (name, maybe_explicit_context, params, inner, maybe_else, _closing_name)) = - tuple(( - preceded(tag(open_matcher), tag(tag_name)), - opt(preceded(tag(":"), path)), - terminated( - opt(delimited( - space1, - separated_list1(space1, key_value_pair), - space0, - )), - tag("}"), - ), - opt(body), - opt(preceded(tag("{:else}"), opt(body))), - delimited(tag("{/"), tag(tag_name), tag("}")), - ))(i)?; + let (i, (opening_name, maybe_explicit_context, params, inner, maybe_else, _closing_name)) = + verify( + tuple(( + preceded(tag(open_matcher), name_matcher), + opt(preceded(tag(":"), path)), + terminated( + opt(delimited( + space1, + separated_list1(space1, key_value_pair), + space0, + )), + tag("}"), + ), + opt(body), + opt(preceded(tag("{:else}"), opt(body))), + delimited(tag("{/"), name_matcher, tag("}")), + )), + |(open, _maybe_explicit, _params, _inn, _maybe_else, close)| open == close, + )(i)?; Ok(( i, ParameterizedBlock { - name: name, + path: opening_name, explicit_context: maybe_explicit_context, params: params.unwrap_or(Vec::new()), contents: inner, @@ -514,15 +540,18 @@ fn parameterized_block_with_body<'a>( } } -fn parameterized_self_closing_block<'a>( +fn parameterized_self_closing_block<'a, F>( open_matcher: &'static str, - tag_name: &'static str, -) -> impl Fn(&'a str) -> IResult<&'a str, ParameterizedBlock<'a>> { + name_matcher: F, +) -> impl Fn(&'a str) -> IResult<&'a str, ParameterizedBlock<'a>> +where + F: Copy + Fn(&'a str) -> IResult<&'a str, Path<'a>>, +{ move |i: &'a str| { - let (i, (name, maybe_explicit_context, params)) = delimited( + let (i, (opening_name, maybe_explicit_context, params)) = delimited( tag(open_matcher), tuple(( - tag(tag_name), + name_matcher, opt(preceded(tag(":"), path)), opt(delimited( space1, @@ -536,7 +565,7 @@ fn parameterized_self_closing_block<'a>( Ok(( i, ParameterizedBlock { - name: name, + path: opening_name, explicit_context: maybe_explicit_context, params: params.unwrap_or(Vec::new()), contents: None, @@ -1325,7 +1354,7 @@ mod tests { Ok(( "", DustTag::DTHelperEquals(ParameterizedBlock { - name: "eq", + path: Path { keys: vec!["eq"] }, explicit_context: None, params: vec![ KVPair { @@ -1362,7 +1391,7 @@ mod tests { Ok(( "", DustTag::DTHelperEquals(ParameterizedBlock { - name: "eq", + path: Path { keys: vec!["eq"] }, explicit_context: None, params: vec![ KVPair { @@ -1388,7 +1417,7 @@ mod tests { Ok(( "", DustTag::DTHelperEquals(ParameterizedBlock { - name: "eq", + path: Path { keys: vec!["eq"] }, explicit_context: Some(Path { keys: vec!["foo", "bar"] }), @@ -1427,7 +1456,7 @@ mod tests { Ok(( "", DustTag::DTHelperEquals(ParameterizedBlock { - name: "eq", + path: Path { keys: vec!["eq"] }, explicit_context: Some(Path { keys: vec!["foo", "bar"] }),