From 09ae91c393d030bf61a7bd18de42cc12b046ddc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Thu, 12 Mar 2026 10:04:15 +0100 Subject: [PATCH] Add parsing of operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- src/parser/mod.rs | 105 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index de0ba97..dcf8a41 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -12,7 +12,10 @@ use winnow::ascii::multispace0; use winnow::ascii::multispace1; use winnow::combinator::alt; use winnow::combinator::cut_err; +use winnow::combinator::dispatch; +use winnow::combinator::empty; use winnow::combinator::eof; +use winnow::combinator::fail; use winnow::combinator::not; use winnow::combinator::opt; use winnow::combinator::peek; @@ -213,6 +216,17 @@ pub enum TokenKind { In, End, Literal(TokenLiteral), + Operator(TokenOperator), +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum TokenOperator { + Plus, + Minus, + Times, + Divide, + And, + Or, } #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -309,6 +323,13 @@ impl TemplateToken { } } + pub fn operator(operator: TokenOperator, source: NomoInput) -> Self { + TemplateToken { + kind: TokenKind::Operator(operator), + source, + } + } + pub fn kind(&self) -> TokenKind { self.kind } @@ -385,7 +406,7 @@ fn parse_interpolate<'input>(input: &mut Input<'input>) -> PResult<'input, Vec(input: &mut Input<'input>) -> PResult<'input, TemplateToken> { trace( "parse_block_token", - alt((parse_ident, parse_keyword, parse_whitespace)), + alt((parse_ident, parse_keyword, parse_whitespace, parse_operator)), ) .parse_next(input) } @@ -474,6 +495,31 @@ fn parse_ident<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateTok .parse_next(input) } +fn parse_operator<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateToken> { + let (operator, source) = trace( + "operator", + dispatch! {any; + '+' => empty.value(TokenOperator::Plus), + '-' => empty.value(TokenOperator::Minus), + '*' => empty.value(TokenOperator::Times), + '/' => empty.value(TokenOperator::Divide), + '&' => alt(( + "&".value(TokenOperator::And), + cut_err(fail), + )), + '|' => alt(( + "|".value(TokenOperator::Or), + cut_err(fail), + )), + _ => fail, + }, + ) + .with_taken() + .parse_next(input)?; + + Ok(TemplateToken::operator(operator, source)) +} + fn ident<'input>(input: &mut Input<'input>) -> PResult<'input, NomoInput> { peek(not(parse_keyword)) .context(ParseError::ctx().msg("Expected an ident, but found a literal instead")) @@ -680,4 +726,61 @@ mod tests { ) "#); } + + #[test] + fn parse_operations() { + let input = "{{= 5 * 4 + 3 / 2 - 1 }}{{ if foo && bar || baz }}{{ end }}"; + let output = parse(input.into()); + + insta::assert_debug_snapshot!(output, @r#" + Ok( + ParsedTemplate { + tokens: [ + [LeftDelim]"{{" (0..2), + [WantsOutput]"=" (2..3), + [Whitespace]" " (3..4), + [Ident]"5" (4..5), + [Whitespace]" " (5..6), + [Operator(Times)]"*" (6..7), + [Whitespace]" " (7..8), + [Ident]"4" (8..9), + [Whitespace]" " (9..10), + [Operator(Plus)]"+" (10..11), + [Whitespace]" " (11..12), + [Ident]"3" (12..13), + [Whitespace]" " (13..14), + [Operator(Divide)]"/" (14..15), + [Whitespace]" " (15..16), + [Ident]"2" (16..17), + [Whitespace]" " (17..18), + [Operator(Minus)]"-" (18..19), + [Whitespace]" " (19..20), + [Ident]"1" (20..21), + [Whitespace]" " (21..22), + [RightDelim]"}}" (22..24), + [LeftDelim]"{{" (24..26), + [Whitespace]" " (26..27), + [ConditionalIf]"if" (27..29), + [Whitespace]" " (29..30), + [Ident]"foo" (30..33), + [Whitespace]" " (33..34), + [Operator(And)]"&&" (34..36), + [Whitespace]" " (36..37), + [Ident]"bar" (37..40), + [Whitespace]" " (40..41), + [Operator(Or)]"||" (41..43), + [Whitespace]" " (43..44), + [Ident]"baz" (44..47), + [Whitespace]" " (47..48), + [RightDelim]"}}" (48..50), + [LeftDelim]"{{" (50..52), + [Whitespace]" " (52..53), + [End]"end" (53..56), + [Whitespace]" " (56..57), + [RightDelim]"}}" (57..59), + ], + }, + ) + "#); + } }