Adds parentheses to the inner parts of ternary operators in
plural expressions, because PHP evaluates ternary operators
from left to right.

@param string $expression the expression without parentheses

@return string the expression with parentheses added
543555
public function parenthesize_plural_exression($expression)
    {
        $expression .= ';';
        $res = '';
        $depth = 0;
        for ($i = 0; $i < strlen($expression); ++$i) {
            $char = $expression[$i];
            switch ($char) {
                case '?':
                    $res .= ' ? (';
                    $depth++;
                    break;
                case ':':
                    $res .= ') : (';
                    break;
                case ';':
                    $res .= str_repeat(')', $depth) . ';';
                    $depth = 0;
                    break;
                default:
                    $res .= $char;
            }
        }

        return rtrim($res, ';');
    }
76751
public function setExpression($expression)
    {
        if (is_string($expression)) {
            $expression = CronExpression::factory($expression);
        }

        $this->expression = $expression;

        return $this;
    }
808382
public function setExpression(Expression $expression)
    {
        $this->map['expressions']->set($expression->hashCode(), $expression->setBuilder($this));
        
        return $this;
    }
1318851
public function addExpression($expression)
    {
        if (!$this->expressions->contains($expression)) {
            $this->expressions[] = $expression;
        }

        return $this;
    }
313008
private static function buildRegex(string $expression, bool $is_prefix = false) : string
    {
        $regex  = self::REGEX_DELIMITER . '^';
        $regex .= preg_replace(array_keys(self::$datatypes), self::$datatypes, $expression);
        $regex .= $is_prefix ? '(.*)' : '';
        $regex .= '$' . self::REGEX_DELIMITER;
        return $regex;
    }
949636
private function parseExpression($expression)
    {
        $result = array();

        if (isset(self::$operatorHash[$expression[0]])) {
            $result['operator'] = $expression[0];
            $expression = substr($expression, 1);
        } else {
            $result['operator'] = '';
        }

        foreach (explode(',', $expression) as $value) {
            $value = trim($value);
            $varspec = array();
            if ($colonPos = strpos($value, ':')) {
                $varspec['value'] = substr($value, 0, $colonPos);
                $varspec['modifier'] = ':';
                $varspec['position'] = (int) substr($value, $colonPos + 1);
            } elseif (substr($value, -1) == '*') {
                $varspec['modifier'] = '*';
                $varspec['value'] = substr($value, 0, -1);
            } else {
                $varspec['value'] = (string) $value;
                $varspec['modifier'] = '';
            }
            $result['values'][] = $varspec;
        }

        return $result;
    }
357499
public function compileForeach($expression)
    {
        $expression = $this->normalizeExpression($expression);
        
        preg_match('/ *(.*) +as *(.*)$/is', $expression, $matches);
        
        $iteratee = trim($matches[1]);
        $iteration = trim($matches[2]);
        $initLoop = '$loop = new ' . Counter::class . "(); \$__currentLoopData = \$loop->loop({$iteratee}); \$__loops->addLoop(\$__currentLoopData);";
        
        return "<?php {$initLoop} foreach(\$loop as {$iteration}): ?>";
    }
1223966
private function truncateCronExpression(string $expression): string
    {
        $expressionParts = preg_split('/\s/', $expression, -1, PREG_SPLIT_NO_EMPTY);
        if (count($expressionParts) === 5) {
            return $expression;
        }

        $expressionParts = array_slice($expressionParts, 0, 5);
        return implode(' ', $expressionParts);
    }
9091
public function addGroupBy(string ...$expression) : self
    {
        $this->groupByClauses = array_merge($this->groupByClauses, $expression);

        return $this;
    }
68351
public function addAnd($expression, ...$expressions) : self
    {
        if (! isset($this->query['$and'])) {
            $this->query['$and'] = [];
        }

        $this->query['$and'] = array_merge(
            $this->query['$and'],
            array_map(
                static function ($expression) {
                    return $expression instanceof Expr ? $expression->getQuery() : $expression;
                },
                func_get_args()
            )
        );

        return $this;
    }
175548
protected function compileForeach($expression)
    {
        preg_match('/\( *(.*) +as *(.*)\)$/is', $expression, $matches);

        $iteratee = trim($matches[1]);

        $iteration = trim($matches[2]);

        $initLoop = "\$__currentLoopData = {$iteratee}; \$__env->addLoop(\$__currentLoopData);";

        $iterateLoop = '$__env->incrementLoopIndices(); $loop = $__env->getLastLoop();';

        return "<?php {$initLoop} foreach(\$__currentLoopData as {$iteration}): {$iterateLoop} ?>";
    }
56760
protected function buildExpression(Expression $expression)
    {
        $template = $expression instanceof Subquery ? '(%s)' : '%s';
        $expressionString = $this->stringifyExpression($expression);
        
        return trim(sprintf($template, $expressionString));
    }
114864
protected function compileLoopStack($expression)
    {
        foreach ($this->getLoopStack() as $token) {
            $out = $this->{'compile'.$token}($expression);

            if (strlen($out) !== 0) {
                $expression = $out;
            }
        }

        return $expression;
    }
127253
public static function parse($expression)
    {
        if (trim($expression) === '') {
            throw new InvalidArgumentException('Console command definition is empty.');
        }

        preg_match('/[^\s]+/', $expression, $matches);

        if (isset($matches[0])) {
            $name = $matches[0];
        } else {
            throw new InvalidArgumentException('Unable to determine command name from signature.');
        }

        preg_match_all('/\{\s*(.*?)\s*\}/', $expression, $matches);

        $tokens = isset($matches[1]) ? $matches[1] : [];

        if (count($tokens)) {
            return array_merge([$name], static::parameters($tokens));
        }

        return [$name, [], []];
    }
4451
public function evaluateExpression($expression)
    {
        if ($this->getTalesMode() === 'php') {
            return PHPTAL_Php_TalesInternal::php($expression);
        }
        return PHPTAL_Php_TalesInternal::compileToPHPExpressions($expression, false);
    }
381000
private function compileTalesToPHPExpression($expression)
    {
        if ($this->getTalesMode() === 'php') {
            return PHPTAL_Php_TalesInternal::php($expression);
        }
        return PHPTAL_Php_TalesInternal::compileToPHPExpression($expression, false);
    }
950537
protected function compileExtends($expression)
    {
        $regex = "/\#extends\s*\(((?:\n|\s|\t)*(?:.+?)(?:\n|\s|\t)*)\)/sm";

        if (preg_match($regex, $expression, $match)) {
            $this->footer[] = "<?php echo \$__tintin->getStackManager()->includeFile({$match[1]}, ['__tintin' => \$__tintin]); ?>";

            return ' ';
        }

        return $expression;
    }