From b0620a00d55965e3f8b7b568e1f760b28571fbf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Mon, 9 Mar 2026 16:02:55 +0100 Subject: [PATCH] Fix issue with repeating {{ else }} blocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- src/ast/mod.rs | 80 +++++++++++++------ tests/checks.rs | 8 +- ...m-288cd3d11ffabe7f439c235924d88509deb93bc4 | 3 + 3 files changed, 63 insertions(+), 28 deletions(-) create mode 100644 tests/checks/minimized-from-288cd3d11ffabe7f439c235924d88509deb93bc4 diff --git a/src/ast/mod.rs b/src/ast/mod.rs index da68d0b..c39dd0e 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -345,39 +345,67 @@ fn parse_conditional_chain<'input>( chain.push(if_block); - loop { - let (content, end_block): (Vec<_>, _) = repeat_till( - 0.., - parse_ast, - trace( - "conditional_chain_else/end", - alt((parse_end, parse_conditional_else)), - ), - ) - .parse_next(input)?; + let content = resume_after_cut( + inner_conditional_chain, + repeat_till(0.., any, parse_end).map(|((), _)| ()), + ) + .parse_next(input)?; - chain.push(TemplateAstExpr::ConditionalContent { content }); - - let is_end = if let TemplateAstExpr::Block { ref expression, .. } = end_block - && let TemplateAstExpr::EndBlock = &**expression - { - true - } else { - false - }; - - chain.push(end_block); - - if is_end { - break; - } - } + chain.extend(content.into_iter().flatten()); Ok(TemplateAstExpr::ConditionalChain { chain }) }) .parse_next(input) } +fn inner_conditional_chain<'input>( + input: &mut Input<'input>, +) -> Result>, AstError> { + let mut needs_end = false; + + let mut chain = vec![]; + + loop { + let (content, end_block): (Vec<_>, _) = repeat_till( + 0.., + parse_ast, + trace( + "conditional_chain_else/end", + alt((parse_end, parse_conditional_else)), + ), + ) + .parse_next(input)?; + + chain.push(TemplateAstExpr::ConditionalContent { content }); + + let is_end = if let TemplateAstExpr::Block { ref expression, .. } = end_block + && let TemplateAstExpr::EndBlock = &**expression + { + true + } else { + false + }; + + if !is_end && needs_end { + return Err(AstError::from_input(input).cut()); + } + + if let TemplateAstExpr::Block { expression, .. } = &end_block + && let TemplateAstExpr::ElseConditional { expression: None } = &**expression + { + needs_end = true; + } + + chain.push(end_block); + + if is_end { + break; + } + } + + Ok(chain) +} + fn parse_conditional_if<'input>( input: &mut Input<'input>, ) -> Result, AstError> { diff --git a/tests/checks.rs b/tests/checks.rs index 900fd9f..56c736a 100644 --- a/tests/checks.rs +++ b/tests/checks.rs @@ -5,9 +5,13 @@ fn check_files() { for file in files { let input = std::fs::read_to_string(file.unwrap().path()).unwrap(); - let parsed = nomo::parser::parse(input.into()).unwrap(); + let Ok(parsed) = nomo::parser::parse(input.into()) else { + continue; + }; - let ast = nomo::ast::parse(parsed.tokens()).unwrap(); + let Ok(ast) = nomo::ast::parse(parsed.tokens()) else { + continue; + }; let _emit = nomo::emit::emit_machine(ast); } diff --git a/tests/checks/minimized-from-288cd3d11ffabe7f439c235924d88509deb93bc4 b/tests/checks/minimized-from-288cd3d11ffabe7f439c235924d88509deb93bc4 new file mode 100644 index 0000000..6405ddf --- /dev/null +++ b/tests/checks/minimized-from-288cd3d11ffabe7f439c235924d88509deb93bc4 @@ -0,0 +1,3 @@ +{{ if t }} +{{else}}{{ else }} +{{end }} \ No newline at end of file