I have implemented the REPEAT combinator. It's now in traditional native PARSE as well as UPARSE.
It's a bit "unfortunate" that you have to put integer variables in a GROUP!:
>> var: 3
>> uparse? "aaa" [repeat (var) "a"]
== #[true]
We could consider if non-literal integers act as rules that do not advance the input and synthesize an integer (in contrast with literal integers that indicate a repeat count). That would make repeat var "a" different from repeat 3 "a" which creates irregularities.
But on the plus side of the current behavior, you can write rules that get the repeat count from the input and apply it immediately. The following example is contrived, but maybe not so much so that you couldn't see something like it ever happening:
>> uparse? ["b" 3 "b" "b" "b"] [rule: <any>, repeat integer! rule]
== #[true]
I think ranges of integers is a sufficiently rare pattern to warrant a combinator specific to the purpose, rather than breaking the coherence of the model to where 2 [3 rule] and 2 3 rule have distinct behavior.
But I do notice that the pattern 0 n rule is really just repeat (n) opt rule.
More generally repeat m n rule can be written as repeat (m) rule, repeat (n - m) opt rule
So I'm going to be killing off ranged repetition in native PARSE. We can discuss what the real answer should be, but that pattern can be used in the meantime.