Early on, I wondered why we couldn't invoke an ordinary function in PARSE, where its arguments were gathered by rules.
For instance: What if you want to call SPLIT on part of the input. Here's a particularly laborious way of doing it:
parse "(((1|2|3)))" [
some "("
let start: here
to ")"
let limit: here
items: (split/part start "|" limit)
some ")"
]
But imagine if we could avoid creating those intermediate START and LIMIT variables, with something more like:
parse "(((1|2|3)))" [some "(", items: split [copy to ")"] ("|"), some ")"]
The concept would be that the arguments to SPLIT would be gathered by PARSE rules. BLOCK!s would behave as rules and pass series, GROUP!s would go through DO.
Another idea could be that any function which takes a /PART would have that /PART implicitly provided by the limit of the parse range of the parameter.
Or even weirder: Maybe functions like SPLIT are expressed as COMBINATOR to begin with, and we then have a distinct behavior for combinators when called outside of PARSE. That would need more thinking through.
Another Example: ENBIN and DEBIN
A frequent lament of mine was how BINARY! parsing has really underperformed the ideal of what it should be capable of. The addition of ENBIN and DEBIN points in the right direction. (Going to use the $ format to start warming you up to the idea of the change, so that #{...} can be used for an alternative TOKEN! representation...I actually think it looks better!)
If we left it as a function that needed a rule to pass as the series parameter, it might wind up looking like:
parse ${FFFF0001FFFFFF} [
some ${FF}
value: debin ([BE + 2]) here
some ${FF}
]
If it were a combinator, then we could assume it communicated the knowledge of how far it processed back to us vs. being solely a consumer-of-input-and-producer-of-value. And perhaps it could be stylized to quote a BLOCK! and know it wasn't to be interpreted as a rule (?)
parse ${FFFF0001FFFFFF} [
some ${FF}
value: debin [BE + 2]
some ${FF}
]
As another issue: we can abstract this rule:
uint2: [debin [BE + 2]]
But then we might need to think about how would we abstract that to a UINT rule that took an N parameter, so we could write:
parse ${FFFF0001FFFFFF} [
some ${FF}
value: uint 2
some ${FF}
]
How Permissive Should PARSE Syntax Get?
Carl was concerned about the idea that PARSE rules were hard enough to understand as-is...and allowing you to call functions could make it worse.
I definitely empathize with the idea that one should be careful here. And up until now, I've been saying that the mechanism for doing abstraction of this sort is that you would always go through some kind of "abstraction operator"...tentatively :(...)
parse ${FFFF0001FFFFFF} [
some ${FF}
value: :(uint 2)
some ${FF}
]
I like having the option of being able to build a rule dynamically like that...off the cuff...from regular code. The example of being able to make LOGIC! expressions that way that control the continuation-or-not of the PARSE is particularly inspired, imo.
But I don't like being disallowed from doing such invocations without decorating them. Combinators are offering a way forward...so maybe if something is declared with the COMBINATOR generator then it is allowed if it is found via just normal binding.
A Lot To Think About...
It should be easy to encode and decode things into parse streams, and people should be able to plug in new decoders easily. Nice to be able to experiment and hack up ideas quickly...(!)