The TALLY Parse Combinator: Count Rule Matches

There are cases where you want to know how many of a certain match there are.

Here's an example:

 uparse "<<<stuff>>>" [
     (n: 0)
     some ["<" (n: n + 1)]
     x: between here n ">"
 ]

Here I'm just trying to match the number of > on the right to how many < were on the left.

(Note: I still think this INTEGER! abstracting of rules is confusing to read. Is a REPEAT/LOOP keyword missing that would help? I've written about this, please register an opinion.)

Meet TALLY!

 uparse "<<<stuff>>>" [
     n: tally "<"
     x: between <here> repeat n ">"
 ]

So oddly enough, TALLY without paying attention to the result can be used as the replacement for historical instances of ANY or WHILE.

>> uparse "aaaccc" [some "a" tally "b" tally "c"]
== 3

>> uparse "aaaccc" [some "a" tally "b" some "c" tally "d"]
== 0

"Count the number of times this matches" along with ignoring the count is pretty lightweight, and perhaps some would consider it idiomatic for opt some

opt some
tally    ; three fewer characters, same as WHILE

I don't care for the tradeoff myself...but...it's worth pointing out that many result-bearing constructs have their results ignored.

1 Like

So I've never used this unusual suggestion of taking advantage of the zero-times-match.

But I'm wondering: are we limiting TALLY's applications by not allowing it to ever fail?

If you want a non-matching TALLY to be zero, that's now easy enough, since integers are literal:

[tally rule | 0]

And if you want NULL in the zero case, you could then say:

opt tally rule

But you don't have these choices when TALLY will never fail.

Still...it's a little hard for me to say it won't consider a count of 0. I can think of a lot of scenarios where that is what you want, and having to write [tally rule | 0] for it feels awkward.