parsica
parsica copied to clipboard
Ternary operator
Wanted to move the discussion from Twitter to here. I looked at the source to evaluate making a PR, and processed through the docs and was struggling with a clear path for multiple reasons.
Firstly, ternary is almost always a ? b : c
, so do you implement with the expectation of those specific tokens? This is a minor question, and the answer is probably, no, don't expect specific tokens, the user provides those.
Secondly, all the current operators work with one symbol, not two and you need two or more symbols so all the Verraes\Parsica\Expression\*Assoc
classes would probably need to change? OR instead there would it be a new ExpressionType
?
Here are some forms of ternary operators to think about
-
if test do: when_true else: when_false
-
test ? when_true : when_false
-
when_true if test else when_false
Throwing out some rough code for handling more complex expressions - maybe that is the answer as opposed to a ternary operator?
<?php
use function Verraes\Parsica\Expression\compound;
// ...
compound(function ($previousPrecedenceLevel) {
return collect([
$token('if'),
$previousPrecedenceLevel,
$token('do:'),
$previousPrecedenceLevel,
$token('else:'),
$previousPrecedenceLevel,
])
->map(fn($v) => [$v[1], $v[3], $v[6]]);
})
->map(fn($test, $whenTrue, $whenFalse) => ... );
Thanks for this input.
Something else to consider: So far the expression handler can deal with expression operator expression
and variations. Ternaries are typically booleanExpr operator expression operator expression
. We'll need to consider whether the parser cares about the difference between booleanExpr and expression.
In math, a ternary operation has the type a -> a -> a -> a
, so everything is the same type.
In C-like PLs, the common pattern is bool -> a -> a -> a
but I see no reason why we should only support conditional ternaries.
https://en.wikipedia.org/wiki/Ternary_operation
#21 is an experiment to gain some insights into how ternary expressions could work.
In my case I didn't want to make a distinction between booleanExpr
vs expression
. I tried creating a custom ExpressionType
and so far it seems to work the way I would expect it.
class Ternary implements ExpressionType {
public function buildPrecedenceLevel(Parser $previousPrecedenceLevel): Parser
{
$question = keepFirst(char("?"), skipHSpace());
$colon = keepFirst(char(":"), skipHSpace());
return choice(
map(
collect(
$previousPrecedenceLevel->thenIgnore($question),
$previousPrecedenceLevel->thenIgnore($colon),
$previousPrecedenceLevel,
),
function(array $v) {
$tern = new _Ternary;
$tern->test = $v[0];
$tern->whenTrue = $v[1];
$tern->whenFalse = $v[2];
return $tern;
}
),
$previousPrecedenceLevel
);
}
}