From efdb597bba3be973e2467fb89eb0eed25cb1797b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kijewski?= Date: Thu, 11 Jul 2024 13:14:35 +0200 Subject: [PATCH] Add `elifdef`+`else` to `ifdef` block --- rinja_derive/src/generator.rs | 21 ++++++--- rinja_derive/src/input.rs | 4 +- rinja_parser/src/node.rs | 84 ++++++++++++++++++++++++++++++----- testing/tests/ifdef.rs | 76 +++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+), 18 deletions(-) diff --git a/rinja_derive/src/generator.rs b/rinja_derive/src/generator.rs index 11818c1b..f20ce434 100644 --- a/rinja_derive/src/generator.rs +++ b/rinja_derive/src/generator.rs @@ -725,12 +725,21 @@ impl<'a> Generator<'a> { ifdef: &'a WithSpan<'_, IfdefBlock<'_>>, level: AstLevel, ) -> Result { - self.handle_ws(ifdef.ws1); - let size_hint = match self.input.test_ifdef_cond(ctx, &ifdef.cond)? { - true => self.handle(ctx, &ifdef.nodes, buf, level)?, - false => 0, - }; - self.prepare_ws(ifdef.ws2); + let mut size_hint = 0; + let mut found = false; + for branch in &ifdef.branches { + self.handle_ws(branch.ws); + if !found { + found = match &branch.cond { + Some(cond) => self.input.test_ifdef_cond(ctx, cond)?, + None => true, + }; + if found { + size_hint = self.handle(ctx, &branch.nodes, buf, level)? + } + } + } + self.handle_ws(ifdef.last_ws); Ok(size_hint) } diff --git a/rinja_derive/src/input.rs b/rinja_derive/src/input.rs index 9a20f871..8caf8896 100644 --- a/rinja_derive/src/input.rs +++ b/rinja_derive/src/input.rs @@ -195,7 +195,9 @@ impl TemplateInput<'_> { } } Node::Ifdef(i) => { - nested.push(&i.nodes); + for branch in &i.branches { + nested.push(&branch.nodes); + } } Node::Lit(_) | Node::Comment(_) diff --git a/rinja_parser/src/node.rs b/rinja_parser/src/node.rs index c4627e1e..a2dd59ab 100644 --- a/rinja_parser/src/node.rs +++ b/rinja_parser/src/node.rs @@ -1046,10 +1046,15 @@ impl<'a> Comment<'a> { #[derive(Debug, PartialEq)] pub struct IfdefBlock<'a> { - pub ws1: Ws, - pub cond: WithSpan<'a, IfdefTest<'a>>, + pub branches: Vec>>, + pub last_ws: Ws, +} + +#[derive(Debug, PartialEq)] +pub struct IfdefBranch<'a> { + pub ws: Ws, + pub cond: Option>>, pub nodes: Vec>, - pub ws2: Ws, } #[derive(Debug, PartialEq)] @@ -1062,28 +1067,85 @@ pub enum IfdefTest<'a> { impl<'a> IfdefBlock<'a> { fn parse(start: &'a str, s: &State<'_>) -> ParseResult<'a, WithSpan<'a, Self>> { - let (i, (pws1, _, (cond, nws1, _, nodes, _, pws2, _, nws2))) = tuple(( + let end = map( + tuple(( + opt(Whitespace::parse), + ws(keyword("endifdef")), + opt(Whitespace::parse), + )), + |(pws, _, nws)| Ws(pws, nws), + ); + + let (i, (fst, (mut branches, otherwise, last_ws))) = s.nest( + start, + pair( + |i| IfdefBranch::parse(i, s, "ifdef"), + cut(tuple(( + many0(|i| IfdefBranch::parse(i, s, "elifdef")), + opt(|i| IfdefBranch::parse_else(i, s)), + end, + ))), + ), + )?; + + branches.reserve_exact(1 + otherwise.is_some() as usize); + branches.insert(0, fst); + if let Some(otherwise) = otherwise { + branches.push(otherwise); + } + + Ok((i, WithSpan::new(Self { branches, last_ws }, start))) + } +} + +impl<'a> IfdefBranch<'a> { + fn parse( + start: &'a str, + s: &State<'_>, + kw: &'static str, + ) -> ParseResult<'a, WithSpan<'a, Self>> { + let (i, (pws, _, (cond, nws, _, nodes, _))) = tuple(( opt(Whitespace::parse), - ws(keyword("ifdef")), + ws(keyword(kw)), cut(tuple(( ws(|i| IfdefTest::parse(i, s)), opt(Whitespace::parse), |i| s.tag_block_end(i), |i| Node::many(i, s), |i| s.tag_block_start(i), + ))), + ))(start)?; + Ok(( + i, + WithSpan::new( + IfdefBranch { + ws: Ws(pws, nws), + cond: Some(cond), + nodes, + }, + start, + ), + )) + } + + fn parse_else(start: &'a str, s: &State<'_>) -> ParseResult<'a, WithSpan<'a, Self>> { + let (i, (pws, _, (nws, _, nodes, _))) = tuple(( + opt(Whitespace::parse), + ws(keyword("else")), + cut(tuple(( opt(Whitespace::parse), - ws(keyword("endifdef")), - opt(Whitespace::parse), + |i| s.tag_block_end(i), + |i| Node::many(i, s), + |i| s.tag_block_start(i), ))), ))(start)?; Ok(( i, WithSpan::new( - Self { - ws1: Ws(pws1, nws1), - cond, + IfdefBranch { + ws: Ws(pws, nws), + cond: None, nodes, - ws2: Ws(pws2, nws2), }, start, ), diff --git a/testing/tests/ifdef.rs b/testing/tests/ifdef.rs index be83a898..7656a9cb 100644 --- a/testing/tests/ifdef.rs +++ b/testing/tests/ifdef.rs @@ -106,3 +106,79 @@ fn test_b() { assert_eq!(B { b: 2 }.to_string(), "b=2d=!"); } + +#[test] +fn test_else_abcd() { + #[derive(Template)] + #[template( + source = " + {%- ifdef a -%} a={{a}} + {%- elifdef b -%} b={{b}} + {%- elifdef c -%} c={{c}} + {%- else -%} ? + {%- endifdef -%} + ", + ext = "txt" + )] + #[allow(dead_code)] + struct Abcd { + a: u32, + b: u32, + c: u32, + d: u32, + } + + assert_eq!( + Abcd { + a: 1, + b: 2, + c: 3, + d: 4, + } + .to_string(), + "a=1" + ); +} + +#[test] +fn test_else_cd() { + #[derive(Template)] + #[template( + source = " + {%- ifdef a -%} a={{a}} + {%- elifdef b -%} b={{b}} + {%- elifdef c -%} c={{c}} + {%- else -%} ? + {%- endifdef -%} + ", + ext = "txt" + )] + #[allow(dead_code)] + struct Cd { + c: u32, + d: u32, + } + + assert_eq!(Cd { c: 3, d: 4 }.to_string(), "c=3"); +} + +#[test] +fn test_else_d() { + #[derive(Template)] + #[template( + source = " + {%- ifdef a -%} a={{a}} + {%- elifdef b -%} b={{b}} + {%- elifdef c -%} c={{c}} + {%- else -%} ? + {%- endifdef -%} + ", + ext = "txt" + )] + #[allow(dead_code)] + struct D { + d: u32, + } + + assert_eq!(D { d: 4 }.to_string(), "?"); +}