@param mixed|self $expression

@return mixed
494717
private function ensureArray($expression)
    {
        if (is_string($expression) && substr($expression, 0, 1) === '$') {
            return '$' . $this->getDocumentPersister()->prepareFieldName(substr($expression, 1));
        } elseif (is_array($expression)) {
            return array_map([$this, 'ensureArray'], $expression);
        } elseif ($expression instanceof self) {
            return $expression->getExpression();
        }

        // Convert PHP types to MongoDB types for everything else
        return Type::convertPHPToDatabaseValue($expression);
    }
523136
public function normalizeExpression(Expression $expression)
    {
        $expression = $this->preProcessExpression($expression);
        
        switch (true) {
            // if has array parameters expression handle it recursively
            // if function expression extract from it all parameters and handle its
            case $expression instanceof Expr\Parameters:
            case $expression instanceof Expr\Func:
                
                $parameters = ($expression instanceof Expr\Func)
                    ? (new Expr\Parameters($expression->getParameters()))->getParameters()
                    : $expression->getParameters();
                
                foreach ($parameters as &$parameter) {
                    $parameter = $this->normalizeExpression($parameter);
                }
                
                $expression->setParameters($parameters);
                
                break;
            
            case $expression instanceof Expr\Table:
                
                if ($this->isReplaceAliases() === true) {
                    // replace table alias to real table name
                    if ($this->hasTableAlias($expression->getName())) {
                        $expression = $this->getTableByAlias($expression->getName());
                    }
                }
                
                break;
            
            // for column process it alias and real table if exist
            case $expression instanceof Expr\Column:
                
                if ($this->isReplaceAliases() === true) {
                    // replace column alias to real column name
                    if ($this->hasColumnAlias($expression->getName())) {
                        $expression = $this->getColumnByAlias($expression->getName());
                    }
                }
                
                break;
        }
        
        $expression = $this->postProcessExpression($expression);
        
        return $expression;
    }
215709
public function then($expression) : self
    {
        if (! is_array($this->switchBranch)) {
            throw new BadMethodCallException(static::class . '::then requires a valid case statement (call case() first).');
        }

        $this->switchBranch['then'] = $expression;

        if ($this->currentField) {
            $this->expr[$this->currentField]['$switch']['branches'][] = $this->ensureArray($this->switchBranch);
        } else {
            $this->expr['$switch']['branches'][] = $this->ensureArray($this->switchBranch);
        }

        $this->switchBranch = null;

        return $this;
    }
173893
public function getValueForOperand($expression)
    {
        if (is_array($expression)) {
            $result = [];
            foreach ($expression as $expressionEntry) {
                $result[] = $this->getValueForOperand($expressionEntry);
            }
            return $result;
        } elseif (is_numeric($expression)) {
            return $expression;
        } elseif ($expression === true) {
            return true;
        } elseif ($expression === false) {
            return false;
        } elseif ($expression === null) {
            return null;
        } elseif (strpos($expression, 'context.') === 0) {
            $objectAccess = explode('.', $expression, 3);
            $globalObjectsRegisteredClassName = $this->globalObjects[$objectAccess[1]];
            $globalObject = $this->objectManager->get($globalObjectsRegisteredClassName);
            $this->securityContext->withoutAuthorizationChecks(function () use ($globalObject, $objectAccess, &$globalObjectValue) {
                $globalObjectValue = $this->getObjectValueByPath($globalObject, $objectAccess[2]);
            });

            return $globalObjectValue;
        } else {
            return trim($expression, '"\'');
        }
    }
689276
public function walkCaseExpression($expression)
    {
        switch (true) {
            case ($expression instanceof AST\CoalesceExpression):
                return $this->walkCoalesceExpression($expression);

            case ($expression instanceof AST\NullIfExpression):
                return $this->walkNullIfExpression($expression);

            case ($expression instanceof AST\GeneralCaseExpression):
                return $this->walkGeneralCaseExpression($expression);

            case ($expression instanceof AST\SimpleCaseExpression):
                return $this->walkSimpleCaseExpression($expression);

            default:
                return '';
        }
    }
684976
public function andWhere(Expression $expression) : self
    {
        if ($this->expression === null) {
            return $this->where($expression);
        }

        $this->expression = new CompositeExpression(
            CompositeExpression::TYPE_AND,
            [$this->expression, $expression]
        );

        return $this;
    }
524599
public function setExpr($expression) {
		$this->valueList = func_get_args();
		$this->expression = array_shift($this->valueList);
		return $this;
	}
529575
public function eq($expression1, $expression2) : self
    {
        $this->expr->eq($expression1, $expression2);

        return $this;
    }
817482
public function withExpression(string $expression): self
    {
        if (!(new \ReflectionClass($expression))->implementsInterface(Expression::class)) {
            throw new DomainException($expression);
        }

        $self = clone $this;
        $self->expression = new $expression($self->name);

        return $self;
    }
695375
public function compile($expression, CompilationContext $compilationContext)
    {
        $conditions = $this->optimizeTypeOf($expression, $compilationContext);
        if (false !== $conditions) {
            return $conditions;
        }

        if (!isset($expression['left'])) {
            throw new CompilerException('Missing left part of the expression', $expression);
        }

        if (!isset($expression['right'])) {
            throw new CompilerException('Missing right part of the expression', $expression);
        }

        $leftExpr = new Expression($expression['left']);
        $leftExpr->setReadOnly(true);
        $left = $leftExpr->compile($compilationContext);

        $rightExpr = new Expression($expression['right']);
        $rightExpr->setReadOnly(true);
        $right = $rightExpr->compile($compilationContext);

        switch ($left->getType()) {
            case 'null':
                switch ($right->getType()) {
                    case 'null':
                        return new CompiledExpression('bool', '(0 '.$this->operator.' 0)', $expression);

                    case 'int':
                    case 'uint':
                    case 'long':
                    case 'ulong':
                        return new CompiledExpression('bool', '(0 '.$this->operator.' '.$right->getCode().')', $expression);

                    case 'char':
                    case 'uchar':
                        return new CompiledExpression('bool', '(\'\\0\' '.$this->operator.' \''.$right->getCode().'\')', $expression);

                    case 'double':
                        return new CompiledExpression('bool', '(0 '.$this->operator.' (int) '.$right->getCode().')', $expression);

                    case 'variable':
                        $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                        switch ($variableRight->getType()) {
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                            case 'double':
                                $compilationContext->headersManager->add('kernel/operators');

                                return new CompiledExpression('bool', '0 '.$this->operator.' '.$variableRight->getName(), $expression);

                            case 'variable':
                                $compilationContext->headersManager->add('kernel/operators');
                                $condition = $compilationContext->backend->getTypeofCondition($variableRight, $this->operator, 'null', $compilationContext);

                                return new CompiledExpression('bool', $condition, $expression);

                            default:
                                throw new CompilerException('Unknown type: '.$variableRight->getType(), $expression['right']);
                        }
                        break;

                    default:
                        throw new CompilerException('Unknown type: '.$right->getType(), $expression);
                }
                break;

            case 'int':
            case 'uint':
            case 'long':
            case 'double':
            case 'ulong':
            case 'char':
            case 'uchar':
                switch ($right->getType()) {
                    case 'null':
                        return new CompiledExpression('bool', $left->getCode().' '.$this->operator, $expression);

                    case 'int':
                    case 'uint':
                    case 'long':
                    case 'ulong':
                        return new CompiledExpression('bool', $left->getCode().' '.$this->operator.' '.$right->getCode(), $expression);

                    case 'char':
                    case 'uchar':
                        return new CompiledExpression('bool', $left->getCode().' '.$this->operator.' \''.$right->getCode().'\'', $expression);

                    case 'double':
                        return new CompiledExpression('bool', $left->getCode().' '.$this->operator.' (int) '.$right->getCode(), $expression);

                    case 'variable':
                        $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                        switch ($variableRight->getType()) {
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                            case 'double':
                                $compilationContext->headersManager->add('kernel/operators');

                                return new CompiledExpression('bool', $left->getCode().' '.$this->operator.' '.$variableRight->getName(), $expression);

                            case 'variable':
                                $compilationContext->headersManager->add('kernel/operators');
                                $variableCode = $compilationContext->backend->getVariableCode($variableRight);

                                return new CompiledExpression('bool', $this->zvalLongNegOperator.'('.$variableCode.', '.$left->getCode().')', $expression);

                            default:
                                throw new CompilerException('Unknown type: '.$variableRight->getType(), $expression['right']);
                        }
                        break;

                    default:
                        throw new CompilerException('Cannot compare '.$left->getType().' with '.$right->getType(), $expression);
                }
                break;

            case 'bool':
                switch ($right->getType()) {
                    case 'null':
                        return new CompiledExpression('bool', $left->getBooleanCode().' '.$this->operator.' 0', $expression);

                    case 'int':
                    case 'uint':
                    case 'long':
                    case 'ulong':
                        return new CompiledExpression('bool', $left->getBooleanCode().' '.$this->operator.' '.$right->getCode(), $expression);

                    case 'char':
                    case 'uchar':
                        return new CompiledExpression('bool', $left->getBooleanCode().' '.$this->operator.' \''.$right->getCode().'\'', $expression);

                    case 'double':
                        return new CompiledExpression('bool', $left->getBooleanCode().' '.$this->operator.' (int) '.$right->getCode(), $expression);

                    case 'bool':
                        return new CompiledExpression('bool', $left->getBooleanCode().' '.$this->operator.' '.$right->getBooleanCode(), $expression);

                    case 'variable':
                        $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                        switch ($variableRight->getType()) {
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                            case 'double':
                                $compilationContext->headersManager->add('kernel/operators');

                                return new CompiledExpression('bool', $left->getBooleanCode().' '.$this->operator.' '.$variableRight->getName(), $expression);

                            case 'variable':
                                $compilationContext->headersManager->add('kernel/operators');
                                $boolOperator = '1' == $left->getBooleanCode() ? $this->zvalBoolTrueOperator : $this->zvalBoolFalseOperator;
                                $variableRight = $compilationContext->backend->getVariableCode($variableRight);

                                return new CompiledExpression('bool', $boolOperator.'('.$variableRight.')', $expression);
                            default:
                                throw new CompilerException('Unknown type: '.$variableRight->getType(), $expression['right']);
                        }
                        break;

                    default:
                        throw new CompilerException('Cannot compare '.$left->getType().' with '.$right->getType(), $expression);
                }
                break;

            case 'string':
                $variableLeft = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $expression);
                $variableLeftCode = $compilationContext->backend->getVariableCode($variableLeft);
                $compilationContext->backend->assignString($variableLeft, $left->getCode(), $compilationContext, true, false);
                switch ($right->getType()) {
                    case 'string':
                    case 'null':
                        $rightStr = 'null' == $right->getType() ? '' : $right->getCode();
                        $compilationContext->headersManager->add('kernel/operators');

                        return new CompiledExpression('bool', $this->zvalStringOperator.'('.$variableLeftCode.', "'.$rightStr.'")', $expression['left']);
                        break;

                    case 'variable':
                        $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                        switch ($variableRight->getType()) {
                            case 'string':
                            case 'variable':
                                $compilationContext->headersManager->add('kernel/operators');
                                $variableRight = $compilationContext->backend->getVariableCode($variableRight);

                                return new CompiledExpression('bool', $this->zvalOperator.'('.$variableLeftCode.', '.$variableRight.')', $expression);
                                break;

                            default:
                                throw new CompilerException('Unknown type: '.$variableRight->getType(), $expression['right']);
                        }
                        break;

                    default:
                        throw new CompilerException('Unknown type: '.$right->getType(), $expression['left']);
                }
                break;

            case 'variable':
                $variable = $compilationContext->symbolTable->getVariableForRead($left->getCode(), $compilationContext, $expression['left']);
                $variableCode = $compilationContext->backend->getVariableCode($variable);
                switch ($variable->getType()) {
                    case 'int':
                    case 'uint':
                    case 'long':
                    case 'ulong':
                    case 'char':
                    case 'uchar':
                        switch ($right->getType()) {
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                            case 'double':
                                return new CompiledExpression('bool', $left->getCode().' '.$this->operator.' '.$right->getCode(), $expression);

                            case 'char':
                            case 'uchar':
                                return new CompiledExpression('bool', $left->getCode().' '.$this->operator.' \''.$right->getCode().'\'', $expression);

                            case 'bool':
                                return new CompiledExpression('bool', $left->getCode().' '.$this->operator.' '.$right->getBooleanCode(), $expression);

                            case 'variable':
                                $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                                switch ($variableRight->getType()) {
                                    case 'int':
                                    case 'uint':
                                    case 'long':
                                    case 'ulong':
                                    case 'char':
                                    case 'uchar':
                                    case 'double':
                                        return new CompiledExpression('bool', $variable->getName().' '.$this->operator.' '.$variableRight->getName(), $expression);

                                    case 'variable':
                                        $compilationContext->headersManager->add('kernel/operators');
                                        $variableRightCode = $compilationContext->backend->getVariableCode($variableRight);
                                        $variableCode = $compilationContext->backend->getVariableCode($variable);

                                        return new CompiledExpression('bool', $this->zvalLongNegOperator.'('.$variableRightCode.', '.$variableCode.')', $expression);
                                        break;

                                    default:
                                        throw new CompilerException('Unknown type: '.$variableRight->getType(), $expression['right']);
                                }
                                break;

                            default:
                                throw new CompilerException('Cannot compare variable: '.$variable->getType().' with: '.$right->getType(), $expression);
                        }
                        break;

                    case 'double':
                        switch ($right->getType()) {
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                            case 'double':
                                return new CompiledExpression('bool', $left->getCode().' '.$this->operator.' '.$right->getCode(), $expression);

                            case 'bool':
                                return new CompiledExpression('bool', $left->getCode().' '.$this->operator.' '.$right->getBooleanCode(), $expression);

                            case 'char':
                            case 'uchar':
                                return new CompiledExpression('bool', $left->getCode().' '.$this->operator.' \''.$right->getCode().'\'', $expression);

                            case 'variable':
                                $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                                switch ($variableRight->getType()) {
                                    case 'int':
                                    case 'uint':
                                    case 'long':
                                    case 'ulong':
                                    case 'double':
                                        return new CompiledExpression('bool', $variable->getName().' '.$this->operator.' '.$variableRight->getName(), $expression);

                                    case 'variable':
                                        $compilationContext->headersManager->add('kernel/operators');
                                        $variableRightCode = $compilationContext->backend->getVariableCode($variableRight);
                                        $variableCode = $compilationContext->backend->getVariableCode($variable);

                                        return new CompiledExpression('bool', $this->zvalDoubleNegOperator.'('.$variableRightCode.', '.$variableCode.')', $expression);

                                    default:
                                        throw new CompilerException('Unknown type: '.$variableRight->getType(), $expression['right']);
                                }
                                break;

                            default:
                                throw new CompilerException('Cannot compare variable: '.$variable->getType().' with: '.$right->getType(), $expression);
                        }
                        break;

                    case 'bool':
                        switch ($right->getType()) {
                            case 'int':
                                return new CompiledExpression('bool', $left->getCode().' '.$this->operator.' '.$right->getCode(), $expression['left']);

                            case 'bool':
                                return new CompiledExpression('bool', $left->getCode().' '.$this->operator.' '.$right->getBooleanCode(), $expression['left']);

                            case 'null':
                                return new CompiledExpression('bool', $left->getCode().' '.$this->operator.' 0', $expression['left']);

                            case 'variable':
                                $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);

                                switch ($variableRight->getType()) {
                                    case 'int':
                                    case 'uint':
                                    case 'long':
                                    case 'ulong':
                                    case 'bool':
                                    case 'double':
                                        return new CompiledExpression('bool', $variable->getName().' '.$this->operator.' '.$variableRight->getName(), $expression);

                                    case 'variable':
                                        $compilationContext->headersManager->add('kernel/operators');
                                        $boolOperator = '1' == $left->getBooleanCode() ? $this->zvalBoolTrueOperator : $this->zvalBoolFalseOperator;
                                        $variableRightCode = $compilationContext->backend->getVariableCode($variableRight);

                                        return new CompiledExpression('bool', $boolOperator.'('.$variableRightCode.')', $expression);

                                    default:
                                        throw new CompilerException('Unknown type: '.$variableRight->getType(), $expression['right']);
                                }
                                break;

                            default:
                                throw new CompilerException('Cannot compare variable: '.$variable->getType().' with: '.$right->getType(), $expression);
                        }
                        break;

                    case 'array':
                        switch ($right->getType()) {
                            case 'null':
                                $compilationContext->headersManager->add('kernel/operators');

                                return new CompiledExpression('bool', $this->zvalStringOperator.'('.$variableCode.', "")', $expression['left']);

                            case 'variable':
                                $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                                switch ($variableRight->getType()) {
                                    case 'string':
                                    case 'variable':
                                    case 'array':
                                        $compilationContext->headersManager->add('kernel/operators');
                                        $variableRight = $compilationContext->backend->getVariableCode($variableRight);

                                        return new CompiledExpression('bool', $this->zvalOperator.'('.$variableCode.', '.$variableRight.')', $expression);

                                    default:
                                        throw new CompilerException('Unknown type: '.$variableRight->getType(), $expression['right']);
                                }
                                break;

                            default:
                                throw new CompilerException('Unknown type: '.$right->getType(), $expression['left']);
                        }
                        break;

                    case 'string':
                        switch ($right->getType()) {
                            case 'null':
                                $compilationContext->headersManager->add('kernel/operators');

                                return new CompiledExpression('bool', $this->zvalStringOperator.'('.$variableCode.', "")', $expression['left']);

                            case 'string':
                                $compilationContext->headersManager->add('kernel/operators');

                                return new CompiledExpression('bool', $this->zvalStringOperator.'('.$variableCode.', "'.$right->getCode().'")', $expression['left']);

                            case 'variable':
                                $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                                switch ($variableRight->getType()) {
                                    case 'string':
                                    case 'variable':
                                        $compilationContext->headersManager->add('kernel/operators');
                                        $variableRight = $compilationContext->backend->getVariableCode($variableRight);

                                        return new CompiledExpression('bool', $this->zvalOperator.'('.$variableCode.', '.$variableRight.')', $expression);

                                    default:
                                        throw new CompilerException('Unknown type: '.$variableRight->getType(), $expression['right']);
                                }
                                break;

                            default:
                                throw new CompilerException('Unknown type: '.$right->getType(), $expression['left']);
                        }
                        break;

                    case 'variable':
                        switch ($right->getType()) {
                            case 'null':
                                $compilationContext->headersManager->add('kernel/operators');
                                $condition = $compilationContext->backend->getTypeofCondition($variable, $this->operator, 'null', $compilationContext);

                                return new CompiledExpression('bool', $condition, $expression['left']);

                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                            case 'double':
                                $compilationContext->headersManager->add('kernel/operators');

                                return new CompiledExpression('bool', $this->zvalLongOperator.'('.$variableCode.', '.$right->getCode().')', $expression['left']);

                            case 'char':
                            case 'uchar':
                                $compilationContext->headersManager->add('kernel/operators');

                                return new CompiledExpression('bool', $this->zvalLongOperator.'('.$variableCode.', \''.$right->getCode().'\')', $expression['left']);

                            case 'bool':
                                $compilationContext->headersManager->add('kernel/operators');
                                $zvalBoolOperator = 'true' == $right->getCode() ? $this->zvalBoolTrueOperator : $this->zvalBoolFalseOperator;

                                return new CompiledExpression('bool', $zvalBoolOperator.'('.$variableCode.')', $expression['left']);

                            case 'string':
                                $compilationContext->headersManager->add('kernel/operators');

                                return new CompiledExpression('bool', $this->zvalStringOperator.'('.$variableCode.', "'.$right->getCode().'")', $expression['left']);

                            case 'variable':
                                $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                                switch ($variableRight->getType()) {
                                    case 'int':
                                    case 'uint':
                                    case 'long':
                                    case 'ulong':
                                        $compilationContext->headersManager->add('kernel/operators');

                                        return new CompiledExpression('bool', $this->zvalLongOperator.'('.$variableCode.', '.$variableRight->getName().')', $expression);

                                    case 'double':
                                        $compilationContext->headersManager->add('kernel/operators');

                                        return new CompiledExpression('bool', $this->zvalDoubleOperator.'('.$variableCode.', '.$variableRight->getName().')', $expression);

                                    case 'bool':
                                        $compilationContext->headersManager->add('kernel/operators');

                                        return new CompiledExpression('bool', $this->zvalBoolOperator.'('.$variableCode.', '.$variableRight->getName().')', $expression);

                                    case 'string':
                                    case 'variable':
                                    case 'array':
                                        $compilationContext->headersManager->add('kernel/operators');
                                        $variableRight = $compilationContext->backend->getVariableCode($variableRight);

                                        return new CompiledExpression('bool', $this->zvalOperator.'('.$variableCode.', '.$variableRight.')', $expression);

                                    default:
                                        throw new CompilerException('Unknown type: '.$variableRight->getType(), $expression['right']);
                                }
                                break;

                            default:
                                throw new CompilerException('Unknown type: '.$right->getType(), $expression['left']);
                        }
                        break;

                    default:
                        throw new CompilerException('Unknown type: '.$variable->getType(), $expression);
                }
                break;

            default:
                throw new CompilerException('Unknown type: '.$left->getType(), $expression);
        }
    }
885122
public function evaluateExpression(string $expression)
    {
        $expressionLanguage = new ExpressionLanguage();

        return $expressionLanguage->evaluate($expression, $this->services);
    }
974189
public function groupBy($expression)
    {
        assert($this->bucket instanceof Stage\Bucket);
        return $this->bucket->groupBy($expression);
    }
701623
private static function makeCallable($expression)
    {
        if (! array_key_exists($expression, static::$map)) {
            $return = "return ($expression);";
            try {
                $lambda = create_function(static::$signature, $return);
            } catch (\ParseError $ex) {
                $lambda = false;
            } finally {
                if (false === $lambda) {
                    throw new \LogicException(sprintf(
                        'Expression is not valid PHP code: given=[%s], becomes=[%s]',
                        $expression,
                        $return
                    ));
                } else {
                    static::$map[$expression] = $lambda;
                }
            }
        }
        return static::$map[$expression];
    }
988346
public function match($expression)
    {
        if (is_callable($expression)) {
            $expressionConfigurator = $expression;
            $expression = new Expression();
            call_user_func($expressionConfigurator, $expression);
        }

        if ($expression instanceof Expression) {
            $expression = $expression->toArray();
        } elseif (!is_array($expression)) {
            throw new Exception('Must be array, callable or instance of \Sokil\Mongo\Expression');
        }

        $this->addStage('$match', $expression);
        return $this;
    }
752766
public function search($expression)
    {
        $results = [];

        foreach ($this->providers as $provider) {
            $results = array_merge($results, $provider->search($expression));
        }

        usort($results, function (Result $a, Result $b) {
            if ($a->getScore() == $b->getScore()) {
                return 0;
            }
            return $a->getScore() > $b->getScore() ? -1 : 1;
        });

        return $results;
    }
1369081
public function addUsing(string ...$expression) : self
    {
        $this->usingExpressions = array_merge($this->usingExpressions, $expression);

        return $this;
    }
408337
public function compile(Expression $expression)
    {

        if ($expression instanceof ConstraintContract || $expression instanceof ConstraintGroupContract) {
            return $this->compileConstraint($expression);
        }

        if ($expression instanceof ConditionContract) {
            return $this->compileCondition($expression);
        }

        if ($expression instanceof ConditionGroupContract) {
            return $this->compileConditionGroup($expression);
        }

        throw new TypeException('Matcher can only match Constraint, ConstraintGroup, Condition and ConditionGroup');

    }