96 lines
2.8 KiB
PHP
96 lines
2.8 KiB
PHP
<?php
|
|
|
|
require_once __DIR__ '/../functions.php';
|
|
|
|
/**
|
|
* Поиск в индексе
|
|
*/
|
|
class Search
|
|
{
|
|
private $lexer;
|
|
private $index;
|
|
function __construct ($index)
|
|
{
|
|
$this->lexer = new Lexer();
|
|
$this->index = $index;
|
|
|
|
$this->op = array ($this, 'Op');
|
|
$this->binary = array ($this, 'binaryOp');
|
|
$this->union = array ($this, 'union');
|
|
$this->intersection = lcurry($this->op, 'array_uintersect', $this->union);
|
|
|
|
$this->notQuery = lcurry ($this->binary, Lexer::TOKEN_NOT,
|
|
lcurry($this->op, 'array_udiff', 'array_udiff'), array ($this, 'easyQuery'));
|
|
|
|
$this->orQuery = lcurry ($this->binary, Lexer::TOKEN_OR,
|
|
lcurry($this->op, $this->union, $this->union), $this->notQuery);
|
|
|
|
$this->andQuery = lcurry ($this->binary, Lexer::TOKEN_AND, $this->intersection, $this->orQuery);
|
|
}
|
|
|
|
function union ($a, $b, $callback)
|
|
{
|
|
return array_merge($a, $b);
|
|
}
|
|
|
|
function Eq ($a, $b)
|
|
{
|
|
return $a == $b;
|
|
}
|
|
|
|
function Op ($files, $words, $a, $b) {
|
|
return array (
|
|
'words' => call_user_func ($words, $a['words'], $b['words'], array ($this, 'eq')),
|
|
'files' => call_user_func ($files, $a['files'], $b['files'], array ($this, 'eq'))
|
|
);
|
|
}
|
|
|
|
public function getQuery ($source)
|
|
{
|
|
$this->lexer->setSource ($source);
|
|
$this->lexer->nextToken();
|
|
return $this->topQuery();
|
|
}
|
|
|
|
function topQuery ()
|
|
{
|
|
$result = call_user_func ($this->andQuery);
|
|
while ($this->lexer->token[0] == Lexer::TOKEN_LPAREN) {
|
|
$result = call_user_func ($this->intersection, $result, call_user_func ($this->andQuery));
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
function easyQuery ()
|
|
{
|
|
$result = null;
|
|
if ($this->lexer->token[0] == Lexer::TOKEN_LPAREN) {
|
|
$this->lexer->nextToken ();
|
|
$result = $this->topQuery ();
|
|
if ($this->lexer->token[0] == Lexer::TOKEN_RPAREN) {
|
|
$this->lexer->nextToken ();
|
|
}
|
|
return $result;
|
|
} else {
|
|
$result = call_user_func ($this->index, $this->lexer->token[1]);
|
|
$this->lexer->nextToken ();
|
|
return $result;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param int $type Тип лексемы
|
|
* @param function $op Функция при совпадении типа лексемы при запросе
|
|
* @param function $next Следующий обработчик запроса
|
|
*/
|
|
function binaryOp ($type, $op, $next)
|
|
{
|
|
$result = call_user_func($next);
|
|
while ($this->lexer->token[0] == $type) {
|
|
$this->lexer->nextToken();
|
|
$result = call_user_func($op, $result, call_user_func ($next));
|
|
}
|
|
return $result;
|
|
}
|
|
}
|
|
|