354 #define _error_context "(%.*s [->]%.*s %.*s)" |
354 #define _error_context "(%.*s [->]%.*s %.*s)" |
355 #define _error_invalid "invalid statement" |
355 #define _error_invalid "invalid statement" |
356 #define _error_unhandled "unhandled error " _error_context |
356 #define _error_unhandled "unhandled error " _error_context |
357 #define _error_unexpected_token "unexpected token " _error_context |
357 #define _error_unexpected_token "unexpected token " _error_context |
358 #define _error_invalid_token "invalid token " _error_context |
358 #define _error_invalid_token "invalid token " _error_context |
359 #define _error_missing_from "missing FROM keyword " _error_context |
359 #define _error_missing_path "expected path " _error_context |
360 #define _error_missing_by "missing BY keyword " _error_context |
360 #define _error_missing_from "expecting FROM keyword " _error_context |
|
361 #define _error_missing_by "expecting BY keyword " _error_context |
361 #define _error_invalid_depth "invalid depth " _error_context |
362 #define _error_invalid_depth "invalid depth " _error_context |
362 #define _error_missing_expr "missing expression " _error_context |
363 #define _error_missing_expr "missing expression " _error_context |
363 #define _error_invalid_unary_op "invalid unary operator " _error_context |
364 #define _error_invalid_unary_op "invalid unary operator " _error_context |
|
365 #define _error_invalid_fmtspec "invalid format specifier " _error_context |
364 |
366 |
365 #define token_sstr(token) (((DavQLToken*)(token)->data)->value) |
367 #define token_sstr(token) (((DavQLToken*)(token)->data)->value) |
366 |
368 |
367 static void dav_error_in_context(int errorcode, const char *errormsg, |
369 static void dav_error_in_context(int errorcode, const char *errormsg, |
368 DavQLStatement *stmt, UcxList *token) { |
370 DavQLStatement *stmt, UcxList *token) { |
537 |
539 |
538 static int dav_parse_binary_expr(DavQLStatement* stmt, UcxList* token, |
540 static int dav_parse_binary_expr(DavQLStatement* stmt, UcxList* token, |
539 DavQLExpression* expr, exprparser_f parseL, char* opc, int* opv, |
541 DavQLExpression* expr, exprparser_f parseL, char* opc, int* opv, |
540 exprparser_f parseR) { |
542 exprparser_f parseR) { |
541 |
543 |
542 int total_consumed = 0, consumed; |
544 if (!token) { |
|
545 return 0; |
|
546 } |
|
547 |
|
548 int total_consumed = 0, consumed; |
543 |
549 |
544 // save temporarily on stack (copy to heap later on) |
550 // save temporarily on stack (copy to heap later on) |
545 DavQLExpression left, right; |
551 DavQLExpression left, right; |
546 |
552 |
547 // RULE: LEFT, [Operator, RIGHT] |
553 // RULE: LEFT, [Operator, RIGHT] |
551 return 0; |
557 return 0; |
552 } |
558 } |
553 total_consumed += consumed; |
559 total_consumed += consumed; |
554 token = ucx_list_get(token, consumed); |
560 token = ucx_list_get(token, consumed); |
555 |
561 |
556 char *op = strchr(opc, token_sstr(token).ptr[0]); // locate operator |
562 char *op; |
557 if (token_is(token, DAVQL_TOKEN_OPERATOR) && op) { |
563 if (token_is(token, DAVQL_TOKEN_OPERATOR) && |
|
564 (op = strchr(opc, token_sstr(token).ptr[0]))) { |
558 expr->op = opv[op-opc]; |
565 expr->op = opv[op-opc]; |
559 total_consumed++; |
566 total_consumed++; |
560 token = token->next; |
567 token = token->next; |
561 memset(&right, 0, sizeof(DavQLExpression)); |
568 memset(&right, 0, sizeof(DavQLExpression)); |
562 consumed = parseR(stmt, token, &right); |
569 consumed = parseR(stmt, token, &right); |
578 } |
585 } |
579 |
586 |
580 return total_consumed; |
587 return total_consumed; |
581 } |
588 } |
582 |
589 |
|
590 static int dav_parse_literal(DavQLStatement* stmt, UcxList* token, |
|
591 DavQLExpression* expr) { |
|
592 |
|
593 expr->srctext = token_sstr(token); |
|
594 if (token_is(token, DAVQL_TOKEN_NUMBER)) { |
|
595 expr->type = DAVQL_NUMBER; |
|
596 } else if (token_is(token, DAVQL_TOKEN_STRING)) { |
|
597 expr->type = DAVQL_STRING; |
|
598 } else if (token_is(token, DAVQL_TOKEN_TIMESTAMP)) { |
|
599 expr->type = DAVQL_TIMESTAMP; |
|
600 } else if (token_is(token, DAVQL_TOKEN_FMTSPEC) |
|
601 && expr->srctext.length == 2) { |
|
602 switch (expr->srctext.ptr[1]) { |
|
603 case 'd': expr->type = DAVQL_NUMBER; break; |
|
604 case 's': expr->type = DAVQL_STRING; break; |
|
605 case 't': expr->type = DAVQL_TIMESTAMP; break; |
|
606 default: |
|
607 dav_error_in_context(DAVQL_ERROR_INVALID_FMTSPEC, |
|
608 _error_invalid_fmtspec, stmt, token); |
|
609 return 0; |
|
610 } |
|
611 } else { |
|
612 return 0; |
|
613 } |
|
614 |
|
615 return 1; |
|
616 } |
|
617 |
|
618 static int dav_parse_funccall(DavQLStatement* stmt, UcxList* token, |
|
619 DavQLExpression* expr) { |
|
620 |
|
621 // TODO: make it so |
|
622 return 0; |
|
623 } |
583 |
624 |
584 static int dav_parse_unary_expr(DavQLStatement* stmt, UcxList* token, |
625 static int dav_parse_unary_expr(DavQLStatement* stmt, UcxList* token, |
585 DavQLExpression* expr) { |
626 DavQLExpression* expr) { |
586 |
627 |
587 int total_consumed = 0; |
628 int total_consumed = 0; |
588 DavQLExpression *litexpr = expr; |
629 |
589 |
|
590 // optional unary operator |
630 // optional unary operator |
591 if (token_is(token, DAVQL_TOKEN_OPERATOR)) { |
631 if (token_is(token, DAVQL_TOKEN_OPERATOR)) { |
592 char *op = strchr("+-~", token_sstr(token).ptr[0]); |
632 char *op = strchr("+-~", token_sstr(token).ptr[0]); |
593 if (op) { |
633 if (op) { |
594 expr->type = DAVQL_UNARY; |
634 expr->type = DAVQL_UNARY; |
596 case '+': expr->op = DAVQL_ADD; break; |
636 case '+': expr->op = DAVQL_ADD; break; |
597 case '-': expr->op = DAVQL_SUB; break; |
637 case '-': expr->op = DAVQL_SUB; break; |
598 case '~': expr->op = DAVQL_NEG; break; |
638 case '~': expr->op = DAVQL_NEG; break; |
599 } |
639 } |
600 expr->left = calloc(sizeof(DavQLExpression), 1); |
640 expr->left = calloc(sizeof(DavQLExpression), 1); |
601 litexpr = expr->left; |
641 expr = expr->left; |
602 total_consumed++; |
642 total_consumed++; |
603 token = token->next; |
643 token = token->next; |
604 } else { |
644 } else { |
605 dav_error_in_context(DAVQL_ERROR_INVALID_UNARY_OP, |
645 dav_error_in_context(DAVQL_ERROR_INVALID_UNARY_OP, |
606 _error_invalid_unary_op, stmt, token); |
646 _error_invalid_unary_op, stmt, token); |
611 // RULE: (ParExpression | AtomicExpression) |
651 // RULE: (ParExpression | AtomicExpression) |
612 if (token_is(token, DAVQL_TOKEN_OPENP)) { |
652 if (token_is(token, DAVQL_TOKEN_OPENP)) { |
613 // TODO: make it so (and don't forget CLOSEP) |
653 // TODO: make it so (and don't forget CLOSEP) |
614 } else { |
654 } else { |
615 // RULE: FunctionCall |
655 // RULE: FunctionCall |
616 // TODO: make it so |
656 int consumed = dav_parse_funccall(stmt, token, expr); |
617 |
657 if (consumed) { |
618 // RULE: Identifier |
658 total_consumed += consumed; |
619 /*else*/ if (token_is(token, DAVQL_TOKEN_IDENTIFIER)) { |
659 } else if (token_is(token, DAVQL_TOKEN_IDENTIFIER)) { |
|
660 // RULE: Identifier |
620 total_consumed++; |
661 total_consumed++; |
621 litexpr->type = DAVQL_IDENTIFIER; |
662 expr->type = DAVQL_IDENTIFIER; |
622 litexpr->srctext = token_sstr(token); |
663 expr->srctext = token_sstr(token); |
623 } |
664 } else { |
624 |
665 // RULE: Literal |
625 // RULE: Literal |
666 total_consumed += dav_parse_literal(stmt, token, expr); |
626 // TODO: make it so |
667 } |
627 } |
668 } |
628 |
669 |
629 |
670 |
630 return total_consumed; |
671 return total_consumed; |
631 } |
672 } |
655 |
696 |
656 return dav_parse_binary_expr(stmt, token, expr, |
697 return dav_parse_binary_expr(stmt, token, expr, |
657 dav_parse_multexpr, |
698 dav_parse_multexpr, |
658 "+-", (int[]){DAVQL_ADD, DAVQL_SUB}, |
699 "+-", (int[]){DAVQL_ADD, DAVQL_SUB}, |
659 dav_parse_expression); |
700 dav_parse_expression); |
660 } |
|
661 |
|
662 static int dav_parse_format_spec(DavQLStatement* stmt, UcxList* token) { |
|
663 |
|
664 return 0; |
|
665 } |
701 } |
666 |
702 |
667 static int dav_parse_fieldlist(DavQLStatement *stmt, UcxList *token) { |
703 static int dav_parse_fieldlist(DavQLStatement *stmt, UcxList *token) { |
668 |
704 |
669 // RULE: "-" |
705 // RULE: "-" |
817 while (!token_is(tokens, DAVQL_TOKEN_KEYWORD)) { |
853 while (!token_is(tokens, DAVQL_TOKEN_KEYWORD)) { |
818 sstr_t toksstr = token_sstr(tokens); |
854 sstr_t toksstr = token_sstr(tokens); |
819 stmt->path.length = toksstr.ptr-stmt->path.ptr+toksstr.length; |
855 stmt->path.length = toksstr.ptr-stmt->path.ptr+toksstr.length; |
820 tokens = tokens->next; |
856 tokens = tokens->next; |
821 } |
857 } |
822 } else if (token_is(tokens, DAVQL_TOKEN_FMTSPEC)) { |
858 } else if (token_is(tokens, DAVQL_TOKEN_FMTSPEC) && |
823 // TODO: make it so |
859 tokenvalue_is(tokens, "%s")) { |
|
860 stmt->path = token_sstr(tokens); |
|
861 tokens = tokens->next; |
|
862 } else { |
|
863 dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, |
|
864 _error_missing_path, stmt, tokens); |
|
865 return; |
824 } |
866 } |
825 |
867 |
826 // Consume with clause (if any) |
868 // Consume with clause (if any) |
827 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) |
869 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) |
828 && tokenvalue_is(tokens, "with")) { |
870 && tokenvalue_is(tokens, "with")) { |