Skip to content

Greatly speed up nested array parsing#702

Merged
GuillaumeGomez merged 5 commits intoaskama-rs:mainfrom
GuillaumeGomez:array-fuzz
Feb 17, 2026
Merged

Greatly speed up nested array parsing#702
GuillaumeGomez merged 5 commits intoaskama-rs:mainfrom
GuillaumeGomez:array-fuzz

Conversation

@GuillaumeGomez
Copy link
Collaborator

Fixes https://oss-fuzz.com/testcase-detail/5640096178307072.

The problem was that, we went into the two full array parsing branches and if any failed, we tried the other one, and if this failed, we returned and then we repeat. It's fine as long as the error isn't super deep nested.

This fix simply gets all repeated exprs, and then check if a ; is next and then handle errors if any. So we have only one path instead of 2. And as a nice bonus, code is shorter. :)

Comment on lines 682 to 695
if elements.is_empty() {
return cut_error!(
"expected element expression for array repeat syntax",
sub_span
);
} else if elements.len() != 1 {
return cut_error!(
"unexpected `;` after expression",
elements.last().unwrap().span()
);
}
let count = terminated(Self::array_repeat_count, ']').parse_next(i)?;
return Ok(WithSpan::new(
Box::new(Self::ArrayRepeat(elements.pop().unwrap(), count)),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let Some(elem) = elements.pop() else {
    "expected element expression for array repeat syntax"
};
if !elements.is_empty() {
    "unexpected `;` after expression"
}
return Ok();

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's nicer, good idea!

Comment on lines 681 to 691
if ws(';').parse_next(i).is_ok() {
if elements.is_empty() {
return cut_error!(
"expected element expression for array repeat syntax",
sub_span
);
} else if elements.len() != 1 {
return cut_error!(
"unexpected `;` after expression",
elements.last().unwrap().span()
);
Copy link
Member

@Kijewski Kijewski Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if let Some(span) = opt(ws(';')).span().parse_next(i)? {
   if .. {
       return cut_error!("unexpected `;` after expression", span);
   }
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@Kijewski
Copy link
Member

Oh, that's much nicer than potentially parsing everything twice! Just two minor comments.

@GuillaumeGomez
Copy link
Collaborator Author

Applied comments. :)

* inline tiny function `array_repeat_element`
* make sure to return an error with a message
* for errors with array repeat, point to the `;`, not `[`
* re-use `any_rust_token()` to tell what we found instead of `]`
* add grouping characters to `any_rust_token()`
@Kijewski
Copy link
Member

I was not happy with the uninformative "failed to parse template source" error messages, so I tried to better derive the error condition and position.

@GuillaumeGomez
Copy link
Collaborator Author

Can't approve your commit but it's a great improvement, thanks!

@GuillaumeGomez GuillaumeGomez merged commit a0fafb7 into askama-rs:main Feb 17, 2026
50 checks passed
@GuillaumeGomez GuillaumeGomez deleted the array-fuzz branch February 17, 2026 10:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants