libidav/davqlparser.c

changeset 101
95a215337b53
parent 99
579238097973
child 102
e9ae1318a559
equal deleted inserted replaced
100:f4127c4d1018 101:95a215337b53
47 } 47 }
48 } 48 }
49 49
50 static const char* _map_exprtype(davqlexprtype_t type) { 50 static const char* _map_exprtype(davqlexprtype_t type) {
51 switch(type) { 51 switch(type) {
52 case DAVQL_LITERAL: return "LITERAL"; 52 case DAVQL_UNDEFINED_TYP: return "undefined";
53 case DAVQL_NUMBER: return "NUMBER";
54 case DAVQL_STRING: return "STRING";
55 case DAVQL_TIMESTAMP: return "TIMESTAMP";
53 case DAVQL_IDENTIFIER: return "IDENTIFIER"; 56 case DAVQL_IDENTIFIER: return "IDENTIFIER";
54 case DAVQL_UNARY: return "UNARY"; 57 case DAVQL_UNARY: return "UNARY";
55 case DAVQL_BINARY: return "BINARY"; 58 case DAVQL_BINARY: return "BINARY";
56 case DAVQL_LOGICAL: return "LOGICAL"; 59 case DAVQL_LOGICAL: return "LOGICAL";
57 case DAVQL_FUNCCALL: return "FUNCCALL"; 60 case DAVQL_FUNCCALL: return "FUNCCALL";
88 91
89 static void dav_debug_ql_stmt_print(DavQLStatement *stmt) { 92 static void dav_debug_ql_stmt_print(DavQLStatement *stmt) {
90 // Basic information 93 // Basic information
91 size_t fieldcount = ucx_list_size(stmt->fields); 94 size_t fieldcount = ucx_list_size(stmt->fields);
92 int specialfield = 0; 95 int specialfield = 0;
93 UCX_FOREACH(elm, stmt->fields) { 96 if (stmt->fields) {
94 DavQLExpression* expr = (DavQLExpression*)elm->data; 97 DavQLField* firstfield = (DavQLField*)stmt->fields->data;
95 if (expr->type == DAVQL_IDENTIFIER && expr->srctext.length == 1) { 98 if (firstfield->expr->type == DAVQL_IDENTIFIER) {
96 if (expr->srctext.ptr[0] == '*') { 99 switch (firstfield->expr->srctext.ptr[0]) {
97 specialfield = 1; 100 case '*': specialfield = 1; break;
98 } else if (expr->srctext.ptr[0] == '-') { 101 case '-': specialfield = 2; break;
99 specialfield = 2;
100 } 102 }
101 } 103 }
102 } 104 }
103 if (specialfield) { 105 if (specialfield) {
104 fieldcount--; 106 fieldcount--;
109 _map_querytype(stmt->type), 111 _map_querytype(stmt->type),
110 fieldcount, 112 fieldcount,
111 _map_specialfield(specialfield), 113 _map_specialfield(specialfield),
112 sfmtarg(stmt->path), 114 sfmtarg(stmt->path),
113 stmt->where ? "yes" : "no"); 115 stmt->where ? "yes" : "no");
114 if (stmt->type == DAVQL_SET) {
115 printf("Value list size matches: %s",
116 ucx_list_size(stmt->fields) == ucx_list_size(stmt->setvalues)
117 ? "yes" : "no");
118 }
119 116
120 // WITH attributes 117 // WITH attributes
121 if (stmt->depth < 0) { 118 if (stmt->depth == DAV_DEPTH_INFINITY) {
122 printf("Depth: infinity\n"); 119 printf("Depth: infinity\n");
120 } else if (stmt->depth == DAV_DEPTH_PLACEHOLDER) {
121 printf("Depth: placeholder\n");
123 } else { 122 } else {
124 printf("Depth: %d\n", stmt->depth); 123 printf("Depth: %d\n", stmt->depth);
125 } 124 }
125
126 // order by clause
127 printf("Order by: ");
128 if (stmt->orderby) {
129 UCX_FOREACH(crit, stmt->orderby) {
130 DavQLOrderCriterion *critdata = crit->data;
131 printf("%.*s %s%s", sfmtarg(critdata->column->srctext),
132 critdata->descending ? "desc" : "asc",
133 crit->next ? ", " : "\n");
134 }
135 } else {
136 printf("nothing\n");
137 }
138
139 // error messages
126 if (stmt->errorcode) { 140 if (stmt->errorcode) {
127 printf("\nError code: %d\nError: %s\n", 141 printf("\nError code: %d\nError: %s\n",
128 stmt->errorcode, stmt->errormessage); 142 stmt->errorcode, stmt->errormessage);
129 } 143 }
130 } 144 }
140 154
141 static void dav_debug_ql_expr_print(DavQLExpression *expr) { 155 static void dav_debug_ql_expr_print(DavQLExpression *expr) {
142 if (dav_debug_ql_expr_selected(expr)) { 156 if (dav_debug_ql_expr_selected(expr)) {
143 sstr_t empty = ST("(empty)"); 157 sstr_t empty = ST("(empty)");
144 printf( 158 printf(
145 "Text: %.*s\nType: %s\nOperator: %s\n" 159 "Text: %.*s\nType: %s\nOperator: %s\n",
146 "Left hand: %.*s\nRight hand: %.*s\n",
147 sfmtarg(expr->srctext), 160 sfmtarg(expr->srctext),
148 _map_exprtype(expr->type), 161 _map_exprtype(expr->type),
149 _map_operator(expr->op), 162 _map_operator(expr->op));
150 sfmtarg(expr->left?expr->left->srctext:empty), 163 if (expr->left || expr->right) {
151 sfmtarg(expr->right?expr->right->srctext:empty)); 164 printf("Left hand: %.*s\nRight hand: %.*s\n",
165 sfmtarg(expr->left?expr->left->srctext:empty),
166 sfmtarg(expr->right?expr->right->srctext:empty));
167 }
152 } 168 }
153 } 169 }
154 170
155 #define DQLD_CMD_Q 0 171 #define DQLD_CMD_Q 0
156 #define DQLD_CMD_PS 1 172 #define DQLD_CMD_PS 1
157 #define DQLD_CMD_PE 2 173 #define DQLD_CMD_PE 2
158 #define DQLD_CMD_P 10 174 #define DQLD_CMD_F 10
175 #define DQLD_CMD_W 11
176 #define DQLD_CMD_O 12
159 #define DQLD_CMD_L 21 177 #define DQLD_CMD_L 21
160 #define DQLD_CMD_R 22 178 #define DQLD_CMD_R 22
179 #define DQLD_CMD_N 23
180 #define DQLD_CMD_P 24
161 #define DQLD_CMD_H 100 181 #define DQLD_CMD_H 100
162 182
163 static int dav_debug_ql_command() { 183 static int dav_debug_ql_command() {
164 printf("> "); 184 printf("> ");
165 185
166 char buffer[16]; 186 char buffer[8];
167 fgets(buffer, 16, stdin); 187 fgets(buffer, 8, stdin);
188 // discard remaining chars
189 if (!strchr(buffer, '\n')) {
190 int chr;
191 while ((chr = fgetc(stdin) != '\n') && chr != EOF);
192 }
193
168 if (!strcmp(buffer, "q\n")) { 194 if (!strcmp(buffer, "q\n")) {
169 return DQLD_CMD_Q; 195 return DQLD_CMD_Q;
170 } else if (!strcmp(buffer, "ps\n")) { 196 } else if (!strcmp(buffer, "ps\n")) {
171 return DQLD_CMD_PS; 197 return DQLD_CMD_PS;
172 } else if (!strcmp(buffer, "pe\n")) { 198 } else if (!strcmp(buffer, "pe\n")) {
175 return DQLD_CMD_L; 201 return DQLD_CMD_L;
176 } else if (!strcmp(buffer, "r\n")) { 202 } else if (!strcmp(buffer, "r\n")) {
177 return DQLD_CMD_R; 203 return DQLD_CMD_R;
178 } else if (!strcmp(buffer, "h\n")) { 204 } else if (!strcmp(buffer, "h\n")) {
179 return DQLD_CMD_H; 205 return DQLD_CMD_H;
206 } else if (!strcmp(buffer, "f\n")) {
207 return DQLD_CMD_F;
208 } else if (!strcmp(buffer, "w\n")) {
209 return DQLD_CMD_W;
210 } else if (!strcmp(buffer, "o\n")) {
211 return DQLD_CMD_O;
212 } else if (!strcmp(buffer, "n\n")) {
213 return DQLD_CMD_N;
214 } else if (!strcmp(buffer, "p\n")) {
215 return DQLD_CMD_P;
180 } else { 216 } else {
181 return -1; 217 return -1;
182 } 218 }
183 } 219 }
184 220
194 if (stmt->errorcode) { 230 if (stmt->errorcode) {
195 return; 231 return;
196 } 232 }
197 233
198 DavQLExpression *examineexpr = NULL; 234 DavQLExpression *examineexpr = NULL;
235 UcxList *examineelem = NULL;
236 int examineclause = 0;
199 237
200 while(1) { 238 while(1) {
201 int cmd = dav_debug_ql_command(); 239 int cmd = dav_debug_ql_command();
202 switch (cmd) { 240 switch (cmd) {
203 case DQLD_CMD_Q: return; 241 case DQLD_CMD_Q: return;
204 case DQLD_CMD_PS: dav_debug_ql_stmt_print(stmt); break; 242 case DQLD_CMD_PS: dav_debug_ql_stmt_print(stmt); break;
205 case DQLD_CMD_PE: dav_debug_ql_expr_print(examineexpr); break; 243 case DQLD_CMD_PE: dav_debug_ql_expr_print(examineexpr); break;
244 case DQLD_CMD_F:
245 if (examineclause != DQLD_CMD_F) {
246 examineclause = DQLD_CMD_F;
247 examineelem = stmt->fields;
248 examineexpr = stmt->fields ?
249 ((DavQLField*)stmt->fields->data)->expr : NULL;
250 dav_debug_ql_expr_print(examineexpr);
251 }
252 break;
253 case DQLD_CMD_W:
254 examineclause = 0; examineelem = NULL;
255 examineexpr = stmt->where;
256 dav_debug_ql_expr_print(examineexpr);
257 break;
258 case DQLD_CMD_O:
259 if (examineclause != DQLD_CMD_O) {
260 examineclause = DQLD_CMD_O;
261 examineelem = stmt->orderby;
262 examineexpr = stmt->orderby ?
263 ((DavQLOrderCriterion*)stmt->orderby->data)->column : NULL;
264 dav_debug_ql_expr_print(examineexpr);
265 }
266 break;
267 case DQLD_CMD_N:
268 case DQLD_CMD_P:
269 if (examineelem) {
270 UcxList *newelem = (cmd == DQLD_CMD_N ?
271 examineelem->next : examineelem->prev);
272 if (newelem) {
273 examineelem = newelem;
274 if (examineclause == DQLD_CMD_O) {
275 examineexpr = ((DavQLOrderCriterion*)
276 examineelem->data)->column;
277 } else if (examineclause == DQLD_CMD_F) {
278 examineexpr = ((DavQLField*)examineelem->data)->expr;
279 } else {
280 printf("Examining unknown clause type.");
281 }
282 dav_debug_ql_expr_print(examineexpr);
283 } else {
284 printf("Reached end of list.\n");
285 }
286 } else {
287 printf("Currently not examining an expression list.\n");
288 }
289 break;
206 case DQLD_CMD_L: 290 case DQLD_CMD_L:
207 if (dav_debug_ql_expr_selected(examineexpr)) { 291 if (dav_debug_ql_expr_selected(examineexpr)) {
208 if (examineexpr->left) { 292 if (examineexpr->left) {
209 examineexpr = examineexpr->left; 293 examineexpr = examineexpr->left;
210 dav_debug_ql_expr_print(examineexpr); 294 dav_debug_ql_expr_print(examineexpr);
225 break; 309 break;
226 case DQLD_CMD_H: 310 case DQLD_CMD_H:
227 printf( 311 printf(
228 "\nCommands:\n" 312 "\nCommands:\n"
229 "ps: print statement information\n" 313 "ps: print statement information\n"
314 "o: examine order by clause\n"
315 "f: examine field list\n"
316 "w: examine where clause\n"
317 "n: examine next expression "
318 "(in order by clause or field list)\n"
319 "p: examine previous expression "
320 "(in order by clause or field list)\n"
230 "q: quit\n\n" 321 "q: quit\n\n"
231 "\nExpression examination:\n" 322 "\nExpression examination:\n"
232 "pe: print expression information\n" 323 "pe: print expression information\n"
233 "l: enter left subtree\n" 324 "l: enter left subtree\n"
234 "r: enter right subtree\n"); 325 "r: enter right subtree\n");
243 // ------------------------------------------------------------------------ 334 // ------------------------------------------------------------------------
244 335
245 #define _unexpected_end_msg "unexpected end of statement" 336 #define _unexpected_end_msg "unexpected end of statement"
246 #define _invalid_msg "invalid statement" 337 #define _invalid_msg "invalid statement"
247 #define _unexpected_token "unexpected token (%.*s [->]%.*s %.*s)" 338 #define _unexpected_token "unexpected token (%.*s [->]%.*s %.*s)"
339 #define _expected_token "expected token '%s' before '%.*s'"
340 #define _expected_by "expected 'by' after 'order' (order [->]%.*s)"
341 #define _missing_fmtspec "format specifier missing (%.*s [->]%.*s %.*s)"
342 #define _invalid_fmtspec "invalid format specifier (%.*s [->]%.*s %.*s)"
343 #define _unknown_fmtspec "unknown format specifier (%.*s [->]%.*s %.*s)"
248 #define _missing_quote "missing closing quote symbol (%.*s)" 344 #define _missing_quote "missing closing quote symbol (%.*s)"
345 #define _parser_state "parser reached invalid state"
346 #define _unknown_attribute "unknown attribute '%.*s'"
347 #define _duplicated_attribute "duplicated attribute '%.*s'"
348 #define _invalid_depth "invalid depth"
349 #define _invalid_path "invalid path"
350
351 #define _identifier_expected "identifier expected (%.*s [->]%.*s %.*s)"
352 #define _idornum_expected "identifier or number expected (%.*s [->]%.*s %.*s)"
353 #define _idorstr_expected "identifier or string expected (%.*s [->]%.*s %.*s)"
354 #define _idorts_expected "identifier or timestamp expected (%.*s [->]%.*s %.*s)"
355
356 #define token_sstr(listelem) ((sstr_t*)(listelem)->data)
357
358 static void dav_error_in_context(int errorcode, const char *errormsg,
359 DavQLStatement *stmt, UcxList *token) {
360 sstr_t emptystring = ST("");
361 stmt->errorcode = errorcode;
362 stmt->errormessage = ucx_sprintf(errormsg,
363 sfmtarg(token->prev?*token_sstr(token->prev):emptystring),
364 sfmtarg(*token_sstr(token)),
365 sfmtarg(token->next?*token_sstr(token->next):emptystring)).ptr;
366 }
367
368 // special symbols are single tokens - the % sign MUST NOT be a special symbol
369 static const char *special_token_symbols = ",()+-*/&|^~=!<>";
249 370
250 static UcxList* dav_parse_tokenize(sstr_t src) { 371 static UcxList* dav_parse_tokenize(sstr_t src) {
251 UcxList *tokens = NULL; 372 UcxList *tokens = NULL;
252 373
253 // Delimiters: whitespace and dead whitespace around commas
254 sstr_t *token = NULL; 374 sstr_t *token = NULL;
255 char insequence = '\0'; 375 char insequence = '\0';
256 for (size_t i = 0 ; i < src.length ; i++) { 376 for (size_t i = 0 ; i < src.length ; i++) {
257 // quoted strings / identifiers are a single token 377 // quoted strings / identifiers are a single token
258 if (src.ptr[i] == '\'' || src.ptr[i] == '`') { 378 if (src.ptr[i] == '\'' || src.ptr[i] == '`') {
281 // add token before spaces to list (if any) 401 // add token before spaces to list (if any)
282 if (token) { 402 if (token) {
283 tokens = ucx_list_append(tokens, token); 403 tokens = ucx_list_append(tokens, token);
284 token = NULL; 404 token = NULL;
285 } 405 }
286 } else if (src.ptr[i] == ',') { 406 } else if (strchr(special_token_symbols, src.ptr[i])) {
287 // add token before comma to list (if any) 407 // add token before special symbol to list (if any)
288 if (token) { 408 if (token) {
289 tokens = ucx_list_append(tokens, token); 409 tokens = ucx_list_append(tokens, token);
290 token = NULL; 410 token = NULL;
291 } 411 }
292 // add comma as token to list 412 // add special symbol as single token to list
293 token = malloc(sizeof(sstr_t)); 413 token = malloc(sizeof(sstr_t));
294 token->ptr = src.ptr + i; 414 token->ptr = src.ptr + i;
295 token->length = 1; 415 token->length = 1;
296 tokens = ucx_list_append(tokens, token); 416 tokens = ucx_list_append(tokens, token);
297 // set tokenizer ready to read more tokens 417 // set tokenizer ready to read more tokens
313 } 433 }
314 434
315 return tokens; 435 return tokens;
316 } 436 }
317 437
318 #define token_sstr(listelem) ((sstr_t*)(listelem)->data)
319 static DavQLExpression* dav_parse_expression( 438 static DavQLExpression* dav_parse_expression(
320 DavQLStatement* stmt, UcxList* starttoken, size_t n) { 439 DavQLStatement* stmt, UcxList* starttoken, size_t n) {
321 if (n == 0) { 440 if (n == 0) {
322 return NULL; 441 return NULL;
323 } 442 }
330 // special case - only one token 449 // special case - only one token
331 if (n == 1) { 450 if (n == 1) {
332 expr->srctext.length = token_sstr(starttoken)->length; 451 expr->srctext.length = token_sstr(starttoken)->length;
333 char firstchar = expr->srctext.ptr[0]; 452 char firstchar = expr->srctext.ptr[0];
334 char lastchar = expr->srctext.ptr[expr->srctext.length-1]; 453 char lastchar = expr->srctext.ptr[expr->srctext.length-1];
335 if (firstchar == '\'' || isdigit(firstchar)) { 454 if (firstchar == '\'') {
336 expr->type = DAVQL_LITERAL; 455 expr->type = DAVQL_STRING;
456 } else if (isdigit(firstchar)) {
457 expr->type = DAVQL_NUMBER;
458 } else if (firstchar == '%') {
459 if (expr->srctext.length == 1) {
460 dav_error_in_context(DAVQL_ERROR_MISSING_FMTSPEC,
461 _missing_fmtspec, stmt, starttoken);
462 } else if (expr->srctext.length == 2) {
463 switch (expr->srctext.ptr[1]) {
464 case 'd': expr->type = DAVQL_NUMBER; break;
465 case 's': expr->type = DAVQL_STRING; break;
466 case 't': expr->type = DAVQL_TIMESTAMP; break;
467 default:
468 dav_error_in_context(DAVQL_ERROR_UNKNOWN_FMTSPEC,
469 _unknown_fmtspec, stmt, starttoken);
470 }
471 } else {
472 dav_error_in_context(DAVQL_ERROR_INVALID_FMTSPEC,
473 _invalid_fmtspec, stmt, starttoken);
474 }
337 } else { 475 } else {
338 expr->type = DAVQL_IDENTIFIER; 476 expr->type = DAVQL_IDENTIFIER;
339 } 477 }
340 // remove quotes (if any) 478 // remove quotes (if any)
341 if (firstchar == '\'' || firstchar == '`') { 479 if (firstchar == '\'' || firstchar == '`') {
365 } 503 }
366 } 504 }
367 505
368 // process tokens 506 // process tokens
369 for (size_t i = 0 ; i < n ; i++) { 507 for (size_t i = 0 ; i < n ; i++) {
508 sstr_t tokendata = *token_sstr(token);
370 509
371 // TODO: make it so 510 // TODO: make it so
372 511
373 // go to next token (if this is not the last token) 512 // go to next token (if this is not the last token)
374 if (i < n-1) { 513 if (i < n-1) {
391 if (expr->right) { 530 if (expr->right) {
392 dav_free_expression(expr->right); 531 dav_free_expression(expr->right);
393 } 532 }
394 free(expr); 533 free(expr);
395 } 534 }
396 535
397 static void dav_parse_unexpected_token(DavQLStatement *stmt, UcxList *token) { 536 #define _step_fieldlist_ 10 // field list
398 sstr_t emptystring = ST(""); 537 #define _step_FROM_ 20 // FROM clause
399 stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN; 538 #define _step_WITH_ 30 // WITH clause
400 sstr_t errormsg = ucx_sprintf(_unexpected_token, 539 #define _step_WHERE_ 40 // WHERE clause
401 sfmtarg(token->prev?*token_sstr(token->prev):emptystring), 540 #define _step_ORDER_BYopt_ 552 // expecting more ORDER BY details or end
402 sfmtarg(*token_sstr(token)), 541 #define _step_ORDER_BY_ 50 // ORDER BY clause
403 sfmtarg(token->next?*token_sstr(token->next):emptystring)); 542 #define _step_end_ 500 // expect end
404 stmt->errormessage = errormsg.ptr; 543
544 struct fieldlist_parser_state {
545 UcxList *expr_firsttoken;
546 DavQLField *currentfield;
547 size_t expr_len;
548 /*
549 * 0: begin of field list - may encounter "*" or "-" special fields
550 * 1: collect expression token
551 * switch to step 2 on keyword "as"
552 * expect "," or "from" only if expr_len is 1 (add to list and continue)
553 * 2: expect one token (identifier) for as clause
554 * 3: expect a ",": continue with step 1
555 * or a "from": leave field list parser
556 * 4: expect end of field list (i.e. a "from" keyword)
557 */
558 int step;
559 };
560
561 static void dav_free_field(DavQLField *field) {
562 dav_free_expression(field->expr);
563 free(field);
564 }
565
566 static int dav_parse_fieldlist(DavQLStatement *stmt, UcxList *token,
567 struct fieldlist_parser_state *state) {
568 sstr_t tokendata = *token_sstr(token);
569
570 _Bool fromkeyword = !sstrcasecmp(tokendata, S("from"));
571 _Bool comma = !sstrcmp(tokendata, S(","));
572
573 switch (state->step) {
574 case 0:
575 if (!sstrcmp(tokendata, S("*")) || !sstrcmp(tokendata, S("-"))) {
576 DavQLField *field = malloc(sizeof(DavQLField));
577 field->name = tokendata;
578 field->expr = calloc(1, sizeof(DavQLExpression));
579 field->expr->type = DAVQL_IDENTIFIER;
580 field->expr->srctext = tokendata;
581 stmt->fields = ucx_list_append(stmt->fields, field);
582
583 if (tokendata.ptr[0] == '-') {
584 // no further fields may follow, if dash symbol has been found
585 state->step = 4;
586 } else {
587 state->step = 3;
588 }
589 return _step_fieldlist_;
590 }
591 // did not encounter special field, fall through to step 1
592 state->step = 1;
593 case 1:
594 if (fromkeyword || comma) {
595 // add possible identifier to list
596 if (state->expr_firsttoken) {
597 // TODO: skip comma in function call)
598 if (state->expr_len > 1) {
599 stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN;
600 stmt->errormessage = ucx_sprintf(_expected_token,
601 "AS", sfmtarg(tokendata)).ptr;
602 return 0;
603 }
604
605 DavQLExpression *expr = dav_parse_expression(
606 stmt, state->expr_firsttoken, state->expr_len);
607
608 if (expr->type != DAVQL_IDENTIFIER) {
609 dav_free_expression(expr);
610 stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN;
611 stmt->errormessage = ucx_sprintf(_expected_token,
612 "AS", sfmtarg(tokendata)).ptr;
613 return 0;
614 } // TODO: do not allow identifier when wildcard is present
615
616 DavQLField *field = malloc(sizeof(DavQLField));
617 field->expr = expr;
618 field->name = field->expr->srctext;
619 stmt->fields = ucx_list_append(stmt->fields, field);
620
621 state->expr_firsttoken = NULL;
622 state->expr_len = 0;
623
624 if (fromkeyword) {
625 return _step_FROM_;
626 }
627 } else {
628 dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN,
629 _unexpected_token, stmt, token);
630 return 0;
631 }
632 } else if (!sstrcasecmp(tokendata, S("as"))) {
633 // TODO: return error, if expr_first_token is NULL
634 state->currentfield = malloc(sizeof(DavQLField));
635 state->currentfield->expr = dav_parse_expression(
636 stmt, state->expr_firsttoken, state->expr_len);
637
638 state->expr_firsttoken = NULL;
639 state->expr_len = 0;
640
641 state->step = 2;
642 } else {
643 // collect tokens for field expression
644 if (state->expr_firsttoken) {
645 state->expr_len++;
646 } else {
647 state->expr_firsttoken = token;
648 state->expr_len = 1;
649 }
650 }
651
652 return _step_fieldlist_;
653 case 2: {
654 DavQLExpression *expr = dav_parse_expression(stmt, token, 1);
655 if (expr->type == DAVQL_IDENTIFIER) {
656 state->currentfield->name = expr->srctext;
657 stmt->fields = ucx_list_append(stmt->fields, state->currentfield);
658 state->currentfield = NULL;
659 } else {
660 dav_free_field(state->currentfield);
661 dav_error_in_context(DAVQL_ERROR_IDENTIFIER_EXPECTED,
662 _identifier_expected, stmt, token);
663
664 }
665 dav_free_expression(expr);
666 state->step = 3;
667
668 return _step_fieldlist_;
669 }
670 case 3:
671 if (fromkeyword) {
672 return _step_FROM_;
673 } else if (comma) {
674 state->step = 1;
675 return _step_fieldlist_;
676 } else {
677 dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN,
678 _unexpected_token, stmt, token);
679 return 0;
680 }
681 case 4:
682 if (fromkeyword) {
683 return _step_FROM_;
684 } else {
685 stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN;
686 stmt->errormessage = ucx_sprintf(_expected_token,
687 "FROM", sfmtarg(tokendata)).ptr;
688 return 0;
689 }
690 }
691 }
692
693 static int dav_parse_from(DavQLStatement *stmt, UcxList *token) {
694 sstr_t tokendata = *token_sstr(token);
695
696 if (!sstrcasecmp(tokendata, S("with"))) {
697 return _step_WITH_;
698 } else if (!sstrcasecmp(tokendata, S("where"))) {
699 return _step_WHERE_;
700 } else if (!sstrcasecmp(tokendata, S("order"))) {
701 return _step_ORDER_BY_;
702 } else {
703 if (stmt->path.ptr) {
704 if (stmt->path.ptr[0] == '/') {
705 char *end = tokendata.ptr+tokendata.length;
706 stmt->path.length = end - stmt->path.ptr;
707 } else {
708 stmt->errorcode = DAVQL_ERROR_INVALID_PATH;
709 stmt->errormessage = strdup(_invalid_path);
710 }
711 } else {
712 if (tokendata.ptr[0] == '/' || !sstrcmp(tokendata, S("%s"))) {
713 stmt->path = tokendata;
714 } else {
715 stmt->errorcode = DAVQL_ERROR_INVALID_PATH;
716 stmt->errormessage = strdup(_invalid_path);
717 }
718 }
719 return _step_FROM_;
720 }
721 }
722
723 struct with_parser_state {
724 /*
725 * 0: key
726 * 1: =
727 * 2: value
728 * 3: comma or new clause
729 */
730 int step;
731 /*
732 * 1: depth
733 */
734 int key;
735 int keymask;
736 };
737
738 static int dav_parse_with_clause(DavQLStatement *stmt, UcxList *token,
739 struct with_parser_state *state) {
740 sstr_t tokendata = *token_sstr(token);
741
742 switch (state->step) {
743 case 0:
744 if (!sstrcasecmp(tokendata, S("depth"))) {
745 state->key = 1;
746 state->step = 1;
747 } else {
748 stmt->errorcode = DAVQL_ERROR_UNKNOWN_ATTRIBUTE;
749 stmt->errormessage = ucx_sprintf(_unknown_attribute,
750 sfmtarg(tokendata)).ptr;
751 break;
752 }
753 if (state->keymask & state->key) {
754 stmt->errorcode = DAVQL_ERROR_DUPLICATED_ATTRIBUTE;
755 stmt->errormessage = ucx_sprintf(_duplicated_attribute,
756 sfmtarg(tokendata)).ptr;
757 } else {
758 state->keymask |= state->key;
759 }
760 return _step_WITH_; // continue parsing WITH clause
761 case 1:
762 if (sstrcmp(tokendata, S("="))) {
763 stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN;
764 stmt->errormessage = ucx_sprintf(_expected_token,
765 "=", sfmtarg(tokendata)).ptr;
766 } else {
767 state->step = 2;
768 }
769 return _step_WITH_; // continue parsing WITH clause
770 case 2:
771 switch (state->key) {
772 case 1: /* depth */
773 if (!sstrcasecmp(tokendata, S("infinity"))) {
774 stmt->depth = DAV_DEPTH_INFINITY;
775 } else {
776 DavQLExpression *depthexpr =
777 dav_parse_expression(stmt, token, 1);
778
779 if (depthexpr->type == DAVQL_NUMBER) {
780 if (depthexpr->srctext.ptr[0] == '%') {
781 stmt->depth = DAV_DEPTH_PLACEHOLDER;
782 } else {
783 sstr_t depthstr = depthexpr->srctext;
784 char *conv = malloc(depthstr.length+1);
785 char *chk;
786 memcpy(conv, depthstr.ptr, depthstr.length);
787 conv[depthstr.length] = '\0';
788 stmt->depth = strtol(conv, &chk, 10);
789 if (*chk || stmt->depth < -1) {
790 stmt->errorcode = DAVQL_ERROR_INVALID_DEPTH;
791 stmt->errormessage = strdup(_invalid_depth);
792 }
793 free(conv);
794 }
795 } else {
796 stmt->errorcode = DAVQL_ERROR_INVALID_DEPTH;
797 stmt->errormessage = strdup(_invalid_depth);
798 }
799
800 dav_free_expression(depthexpr);
801 }
802 break;
803 }
804 state->step = 3;
805 return _step_WITH_; // continue parsing WITH clause
806 case 3:
807 // a with clause may be continued with a comma
808 // or another clause may follow
809 if (!sstrcmp(tokendata, S(","))) {
810 state->step = 0; // reset clause parser
811 return _step_WITH_;
812 } else if (!sstrcasecmp(tokendata, S("where"))) {
813 return _step_WHERE_;
814 } else if (!sstrcasecmp(tokendata, S("order"))) {
815 return _step_ORDER_BY_;
816 } else {
817 dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN,
818 _unexpected_token, stmt, token);
819 return 0;
820 }
821 default:
822 stmt->errorcode = DAVQL_ERROR_INVALID;
823 stmt->errormessage = strdup(_parser_state);
824 return 0;
825 }
826 }
827
828 struct orderby_parser_state {
829 /*
830 * 0: expect by keyword
831 * 1: expect identifier / number
832 * 2: expect asc / desc or comma
833 * 3: expect comma
834 */
835 int step;
836 DavQLOrderCriterion *crit;
837 };
838
839 static int dav_parse_orderby_clause(DavQLStatement *stmt, UcxList *token,
840 struct orderby_parser_state *state) {
841
842 sstr_t tokendata = *token_sstr(token);
843
844 switch (state->step) {
845 case 0:
846 if (!sstrcasecmp(tokendata, S("by"))) {
847 state->step++;
848 } else {
849 stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN;
850 stmt->errormessage = ucx_sprintf(_expected_by,
851 sfmtarg(tokendata)).ptr;
852 }
853 return _step_ORDER_BY_;
854 case 1:
855 state->crit = malloc(sizeof(DavQLOrderCriterion));
856 state->crit->column = dav_parse_expression(stmt, token, 1);
857 state->crit->descending = 0;
858
859 if (!state->crit->column || (
860 state->crit->column->type != DAVQL_NUMBER &&
861 state->crit->column->type != DAVQL_IDENTIFIER)) {
862 free(state->crit);
863 dav_error_in_context(DAVQL_ERROR_IDORNUM_EXPECTED,
864 _idornum_expected, stmt, token);
865 } else {
866 stmt->orderby = ucx_list_append(stmt->orderby, state->crit);
867 }
868
869 // continue parsing clause, if more tokens available
870 state->step++;
871 return _step_ORDER_BYopt_;
872 case 2:
873 if (!sstrcasecmp(tokendata, S("desc"))) {
874 state->crit->descending = 1;
875 } else if (!sstrcasecmp(tokendata, S("asc"))) {
876 state->crit->descending = 0;
877 } else if (!sstrcmp(tokendata, S(","))) {
878 state->step = 1; // reset clause parser
879 return _step_ORDER_BY_; // statement must not end now
880 } else {
881 dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN,
882 _unexpected_token, stmt, token);
883 return 0;
884 }
885 // continue parsing clause, if more tokens available
886 state++;
887 return _step_ORDER_BYopt_;
888 case 3:
889 if (!sstrcmp(tokendata, S(","))) {
890 state->step = 1; // reset clause parser
891 return _step_ORDER_BY_; // statement must not end now
892 } else {
893 dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN,
894 _unexpected_token, stmt, token);
895 return 0;
896 }
897 }
898
899 return _step_end_;
900 }
901
902 static void dav_free_order_criterion(DavQLOrderCriterion *crit) {
903 if (crit->column) { // do it null-safe though column is expected to be set
904 dav_free_expression(crit->column);
905 }
906 free(crit);
405 } 907 }
406 908
407 static void dav_parse_get_statement(DavQLStatement *stmt, UcxList *tokens) { 909 static void dav_parse_get_statement(DavQLStatement *stmt, UcxList *tokens) {
408 stmt->type = DAVQL_GET; 910 stmt->type = DAVQL_GET;
409 911
410 /* 912 int step = _step_fieldlist_;
411 * 10: field list 913
412 * 20: FROM clause 914 struct with_parser_state state_with;
413 * 520: expecting WHERE or WITH clause 915 memset(&state_with, 0, sizeof(struct with_parser_state));
414 * 30: WHERE clause 916 struct orderby_parser_state state_orderby;
415 * 530: expecting WITH clause 917 memset(&state_orderby, 0, sizeof(struct orderby_parser_state));
416 * 40: WITH clause 918 struct fieldlist_parser_state state_fieldlist;
417 * 500: ready to quit 919 memset(&state_fieldlist, 0, sizeof(struct fieldlist_parser_state));
418 * 999: error
419 *
420 */
421 int step = 10;
422
423 // Variables for token sublists for expressions
424 UcxList *exprstart = NULL;
425 size_t exprlen = 0;
426 920
427 // Process tokens 921 // Process tokens
428 UCX_FOREACH(token, tokens) { 922 UCX_FOREACH(token, tokens) {
923 switch (step) {
924 // too much input data
925 case _step_end_:
926 dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN,
927 _unexpected_token, stmt, token);
928 break;
929 // field list
930 case _step_fieldlist_: {
931 step = dav_parse_fieldlist(stmt, token, &state_fieldlist);
932 break;
933 }
934 // from clause
935 case _step_FROM_: {
936 step = dav_parse_from(stmt, token);
937 break;
938 }
939 // with clause
940 case _step_WITH_: {
941 step = dav_parse_with_clause(stmt, token, &state_with);
942 break;
943 }
944 // where clause
945 case _step_WHERE_:
946 // TODO: implement
947 step = _step_end_;
948 break;
949 // order by clause
950 case _step_ORDER_BY_:
951 case _step_ORDER_BYopt_:
952 step = dav_parse_orderby_clause(stmt, token, &state_orderby);
953 break;
954 default:
955 stmt->errorcode = DAVQL_ERROR_INVALID;
956 stmt->errormessage = strdup(_parser_state);
957 }
958
959 // cancel processing, when an error has been detected
429 if (stmt->errorcode) { 960 if (stmt->errorcode) {
430 ultrabreak: break; 961 break;
431 } 962 }
432 963 }
433 sstr_t tokendata = *token_sstr(token); 964
434 965 if (!stmt->errorcode && step < _step_end_) {
435 switch (step) {
436 // optional clauses
437 case 520:
438 if (!sstrcasecmp(tokendata, S("where"))) {
439 step = 30;
440 }
441 /* no break and no else*/
442 case 530:
443 if (!sstrcasecmp(tokendata, S("with"))) {
444 step = 40;
445 } else {
446 dav_parse_unexpected_token(stmt, token);
447 goto ultrabreak;
448 }
449 break;
450 // field list
451 case 10: {
452 _Bool fromkeyword = !sstrcasecmp(tokendata, S("from"));
453 if (fromkeyword || !sstrcmp(tokendata, S(","))) {
454 if (exprstart) {
455 stmt->fields = ucx_list_append(stmt->fields,
456 dav_parse_expression(stmt, exprstart, exprlen));
457 exprstart = NULL;
458 exprlen = 0;
459 } else {
460 // TODO: throw syntax error
461 }
462
463 if (fromkeyword) {
464 step = 20;
465 }
466 } else {
467 // collect tokens for field expression
468 if (exprstart) {
469 exprlen++;
470 } else {
471 exprstart = token;
472 exprlen = 1;
473 }
474 }
475 break;
476 }
477 // from clause
478 case 20: {
479 DavQLExpression *expr = dav_parse_expression(stmt, token, 1);
480 stmt->path = expr->srctext;
481 dav_free_expression(expr);
482 step = 520;
483 break;
484 }
485 // where clause
486 case 30:
487 step = 530;
488 break;
489 // with clause
490 case 40:
491 step = 500;
492 break;
493 }
494 }
495
496 if (step < 500) {
497 stmt->errorcode = DAVQL_ERROR_UNEXPECTED_END; 966 stmt->errorcode = DAVQL_ERROR_UNEXPECTED_END;
498 stmt->errormessage = strdup(_unexpected_end_msg); 967 stmt->errormessage = strdup(_unexpected_end_msg);
499 } 968 }
500 } 969 }
501 970
551 return stmt; 1020 return stmt;
552 } 1021 }
553 1022
554 void dav_free_statement(DavQLStatement *stmt) { 1023 void dav_free_statement(DavQLStatement *stmt) {
555 UCX_FOREACH(expr, stmt->fields) { 1024 UCX_FOREACH(expr, stmt->fields) {
556 dav_free_expression(expr->data); 1025 dav_free_field(expr->data);
557 } 1026 }
558 ucx_list_free(stmt->fields); 1027 ucx_list_free(stmt->fields);
559 UCX_FOREACH(expr, stmt->setvalues) {
560 dav_free_expression(expr->data);
561 }
562 ucx_list_free(stmt->setvalues);
563 1028
564 if (stmt->where) { 1029 if (stmt->where) {
565 dav_free_expression(stmt->where); 1030 dav_free_expression(stmt->where);
566 } 1031 }
567 if (stmt->errormessage) { 1032 if (stmt->errormessage) {
568 free(stmt->errormessage); 1033 free(stmt->errormessage);
569 } 1034 }
1035 UCX_FOREACH(crit, stmt->orderby) {
1036 dav_free_order_criterion(crit->data);
1037 }
1038 ucx_list_free(stmt->orderby);
570 free(stmt); 1039 free(stmt);
571 } 1040 }

mercurial