Add ast parsing for for loops
Signed-off-by: Marcel Müller <neikos@neikos.email>
This commit is contained in:
parent
a099c74b1b
commit
e64256b65f
3 changed files with 165 additions and 0 deletions
|
|
@ -230,6 +230,18 @@ pub enum TemplateAstExpr<'input> {
|
|||
ConditionalChain {
|
||||
chain: Vec<TemplateAstExpr<'input>>,
|
||||
},
|
||||
ForChain {
|
||||
for_block: Box<TemplateAstExpr<'input>>,
|
||||
content: Vec<TemplateAstExpr<'input>>,
|
||||
else_block: Option<Box<TemplateAstExpr<'input>>>,
|
||||
else_content: Option<Vec<TemplateAstExpr<'input>>>,
|
||||
end_block: Box<TemplateAstExpr<'input>>,
|
||||
},
|
||||
For {
|
||||
value_ident: TemplateToken,
|
||||
value_expression: Box<TemplateAstExpr<'input>>,
|
||||
},
|
||||
ForElse,
|
||||
VariableAccess(TemplateToken),
|
||||
IfConditional {
|
||||
expression: Box<TemplateAstExpr<'input>>,
|
||||
|
|
@ -316,6 +328,7 @@ fn parse_action<'input>(input: &mut Input<'input>) -> Result<TemplateAstExpr<'in
|
|||
"action",
|
||||
alt((
|
||||
parse_conditional_chain,
|
||||
parse_for_chain,
|
||||
(parse_block(
|
||||
cut_err(not(repeat_till(
|
||||
0..,
|
||||
|
|
@ -336,6 +349,67 @@ fn parse_action<'input>(input: &mut Input<'input>) -> Result<TemplateAstExpr<'in
|
|||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn parse_for_chain<'input>(input: &mut Input<'input>) -> Result<TemplateAstExpr<'input>, AstError> {
|
||||
trace("for_loop", |input: &mut Input<'input>| {
|
||||
let for_block = parse_for_loop.map(Box::new).parse_next(input)?;
|
||||
|
||||
let loop_end = (
|
||||
opt((
|
||||
parse_loop_else.map(Box::new),
|
||||
repeat_till(0.., parse_ast, peek(parse_end)).map(|(val, _)| val),
|
||||
)),
|
||||
parse_end.map(Box::new),
|
||||
);
|
||||
|
||||
let (content, taken) = resume_after_cut(
|
||||
repeat_till(0.., parse_ast, loop_end),
|
||||
repeat_till(0.., any, parse_end).map(|((), _)| ()),
|
||||
)
|
||||
.with_taken()
|
||||
.parse_next(input)?;
|
||||
|
||||
let Some((content, (else_stuff, end_block))) = content else {
|
||||
return Ok(TemplateAstExpr::Invalid(taken));
|
||||
};
|
||||
|
||||
let (else_block, else_content) = else_stuff.unzip();
|
||||
|
||||
Ok(TemplateAstExpr::ForChain {
|
||||
for_block,
|
||||
content,
|
||||
else_block,
|
||||
else_content,
|
||||
end_block,
|
||||
})
|
||||
})
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn parse_for_loop<'input>(input: &mut Input<'input>) -> Result<TemplateAstExpr<'input>, AstError> {
|
||||
trace(
|
||||
"for_loop_inner",
|
||||
parse_block(
|
||||
(
|
||||
ws,
|
||||
TokenKind::For,
|
||||
ws,
|
||||
TokenKind::Ident,
|
||||
ws,
|
||||
TokenKind::In,
|
||||
ws,
|
||||
parse_value_expression.map(Box::new),
|
||||
)
|
||||
.map(|(_, _for, _, value_ident, _, _in, _, value_expression)| {
|
||||
TemplateAstExpr::For {
|
||||
value_ident,
|
||||
value_expression,
|
||||
}
|
||||
}),
|
||||
),
|
||||
)
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn parse_conditional_chain<'input>(
|
||||
input: &mut Input<'input>,
|
||||
) -> Result<TemplateAstExpr<'input>, AstError> {
|
||||
|
|
@ -447,6 +521,18 @@ fn parse_conditional_else<'input>(
|
|||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn parse_loop_else<'input>(input: &mut Input<'input>) -> Result<TemplateAstExpr<'input>, AstError> {
|
||||
trace(
|
||||
"end",
|
||||
parse_block(
|
||||
TokenKind::ConditionalElse
|
||||
.value(TemplateAstExpr::ForElse)
|
||||
.context(AstError::ctx().msg("Expected an else block here")),
|
||||
),
|
||||
)
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn parse_end<'input>(input: &mut Input<'input>) -> Result<TemplateAstExpr<'input>, AstError> {
|
||||
trace(
|
||||
"end",
|
||||
|
|
@ -815,4 +901,15 @@ mod tests {
|
|||
|
||||
insta::assert_debug_snapshot!(ast);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_for_loop() {
|
||||
let input = "{{ for value in array }} Hi: {{= value }} {{ else }} No Content :C {{ end }}";
|
||||
|
||||
let parsed = crate::parser::parse(input.into()).unwrap();
|
||||
|
||||
let ast = panic_pretty(input, parse(parsed.tokens()));
|
||||
|
||||
insta::assert_debug_snapshot!(ast);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
61
src/ast/snapshots/nomo__ast__tests__check_for_loop.snap
Normal file
61
src/ast/snapshots/nomo__ast__tests__check_for_loop.snap
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
---
|
||||
source: src/ast/mod.rs
|
||||
expression: ast
|
||||
---
|
||||
TemplateAst {
|
||||
root: [
|
||||
ForChain {
|
||||
for_block: Block {
|
||||
prev_whitespace_content: None,
|
||||
expression: For {
|
||||
value_ident: [Ident]"value" (7..12),
|
||||
value_expression: VariableAccess(
|
||||
[Ident]"array" (16..21),
|
||||
),
|
||||
},
|
||||
post_whitespace_content: Some(
|
||||
[Whitespace]" " (24..25),
|
||||
),
|
||||
},
|
||||
content: [
|
||||
StaticContent(
|
||||
[Content]"Hi:" (25..28),
|
||||
),
|
||||
Interpolation {
|
||||
prev_whitespace_content: Some(
|
||||
[Whitespace]" " (28..29),
|
||||
),
|
||||
expression: VariableAccess(
|
||||
[Ident]"value" (33..38),
|
||||
),
|
||||
post_whitespace_content: Some(
|
||||
[Whitespace]" " (41..42),
|
||||
),
|
||||
},
|
||||
],
|
||||
else_block: Some(
|
||||
Block {
|
||||
prev_whitespace_content: None,
|
||||
expression: ForElse,
|
||||
post_whitespace_content: Some(
|
||||
[Whitespace]" " (52..53),
|
||||
),
|
||||
},
|
||||
),
|
||||
else_content: Some(
|
||||
[
|
||||
StaticContent(
|
||||
[Content]"No Content :C" (53..66),
|
||||
),
|
||||
],
|
||||
),
|
||||
end_block: Block {
|
||||
prev_whitespace_content: Some(
|
||||
[Whitespace]" " (66..67),
|
||||
),
|
||||
expression: EndBlock,
|
||||
post_whitespace_content: None,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
|
@ -205,6 +205,9 @@ fn emit_ast_expr(
|
|||
| TemplateAstExpr::IfConditional { .. }
|
||||
| TemplateAstExpr::ConditionalContent { .. }
|
||||
| TemplateAstExpr::ElseConditional { .. }
|
||||
| TemplateAstExpr::ForChain { .. }
|
||||
| TemplateAstExpr::For { .. }
|
||||
| TemplateAstExpr::ForElse
|
||||
| TemplateAstExpr::Invalid { .. }
|
||||
| TemplateAstExpr::VariableAccess { .. } => eval.push(Instruction::Abort),
|
||||
}
|
||||
|
|
@ -231,6 +234,10 @@ fn emit_expr_load(
|
|||
TemplateAstExpr::ElseConditional { .. } => todo!(),
|
||||
TemplateAstExpr::EndBlock => todo!(),
|
||||
TemplateAstExpr::Block { .. } => todo!(),
|
||||
TemplateAstExpr::ForChain { .. } => todo!(),
|
||||
TemplateAstExpr::For { .. } => todo!(),
|
||||
TemplateAstExpr::ForElse => todo!(),
|
||||
|
||||
TemplateAstExpr::IfConditional { .. } => todo!(),
|
||||
TemplateAstExpr::ConditionalContent { .. } => todo!(),
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue