59 } |
59 } |
60 |
60 |
61 static const char* _map_operator(davqloperator_t op) { |
61 static const char* _map_operator(davqloperator_t op) { |
62 // don't use string array, because enum values may change |
62 // don't use string array, because enum values may change |
63 switch(op) { |
63 switch(op) { |
64 case ADD: return "+"; case SUB: return "-"; case MUL: return "*"; |
64 case DAVQL_NOOP: return "no operator"; |
65 case DIV: return "/"; case AND: return "&"; case OR: return "|"; |
65 case DAVQL_ADD: return "+"; case DAVQL_SUB: return "-"; |
66 case XOR: return "^"; case NEG: return "~"; case NOT: return "NOT"; |
66 case DAVQL_MUL: return "*"; case DAVQL_DIV: return "/"; |
67 case LAND: return "AND"; case LOR: return "OR"; case LXOR: return "XOR"; |
67 case DAVQL_AND: return "&"; case DAVQL_OR: return "|"; |
68 case EQ: return "="; case NEQ: return "!="; case LT: return "<"; |
68 case DAVQL_XOR: return "^"; case DAVQL_NEG: return "~"; |
69 case GT: return ">"; case LE: return "<="; case GE: return ">="; |
69 case DAVQL_NOT: return "NOT"; case DAVQL_LAND: return "AND"; |
70 case LIKE: return "LIKE"; case UNLIKE: return "UNLIKE"; |
70 case DAVQL_LOR: return "OR"; case DAVQL_LXOR: return "XOR"; |
|
71 case DAVQL_EQ: return "="; case DAVQL_NEQ: return "!="; |
|
72 case DAVQL_LT: return "<"; case DAVQL_GT: return ">"; |
|
73 case DAVQL_LE: return "<="; case DAVQL_GE: return ">="; |
|
74 case DAVQL_LIKE: return "LIKE"; case DAVQL_UNLIKE: return "UNLIKE"; |
71 default: return "unknown"; |
75 default: return "unknown"; |
72 } |
76 } |
73 } |
77 } |
74 |
78 |
75 static void dav_debug_ql_stmt_print(DavQLStatement *stmt) { |
79 static void dav_debug_ql_stmt_print(DavQLStatement *stmt) { |
84 // Has wildcard |
88 // Has wildcard |
85 _Bool wildcard = 0; |
89 _Bool wildcard = 0; |
86 UCX_FOREACH(elm, stmt->fields) { |
90 UCX_FOREACH(elm, stmt->fields) { |
87 DavQLExpression* expr = (DavQLExpression*)elm->data; |
91 DavQLExpression* expr = (DavQLExpression*)elm->data; |
88 if (expr->type == DAVQL_IDENTIFIER && |
92 if (expr->type == DAVQL_IDENTIFIER && |
89 expr->srctext.length == 1 && *(expr->srctext.ptr) == '*') { |
93 expr->srctext.length == 1 && expr->srctext.ptr[0] == '*') { |
90 wildcard = 1; |
94 wildcard = 1; |
91 } |
95 } |
92 } |
96 } |
93 printf(" %s wildcard\nPath: %.*s\nHas where clause: %s\n", |
97 printf(" %s wildcard\nPath: %.*s\nHas where clause: %s\n", |
94 wildcard?"with":"without", |
98 wildcard?"with":"without", |
263 |
267 |
264 if (token) { |
268 if (token) { |
265 tokens = ucx_list_append(tokens, token); |
269 tokens = ucx_list_append(tokens, token); |
266 } |
270 } |
267 |
271 |
|
272 // now find quotes and backsticks and merge enclosed tokens |
|
273 // TODO: make it so or disable tokenization in such cases in above code |
|
274 |
268 return tokens; |
275 return tokens; |
269 } |
276 } |
270 |
277 |
271 static DavQLExpression* dav_parse_expression(sstr_t src) { |
278 #define token_sstr(listelem) ((sstr_t*)(listelem)->data) |
|
279 static DavQLExpression* dav_parse_expression(UcxList* starttoken, size_t n) { |
|
280 if (n == 0) { |
|
281 return NULL; |
|
282 } |
|
283 |
272 DavQLExpression *expr = calloc(1, sizeof(DavQLExpression)); |
284 DavQLExpression *expr = calloc(1, sizeof(DavQLExpression)); |
273 expr->srctext = src; |
285 |
|
286 // set pointer for source text |
|
287 expr->srctext.ptr = token_sstr(starttoken)->ptr; |
|
288 |
|
289 // special case - only one token |
|
290 if (n == 1) { |
|
291 expr->srctext.length = token_sstr(starttoken)->length; |
|
292 char firstchar = expr->srctext.ptr[0]; |
|
293 if (firstchar == '\'' || isdigit(firstchar)) { |
|
294 expr->type = DAVQL_LITERAL; |
|
295 } else { |
|
296 expr->type = DAVQL_IDENTIFIER; |
|
297 } |
|
298 } else { |
|
299 UcxList* token = starttoken; |
|
300 |
|
301 // check, if first token is ( |
|
302 // if so, verify that last token is ) and throw both away |
|
303 if (!sstrcmp(*token_sstr(token), S("("))) { |
|
304 if (!sstrcmp(*token_sstr(ucx_list_get(token, n-1)), S(")"))) { |
|
305 token = token->next; |
|
306 n -= 2; |
|
307 } else { |
|
308 // TODO: throw syntax error |
|
309 } |
|
310 } |
|
311 |
|
312 // process tokens |
|
313 for (size_t i = 0 ; i < n ; i++) { |
|
314 |
|
315 // TODO: make it so |
|
316 |
|
317 // go to next token (if this is not the last token) |
|
318 if (i < n-1) { |
|
319 token = token->next; |
|
320 } |
|
321 } |
|
322 |
|
323 // compute length of source text (including delimiters) |
|
324 expr->srctext.length = token_sstr(token)->ptr + |
|
325 token_sstr(token)->length - expr->srctext.ptr; |
|
326 } |
274 |
327 |
275 return expr; |
328 return expr; |
276 } |
329 } |
277 |
330 |
278 static void dav_parse_get_statement(DavQLStatement *stmt, UcxList *tokens) { |
331 static void dav_parse_get_statement(DavQLStatement *stmt, UcxList *tokens) { |
288 * 500: ready to quit |
341 * 500: ready to quit |
289 * |
342 * |
290 */ |
343 */ |
291 int step = 10; |
344 int step = 10; |
292 |
345 |
|
346 // Variables for token sublists for expressions |
|
347 UcxList *exprstart = NULL; |
|
348 size_t exprlen = 0; |
|
349 |
|
350 // Process tokens |
293 UCX_FOREACH(token, tokens) { |
351 UCX_FOREACH(token, tokens) { |
294 sstr_t tokendata = *(sstr_t*)token->data; |
352 sstr_t tokendata = *token_sstr(token); |
295 |
353 |
296 switch (step) { |
354 switch (step) { |
297 // optional clauses |
355 // optional clauses |
298 case 520: |
356 case 520: |
299 if (!sstrcasecmp(tokendata, S("where"))) { |
357 if (!sstrcasecmp(tokendata, S("where"))) { |
304 if (!sstrcasecmp(tokendata, S("with"))) { |
362 if (!sstrcasecmp(tokendata, S("with"))) { |
305 step = 40; |
363 step = 40; |
306 } |
364 } |
307 break; |
365 break; |
308 // field list |
366 // field list |
309 case 10: |
367 case 10: { |
310 if (!sstrcasecmp(tokendata, S("from"))) { |
368 _Bool fromkeyword = !sstrcasecmp(tokendata, S("from")); |
311 step = 20; |
369 if (fromkeyword || !sstrcmp(tokendata, S(","))) { |
|
370 if (exprstart) { |
|
371 stmt->fields = ucx_list_append(stmt->fields, |
|
372 dav_parse_expression(exprstart, exprlen)); |
|
373 exprstart = NULL; |
|
374 exprlen = 0; |
|
375 } else { |
|
376 // TODO: throw syntax error |
|
377 } |
|
378 |
|
379 if (fromkeyword) { |
|
380 step = 20; |
|
381 } |
312 } else { |
382 } else { |
313 stmt->fields = ucx_list_append(stmt->fields, |
383 // collect tokens for field expression |
314 dav_parse_expression(tokendata)); |
384 if (exprstart) { |
315 } |
385 exprlen++; |
316 break; |
386 } else { |
|
387 exprstart = token; |
|
388 exprlen = 1; |
|
389 } |
|
390 } |
|
391 break; |
|
392 } |
317 // from clause |
393 // from clause |
318 case 20: |
394 case 20: |
319 stmt->path = dav_parse_expression(tokendata); |
395 stmt->path = dav_parse_expression(token, 1); |
320 step = 520; |
396 step = 520; |
321 break; |
397 break; |
322 // where clause |
398 // where clause |
323 case 30: |
399 case 30: |
324 step = 530; |
400 step = 530; |
340 |
414 |
341 static void dav_parse_set_statement(DavQLStatement *stmt, UcxList *tokens) { |
415 static void dav_parse_set_statement(DavQLStatement *stmt, UcxList *tokens) { |
342 stmt->type = DAVQL_SET; |
416 stmt->type = DAVQL_SET; |
343 |
417 |
344 UCX_FOREACH(token, tokens) { |
418 UCX_FOREACH(token, tokens) { |
345 sstr_t tokendata = *(sstr_t*)token->data; |
419 sstr_t tokendata = *token_sstr(token); |
346 |
420 |
347 // just free the tokens, until the function is implemented |
|
348 |
|
349 free(token->data); |
|
350 } |
421 } |
351 } |
422 } |
352 |
423 |
353 DavQLStatement* dav_parse_statement(sstr_t srctext) { |
424 DavQLStatement* dav_parse_statement(sstr_t srctext) { |
354 DavQLStatement *stmt = calloc(1, sizeof(DavQLStatement)); |
425 DavQLStatement *stmt = calloc(1, sizeof(DavQLStatement)); |
361 stmt->srctext = sstrtrim(srctext); |
432 stmt->srctext = sstrtrim(srctext); |
362 |
433 |
363 // tokenization |
434 // tokenization |
364 UcxList* tokens = dav_parse_tokenize(stmt->srctext); |
435 UcxList* tokens = dav_parse_tokenize(stmt->srctext); |
365 |
436 |
366 // use first token to determine query type |
|
367 if (tokens) { |
437 if (tokens) { |
368 sstr_t token = *(sstr_t*)tokens->data; |
438 // use first token to determine query type |
|
439 sstr_t token = *token_sstr(tokens); |
369 free(tokens->data); |
440 free(tokens->data); |
370 tokens = ucx_list_remove(tokens, tokens); |
441 tokens = ucx_list_remove(tokens, tokens); |
|
442 |
371 if (!sstrcasecmp(token, S("get"))) { |
443 if (!sstrcasecmp(token, S("get"))) { |
372 dav_parse_get_statement(stmt, tokens); |
444 dav_parse_get_statement(stmt, tokens); |
373 } else if (!sstrcasecmp(token, S("set"))) { |
445 } else if (!sstrcasecmp(token, S("set"))) { |
374 dav_parse_set_statement(stmt, tokens); |
446 dav_parse_set_statement(stmt, tokens); |
375 } else { |
447 } else { |
376 stmt->type = DAVQL_ERROR; |
448 stmt->type = DAVQL_ERROR; |
377 } |
449 } |
|
450 |
|
451 // free token data |
|
452 UCX_FOREACH(token, tokens) { |
|
453 free(token->data); |
|
454 } |
378 ucx_list_free(tokens); |
455 ucx_list_free(tokens); |
379 } else { |
456 } else { |
380 stmt->type = DAVQL_ERROR; |
457 stmt->type = DAVQL_ERROR; |
381 } |
458 } |
382 |
459 |