parsica icon indicating copy to clipboard operation
parsica copied to clipboard

Ternary operator

Open rezen opened this issue 4 years ago • 6 comments

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?

rezen avatar Dec 14 '20 23:12 rezen

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

rezen avatar Dec 14 '20 23:12 rezen

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) => ... );

rezen avatar Dec 14 '20 23:12 rezen

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.

mathiasverraes avatar Dec 19 '20 09:12 mathiasverraes

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

mathiasverraes avatar Dec 19 '20 09:12 mathiasverraes

#21 is an experiment to gain some insights into how ternary expressions could work.

mathiasverraes avatar Dec 19 '20 11:12 mathiasverraes

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
        );
    }
}

rezen avatar Dec 21 '20 21:12 rezen