libidav/davqlparser.c

changeset 86
ecba8bdf9741
parent 85
0ab1cf261a44
child 87
ed21d95984bb
equal deleted inserted replaced
85:0ab1cf261a44 86:ecba8bdf9741
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 28
29 #include "davqlparser.h" 29 #include "davqlparser.h"
30 #include <ucx/utils.h>
30 #include <string.h> 31 #include <string.h>
31 #include <stdio.h> 32 #include <stdio.h>
32 #include <ctype.h> 33 #include <ctype.h>
33 34
34 #define sfmtarg(s) ((int)(s).length), (s).ptr 35 #define sfmtarg(s) ((int)(s).length), (s).ptr
53 case DAVQL_UNARY: return "UNARY"; 54 case DAVQL_UNARY: return "UNARY";
54 case DAVQL_BINARY: return "BINARY"; 55 case DAVQL_BINARY: return "BINARY";
55 case DAVQL_LOGICAL: return "LOGICAL"; 56 case DAVQL_LOGICAL: return "LOGICAL";
56 case DAVQL_FUNCCALL: return "FUNCCALL"; 57 case DAVQL_FUNCCALL: return "FUNCCALL";
57 default: return "unknown"; 58 default: return "unknown";
59 }
60 }
61
62 static const char* _map_specialfield(int info) {
63 switch(info) {
64 case 0: return "";
65 case 1: return "with wildcard";
66 case 2: return "(resource data only)";
67 default: return "with mysterious identifier";
58 } 68 }
59 } 69 }
60 70
61 static const char* _map_operator(davqloperator_t op) { 71 static const char* _map_operator(davqloperator_t op) {
62 // don't use string array, because enum values may change 72 // don't use string array, because enum values may change
78 88
79 static void dav_debug_ql_stmt_print(DavQLStatement *stmt) { 89 static void dav_debug_ql_stmt_print(DavQLStatement *stmt) {
80 sstr_t empty = ST("(empty)"); 90 sstr_t empty = ST("(empty)");
81 91
82 // Basic information 92 // Basic information
83 printf("Statement: %.*s\nType: %s\nField count: %zu", 93 size_t fieldcount = ucx_list_size(stmt->fields);
94 int specialfield = 0;
95 UCX_FOREACH(elm, stmt->fields) {
96 DavQLExpression* expr = (DavQLExpression*)elm->data;
97 if (expr->type == DAVQL_IDENTIFIER && expr->srctext.length == 1) {
98 if (expr->srctext.ptr[0] == '*') {
99 specialfield = 1;
100 } else if (expr->srctext.ptr[0] == '-') {
101 specialfield = 2;
102 }
103 }
104 }
105 if (specialfield) {
106 fieldcount--;
107 }
108 printf("Statement: %.*s\nType: %s\nField count: %zu %s\nPath: %.*s\n"
109 "Has where clause: %s\n",
84 sfmtarg(stmt->srctext), 110 sfmtarg(stmt->srctext),
85 _map_querytype(stmt->type), 111 _map_querytype(stmt->type),
86 ucx_list_size(stmt->fields)); 112 fieldcount,
87 113 _map_specialfield(specialfield),
88 // Has wildcard
89 _Bool wildcard = 0;
90 UCX_FOREACH(elm, stmt->fields) {
91 DavQLExpression* expr = (DavQLExpression*)elm->data;
92 if (expr->type == DAVQL_IDENTIFIER &&
93 expr->srctext.length == 1 && expr->srctext.ptr[0] == '*') {
94 wildcard = 1;
95 }
96 }
97 printf(" %s wildcard\nPath: %.*s\nHas where clause: %s\n",
98 wildcard?"with":"without",
99 sfmtarg(stmt->path ? stmt->path->srctext : empty), 114 sfmtarg(stmt->path ? stmt->path->srctext : empty),
100 stmt->where ? "yes" : "no"); 115 stmt->where ? "yes" : "no");
101 if (stmt->type == DAVQL_SET) { 116 if (stmt->type == DAVQL_SET) {
102 printf("Value list size matches: %s", 117 printf("Value list size matches: %s",
103 ucx_list_size(stmt->fields) == ucx_list_size(stmt->setvalues) 118 ucx_list_size(stmt->fields) == ucx_list_size(stmt->setvalues)
107 // WITH attributes 122 // WITH attributes
108 if (stmt->depth < 0) { 123 if (stmt->depth < 0) {
109 printf("Depth: infinity\n"); 124 printf("Depth: infinity\n");
110 } else { 125 } else {
111 printf("Depth: %d\n", stmt->depth); 126 printf("Depth: %d\n", stmt->depth);
127 }
128 if (stmt->errorcode) {
129 printf("\nError code: %d\nError: %s\n",
130 stmt->errorcode, stmt->errormessage);
112 } 131 }
113 } 132 }
114 133
115 static int dav_debug_ql_expr_selected(DavQLExpression *expr) { 134 static int dav_debug_ql_expr_selected(DavQLExpression *expr) {
116 if (!expr) { 135 if (!expr) {
174 } 193 }
175 194
176 printf("Starting DavQL debugger (type 'h' for help)...\n\n"); 195 printf("Starting DavQL debugger (type 'h' for help)...\n\n");
177 dav_debug_ql_stmt_print(stmt); 196 dav_debug_ql_stmt_print(stmt);
178 197
198 if (stmt->errorcode) {
199 return;
200 }
201
179 DavQLExpression *examineexpr = NULL; 202 DavQLExpression *examineexpr = NULL;
180 203
181 while(1) { 204 while(1) {
182 int cmd = dav_debug_ql_command(); 205 int cmd = dav_debug_ql_command();
183 switch (cmd) { 206 switch (cmd) {
225 } 248 }
226 249
227 // ------------------------------------------------------------------------ 250 // ------------------------------------------------------------------------
228 // P A R S E R 251 // P A R S E R
229 // ------------------------------------------------------------------------ 252 // ------------------------------------------------------------------------
253
254 #define _unexpected_end_msg "unexpected end of statement"
255 #define _invalid_msg "invalid statement"
256 #define _unexpected_token "unexpected token (%.*s [->]%.*s %.*s)"
230 257
231 static UcxList* dav_parse_tokenize(sstr_t src) { 258 static UcxList* dav_parse_tokenize(sstr_t src) {
232 UcxList *tokens = NULL; 259 UcxList *tokens = NULL;
233 260
234 // Delimiters: whitespace and dead whitespace around commas 261 // Delimiters: whitespace and dead whitespace around commas
326 } 353 }
327 354
328 return expr; 355 return expr;
329 } 356 }
330 357
358 static void dav_parse_unexpected_token(DavQLStatement *stmt, UcxList *token) {
359 sstr_t emptystring = ST("");
360 stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN;
361 sstr_t errormsg = ucx_sprintf(_unexpected_token,
362 sfmtarg(token->prev?*token_sstr(token->prev):emptystring),
363 sfmtarg(*token_sstr(token)),
364 sfmtarg(token->next?*token_sstr(token->next):emptystring));
365 stmt->errormessage = errormsg.ptr;
366 }
367
331 static void dav_parse_get_statement(DavQLStatement *stmt, UcxList *tokens) { 368 static void dav_parse_get_statement(DavQLStatement *stmt, UcxList *tokens) {
332 stmt->type = DAVQL_GET; 369 stmt->type = DAVQL_GET;
333 370
334 /* 371 /*
335 * 10: field list 372 * 10: field list
337 * 520: expecting WHERE or WITH clause 374 * 520: expecting WHERE or WITH clause
338 * 30: WHERE clause 375 * 30: WHERE clause
339 * 530: expecting WITH clause 376 * 530: expecting WITH clause
340 * 40: WITH clause 377 * 40: WITH clause
341 * 500: ready to quit 378 * 500: ready to quit
379 * 999: error
342 * 380 *
343 */ 381 */
344 int step = 10; 382 int step = 10;
345 383
346 // Variables for token sublists for expressions 384 // Variables for token sublists for expressions
355 // optional clauses 393 // optional clauses
356 case 520: 394 case 520:
357 if (!sstrcasecmp(tokendata, S("where"))) { 395 if (!sstrcasecmp(tokendata, S("where"))) {
358 step = 30; 396 step = 30;
359 } 397 }
360 /* no break */ 398 /* no break and no else*/
361 case 530: 399 case 530:
362 if (!sstrcasecmp(tokendata, S("with"))) { 400 if (!sstrcasecmp(tokendata, S("with"))) {
363 step = 40; 401 step = 40;
402 } else {
403 dav_parse_unexpected_token(stmt, token);
404 step = 999;
364 } 405 }
365 break; 406 break;
366 // field list 407 // field list
367 case 10: { 408 case 10: {
368 _Bool fromkeyword = !sstrcasecmp(tokendata, S("from")); 409 _Bool fromkeyword = !sstrcasecmp(tokendata, S("from"));
405 break; 446 break;
406 } 447 }
407 } 448 }
408 449
409 if (step < 500) { 450 if (step < 500) {
410 stmt->type = DAVQL_ERROR; 451 stmt->errorcode = DAVQL_ERROR_UNEXPECTED_END;
411 // TODO: save parse error message 452 stmt->errormessage = strdup(_unexpected_end_msg);
412 } 453 }
413 } 454 }
414 455
415 static void dav_parse_set_statement(DavQLStatement *stmt, UcxList *tokens) { 456 static void dav_parse_set_statement(DavQLStatement *stmt, UcxList *tokens) {
416 stmt->type = DAVQL_SET; 457 stmt->type = DAVQL_SET;
444 dav_parse_get_statement(stmt, tokens); 485 dav_parse_get_statement(stmt, tokens);
445 } else if (!sstrcasecmp(token, S("set"))) { 486 } else if (!sstrcasecmp(token, S("set"))) {
446 dav_parse_set_statement(stmt, tokens); 487 dav_parse_set_statement(stmt, tokens);
447 } else { 488 } else {
448 stmt->type = DAVQL_ERROR; 489 stmt->type = DAVQL_ERROR;
490 stmt->errorcode = DAVQL_ERROR_INVALID;
491 stmt->errormessage = strdup(_invalid_msg);
449 } 492 }
450 493
451 // free token data 494 // free token data
452 UCX_FOREACH(token, tokens) { 495 UCX_FOREACH(token, tokens) {
453 free(token->data); 496 free(token->data);
454 } 497 }
455 ucx_list_free(tokens); 498 ucx_list_free(tokens);
456 } else { 499 } else {
457 stmt->type = DAVQL_ERROR; 500 stmt->type = DAVQL_ERROR;
501 stmt->errorcode = DAVQL_ERROR_INVALID;
502 stmt->errormessage = strdup(_invalid_msg);
458 } 503 }
459 504
460 return stmt; 505 return stmt;
461 } 506 }
462 507
484 dav_free_expression(stmt->path); 529 dav_free_expression(stmt->path);
485 } 530 }
486 if (stmt->where) { 531 if (stmt->where) {
487 dav_free_expression(stmt->where); 532 dav_free_expression(stmt->where);
488 } 533 }
534 if (stmt->errormessage) {
535 free(stmt->errormessage);
536 }
489 free(stmt); 537 free(stmt);
490 } 538 }

mercurial