179 sfmtarg(expr->right?expr->right->srctext:empty)); |
179 sfmtarg(expr->right?expr->right->srctext:empty)); |
180 } |
180 } |
181 } |
181 } |
182 } |
182 } |
183 |
183 |
|
184 static void dav_debug_ql_tree_print(DavQLExpression *expr, int depth) { |
|
185 if (expr) { |
|
186 if (expr->left) { |
|
187 printf("%*c%s\n", depth, ' ', _map_operator(expr->op)); |
|
188 dav_debug_ql_tree_print(expr->left, depth+1); |
|
189 dav_debug_ql_tree_print(expr->right, depth+1); |
|
190 } else if (expr->type == DAVQL_UNARY) { |
|
191 printf("%*c%s %.*s\n", depth, ' ', _map_operator(expr->op), |
|
192 sfmtarg(expr->srctext)); |
|
193 } else { |
|
194 printf("%*c%.*s\n", depth, ' ', sfmtarg(expr->srctext)); |
|
195 } |
|
196 } |
|
197 } |
|
198 |
184 #define DQLD_CMD_Q 0 |
199 #define DQLD_CMD_Q 0 |
185 #define DQLD_CMD_PS 1 |
200 #define DQLD_CMD_PS 1 |
186 #define DQLD_CMD_PE 2 |
201 #define DQLD_CMD_PE 2 |
187 #define DQLD_CMD_PF 3 |
202 #define DQLD_CMD_PF 3 |
|
203 #define DQLD_CMD_PT 4 |
188 #define DQLD_CMD_F 10 |
204 #define DQLD_CMD_F 10 |
189 #define DQLD_CMD_W 11 |
205 #define DQLD_CMD_W 11 |
190 #define DQLD_CMD_O 12 |
206 #define DQLD_CMD_O 12 |
191 #define DQLD_CMD_L 21 |
207 #define DQLD_CMD_L 21 |
192 #define DQLD_CMD_R 22 |
208 #define DQLD_CMD_R 22 |
211 return DQLD_CMD_PS; |
227 return DQLD_CMD_PS; |
212 } else if (!strcmp(buffer, "pe\n")) { |
228 } else if (!strcmp(buffer, "pe\n")) { |
213 return DQLD_CMD_PE; |
229 return DQLD_CMD_PE; |
214 } else if (!strcmp(buffer, "pf\n")) { |
230 } else if (!strcmp(buffer, "pf\n")) { |
215 return DQLD_CMD_PF; |
231 return DQLD_CMD_PF; |
|
232 } else if (!strcmp(buffer, "pt\n")) { |
|
233 return DQLD_CMD_PT; |
216 } else if (!strcmp(buffer, "l\n")) { |
234 } else if (!strcmp(buffer, "l\n")) { |
217 return DQLD_CMD_L; |
235 return DQLD_CMD_L; |
218 } else if (!strcmp(buffer, "r\n")) { |
236 } else if (!strcmp(buffer, "r\n")) { |
219 return DQLD_CMD_R; |
237 return DQLD_CMD_R; |
220 } else if (!strcmp(buffer, "h\n")) { |
238 } else if (!strcmp(buffer, "h\n")) { |
255 int cmd = dav_debug_ql_command(); |
273 int cmd = dav_debug_ql_command(); |
256 switch (cmd) { |
274 switch (cmd) { |
257 case DQLD_CMD_Q: return; |
275 case DQLD_CMD_Q: return; |
258 case DQLD_CMD_PS: dav_debug_ql_stmt_print(stmt); break; |
276 case DQLD_CMD_PS: dav_debug_ql_stmt_print(stmt); break; |
259 case DQLD_CMD_PE: dav_debug_ql_expr_print(examineexpr); break; |
277 case DQLD_CMD_PE: dav_debug_ql_expr_print(examineexpr); break; |
|
278 case DQLD_CMD_PT: dav_debug_ql_tree_print(examineexpr, 1); break; |
260 case DQLD_CMD_PF: dav_debug_ql_fnames_print(stmt); break; |
279 case DQLD_CMD_PF: dav_debug_ql_fnames_print(stmt); break; |
261 case DQLD_CMD_F: |
280 case DQLD_CMD_F: |
262 if (examineclause != DQLD_CMD_F) { |
281 if (examineclause != DQLD_CMD_F) { |
263 examineclause = DQLD_CMD_F; |
282 examineclause = DQLD_CMD_F; |
264 examineelem = stmt->fields; |
283 examineelem = stmt->fields; |
337 "p: examine previous expression " |
356 "p: examine previous expression " |
338 "(in order by clause or field list)\n" |
357 "(in order by clause or field list)\n" |
339 "q: quit\n\n" |
358 "q: quit\n\n" |
340 "\nExpression examination:\n" |
359 "\nExpression examination:\n" |
341 "pe: print expression information\n" |
360 "pe: print expression information\n" |
|
361 "pt: print full syntax tree of current (sub-)expression\n" |
342 "l: enter left subtree\n" |
362 "l: enter left subtree\n" |
343 "r: enter right subtree\n"); |
363 "r: enter right subtree\n"); |
344 break; |
364 break; |
345 default: printf("unknown command\n"); |
365 default: printf("unknown command\n"); |
346 } |
366 } |
582 } else { |
602 } else { |
583 expr->left = malloc(sizeof(DavQLExpression)); |
603 expr->left = malloc(sizeof(DavQLExpression)); |
584 memcpy(expr->left, &left, sizeof(DavQLExpression)); |
604 memcpy(expr->left, &left, sizeof(DavQLExpression)); |
585 expr->right = malloc(sizeof(DavQLExpression)); |
605 expr->right = malloc(sizeof(DavQLExpression)); |
586 memcpy(expr->right, &right, sizeof(DavQLExpression)); |
606 memcpy(expr->right, &right, sizeof(DavQLExpression)); |
|
607 |
|
608 expr->srctext.ptr = expr->left->srctext.ptr; |
|
609 expr->srctext.length = |
|
610 expr->right->srctext.ptr - |
|
611 expr->left->srctext.ptr + expr->right->srctext.length; |
587 } |
612 } |
588 |
613 |
589 return total_consumed; |
614 return total_consumed; |
590 } |
615 } |
591 |
616 |
625 } |
650 } |
626 |
651 |
627 static int dav_parse_unary_expr(DavQLStatement* stmt, UcxList* token, |
652 static int dav_parse_unary_expr(DavQLStatement* stmt, UcxList* token, |
628 DavQLExpression* expr) { |
653 DavQLExpression* expr) { |
629 |
654 |
|
655 DavQLExpression* atom = expr; |
|
656 expr->srctext.ptr = token_sstr(token).ptr; |
|
657 |
630 int total_consumed = 0; |
658 int total_consumed = 0; |
631 |
659 |
632 // optional unary operator |
660 // optional unary operator |
633 if (token_is(token, DAVQL_TOKEN_OPERATOR)) { |
661 if (token_is(token, DAVQL_TOKEN_OPERATOR)) { |
634 char *op = strchr("+-~", token_sstr(token).ptr[0]); |
662 char *op = strchr("+-~", token_sstr(token).ptr[0]); |
638 case '+': expr->op = DAVQL_ADD; break; |
666 case '+': expr->op = DAVQL_ADD; break; |
639 case '-': expr->op = DAVQL_SUB; break; |
667 case '-': expr->op = DAVQL_SUB; break; |
640 case '~': expr->op = DAVQL_NEG; break; |
668 case '~': expr->op = DAVQL_NEG; break; |
641 } |
669 } |
642 expr->left = calloc(sizeof(DavQLExpression), 1); |
670 expr->left = calloc(sizeof(DavQLExpression), 1); |
643 expr = expr->left; |
671 atom = expr->left; |
644 total_consumed++; |
672 total_consumed++; |
645 token = token->next; |
673 token = token->next; |
646 } else { |
674 } else { |
647 dav_error_in_context(DAVQL_ERROR_INVALID_UNARY_OP, |
675 dav_error_in_context(DAVQL_ERROR_INVALID_UNARY_OP, |
648 _error_invalid_unary_op, stmt, token); |
676 _error_invalid_unary_op, stmt, token); |
653 // RULE: (ParExpression | AtomicExpression) |
681 // RULE: (ParExpression | AtomicExpression) |
654 if (token_is(token, DAVQL_TOKEN_OPENP)) { |
682 if (token_is(token, DAVQL_TOKEN_OPENP)) { |
655 // TODO: make it so (and don't forget CLOSEP) |
683 // TODO: make it so (and don't forget CLOSEP) |
656 } else { |
684 } else { |
657 // RULE: FunctionCall |
685 // RULE: FunctionCall |
658 int consumed = dav_parse_funccall(stmt, token, expr); |
686 int consumed = dav_parse_funccall(stmt, token, atom); |
659 if (consumed) { |
687 if (consumed) { |
660 total_consumed += consumed; |
688 total_consumed += consumed; |
661 } else if (token_is(token, DAVQL_TOKEN_IDENTIFIER)) { |
689 } else if (token_is(token, DAVQL_TOKEN_IDENTIFIER)) { |
662 // RULE: Identifier |
690 // RULE: Identifier |
663 total_consumed++; |
691 total_consumed++; |
664 expr->type = DAVQL_IDENTIFIER; |
692 atom->type = DAVQL_IDENTIFIER; |
665 expr->srctext = token_sstr(token); |
693 atom->srctext = token_sstr(token); |
666 } else { |
694 } else { |
667 // RULE: Literal |
695 // RULE: Literal |
668 total_consumed += dav_parse_literal(stmt, token, expr); |
696 total_consumed += dav_parse_literal(stmt, token, atom); |
669 } |
697 } |
|
698 } |
|
699 |
|
700 // recover source text |
|
701 if (atom != expr) { |
|
702 expr->srctext.length = |
|
703 atom->srctext.ptr - expr->srctext.ptr + atom->srctext.length; |
670 } |
704 } |
671 |
705 |
672 |
706 |
673 return total_consumed; |
707 return total_consumed; |
674 } |
708 } |
691 dav_parse_multexpr); |
725 dav_parse_multexpr); |
692 } |
726 } |
693 |
727 |
694 static int dav_parse_expression(DavQLStatement* stmt, UcxList* token, |
728 static int dav_parse_expression(DavQLStatement* stmt, UcxList* token, |
695 DavQLExpression* expr) { |
729 DavQLExpression* expr) { |
696 |
|
697 // TODO: save source text |
|
698 |
730 |
699 return dav_parse_binary_expr(stmt, token, expr, |
731 return dav_parse_binary_expr(stmt, token, expr, |
700 dav_parse_multexpr, |
732 dav_parse_multexpr, |
701 "+-", (int[]){DAVQL_ADD, DAVQL_SUB}, |
733 "+-", (int[]){DAVQL_ADD, DAVQL_SUB}, |
702 dav_parse_expression); |
734 dav_parse_expression); |