A `{% filter %}` block could have an unbound number of filters chained
one after another. This chain would wind up as a nested structure on the
heap. When dropped, this would cause a stackoverflow.
Resolves <https://issues.oss-fuzz.com/issues/386547457>.
This PR adds an `enum Digits` that contains all possible values for
two-digit decimal numbers: `b"00" ..= b"99"`. This seems to enable rust
and/or llvm to make better use of niches. Previously there were no
niches, and we compared against `0` manually. Now most of the u16-space
are niches.
```text
Escaping time: [3.3437 µs 3.3497 µs 3.3578 µs]
change: [-18.807% -18.620% -18.452%] (p = 0.00 < 0.05)
Performance has improved.
```
Recursive macro calls, direct and indirect, would cause a stackoverflow.
This PR lets the macro call handler keep track of the stack of called
macros we are currently in, so we can abort with an error message
instead of panicking.
Not for all operations the nesting level was incremented when needed
and/or the un-incremented nesting level was used in subfunction calls.
Binary operators such as `*` did not properly increment the nesting
level.
This PR changes `Level` in such a way that it can be used to keep track
of the nesting level when used in a loop. It is now impossible to
accidentally refer to an old nesting level value.
Resolves <https://issues.oss-fuzz.com/issues/385256115>.
* refactor(parser): Consistently use 'i' in skip_till
* refactor(parser): Clarify second input in skip_till
* refactor(parser): Consistently use 'i' in Comment::parse::content
* refactor(parser): Clarify second input in Comment::parse::content
* refactor(parser): Rename ParseResult to InputParseResult
This leaves room for a new `ParseResult` that doesn't have the input as
we transition to the Winnow 0.5 API.
* refactor(parser): Temporarily switch from parse_next to parse_peek
In 0.4, `parse_next` and `parse_peek` are the same.
In 0.5, `parse_next`s signature will change.
By switching to `parse_peek` now, we can make it so we gradually adopt
the new `parse_next` signature.
* refactor(parser): Temporarilly add unpeeks
In 0.4, `unpeek` is a no-op.
In 0.5, the `FnMut` signature impled for `Parser` changes and `unpeek`
will take the old signature and adapt it to work.
This allows us to more gradually migrate to the new `FnMut` signature.
Yes, the name `unpeek` isn't ideal but its only transitional.
* refactor(parser): Upgrade to Winnow 0.5
Note: `tests::fuzzed_target_recursion` fails on debug builds because of
the extra overhead from the deprecated APIs adapting to their
non-deprecated forms
* refactor(parser): Update signature for 'identifier'
* refactor(parser): Update signature for 'bool_lit'
* refactor(parser): Update signature for 'num_lit_suffix'
* refactor(parser): Update body for 'num_lit::int_with_base'
* refactor(parser): Update signature for 'num_lit::float'
* refactor(parser): Update signature for 'num_lit'
* refactor(parser): Update signature for 'str_lit_without_prefix'
* refactor(parser): Update signature for 'str_lit'
* refactor(parser): Update signature for 'char_lit'
* refactor(parser): Update signature for 'Char::parse'
* refactor(parser): Update signature for 'path_or_identifier'
* refactor(parser): Update signature for 'filter'
* refactor(parser): Update signature for 'State::tag_block_start'
* refactor(parser): Update signature for 'State::tag_block_end'
* refactor(parser): Update signature for 'State::tag_comment_start'
* refactor(parser): Update signature for 'State::tag_comment_end'
* refactor(parser): Update signature for 'State::tag_expr_start'
* refactor(parser): Update signature for 'State::tag_expr_end'
* refactor(parser): Update signature for 'State::nest'
* refactor(parser): Update signature for 'Level::nest'
I had considered making the input a `&mut &str` but didn't really see
the benefit, especially at this stage.
That can always be changed later.
* refactor(parser): Update signature for 'skip_ws0'
* refactor(parser): Update signature for 'skip_ws1'
* refactor(parser): Update signature for 'separated_digits' closure
* refactor(parser): Update signature for 'skip_till' closure
* refactor(parser): Update signature for 'Target::lit'
* refactor(parser): Update signature for 'Target::unnamed'
* refactor(parser): Update signature for 'Target::named'
* refactor(parser): Update signature for 'Target::rest'
* refactor(parser): Update signature for 'collect_targets'
* refactor(parser): Update signature for 'Target::parse'
* refactor(parser): Update signature for 'Target::parse_one'
* refactor(parser): Update signature for 'Suffix::try'
* refactor(parser): Update signature for 'Suffix::call'
* refactor(parser): Update signature for 'Suffix::index'
* refactor(parser): Update signature for 'Suffix::attr'
* refactor(parser): Update signature for 'Suffix::macro'
* refactor(parser): Update signature for 'token_bitand'
* refactor(parser): Update signature for 'token_xor'
* refactor(parser): Update signature for 'Expr::char'
* refactor(parser): Update signature for 'Expr::num'
* refactor(parser): Update signature for 'Expr::str'
* refactor(parser): Update signature for 'Expr::path_var_bool'
* refactor(parser): Update signature for 'Expr::array'
* refactor(parser): Update signature for 'Expr::group'
* refactor(parser): Update signature for 'Expr::single'
* refactor(parser): Update signature for 'Expr::prefix'
* refactor(parser): Update signature for 'Expr::filtered'
* refactor(parser): Update signature for 'Expr::is_as'
* refactor(parser): Update signature for 'Expr::concat'
* refactor(parser): Update signature for 'expr_prec_layer'
* refactor(parser): Update signature for 'Suffix::parse'
* refactor(parser): Update signature for 'Expr::parse'
* refactor(parser): Update signature for 'Expr::named_argument'
* refactor(parser): Update signature for 'Expr::arguments'
* refactor(parser): Update signature for 'Expr::arguments' closure
* refactor(parser): Update signature for 'Comment::parse::tag
* refactor(parser): Update signature for 'Comment::parse::content
* refactor(parser): Update signature for 'Comment::parse'
* refactor(parser): Update signature for 'Extends::parse'
* refactor(parser): Update signature for 'Include::parse'
* refactor(parser): Update signature for 'Import::parse'
* refactor(parser): Update signature for 'Whitespace::parse'
* refactor(parser): Update signature for 'Lit::parse'
* refactor(parser): Update signature for 'Node::expr'
* refactor(parser): Update signature for 'Node::many'
* refactor(parser): Update signature for 'Node::parse'
* refactor(parser): Update signature for 'Node::parse_template'
* refactor(parser): Update signature for 'cut_node' closure
* refactor(parser): Avoid 'parse_peek' in 'cut_node'
* refactor(parser): Update signature for 'unexpected_raw_tag'
* refactor(parser): Update signature for 'unexpected_tag'
* refactor(parser): Update signature for 'check_end_name'
* refactor(parser): Update signature for 'CondTest::parse_cond'
* refactor(parser): Update signature for 'check_block_start'
* refactor(parser): Update signature for 'Loop::parse::content'
* refactor(parser): Update signature for 'Macro::parse::parameters'
* refactor(parser): Update signature for 'Loop::parse::else_block'
* refactor(parser): Update signature for 'Loop::parse::body_and_end'
* refactor(parser): Reuse built-in empty parser
* refactor(parser): Update signature for remaining '*::parse'
* refactor(parser): Resolve remaining deprecations