this was a parsing idea I had a long time ago, and wanted to write down here because I think Zig will make it a lot easier!
we have this common pattern where the parser encounters something like this:
{ a, b }
in isolation, this looks like an expression. But after parsing some more, it might turn out to be a pattern:
{ a, b } =
{ a, b } ->
there is a ton of overlap between our pattern and expr nodes
not full overlap though - as
and |
are only allowed in patterns, function application is only allowed in exprs, etc.
but let's suppose we ignored those differences at the parsing stage, and said we had one node type called like ExprOrPattern
(ideally with a better name, but let's run with it for now)
and it supported as
, |
, function application, etc. - just a superset of all the things exprs and patterns can have
and then I believe there's a way in Zig (haven't looked into specifically how this would look) to customize the discriminant of the tag union, such that we can say both:
at that point, we can have all of these nodes begin life as an expr, and then later on when we discover it's a pattern (e.g. we encounter an =
) we just flip the bit on the node we've been working on
so we don't have to go back and reassemble anything, it just goes from being an ExprOrPattern
with the expr bit set to the same node but with the pattern bit set
then, later on in canonicalization, we can report errors like "you can't have |
in an expr" or "you can't have function application in a pattern"
this is separately consistent with our desire to have an error-tolerant parser
e.g. just because I have as
in an expr where it's not allowed, that shouldn't break the formatter
the formatter should still be able to know what to do there, we just need to report an error during canonicalization of "you can't do that here, maybe you want _________ instead?"
so this seems like it would simplify a bunch of logic we have now around discovering later that what looked like an expr actually turned out to be a pattern
bc we wouldn't have to build a Pattern
from an Expr
, we just flip a bit
anyway, curious what anyone thinks of this!
cc @Joshua Warner @Anthony Bullard
Including |
for patterns in the same parser as |args| body
closures will cause problems
hm true
:thinking: what if we changed those to or
?
like Foo or Bar(baz) ->
seems very self-descriptive!
I'm not sure if we actually need to include |
in the expression parser. I believe that's only used for when branches, where we can just call the expr parser with a flag saying to disallow closures, and then handle the |
in the when branch code.
That said, I would be fine with or
I know you would be against it more than likely Richard, but if the current |
were replaced with or
, then it could be repurposed to introducing a when branch and then there would be no amibiguity
Do you have thoughts here @Joshua Warner ?
That does make when parsing easier.
Looks weird to my eyes tho. (Subjective opinion!)
Pretty common in ML, though
Guess which language family I’ve spent the least time using :wink:
If pipe introduces branches, I’d have that also separate branch patterns
I wouldn’t mix pipe and or for that
Yeah, that's what other MLs do
I don’t think the pipe ambiguity will be a problem in practice here
But not Haskell (which is actually Miranda derived)
Huh; what does that use?
WSS
Or dear old friend
And to my memory (it's been a couple of years) it is NOT forgiving
case (x, y) of
(a, b) -> print ("x: " ++ show a ++ ", y: " ++ show b)
But
case (x, y) of
(a, b) -> print ("x: " ++ show a ++ ", y: " ++ show b)
WILL NOT parse if I remember correctly
Ahhh for some reason I thought you meant it used something else besides '|' to separate patterns
Yes that much matches my memory, given my (very limited) haskell experience
Last updated: Jul 06 2025 at 12:14 UTC