From bb3449467a39d4c60eec916f555555e87c4c739a Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sat, 9 May 2020 15:02:54 -0400 Subject: [PATCH 1/5] Running into an error parsing one of the partial test templates. --- src/parser/parser.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 4a6db06..20134ee 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -1052,4 +1052,19 @@ mod tests { )) ); } + + #[test] + fn test_full_document_temp() { + assert_eq!( + super::template( + r#"{#level3.level4}{>partialtwo v1="b" v2="b" v3="b" v4="b" v5="b" /}{/level3.level4}"# + ), + Ok::<_, nom::Err<(&str, ErrorKind)>>(( + "", + Template { + contents: Body { elements: vec![] } + } + )) + ); + } } From 569b4594be8e401ce8d689162dccb2cf128d8575 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sat, 9 May 2020 15:05:29 -0400 Subject: [PATCH 2/5] works fine without the partial. --- src/parser/parser.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 20134ee..e7e6fe0 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -1056,13 +1056,19 @@ mod tests { #[test] fn test_full_document_temp() { assert_eq!( - super::template( - r#"{#level3.level4}{>partialtwo v1="b" v2="b" v3="b" v4="b" v5="b" /}{/level3.level4}"# - ), + super::template(r#"{#level3.level4}{/level3.level4}"#), Ok::<_, nom::Err<(&str, ErrorKind)>>(( "", Template { - contents: Body { elements: vec![] } + contents: Body { + elements: vec![TemplateElement::TETag(DustTag::DTSection(Container { + path: Path { + keys: vec!["level3", "level4"] + }, + contents: None, + else_contents: None + }))] + } } )) ); From 710785139aa54f99c73c5269f0cfccf82b29d0d9 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sat, 9 May 2020 15:08:31 -0400 Subject: [PATCH 3/5] Works fine with the partial but without parameters. --- src/parser/parser.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/parser/parser.rs b/src/parser/parser.rs index e7e6fe0..467521f 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -1056,7 +1056,7 @@ mod tests { #[test] fn test_full_document_temp() { assert_eq!( - super::template(r#"{#level3.level4}{/level3.level4}"#), + super::template(r#"{#level3.level4}{>partialtwo/}{/level3.level4}"#), Ok::<_, nom::Err<(&str, ErrorKind)>>(( "", Template { @@ -1065,7 +1065,14 @@ mod tests { path: Path { keys: vec!["level3", "level4"] }, - contents: None, + contents: Some(Body { + elements: vec![TemplateElement::TETag(DustTag::DTPartial( + Partial { + name: "partialtwo".to_owned(), + params: vec![] + } + ))] + }), else_contents: None }))] } From 369fbaf579ba5900e07ebab155beabd5078ea1f6 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sat, 9 May 2020 15:11:04 -0400 Subject: [PATCH 4/5] works fine with one parameter. --- src/parser/parser.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 467521f..44587ca 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -1054,9 +1054,9 @@ mod tests { } #[test] - fn test_full_document_temp() { + fn test_full_document_parameterized_partial() { assert_eq!( - super::template(r#"{#level3.level4}{>partialtwo/}{/level3.level4}"#), + super::template(r#"{#level3.level4}{>partialtwo v1="b"/}{/level3.level4}"#), Ok::<_, nom::Err<(&str, ErrorKind)>>(( "", Template { @@ -1069,7 +1069,10 @@ mod tests { elements: vec![TemplateElement::TETag(DustTag::DTPartial( Partial { name: "partialtwo".to_owned(), - params: vec![] + params: vec![KVPair { + key: "v1", + value: RValue::RVString("b".to_owned()) + }] } ))] }), From 2a9657e3d50d6c5a86b3b3e4e9a46b40c1afc0cb Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sat, 9 May 2020 15:15:43 -0400 Subject: [PATCH 5/5] Turns out the issue was the trailing space on the parameters. --- src/parser/parser.rs | 50 +++++++++++++++++++++++++++++++------- src/renderer/walking.rs | 53 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 9 deletions(-) create mode 100644 src/renderer/walking.rs diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 44587ca..9422a6d 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -6,7 +6,7 @@ use nom::bytes::complete::{tag, take_until, take_until_parser_matches}; use nom::character::complete::line_ending; use nom::character::complete::multispace0; use nom::character::complete::one_of; -use nom::character::complete::space1; +use nom::character::complete::{space0, space1}; use nom::combinator::all_consuming; use nom::combinator::map; use nom::combinator::opt; @@ -387,7 +387,11 @@ where let (i, (name, params, inner, maybe_else, _closing_name)) = tuple(( preceded(tag(open_matcher), tag(tag_name)), terminated( - opt(preceded(space1, separated_list1(space1, key_value_pair))), + opt(delimited( + space1, + separated_list1(space1, key_value_pair), + space0, + )), tag("}"), ), opt(body), @@ -420,7 +424,11 @@ where tag(open_matcher), tuple(( tag(tag_name), - opt(preceded(space1, separated_list1(space1, key_value_pair))), + opt(delimited( + space1, + separated_list1(space1, key_value_pair), + space0, + )), )), tag("/}"), )(i)?; @@ -449,7 +457,11 @@ where tag(open_matcher), tuple(( alt((map(key, String::from), quoted_string)), - opt(preceded(space1, separated_list1(space1, key_value_pair))), + opt(delimited( + space1, + separated_list1(space1, key_value_pair), + space0, + )), )), tag("/}"), )(i)?; @@ -1056,7 +1068,9 @@ mod tests { #[test] fn test_full_document_parameterized_partial() { assert_eq!( - super::template(r#"{#level3.level4}{>partialtwo v1="b"/}{/level3.level4}"#), + super::template( + r#"{#level3.level4}{>partialtwo v1="b" v2="b" v3="b" v4="b" v5="b" /}{/level3.level4}"# + ), Ok::<_, nom::Err<(&str, ErrorKind)>>(( "", Template { @@ -1069,10 +1083,28 @@ mod tests { elements: vec![TemplateElement::TETag(DustTag::DTPartial( Partial { name: "partialtwo".to_owned(), - params: vec![KVPair { - key: "v1", - value: RValue::RVString("b".to_owned()) - }] + params: vec![ + KVPair { + key: "v1", + value: RValue::RVString("b".to_owned()) + }, + KVPair { + key: "v2", + value: RValue::RVString("b".to_owned()) + }, + KVPair { + key: "v3", + value: RValue::RVString("b".to_owned()) + }, + KVPair { + key: "v4", + value: RValue::RVString("b".to_owned()) + }, + KVPair { + key: "v5", + value: RValue::RVString("b".to_owned()) + } + ] } ))] }), diff --git a/src/renderer/walking.rs b/src/renderer/walking.rs new file mode 100644 index 0000000..feadce3 --- /dev/null +++ b/src/renderer/walking.rs @@ -0,0 +1,53 @@ +use crate::renderer::context_element::ContextElement; +use crate::renderer::WalkError; + +enum WalkResult<'a> { + NoWalk, + PartialWalk, + FullyWalked(&'a dyn ContextElement), +} + +fn walk_path_from_single_level<'a>( + context: &'a dyn ContextElement, + path: &Vec<&str>, +) -> WalkResult<'a> { + if path.is_empty() { + return WalkResult::FullyWalked(context); + } + + let mut walk_failure = WalkResult::NoWalk; + let mut output = context; + for elem in path.iter() { + let new_val = output.walk(elem); + match output.walk(elem) { + Err(WalkError::CantWalk { .. }) => { + return walk_failure; + } + Ok(new_val) => { + walk_failure = WalkResult::PartialWalk; + output = new_val; + } + } + } + + WalkResult::FullyWalked(output) +} + +pub fn walk_path<'a>( + breadcrumbs: &Vec<&'a dyn ContextElement>, + path: &'a Vec<&str>, +) -> Result<&'a dyn ContextElement, WalkError> { + for context in breadcrumbs.iter().rev() { + match walk_path_from_single_level(*context, path) { + // If no walking was done at all, keep looping + WalkResult::NoWalk => {} + // If we partially walked then stop trying to find + // anything + WalkResult::PartialWalk => { + return Err(WalkError::CantWalk); + } + WalkResult::FullyWalked(new_context) => return Ok(new_context), + } + } + Err(WalkError::CantWalk) +}