8 void MessageQuery::tokenize() {
14 std::string::const_iterator current = _query.begin();
15 std::string::const_iterator end = _query.end();
17 static std::vector<std::pair<TokenType, std::regex>> expression_map = {
18 {TokenType::Space, std::regex(
"\\s+")},
19 {TokenType::Symbol, std::regex(
"[A-Za-z_][A-Za-z0-9_]*")},
20 {TokenType::Dot, std::regex(
"\\.")},
21 {TokenType::String, std::regex(
"\\\"[^\\\"]*\\\"|\\'[^\\']*\\'")},
22 {TokenType::Integer, std::regex(
"[0-9]+")},
23 {TokenType::IndexBegin, std::regex(
"\\[")},
24 {TokenType::IndexEnd, std::regex(
"\\]")},
25 {TokenType::Equality, std::regex(
"\\=\\=?")},
26 {TokenType::Inequality, std::regex(
"\\!\\=")},
27 {TokenType::GreaterThan, std::regex(
"\\>")},
28 {TokenType::LessThan, std::regex(
"\\<")},
29 {TokenType::GreaterEqual, std::regex(
"\\>\\=")},
30 {TokenType::LessEqual, std::regex(
"\\<\\=")},
32 std::regex(
"[-+]?([0-9]*\\.)?[0-9]+([eE][-+]?[0-9]+)?")},
36 while (current != end) {
38 for (
auto &expression_mapping : expression_map) {
39 auto &token_type = expression_mapping.first;
40 auto &expression = expression_mapping.second;
42 bool ok = std::regex_search(current, end, match, expression,
43 std::regex_constants::match_continuous);
45 token.type = token_type;
48 if (token.type == TokenType::Double ||
49 token.type == TokenType::Integer) {
51 token.number = std::stod(token.str);
52 }
catch (
const std::invalid_argument &ex) {
53 token.type = TokenType::None;
55 }
catch (
const std::out_of_range &ex) {
56 token.type = TokenType::None;
61 if (token.type == TokenType::Integer) {
63 token.integer = std::stoull(token.str);
64 }
catch (
const std::invalid_argument &ex) {
65 token.type = TokenType::None;
67 }
catch (
const std::out_of_range &ex) {
68 token.type = TokenType::None;
73 if (token.type == TokenType::String) {
74 token.str = token.str.substr(1, token.str.size() - 2);
81 token.begin = current - _query.begin();
82 token.end = token.begin + match[0].length();
84 if (token.type != TokenType::None) {
85 if (token.type != TokenType::Space) {
86 _tokens.push_back(token);
88 current += match[0].length();
96 for (
auto &tok : _tokens) {
97 LOG_DEBUG(
"token " << (
int)tok.type <<
" " << tok.str);
101 bool MessageQuery::filter(
const MessageParser &parser,
const TokenInfo &op,
102 const TokenInfo &val)
const {
104 if (val.type == TokenType::Integer || val.type == TokenType::Double) {
107 case TokenType::Equality:
108 return parser.toDouble() == val.number;
111 case TokenType::Inequality:
112 return parser.toDouble() != val.number;
115 case TokenType::LessThan:
116 return parser.toDouble() < val.number;
119 case TokenType::GreaterThan:
120 return parser.toDouble() > val.number;
123 case TokenType::LessEqual:
124 return parser.toDouble() <= val.number;
127 case TokenType::GreaterEqual:
128 return parser.toDouble() >= val.number;
133 if (val.type == TokenType::String) {
136 case TokenType::Equality:
137 return parser.toString() == val.str;
140 case TokenType::Inequality:
141 return parser.toString() != val.str;
149 bool MessageQuery::filter(
151 const std::function<
void(
const TokenIterator &,
const std::string &)>
157 if (msg.isPrimitive()) {
158 complete(current_token,
"==");
159 complete(current_token,
"!=");
160 if (!parser.isString()) {
161 complete(current_token,
"<");
162 complete(current_token,
">");
163 complete(current_token,
"<=");
164 complete(current_token,
">=");
169 if (current_token == _tokens.end()) {
172 TokenInfo op = *current_token;
176 if (msg.isPrimitive()) {
177 auto str = msg.toString();
178 if (msg.isString()) {
179 if (str.find(
"\"") == std::string::npos) {
180 complete(current_token,
"\"" + str +
"\"");
183 complete(current_token, str);
188 if (current_token == _tokens.end()) {
191 TokenInfo val = *current_token;
195 complete(current_token,
"]");
198 return filter(msg, op, val);
203 const std::function<
void(
const TokenIterator &,
const std::string &)>
206 if (!parser.isMessage()) {
211 for (
size_t i = 0; i < parser.size(); i++) {
212 complete(current_token, parser.fieldName(i));
216 if (current_token == _tokens.end() ||
217 current_token->type != TokenType::Symbol) {
221 parser = parser[current_token->str];
226 if (parser.isMessage()) {
229 for (
size_t i = 0; i < parser.size(); i++) {
230 complete(current_token,
"." + parser.fieldName(i));
234 if (current_token != _tokens.end() &&
235 current_token->type == TokenType::Dot &&
236 (current_token + 1) != _tokens.end() &&
237 (current_token + 1)->type == TokenType::Symbol) {
239 parser = parser[(current_token + 1)->str];
246 if (parser.isArray()) {
249 complete(current_token,
"[");
250 for (
size_t i = 0; i <= 3 && i < parser.size(); i++) {
251 complete(current_token,
"[" + std::to_string(i) +
"]");
255 if (current_token != _tokens.end() &&
256 current_token->type == TokenType::IndexBegin) {
258 if ((current_token + 1) != _tokens.end() &&
259 (current_token + 1)->type == TokenType::Integer) {
262 complete(current_token + 2,
"]");
265 if ((current_token + 2) != _tokens.end() &&
266 (current_token + 2)->type == TokenType::IndexEnd) {
268 parser = parser[(current_token + 1)->integer];
275 size_t array_size = parser.size();
277 for (
size_t i = 0; i < array_size; i++) {
279 auto element = parser[i];
280 TokenIterator filter_token = current_token + 1;
281 if (filter(element, filter_token, complete)) {
282 current_token = filter_token;
284 if (current_token == _tokens.end() ||
285 current_token->type != TokenType::IndexEnd) {
310 MessageQuery::MessageQuery() {}
312 MessageQuery::MessageQuery(
const std::string &query) { assign(query); }
314 void MessageQuery::assign(
const std::string &query) {
315 if (query != _query) {
322 PROFILER(
"MessageQuery");
326 TokenIterator current_token = _tokens.begin();
327 auto ret = query(parser, current_token);
328 if (current_token == _tokens.end()) {
338 LOG_DEBUG(
"complete query");
339 LOG_DEBUG(
"query " << _query);
340 std::set<std::string> ret;
341 TokenIterator current_token = _tokens.begin();
343 query(parser, current_token,
344 [&](
const TokenIterator &token,
const std::string &completion) {
346 if (token != _tokens.begin()) {
347 TokenIterator tok = token;
349 LOG_DEBUG(
"token end " << tok->end);
350 prefix = _query.substr(0, tok->end);
352 LOG_DEBUG(
"completion " << prefix << completion);
353 ret.insert(prefix + completion);
355 completion.completed = value.isPrimitive();
356 LOG_DEBUG(
"completed " << (completion.completed ?
"true" :
"false"));
357 completion.items.assign(ret.begin(), ret.end());