@param string  $expression
@param integer $length
@param integer $cursor
@param float   $base

@return \stdClass
344453
private function checkExp($expression, $length, $cursor, $base)
    {
        $response = new \stdClass();

        if ($base < 0) {
            $test_func = preg_replace('/\s+/', '', $expression);
            $test_func = substr($test_func , 0, -strlen(preg_replace('/\s+/', '',
                    $base.substr($expression, $length-$cursor))));
            $test_func_ok = true;
            if (preg_match('/([nstpg]\()|(in|os|an|bs|rt|xp|og)/', substr($test_func, -2)))
                $test_func_ok = false;

            if ($test_func_ok) {
                $expression = substr($expression, $length-$cursor+1);
                $test_exp = ltrim($expression);
                if (isset($test_exp[0]) && $test_exp[0] === '^') {
                    $exp = '';
                    for ($q=0; $q<=$cursor-1; $q++) {
                        if (isset($expression[$q]) && $expression[$q] === '^') {
                            $exp = ' ';
                        } elseif ($exp != '' && !strstr(' ', $expression[$q])) {
                            if (strstr('+-', $expression[$q]) && $exp == ' ') {
                                $exp .= $expression[$q];
                            } elseif (strstr('0123456789.(', $expression[$q])) {
                                if ($expression[$q] != '(')
                                    $exp .= $expression[$q];
                            } else {
                                $exp = trim($exp);
                                $cursor = $cursor - $q;
                                if (isset($exp[0]) && $exp[0] == '+')
                                    $exp = substr($exp, 1);
                                break;
                            }
                        }
                    }
                    $response->cursor = $cursor;
                    if (substr($exp, -1) == '.')
                        $exp = substr($exp, 0, -1);
                    if (!is_numeric($exp) || strstr($exp, '.')) {
                        $this->correct = $response->result = 0;
                    } else {
                        $response->result = pow(abs($base),$exp) * pow(-1,$exp);
                    }
                }
            }
        }
        return $response;
    }
373963
public static Class<?> getType(Object base, String p_expression) {
		Method declaredField = getGetter(base, p_expression);
		if (null != declaredField) {
			return declaredField.getReturnType();
		}
		return null;
	}
25125
public function asSecret(StringLength $length = null)
    {
        return $this->handleFilter(
                function() use($length)
                {
                    return filter\RangeFilter::wrap(
                            filter\SecretFilter::instance(),
                            $length
                    );
                }
        );
    }
1209314
public function compile($expression, CompilationContext $compilationContext)
    {
        $expr = new Expression($expression['right']);
        $resolved = $expr->compile($compilationContext);

        switch ($expression['left']) {
            case 'int':
                switch ($resolved->getType()) {
                    case 'null':
                        return new CompiledExpression('int', 0, $expression);

                    case 'int':
                        return new CompiledExpression('int', $resolved->getCode(), $expression);

                    case 'double':
                        return new CompiledExpression('int', '(int) '.$resolved->getCode(), $expression);

                    case 'bool':
                        return new CompiledExpression('int', $resolved->getBooleanCode(), $expression);

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

                        /**
                         * zephir_get_intval_ex use zval variable
                         * before use with it we create a new variable and assign value of literal.
                         *
                         * @todo Optimize by creating native function for string without zval using
                         */
                        $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('string', $compilationContext);
                        $let = new LetVariable();
                        $original = $resolved->getOriginal();
                        $original['operator'] = 'assign';
                        $let->assign($symbolVariable->getName(), $symbolVariable, $resolved, new ReadDetector(), $compilationContext, $original);
                        $symbol = $compilationContext->backend->getVariableCode($symbolVariable);

                        return new CompiledExpression('int', 'zephir_get_intval_ex('.$symbol.')', $expression);

                    case 'array':
                        $compilationContext->headersManager->add('kernel/operators');
                        $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                        $symbol = $compilationContext->backend->getVariableCode($symbolVariable);

                        return new CompiledExpression('int', 'zephir_get_intval('.$symbol.')', $expression);

                    case 'variable':
                        $compilationContext->headersManager->add('kernel/operators');
                        $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                        switch ($symbolVariable->getType()) {
                            case 'int':
                                return new CompiledExpression('int', $symbolVariable->getName(), $expression);

                            case 'double':
                                return new CompiledExpression('int', '(int) ('.$symbolVariable->getName().')', $expression);

                            case 'bool':
                                return new CompiledExpression('int', '(int) ('.$symbolVariable->getName().')', $expression);

                            case 'array':
                            case 'variable':
                            case 'string':
                                $symbol = $compilationContext->backend->getVariableCode($symbolVariable);

                                return new CompiledExpression('int', 'zephir_get_intval('.$symbol.')', $expression);

                            default:
                                throw new CompilerException('Cannot cast: '.$resolved->getType().'('.$symbolVariable->getType().') to '.$expression['left'], $expression);
                        }
                        break;

                    default:
                        throw new CompilerException('Cannot cast: '.$resolved->getType().' to '.$expression['left'], $expression);
                }
                break;

            case 'long':
                switch ($resolved->getType()) {
                    case 'int':
                        return new CompiledExpression('long', $resolved->getCode(), $expression);

                    case 'double':
                        return new CompiledExpression('long', '(long) '.$resolved->getCode(), $expression);

                    case 'bool':
                        return new CompiledExpression('long', $resolved->getBooleanCode(), $expression);

                    case 'array':
                        $compilationContext->headersManager->add('kernel/operators');
                        $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);

                        return new CompiledExpression('long', 'zephir_get_intval('.$symbolVariable->getName().')', $expression);

                    case 'variable':
                        $compilationContext->headersManager->add('kernel/operators');
                        $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                        switch ($symbolVariable->getType()) {
                            case 'int':
                                return new CompiledExpression('long', $symbolVariable->getName(), $expression);
                            case 'double':
                                return new CompiledExpression('long', '(long) ('.$symbolVariable->getName().')', $expression);
                            case 'variable':
                                $symbol = $compilationContext->backend->getVariableCode($symbolVariable);

                                return new CompiledExpression('long', 'zephir_get_intval('.$symbol.')', $expression);
                            default:
                                throw new CompilerException('Cannot cast: '.$resolved->getType().'('.$symbolVariable->getType().') to '.$expression['left'], $expression);
                        }
                        break;

                    default:
                        throw new CompilerException('Cannot cast: '.$resolved->getType().' to '.$expression['left'], $expression);
                }
                break;

            case 'double':
                switch ($resolved->getType()) {
                    case 'null':
                        return new CompiledExpression('double', 0, $expression);

                    case 'bool':
                        return new CompiledExpression('double', $resolved->getBooleanCode(), $expression);

                    case 'double':
                        return new CompiledExpression('double', $resolved->getCode(), $expression);

                    case 'array':
                        $compilationContext->headersManager->add('kernel/operators');
                        $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                        $symbol = $compilationContext->backend->getVariableCode($symbolVariable);

                        return new CompiledExpression('double', 'zephir_get_doubleval('.$symbol.')', $expression);

                    case 'variable':
                        $compilationContext->headersManager->add('kernel/operators');
                        $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);

                        switch ($symbolVariable->getType()) {
                            case 'int':
                                return new CompiledExpression('double', $symbolVariable->getName(), $expression);
                            case 'double':
                                return new CompiledExpression('double', '(double) ('.$symbolVariable->getName().')', $expression);
                            case 'bool':
                                return new CompiledExpression('double', '(double) ('.$symbolVariable->getName().')', $expression);
                            case 'array':
                            case 'variable':
                                $symbol = $compilationContext->backend->getVariableCode($symbolVariable);

                                return new CompiledExpression('double', 'zephir_get_doubleval('.$symbol.')', $expression);
                            default:
                                throw new CompilerException('Cannot cast: '.$resolved->getType().'('.$symbolVariable->getType().') to '.$expression['left'], $expression);
                        }
                        break;

                    default:
                        throw new CompilerException('Cannot cast: '.$resolved->getType().' to '.$expression['left'], $expression);
                }
                break;

            case 'bool':
                switch ($resolved->getType()) {
                    case 'int':
                        return new CompiledExpression('bool', '(zend_bool) '.$resolved->getCode(), $expression);
                    case 'bool':
                        return new CompiledExpression('bool', $resolved->getCode(), $expression);

                    case 'variable':
                        $compilationContext->headersManager->add('kernel/operators');
                        $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                        $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
                        if ($symbolVariable->isTemporal()) {
                            $symbolVariable->setIdle(true);
                        }
                        switch ($symbolVariable->getType()) {
                            case 'variable':
                                return new CompiledExpression('bool', 'zephir_get_boolval('.$symbol.')', $expression);
                            default:
                                throw new CompilerException('Cannot cast: '.$resolved->getType().'('.$symbolVariable->getType().') to '.$expression['left'], $expression);
                        }
                        break;

                    default:
                        throw new CompilerException('Cannot cast: '.$resolved->getType().' to '.$expression['left'], $expression);
                }
                break;

            case 'char':
                switch ($resolved->getType()) {
                    case 'variable':
                        $compilationContext->headersManager->add('kernel/operators');
                        $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('char', $compilationContext);
                        $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                        $variableCode = $compilationContext->backend->getVariableCode($symbolVariable);
                        $compilationContext->codePrinter->output($tempVariable->getName().' = (char) zephir_get_intval('.$variableCode.');');

                        return new CompiledExpression('variable', $tempVariable->getName(), $expression);

                    default:
                        throw new CompilerException('Cannot cast: '.$resolved->getType().' to '.$expression['left'], $expression);
                }
                break;

            case 'string':
                switch ($resolved->getType()) {
                    case 'variable':
                        $compilationContext->headersManager->add('kernel/operators');
                        $compilationContext->symbolTable->mustGrownStack(true);
                        $symbolVariable = $compilationContext->symbolTable->getTempVariable('string', $compilationContext);
                        $symbolVariable->setMustInitNull(true);
                        $symbolVariable->setIsInitialized(true, $compilationContext);
                        $symbolVariable->increaseUses();
                        $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
                        $resolvedVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext);
                        $resolvedCode = $compilationContext->backend->getVariableCode($resolvedVariable);
                        $compilationContext->codePrinter->output('zephir_get_strval('.$symbol.', '.$resolvedCode.');');
                        if ($symbolVariable->isTemporal()) {
                            $symbolVariable->setIdle(true);
                        }

                        return new CompiledExpression('variable', $symbolVariable->getName(), $expression);

                    default:
                        throw new CompilerException('Cannot cast: '.$resolved->getType().' to '.$expression['left'], $expression);
                }
                break;

            case 'array':
                switch ($resolved->getType()) {
                    case 'variable':
                        $compilationContext->headersManager->add('kernel/operators');
                        $compilationContext->symbolTable->mustGrownStack(true);
                        $symbolVariable = $compilationContext->symbolTable->getTempVariable('array', $compilationContext);
                        $symbolVariable->setMustInitNull(true);
                        $symbolVariable->setIsInitialized(true, $compilationContext);
                        $symbolVariable->increaseUses();
                        $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
                        $resolvedVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext);
                        $resolvedCode = $compilationContext->backend->getVariableCode($resolvedVariable);
                        $compilationContext->codePrinter->output('zephir_get_arrval('.$symbol.', '.$resolvedCode.');');
                        if ($symbolVariable->isTemporal()) {
                            $symbolVariable->setIdle(true);
                        }

                        return new CompiledExpression('variable', $symbolVariable->getName(), $expression);

                    default:
                        throw new CompilerException('Cannot cast: '.$resolved->getType().' to '.$expression['left'], $expression);
                }
                break;

            case 'object':
                switch ($resolved->getType()) {
                    case 'int':
                    case 'double':
                    case 'bool':
                    case 'null':
                    case 'string':
                    case 'array':
                        $compilationContext->headersManager->add('kernel/operators');
                        $compilationContext->symbolTable->mustGrownStack(true);
                        $symbolVariable = $compilationContext->symbolTable->getTempVariable('variable', $compilationContext);
                        $symbol = $compilationContext->backend->getVariableCode($symbolVariable);

                        /**
                         * zephir_convert_to_object use zval variable
                         * before use with it we create a new variable and assign value of literal.
                         */
                        $let = new LetVariable();
                        $original = $resolved->getOriginal();
                        $original['operator'] = 'assign';
                        $let->assign($symbolVariable->getName(), $symbolVariable, $resolved, new ReadDetector(), $compilationContext, $original);

                        $compilationContext->codePrinter->output('zephir_convert_to_object('.$symbol.');');

                        return new CompiledExpression('variable', $symbolVariable->getName(), $expression);

                    case 'variable':
                        $compilationContext->headersManager->add('kernel/operators');
                        $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                        $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
                        if ($symbolVariable->isTemporal()) {
                            $symbolVariable->setIdle(true);
                        }

                        $compilationContext->codePrinter->output('zephir_convert_to_object('.$symbol.');');

                        return new CompiledExpression('variable', $symbolVariable->getName(), $expression);

                    default:
                        throw new CompilerException('Cannot cast: '.$resolved->getType().' to '.$expression['left'], $expression);
                }
                break;

            default:
                throw new CompilerException('Cannot cast: '.$resolved->getType().' to '.$expression['left'], $expression);
        }
    }
524599
public function setExpr($expression) {
		$this->valueList = func_get_args();
		$this->expression = array_shift($this->valueList);
		return $this;
	}
900128
public function char($column, $length = null)
    {
        $length = $length ?: Builder::$defaultStringLength;

        return $this->addColumn('char', $column, compact('length'));
    }
322517
public function compile(array $expression, CompilationContext $compilationContext)
    {
        $classDefinition = new ClassDefinition(
            $compilationContext->config->get('namespace'),
            self::$id.'__closure'
        );

        $classDefinition->setIsFinal(true);

        $compilerFile = new CompilerFileAnonymous($classDefinition, $compilationContext->config);
        $compilerFile->setLogger($compilationContext->logger);

        $compilationContext->compiler->addClassDefinition($compilerFile, $classDefinition);

        /**
         * Builds parameters using the only parameter available.
         */
        $parameters = new ClassMethodParameters([
            [
                'type' => 'parameter',
                'name' => $expression['left']['value'],
                'const' => 0,
                'data-type' => 'variable',
                'mandatory' => 0,
                'reference' => 0,
                'file' => $expression['left']['file'],
                'line' => $expression['left']['line'],
                'char' => $expression['left']['char'],
            ],
        ]);

        $exprBuilder = BuilderFactory::getInstance();
        $statementBlockBuilder = $exprBuilder->statements()->block([
            $exprBuilder->statements()
                ->returnX($exprBuilder->raw($expression['right'])),
        ]);

        $block = $statementBlockBuilder->build();

        $classMethod = new ClassMethod(
            $classDefinition,
            ['public', 'final'],
            '__invoke',
            $parameters,
            new StatementsBlock($block),
            null,
            null,
            $expression
        );
        $classDefinition->addMethod($classMethod, $block);

        $compilationContext->headersManager->add('kernel/object');

        if ($this->expecting) {
            if ($this->expectingVariable) {
                $symbolVariable = $this->expectingVariable;
            } else {
                $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $expression);
            }
        } else {
            $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $expression);
        }

        $symbolVariable->initVariant($compilationContext);
        $compilationContext->backend->createClosure($symbolVariable, $classDefinition, $compilationContext);

        ++self::$id;

        return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
    }
452928
public function process($expression) {
        $tokens = $this->splitSQLIntoTokens($expression);
        $token_count = count($tokens);
        if ($token_count === 0) {
            return null;
        }

        /*
         * Determine if there is an explicit alias after the AS clause.
         * If AS is found, then the next non-whitespace token is captured as the alias.
         * The tokens after (and including) the AS are removed.
         */
        $base_expr = "";
        $stripped = array();
        $capture = false;
        $alias = false;
        $processed = false;

        for ($i = 0; $i < $token_count; ++$i) {
            $token = $tokens[$i];
            $upper = strtoupper($token);

            if ($upper === 'AS') {
                $alias = array('as' => true, "name" => "", "base_expr" => $token);
                $tokens[$i] = "";
                $capture = true;
                continue;
            }

            if (!$this->isWhitespaceToken($upper)) {
                $stripped[] = $token;
            }

            // we have an explicit AS, next one can be the alias
            // but also a comment!
            if ($capture) {
                if (!$this->isWhitespaceToken($upper) && !$this->isCommentToken($upper)) {
                    $alias['name'] .= $token;
                    array_pop($stripped);
                }
                $alias['base_expr'] .= $token;
                $tokens[$i] = "";
                continue;
            }

            $base_expr .= $token;
        }

        if ($alias) {
            // remove quotation from the alias
            $alias['no_quotes'] = $this->revokeQuotation($alias['name']);
            $alias['name'] = trim($alias['name']);
            $alias['base_expr'] = trim($alias['base_expr']);
        }

        $stripped = $this->processExpressionList($stripped);

        // TODO: the last part can also be a comment, don't use array_pop

        // we remove the last token, if it is a colref,
        // it can be an alias without an AS
        $last = array_pop($stripped);
        if (!$alias && $this->isColumnReference($last)) {

            // TODO: it can be a comment, don't use array_pop

            // check the token before the colref
            $prev = array_pop($stripped);

            if ($this->isReserved($prev) || $this->isConstant($prev) || $this->isAggregateFunction($prev)
                    || $this->isFunction($prev) || $this->isExpression($prev) || $this->isSubQuery($prev)
                    || $this->isColumnReference($prev) || $this->isBracketExpression($prev)|| $this->isCustomFunction($prev)) {

                $alias = array('as' => false, 'name' => trim($last['base_expr']),
                               'no_quotes' => $this->revokeQuotation($last['base_expr']),
                               'base_expr' => trim($last['base_expr']));
                // remove the last token
                array_pop($tokens);
            }
        }

        $base_expr = $expression;

        // TODO: this is always done with $stripped, how we do it twice?
        $processed = $this->processExpressionList($tokens);

        // if there is only one part, we copy the expr_type
        // in all other cases we use "EXPRESSION" as global type
        $type = ExpressionType::EXPRESSION;
        if (count($processed) === 1) {
            if (!$this->isSubQuery($processed[0])) {
                $type = $processed[0]['expr_type'];
                $base_expr = $processed[0]['base_expr'];
                $no_quotes = isset($processed[0]['no_quotes']) ? $processed[0]['no_quotes'] : null;
                $processed = $processed[0]['sub_tree']; // it can be FALSE
            }
        }

        $result = array();
        $result['expr_type'] = $type;
        $result['alias'] = $alias;
        $result['base_expr'] = trim($base_expr);
        if (!empty($no_quotes)) {
            $result['no_quotes'] = $no_quotes;
        }
        $result['sub_tree'] = (empty($processed) ? false : $processed);
        return $result;
    }
1122071
public static function StringLengthWithProvider( $context, $provider )
	{
		return ExtFuncs::StringLength( CoreFuncs::StringValue( $context, CoreFuncs::Atomize( CoreFuncs::ContextNode( $provider ) ) ) );
	}
286803
protected function _renderExpression(TermInterface $expression, $context = null)
    {
        if ($expression instanceof ExpressionInterface) {
            return $this->_renderExpressionAndTerms($expression, $context);
        }

        return $this->_renderExpressionTerm($expression, $context);
    }
176492
public function regexp($expression, $description = null): ValidatorChain
    {
        $rule = Validator::rule('regexp', [$expression]);
        if (null !== $description) {
            $rule->setDescription($description);
        }
        $this->addRule($rule);
        return $this;
    }
950696
public static function line( $str, $col = null, $erase = true ) {
		if( $col !== null ) {
			Cursor::rowcol($col, 1);
		}
		if( $erase ) {
			Erase::line();
		}
		fwrite(self::$stream, $str);
	}
862123
public function whereNotStartsWith($expr, $value, $length = null)
    {
        return $value === '' ? $this : $this->whereNotLike($expr, $length === null ? $value . '%' : str_pad($value, $length, '_'));
    }
76751
public function setExpression($expression)
    {
        if (is_string($expression)) {
            $expression = CronExpression::factory($expression);
        }

        $this->expression = $expression;

        return $this;
    }
937677
public static function Generate(int $length = 8, int $poolBase = 62) :string
        {
            if ($length <= 0) {
                throw new \Error("GenerateString \$length mint be positive, non-zero integer");
            }
            else if ($poolBase <= 0 || $poolBase > 62) {
                throw new \Error("GenerateString supports \$poolBase values only from 1 to 62");
            }

            $poolBase -= 1;
            $str      = '';

            while ($length) {
                $str = self::BASE62_POOL[mt_rand(0, $poolBase)] . $str;

                $length--;
            }

            return $str;
        }
644517
protected static function convertNthExpression($expression)
    {
        if ($expression === '') {
            throw new InvalidSelectorException('nth-child (or nth-last-child) expression must not be empty');
        }

        if ($expression === 'odd') {
            return 'position() mod 2 = 1 and position() >= 1';
        }

        if ($expression === 'even') {
            return 'position() mod 2 = 0 and position() >= 0';
        }

        if (is_numeric($expression)) {
            return sprintf('position() = %d', $expression);
        }

        if (preg_match("/^(?P<mul>[0-9]?n)(?:(?P<sign>\+|\-)(?P<pos>[0-9]+))?$/is", $expression, $segments)) {
            if (isset($segments['mul'])) {
                $multiplier = $segments['mul'] === 'n' ? 1 : trim($segments['mul'], 'n');
                $sign = (isset($segments['sign']) && $segments['sign'] === '+') ? '-' : '+';
                $position = isset($segments['pos']) ? $segments['pos'] : 0;

                return sprintf('(position() %s %d) mod %d = 0 and position() >= %d', $sign, $position, $multiplier, $position);
            }
        }

        throw new InvalidSelectorException(sprintf('Invalid nth-child expression "%s"', $expression));
    }
847208
protected static function _tokenize($expression_src)
    {
        // Child selectors
        $expression = str_replace('>', '/', $expression_src);

        // IDs
        $expression = preg_replace('|#([a-z][a-z0-9_-]*)|i', "[@id='$1']", $expression);
        $expression = preg_replace('|(?<![a-z0-9_-])(\[@id=)|i', '*$1', $expression);

        // arbitrary attribute strict equality
        $expression = preg_replace_callback(
            '|\[@?([a-z0-9_-]*)([~\*\^\$\|\!])?=([^\[]+)\]|i',
            static function ($matches) {
                $attr = strtolower($matches[1]);
                $type = $matches[2];
                $val = trim($matches[3], "'\" \t");

                $field = ($attr === '' ? 'text()' : '@' . $attr);

                $items = [];
                foreach (explode(strpos($val, '|') !== false ? '|' : '&', $val) as $word) {
                    if ($type === '') {
                        $items[] = "$field='$word'";
                    } elseif ($type === '~') {
                        $items[] = "contains(concat(' ', normalize-space($field), ' '), ' $word ')";
                    } elseif ($type === '|') {
                        $item = "$field='$word' or starts-with($field,'$word-')";
                        $items[] = $word === $val ? $item : "($item)";
                    } elseif ($type === '!') {
                        $item = "not($field) or $field!='$word'";
                        $items[] = $word === $val ? $item : "($item)";
                    } else {
                        $items[] = ['*' => 'contains', '^' => 'starts-with', '$' => 'ends-with'][$type] . "($field, '$word')";
                    }
                }
                return '[' . implode(strpos($val, '|') !== false ? ' or ' : ' and ', $items) . ']';
            },
            $expression
        );

        //attribute contains specified content
        $expression = preg_replace_callback(
            '|\[(!?)([a-z][a-z0-9_-\|&]*)\]|i',
            static function ($matches) {
                $val = $matches[2];
                $op = strpos($val, '|') !== false ? '|' : '&';

                $items = [];
                foreach (explode($op, $val) as $word) {
                    $items[] = '@' . $word;
                }

                $r = '[' . implode($op === '|' ? ' or ' : ' and ', $items) . ']';
                return $matches[1] === '!' ? "not($r)" : $r;
            },
            $expression
        );
        // Classes
        if (false === strpos($expression, '[@')) {
            $expression = preg_replace(
                '|\.([a-z][a-z0-9_-]*)|i',
                "[contains(concat(' ', normalize-space(@class), ' '), ' \$1 ')]",
                $expression
            );
        }

        /** ZF-9764 -- remove double asterisk */
        $expression = str_replace('**', '*', $expression);

        return $expression;
    }