diff --git a/js/test_cases/dot_leading_path/input1.json b/js/test_cases/dot_leading_path/input1.json new file mode 100644 index 0000000..986d7b4 --- /dev/null +++ b/js/test_cases/dot_leading_path/input1.json @@ -0,0 +1,7 @@ +{ + "commander": "Chris", + "names": { + "captain": "Alice", + "first_officer": "Bob" + } +} diff --git a/js/test_cases/dot_leading_path/main.dust b/js/test_cases/dot_leading_path/main.dust new file mode 100644 index 0000000..ada9456 --- /dev/null +++ b/js/test_cases/dot_leading_path/main.dust @@ -0,0 +1,5 @@ +{#names} + Hello {.captain}!{~n} + Hello {.commander}!{~n} + Hello {commander}!{~n} +{/names} diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 4c0cfd2..c016e7e 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -263,7 +263,14 @@ fn key(i: &str) -> IResult<&str, &str> { fn path(i: &str) -> IResult<&str, Path> { alt(( map(separated_list1(tag("."), key), |body| Path { keys: body }), - value(Path { keys: Vec::new() }, tag(".")), + map( + tuple((tag("."), separated_list1(tag("."), key))), + |(dot, mut body)| { + body.insert(0, dot); + Path { keys: body } + }, + ), + map(tag("."), |dot| Path { keys: vec![dot] }), ))(i) } @@ -1210,7 +1217,7 @@ mod tests { contents: Some(Body { elements: vec![TemplateElement::TETag(DustTag::DTReference( Reference { - path: Path { keys: vec![] }, + path: Path { keys: vec!["."] }, filters: vec![] } ))] @@ -1238,7 +1245,7 @@ mod tests { IgnoredWhitespace::StartOfLine("\n") ), TemplateElement::TETag(DustTag::DTReference(Reference { - path: Path { keys: vec![] }, + path: Path { keys: vec!["."] }, filters: vec![] })), TemplateElement::TEIgnoredWhitespace( diff --git a/src/renderer/walking.rs b/src/renderer/walking.rs index cc91047..b699254 100644 --- a/src/renderer/walking.rs +++ b/src/renderer/walking.rs @@ -9,7 +9,7 @@ enum WalkResult<'a> { fn walk_path_from_single_level<'a>( context: &'a dyn ContextElement, - path: &Vec<&str>, + path: &[&str], ) -> WalkResult<'a> { if path.is_empty() { return WalkResult::FullyWalked(context); @@ -18,7 +18,6 @@ fn walk_path_from_single_level<'a>( 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; @@ -37,6 +36,25 @@ pub fn walk_path<'a>( breadcrumbs: &Vec<&'a dyn ContextElement>, path: &'a Vec<&str>, ) -> Result<&'a dyn ContextElement, WalkError> { + if path.is_empty() { + return Ok(*breadcrumbs + .last() + .expect("Breadcrumbs should never be empty")); + } + if *path.first().expect("Already proved path is not empty") == "." { + return match walk_path_from_single_level( + *breadcrumbs + .last() + .expect("Breadcrumbs should never be empty"), + &path[1..], + ) { + // If no walking was done at all or we partially walked + // then stop trying to find anything because '.' restricts + // us to the current scope + WalkResult::NoWalk | WalkResult::PartialWalk => Err(WalkError::CantWalk), + WalkResult::FullyWalked(new_context) => Ok(new_context), + }; + } for context in breadcrumbs.iter().rev() { match walk_path_from_single_level(*context, path) { // If no walking was done at all, keep looping