Add for loop parsing

Signed-off-by: Marcel Müller <neikos@neikos.email>
This commit is contained in:
Marcel Müller 2026-03-11 10:34:17 +01:00
parent 3f549690c1
commit 018ba3cd2c

View file

@ -209,6 +209,8 @@ pub enum TokenKind {
Invalid, Invalid,
ConditionalIf, ConditionalIf,
ConditionalElse, ConditionalElse,
For,
In,
End, End,
Literal(TokenLiteral), Literal(TokenLiteral),
} }
@ -295,6 +297,8 @@ impl TemplateToken {
invalid => TokenKind::Invalid, invalid => TokenKind::Invalid,
conditional_if => TokenKind::ConditionalIf, conditional_if => TokenKind::ConditionalIf,
conditional_else => TokenKind::ConditionalElse, conditional_else => TokenKind::ConditionalElse,
keyword_for => TokenKind::For,
keyword_in => TokenKind::In,
end => TokenKind::End, end => TokenKind::End,
} }
@ -381,14 +385,7 @@ fn parse_interpolate<'input>(input: &mut Input<'input>) -> PResult<'input, Vec<T
fn parse_block_token<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateToken> { fn parse_block_token<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateToken> {
trace( trace(
"parse_block_token", "parse_block_token",
alt(( alt((parse_ident, parse_keyword, parse_whitespace)),
parse_ident,
terminated(parse_literal, ident_terminator_check),
terminated(parse_condition_if, ident_terminator_check),
terminated(parse_condition_else, ident_terminator_check),
terminated(parse_end, ident_terminator_check),
parse_whitespace,
)),
) )
.parse_next(input) .parse_next(input)
} }
@ -431,6 +428,26 @@ fn parse_end<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateToken
trace("parse_end", "end".map(TemplateToken::end)).parse_next(input) trace("parse_end", "end".map(TemplateToken::end)).parse_next(input)
} }
fn parse_for<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateToken> {
trace("parse_for", "for".map(TemplateToken::keyword_for)).parse_next(input)
}
fn parse_in<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateToken> {
trace("parse_in", "in".map(TemplateToken::keyword_in)).parse_next(input)
}
fn parse_keyword<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateToken> {
alt((
terminated(parse_literal, ident_terminator_check),
terminated(parse_condition_if, ident_terminator_check),
terminated(parse_condition_else, ident_terminator_check),
terminated(parse_for, ident_terminator_check),
terminated(parse_in, ident_terminator_check),
terminated(parse_end, ident_terminator_check),
))
.parse_next(input)
}
fn parse_whitespace<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateToken> { fn parse_whitespace<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateToken> {
trace( trace(
"parse_whitespace", "parse_whitespace",
@ -458,12 +475,7 @@ fn parse_ident<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateTok
} }
fn ident<'input>(input: &mut Input<'input>) -> PResult<'input, NomoInput> { fn ident<'input>(input: &mut Input<'input>) -> PResult<'input, NomoInput> {
peek(not(alt(( peek(not(parse_keyword))
parse_literal,
parse_condition_if,
parse_condition_else,
parse_end,
))))
.context(ParseError::ctx().msg("Expected an ident, but found a literal instead")) .context(ParseError::ctx().msg("Expected an ident, but found a literal instead"))
.parse_next(input)?; .parse_next(input)?;
@ -627,4 +639,45 @@ mod tests {
) )
"#); "#);
} }
#[test]
fn parse_for_loop() {
let input = "{{ for value in array }} Hi: {{= value }} {{ end }}";
let output = parse(input.into());
insta::assert_debug_snapshot!(output, @r#"
Ok(
ParsedTemplate {
tokens: [
[LeftDelim]"{{" (0..2),
[Whitespace]" " (2..3),
[For]"for" (3..6),
[Whitespace]" " (6..7),
[Ident]"value" (7..12),
[Whitespace]" " (12..13),
[In]"in" (13..15),
[Whitespace]" " (15..16),
[Ident]"array" (16..21),
[Whitespace]" " (21..22),
[RightDelim]"}}" (22..24),
[Whitespace]" " (24..25),
[Content]"Hi:" (25..28),
[Whitespace]" " (28..29),
[LeftDelim]"{{" (29..31),
[WantsOutput]"=" (31..32),
[Whitespace]" " (32..33),
[Ident]"value" (33..38),
[Whitespace]" " (38..39),
[RightDelim]"}}" (39..41),
[Whitespace]" " (41..42),
[LeftDelim]"{{" (42..44),
[Whitespace]" " (44..45),
[End]"end" (45..48),
[Whitespace]" " (48..49),
[RightDelim]"}}" (49..51),
],
},
)
"#);
}
} }