Open rezen opened 3 years ago
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.
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
);
}
}
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 newExpressionType
?