Allow trimming of whitespace

Signed-off-by: Marcel Müller <neikos@neikos.email>
This commit is contained in:
Marcel Müller 2026-03-09 13:24:40 +01:00
parent 587cfdea53
commit 59f92e31fe
8 changed files with 243 additions and 9 deletions

View file

@ -264,16 +264,32 @@ fn parse_interpolation<'input>(
) -> Result<TemplateAstExpr<'input>, AstError> {
let expr_parser = resume_after_cut(
parse_value_expression,
repeat_till(0.., any, peek(TokenKind::RightDelim)).map(|((), _)| ()),
repeat_till(
0..,
any,
peek(preceded(
opt(TokenKind::TrimWhitespace),
TokenKind::RightDelim,
)),
)
.map(|((), _)| ()),
)
.with_taken()
.map(|(expr, taken)| expr.unwrap_or(TemplateAstExpr::Invalid(taken)));
let (prev_whitespace, _left, _wants_output, (expression, _right, post_whitespace)) = (
let (
prev_whitespace,
_left,
left_trim,
_wants_output,
(expression, right_trim, _right, post_whitespace),
) = (
opt(TokenKind::Whitespace),
TokenKind::LeftDelim,
opt(TokenKind::TrimWhitespace),
TokenKind::WantsOutput,
cut_err((
surrounded(ws, expr_parser).map(Box::new),
opt(TokenKind::TrimWhitespace),
TokenKind::RightDelim,
opt(TokenKind::Whitespace),
)),
@ -281,9 +297,17 @@ fn parse_interpolation<'input>(
.parse_next(input)?;
Ok(TemplateAstExpr::Interpolation {
prev_whitespace_content: prev_whitespace,
prev_whitespace_content: if left_trim.is_some() {
None
} else {
prev_whitespace
},
expression,
post_whitespace_content: post_whitespace,
post_whitespace_content: if right_trim.is_some() {
None
} else {
post_whitespace
},
})
}
@ -439,19 +463,35 @@ where
(
opt(TokenKind::Whitespace),
TokenKind::LeftDelim,
opt(TokenKind::TrimWhitespace),
not(TokenKind::WantsOutput),
(
surrounded(ws, expr_parser.map(Box::new)),
opt(TokenKind::TrimWhitespace),
TokenKind::RightDelim,
opt(TokenKind::Whitespace),
),
)
.map(
|(prev_whitespace, _left, _not_token, (expression, _right, post_whitespace))| {
|(
prev_whitespace,
_left,
left_trim,
_not_token,
(expression, right_trim, _right, post_whitespace),
)| {
TemplateAstExpr::Block {
prev_whitespace_content: prev_whitespace,
prev_whitespace_content: if left_trim.is_some() {
None
} else {
prev_whitespace
},
expression,
post_whitespace_content: post_whitespace,
post_whitespace_content: if right_trim.is_some() {
None
} else {
post_whitespace
},
}
},
)
@ -736,4 +776,15 @@ mod tests {
insta::assert_debug_snapshot!(ast);
}
#[test]
fn check_trim_whitespace() {
let input = "{{ if foo -}} foo {{- else if bar -}} bar {{- end }}";
let parsed = crate::parser::parse(input.into()).unwrap();
let ast = panic_pretty(input, parse(parsed.tokens()));
insta::assert_debug_snapshot!(ast);
}
}

View file

@ -0,0 +1,51 @@
---
source: src/ast/mod.rs
expression: ast
---
TemplateAst {
root: [
ConditionalChain {
chain: [
Block {
prev_whitespace_content: None,
expression: IfConditional {
expression: VariableAccess(
[Ident]"foo" (6..9),
),
},
post_whitespace_content: None,
},
ConditionalContent {
content: [
StaticContent(
[Content]"foo" (14..17),
),
],
},
Block {
prev_whitespace_content: None,
expression: ElseConditional {
expression: Some(
VariableAccess(
[Ident]"bar" (30..33),
),
),
},
post_whitespace_content: None,
},
ConditionalContent {
content: [
StaticContent(
[Content]"bar" (38..41),
),
],
},
Block {
prev_whitespace_content: None,
expression: EndBlock,
post_whitespace_content: None,
},
],
},
],
}

View file

@ -53,11 +53,12 @@ pub fn execute(
Instruction::PushScope { inherit_parent: _ } => todo!(),
Instruction::Abort => return Err(EvaluationError::ExplicitAbort),
Instruction::JumpIfNotTrue { emit_slot, jump } => {
let jump = if *jump == 0 { 1 } else { *jump };
let dont_jump = scopes.get(emit_slot).unwrap().as_bool().unwrap();
if dont_jump {
// We are done
} else {
let (new_ip, overflow) = ip.overflowing_add_signed(*jump);
let (new_ip, overflow) = ip.overflowing_add_signed(jump);
if overflow {
return Err(EvaluationError::InstructionPointerOverflow);
@ -68,7 +69,8 @@ pub fn execute(
}
}
Instruction::Jump { jump } => {
let (new_ip, overflow) = ip.overflowing_add_signed(*jump);
let jump = if *jump == 0 { 1 } else { *jump };
let (new_ip, overflow) = ip.overflowing_add_signed(jump);
if overflow {
return Err(EvaluationError::InstructionPointerOverflow);