Call-back for arithmetic expression

@param ExpressionType $expressionType The type of arithmetic expression.
@param string         $left           The left expression.
@param string         $right          The left expression.

@return string
170466
public function onArithmeticExpression($expressionType, $left, $right) {
        switch ($expressionType) {
            case ExpressionType::MULTIPLY:
                return $this->_prepareBinaryExpression(self::MULTIPLY, $left, $right);
                break;
            case ExpressionType::DIVIDE:
                return $this->_prepareBinaryExpression(self::DIVIDE, $left, $right);
                break;
            case ExpressionType::MODULO:
                return $this->_prepareBinaryExpression(self::MODULO, $left, $right);
                break;
            case ExpressionType::ADD:
                return $this->_prepareBinaryExpression(self::ADD, $left, $right);
                break;
            case ExpressionType::SUBTRACT:
                return $this->_prepareBinaryExpression(self::SUBTRACT, $left, $right);
                break;
            default:
                throw new \InvalidArgumentException('onArithmeticExpression');
        }
    }
56605
public static function analyzeConcatOp(
        StatementsAnalyzer $statements_analyzer,
        PhpParser\Node\Expr $left,
        PhpParser\Node\Expr $right,
        Context $context,
        Type\Union &$result_type = null
    ) {
        $codebase = $statements_analyzer->getCodebase();

        $left_type = isset($left->inferredType) ? $left->inferredType : null;
        $right_type = isset($right->inferredType) ? $right->inferredType : null;
        $config = Config::getInstance();

        if ($context->infer_types
            && $left_type
            && $right_type
            && ($left_type->isMixed() || $right_type->isMixed())
        ) {
            $source_analyzer = $statements_analyzer->getSource();

            if ($source_analyzer instanceof FunctionLikeAnalyzer) {
                $function_storage = $source_analyzer->getFunctionLikeStorage($statements_analyzer);

                if ($left instanceof PhpParser\Node\Expr\Variable
                    && is_string($left->name)
                    && isset($left->inferredType)
                ) {
                    $context->inferType(
                        $left->name,
                        $function_storage,
                        $left->inferredType,
                        new Type\Union([new Type\Atomic\TString, new Type\Atomic\TInt]),
                        $codebase
                    );
                }

                if ($right instanceof PhpParser\Node\Expr\Variable
                    && is_string($right->name)
                    && isset($right->inferredType)
                ) {
                    $context->inferType(
                        $right->name,
                        $function_storage,
                        $right->inferredType,
                        new Type\Union([new Type\Atomic\TString, new Type\Atomic\TInt]),
                        $codebase
                    );
                }
            }
        }

        if ($left_type && $right_type) {
            $result_type = Type::getString();

            if ($left_type->hasMixed() || $right_type->hasMixed()) {
                if (!$context->collect_initializations
                    && !$context->collect_mutations
                    && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath()
                    && (!(($parent_source = $statements_analyzer->getSource())
                            instanceof \Psalm\Internal\Analyzer\FunctionLikeAnalyzer)
                        || !$parent_source->getSource() instanceof \Psalm\Internal\Analyzer\TraitAnalyzer)
                ) {
                    $codebase->analyzer->incrementMixedCount($statements_analyzer->getFilePath());
                }

                if ($left_type->hasMixed()) {
                    if (IssueBuffer::accepts(
                        new MixedOperand(
                            'Left operand cannot be mixed',
                            new CodeLocation($statements_analyzer->getSource(), $left)
                        ),
                        $statements_analyzer->getSuppressedIssues()
                    )) {
                        // fall through
                    }
                } else {
                    if (IssueBuffer::accepts(
                        new MixedOperand(
                            'Right operand cannot be mixed',
                            new CodeLocation($statements_analyzer->getSource(), $right)
                        ),
                        $statements_analyzer->getSuppressedIssues()
                    )) {
                        // fall through
                    }
                }

                return;
            }

            if (!$context->collect_initializations
                && !$context->collect_mutations
                && $statements_analyzer->getFilePath() === $statements_analyzer->getRootFilePath()
                && (!(($parent_source = $statements_analyzer->getSource())
                        instanceof \Psalm\Internal\Analyzer\FunctionLikeAnalyzer)
                    || !$parent_source->getSource() instanceof \Psalm\Internal\Analyzer\TraitAnalyzer)
            ) {
                $codebase->analyzer->incrementNonMixedCount($statements_analyzer->getFilePath());
            }

            if ($left_type->isNull()) {
                if (IssueBuffer::accepts(
                    new NullOperand(
                        'Cannot concatenate with a ' . $left_type,
                        new CodeLocation($statements_analyzer->getSource(), $left)
                    ),
                    $statements_analyzer->getSuppressedIssues()
                )) {
                    // fall through
                }

                return;
            }

            if ($right_type->isNull()) {
                if (IssueBuffer::accepts(
                    new NullOperand(
                        'Cannot concatenate with a ' . $right_type,
                        new CodeLocation($statements_analyzer->getSource(), $right)
                    ),
                    $statements_analyzer->getSuppressedIssues()
                )) {
                    // fall through
                }

                return;
            }

            if ($left_type->isFalse()) {
                if (IssueBuffer::accepts(
                    new FalseOperand(
                        'Cannot concatenate with a ' . $left_type,
                        new CodeLocation($statements_analyzer->getSource(), $left)
                    ),
                    $statements_analyzer->getSuppressedIssues()
                )) {
                    // fall through
                }

                return;
            }

            if ($right_type->isFalse()) {
                if (IssueBuffer::accepts(
                    new FalseOperand(
                        'Cannot concatenate with a ' . $right_type,
                        new CodeLocation($statements_analyzer->getSource(), $right)
                    ),
                    $statements_analyzer->getSuppressedIssues()
                )) {
                    // fall through
                }

                return;
            }

            if ($left_type->isNullable() && !$left_type->ignore_nullable_issues) {
                if (IssueBuffer::accepts(
                    new PossiblyNullOperand(
                        'Cannot concatenate with a possibly null ' . $left_type,
                        new CodeLocation($statements_analyzer->getSource(), $left)
                    ),
                    $statements_analyzer->getSuppressedIssues()
                )) {
                    // fall through
                }
            }

            if ($right_type->isNullable() && !$right_type->ignore_nullable_issues) {
                if (IssueBuffer::accepts(
                    new PossiblyNullOperand(
                        'Cannot concatenate with a possibly null ' . $right_type,
                        new CodeLocation($statements_analyzer->getSource(), $right)
                    ),
                    $statements_analyzer->getSuppressedIssues()
                )) {
                    // fall through
                }
            }

            if ($left_type->isFalsable() && !$left_type->ignore_falsable_issues) {
                if (IssueBuffer::accepts(
                    new PossiblyFalseOperand(
                        'Cannot concatenate with a possibly false ' . $left_type,
                        new CodeLocation($statements_analyzer->getSource(), $left)
                    ),
                    $statements_analyzer->getSuppressedIssues()
                )) {
                    // fall through
                }
            }

            if ($right_type->isFalsable() && !$right_type->ignore_falsable_issues) {
                if (IssueBuffer::accepts(
                    new PossiblyFalseOperand(
                        'Cannot concatenate with a possibly false ' . $right_type,
                        new CodeLocation($statements_analyzer->getSource(), $right)
                    ),
                    $statements_analyzer->getSuppressedIssues()
                )) {
                    // fall through
                }
            }

            $left_type_match = true;
            $right_type_match = true;

            $left_has_scalar_match = false;
            $right_has_scalar_match = false;

            $has_valid_left_operand = false;
            $has_valid_right_operand = false;

            foreach ($left_type->getTypes() as $left_type_part) {
                if ($left_type_part instanceof Type\Atomic\TTemplateParam) {
                    if (IssueBuffer::accepts(
                        new MixedOperand(
                            'Left operand cannot be mixed',
                            new CodeLocation($statements_analyzer->getSource(), $left)
                        ),
                        $statements_analyzer->getSuppressedIssues()
                    )) {
                        // fall through
                    }

                    return;
                }

                if ($left_type_part instanceof Type\Atomic\TNull || $left_type_part instanceof Type\Atomic\TFalse) {
                    continue;
                }

                $left_type_part_match = TypeAnalyzer::isAtomicContainedBy(
                    $codebase,
                    $left_type_part,
                    new Type\Atomic\TString,
                    false,
                    false,
                    $left_has_scalar_match,
                    $left_type_coerced,
                    $left_type_coerced_from_mixed,
                    $left_to_string_cast
                );

                $left_type_match = $left_type_match && $left_type_part_match;

                $has_valid_left_operand = $has_valid_left_operand || $left_type_part_match;

                if ($left_to_string_cast && $config->strict_binary_operands) {
                    if (IssueBuffer::accepts(
                        new ImplicitToStringCast(
                            'Left side of concat op expects string, '
                                . '\'' . $left_type . '\' provided with a __toString method',
                            new CodeLocation($statements_analyzer->getSource(), $left)
                        ),
                        $statements_analyzer->getSuppressedIssues()
                    )) {
                        // fall through
                    }
                }
            }

            foreach ($right_type->getTypes() as $right_type_part) {
                if ($right_type_part instanceof Type\Atomic\TTemplateParam) {
                    if (IssueBuffer::accepts(
                        new MixedOperand(
                            'Right operand cannot be a template param',
                            new CodeLocation($statements_analyzer->getSource(), $right)
                        ),
                        $statements_analyzer->getSuppressedIssues()
                    )) {
                        // fall through
                    }

                    return;
                }

                if ($right_type_part instanceof Type\Atomic\TNull || $right_type_part instanceof Type\Atomic\TFalse) {
                    continue;
                }

                $right_type_part_match = TypeAnalyzer::isAtomicContainedBy(
                    $codebase,
                    $right_type_part,
                    new Type\Atomic\TString,
                    false,
                    false,
                    $right_has_scalar_match,
                    $right_type_coerced,
                    $right_type_coerced_from_mixed,
                    $right_to_string_cast
                );

                $right_type_match = $right_type_match && $right_type_part_match;

                $has_valid_right_operand = $has_valid_right_operand || $right_type_part_match;

                if ($right_to_string_cast && $config->strict_binary_operands) {
                    if (IssueBuffer::accepts(
                        new ImplicitToStringCast(
                            'Right side of concat op expects string, '
                                . '\'' . $right_type . '\' provided with a __toString method',
                            new CodeLocation($statements_analyzer->getSource(), $right)
                        ),
                        $statements_analyzer->getSuppressedIssues()
                    )) {
                        // fall through
                    }
                }
            }

            if (!$left_type_match && (!$left_has_scalar_match || $config->strict_binary_operands)) {
                if ($has_valid_left_operand) {
                    if (IssueBuffer::accepts(
                        new PossiblyInvalidOperand(
                            'Cannot concatenate with a ' . $left_type,
                            new CodeLocation($statements_analyzer->getSource(), $left)
                        ),
                        $statements_analyzer->getSuppressedIssues()
                    )) {
                        // fall through
                    }
                } else {
                    if (IssueBuffer::accepts(
                        new InvalidOperand(
                            'Cannot concatenate with a ' . $left_type,
                            new CodeLocation($statements_analyzer->getSource(), $left)
                        ),
                        $statements_analyzer->getSuppressedIssues()
                    )) {
                        // fall through
                    }
                }
            }

            if (!$right_type_match && (!$right_has_scalar_match || $config->strict_binary_operands)) {
                if ($has_valid_right_operand) {
                    if (IssueBuffer::accepts(
                        new PossiblyInvalidOperand(
                            'Cannot concatenate with a ' . $right_type,
                            new CodeLocation($statements_analyzer->getSource(), $right)
                        ),
                        $statements_analyzer->getSuppressedIssues()
                    )) {
                        // fall through
                    }
                } else {
                    if (IssueBuffer::accepts(
                        new InvalidOperand(
                            'Cannot concatenate with a ' . $right_type,
                            new CodeLocation($statements_analyzer->getSource(), $right)
                        ),
                        $statements_analyzer->getSuppressedIssues()
                    )) {
                        // fall through
                    }
                }
            }
        }
        // When concatenating two known string literals (with only one possibility),
        // put the concatenated string into $result_type
        if ($left_type && $right_type && $left_type->isSingleStringLiteral() && $right_type->isSingleStringLiteral()) {
            $literal = $left_type->getSingleStringLiteral()->value . $right_type->getSingleStringLiteral()->value;
            if (strlen($literal) <= 1000) {
                // Limit these to 10000 bytes to avoid extremely large union types from repeated concatenations, etc
                $result_type = Type::getString($literal);
            }
        }
    }
1059599
public final <A extends Number & Comparable<?>> BooleanExpression loe(Expression<A> right) {
        return Expressions.booleanOperation(Ops.LOE, mixin, right);
    }
389176
final public static function binaryOperation(Expression $leftOperand, $operator, Expression $rightOperand)
    {
        return new BinaryOperationExpression(
                $leftOperand,
                $operator,
                $rightOperand);
    }
1032760
public function condition(Expression $left, Expression $right, $comparator, $conjunction = Cmp::CONJUNCTION_AND)
    {
        $this->getWhereStatement()->add($left, $right, $comparator, $conjunction);
        
        return $this;
    }
1133837
public static function add(Expr $left, Expr $right) : BinOp
    {
        return new BinOp($left, BinOp::ADD, $right);
    }
350527
public function onLogicalExpression($expressionType, $left, $right)
    {
        $type = $this->unpackExpressionType($expressionType);
        switch ($type) {
            case ExpressionType::AND_LOGICAL:
                return $this->prepareBinaryExpression(self::LOGICAL_AND, $left, $right);
            case ExpressionType::OR_LOGICAL:
                return $this->prepareBinaryExpression(self::LOGICAL_OR, $left, $right);
            default:
                throw new \InvalidArgumentException('onLogicalExpression');
        }
    }
184566
private function getExressionValue($expressionType)
    {
        if (!array_key_exists($expressionType, $this->expressionValues)) {
            $expressions = $this->getExpressions();
            $likeIndex = null;

            /* @var $expr Expression */
            foreach ($expressions as $index => $expr) {
                if ($expr->getExpression() === $expressionType) {
                    $likeIndex = $index;
                    break;
                }
            }

            if (!$likeIndex) {
                return null;
            }

            /* @var $field Expression */
            $field = $expressions[$likeIndex + 1];
            $this->expressionValues[$expressionType] = $field->getExpression();
            $noQuotes = $field->getNoQuotes();

            if ($noQuotes) {
                $this->expressionValues[$expressionType] = $noQuotes->getPartsAsString();
            }
        }

        return $this->expressionValues[$expressionType];
    }
1201682
private double doubleValue( double left, double right ) {
        switch( operator ) {
            case '+':
                return left + right;
            case '-':
                return left - right;
            case '*':
                return left * right;
            case '/':
                return left / right;
            default:
                throw createException( "Not supported Oprator '" + operator + "' for Expression '" + toString() + '\'' );
        }
    }
1288412
function where($left, $operator = Query::EQUAL, $right = null, $quote = null) {
		if (func_num_args() === 1) {
			return $this->addAnd($left);
		}
		return $this->addAnd($left, $right, $operator, $quote);
	}
736758
public static function or_(Expr $left, Expr $right) : BinOp
    {
        return new BinOp($left, BinOp::OR_, $right);
    }
1203882
public function visitExpressionNode(ExpressionNode $node)
    {
        $leftValue = $node->getLeft()->accept($this);
        $operator = $node->getOperator();

        // The operator and the right side are optional, remember?
        if (!$operator)
            return "$leftValue";

        $right = $node->getRight();

        if ($right) {
            $rightValue = $node->getRight()->accept($this);
            return "($operator, $leftValue, $rightValue)";
        } else {
            return "($operator, $leftValue)";
        }

    }
1022546
public function getNewCondition(Expression $left, Expression $right, $comparator)
    {
        switch ($comparator) {
            
            case Cmp::EQ:
            case Cmp::NEQ:
            case Cmp::NEQA:
            case Cmp::GT:
            case Cmp::GTE:
            case Cmp::LT:
            case Cmp::LTE:
                return new Comparison\Logical($this->getBuilder(), $left, $right, $comparator);
            
            case Cmp::LIKE:
            case Cmp::NOT_LIKE:
                return new Comparison\Like($this->getBuilder(), $left, $right, $comparator);
            
            case Cmp::IN:
            case Cmp::NOT_IN:
                return new Comparison\In($this->getBuilder(), $left, $right, $comparator);
            
            case Cmp::IS_NULL:
            case Cmp::NOT_IS_NULL:
                return new Comparison\IsNull($this->getBuilder(), $left, $right, $comparator);
            
            case Cmp::RAW:
                return new Comparison\Custom($this->getBuilder(), $left, $right);
            
            default:
                throw new BadArgumentException('Comparator ":comparator" not defined', [
                    'comparator' => $comparator,
                ]);
        }
    }
872215
private function doubleExponentiation($leftOperand, $rightOperand)
    {
        // (x^a)^b -> x^(ab) for a, b numbers
        if ($leftOperand instanceof ExpressionNode && $leftOperand->getOperator() == '^') {

            $factory = new MultiplicationNodeFactory();
            $power = $factory->makeNode($leftOperand->getRight(), $rightOperand);

            $base = $leftOperand->getLeft();
            return self::makeNode($base,  $power);
        }

        // No simplification found
        return null;
    }
299914
public function having($left, $right, $comparator = Cmp::EQ, $conjunction = Cmp::CONJUNCTION_AND)
    {
        $left = ($left instanceof Expression) ? $left : new Expr\Column($left);
        $right = ($right instanceof Expression) ? $right : new Expr\Parameter($right);
        
        return $this->addHavingCondition($left, $right, $comparator, $conjunction);
    }
542862
public static Add add(Expression<Number> left, Expression<Number> right) {
        return new Add(left, right);
    }
117657
public static function greaterThanOrEqual(Expr $left, Expr $right) : BinOp
    {
        return new BinOp($left, BinOp::GREATER_THAN_OR_EQUAL, $right);
    }