2014-03-10 12:25:37 +00:00
|
|
|
|
#pragma once
|
2010-06-24 19:12:10 +00:00
|
|
|
|
|
|
|
|
|
#include <list>
|
2014-03-10 14:47:04 +00:00
|
|
|
|
#include <memory>
|
2010-06-24 19:12:10 +00:00
|
|
|
|
|
2014-04-13 08:52:50 +00:00
|
|
|
|
#include <DB/Core/Defines.h>
|
2010-06-24 19:12:10 +00:00
|
|
|
|
#include <DB/Core/Types.h>
|
|
|
|
|
#include <DB/Parsers/IAST.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
using Poco::SharedPtr;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Интерфейс для классов-парсеров
|
|
|
|
|
*/
|
|
|
|
|
class IParser
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
typedef const char * Pos;
|
|
|
|
|
|
|
|
|
|
/** Получить текст о том, что парсит этот парсер. */
|
2014-03-10 12:25:37 +00:00
|
|
|
|
virtual const char * getName() const = 0;
|
2010-06-24 19:12:10 +00:00
|
|
|
|
|
|
|
|
|
/** Распарсить кусок текста с позиции pos, но не дальше конца строки (end - позиция после конца строки),
|
|
|
|
|
* переместить указатель pos на максимальное место, до которого удалось распарсить,
|
|
|
|
|
* вернуть в случае успеха true и результат в node, если он нужен, иначе false,
|
|
|
|
|
* в expected записать, что ожидалось в максимальной позиции,
|
|
|
|
|
* до которой удалось распарсить, если парсинг был неуспешным,
|
|
|
|
|
* или что парсит этот парсер, если парсинг был успешным.
|
2014-04-13 08:52:50 +00:00
|
|
|
|
* Строка, в которую входит диапазон [begin, end) может быть не 0-terminated.
|
2010-06-24 19:12:10 +00:00
|
|
|
|
*/
|
2014-03-10 12:25:37 +00:00
|
|
|
|
virtual bool parse(Pos & pos, Pos end, ASTPtr & node, const char *& expected) = 0;
|
2010-06-24 19:12:10 +00:00
|
|
|
|
|
2014-03-10 12:25:37 +00:00
|
|
|
|
bool ignore(Pos & pos, Pos end, const char *& expected)
|
2010-06-24 19:12:10 +00:00
|
|
|
|
{
|
|
|
|
|
ASTPtr ignore_node;
|
|
|
|
|
return parse(pos, end, ignore_node, expected);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ignore(Pos & pos, Pos end)
|
|
|
|
|
{
|
2014-03-10 12:25:37 +00:00
|
|
|
|
const char * expected;
|
2010-06-24 19:12:10 +00:00
|
|
|
|
return ignore(pos, end, expected);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** То же самое, но не двигать позицию и не записывать результат в node.
|
|
|
|
|
*/
|
2014-03-10 12:25:37 +00:00
|
|
|
|
bool check(Pos & pos, Pos end, const char *& expected)
|
2010-06-24 19:12:10 +00:00
|
|
|
|
{
|
|
|
|
|
Pos begin = pos;
|
|
|
|
|
ASTPtr node;
|
|
|
|
|
if (!parse(pos, end, node, expected))
|
|
|
|
|
{
|
|
|
|
|
pos = begin;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual ~IParser() {}
|
|
|
|
|
};
|
|
|
|
|
|
2014-03-10 14:47:04 +00:00
|
|
|
|
typedef std::unique_ptr<IParser> ParserPtr;
|
2010-06-24 19:12:10 +00:00
|
|
|
|
|
2014-04-13 08:52:50 +00:00
|
|
|
|
|
|
|
|
|
/** Из позиции в (возможно многострочном) запросе получить номер строки и номер столбца в строке.
|
|
|
|
|
* Используется в сообщении об ошибках.
|
|
|
|
|
*/
|
|
|
|
|
inline std::pair<size_t, size_t> getLineAndCol(IParser::Pos begin, IParser::Pos pos)
|
|
|
|
|
{
|
|
|
|
|
size_t line = 0;
|
|
|
|
|
|
|
|
|
|
IParser::Pos nl;
|
|
|
|
|
while (nullptr != (nl = reinterpret_cast<IParser::Pos>(memchr(begin, '\n', pos - begin))))
|
|
|
|
|
{
|
|
|
|
|
++line;
|
|
|
|
|
begin = nl + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Нумеруются с единицы.
|
|
|
|
|
return { line + 1, pos - begin + 1 };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Получить сообщение о синтаксической ошибке.
|
|
|
|
|
*/
|
|
|
|
|
inline std::string getSyntaxErrorMessage(
|
|
|
|
|
bool parse_res, /// false, если не удалось распарсить; true, если удалось, но не до конца строки или точки с запятой.
|
|
|
|
|
IParser::Pos begin,
|
|
|
|
|
IParser::Pos end,
|
|
|
|
|
IParser::Pos pos,
|
|
|
|
|
const char * expected,
|
|
|
|
|
const std::string & description = "")
|
|
|
|
|
{
|
|
|
|
|
std::stringstream message;
|
|
|
|
|
|
|
|
|
|
message << "Syntax error ";
|
|
|
|
|
|
|
|
|
|
if (!description.empty())
|
|
|
|
|
message << "(" << description << ")";
|
|
|
|
|
|
|
|
|
|
message << ": failed at position " << (pos - begin + 1);
|
|
|
|
|
|
|
|
|
|
/// Если запрос многострочный.
|
|
|
|
|
IParser::Pos nl = reinterpret_cast<IParser::Pos>(memchr(begin, '\n', end - begin));
|
|
|
|
|
if (nullptr != nl && nl + 1 != end)
|
|
|
|
|
{
|
|
|
|
|
size_t line = 0;
|
|
|
|
|
size_t col = 0;
|
|
|
|
|
std::tie(line, col) = getLineAndCol(begin, pos);
|
|
|
|
|
|
|
|
|
|
message << " (line " << line << ", col " << col << ")";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
message << ": " << std::string(pos, std::min(SHOW_CHARS_ON_SYNTAX_ERROR, end - pos))
|
|
|
|
|
<< ", expected " << (parse_res ? "end of query" : expected) << ".";
|
|
|
|
|
|
|
|
|
|
return message.str();
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-24 19:12:10 +00:00
|
|
|
|
}
|