libidav/davqlparser.c

changeset 113
412b06dc0162
parent 111
39f4c5fcaa60
child 114
943548492a47
equal deleted inserted replaced
112:f62d271675bf 113:412b06dc0162
369 369
370 // ------------------------------------------------------------------------ 370 // ------------------------------------------------------------------------
371 // P A R S E R 371 // P A R S E R
372 // ------------------------------------------------------------------------ 372 // ------------------------------------------------------------------------
373 373
374 #define _error_context "(%.*s [->]%.*s %.*s)" 374 #define _error_context "(%.*s[->]%.*s%.*s)"
375 #define _error_invalid "invalid statement" 375 #define _error_invalid "invalid statement"
376 #define _error_unhandled "unhandled error " _error_context 376 #define _error_unhandled "unhandled error " _error_context
377 #define _error_unexpected_token "unexpected token " _error_context 377 #define _error_unexpected_token "unexpected token " _error_context
378 #define _error_invalid_token "invalid token " _error_context 378 #define _error_invalid_token "invalid token " _error_context
379 #define _error_missing_path "expected path " _error_context 379 #define _error_missing_path "expected path " _error_context
380 #define _error_missing_from "expecting FROM keyword " _error_context 380 #define _error_missing_from "expecting FROM keyword " _error_context
381 #define _error_missing_by "expecting BY keyword " _error_context 381 #define _error_missing_by "expecting BY keyword " _error_context
382 #define _error_missing_as "expecting alias ('as <identifier>') " _error_context
383 #define _error_missing_identifier "expecting identifier " _error_context
382 #define _error_missing_par "missing closed parenthesis " _error_context 384 #define _error_missing_par "missing closed parenthesis " _error_context
383 #define _error_invalid_depth "invalid depth " _error_context 385 #define _error_invalid_depth "invalid depth " _error_context
384 #define _error_missing_expr "missing expression " _error_context 386 #define _error_missing_expr "missing expression " _error_context
385 #define _error_invalid_expr "invalid expression " _error_context 387 #define _error_invalid_expr "invalid expression " _error_context
386 #define _error_invalid_unary_op "invalid unary operator " _error_context 388 #define _error_invalid_unary_op "invalid unary operator " _error_context
388 390
389 #define token_sstr(token) (((DavQLToken*)(token)->data)->value) 391 #define token_sstr(token) (((DavQLToken*)(token)->data)->value)
390 392
391 static void dav_error_in_context(int errorcode, const char *errormsg, 393 static void dav_error_in_context(int errorcode, const char *errormsg,
392 DavQLStatement *stmt, UcxList *token) { 394 DavQLStatement *stmt, UcxList *token) {
395
396 // we try to achieve two things: get as many information as possible
397 // and recover the concrete source string (and not the token strings)
393 sstr_t emptystring = ST(""); 398 sstr_t emptystring = ST("");
399 sstr_t prev = token->prev ? (token->prev->prev ?
400 token_sstr(token->prev->prev) : token_sstr(token->prev))
401 : emptystring;
402 sstr_t tokenstr = token_sstr(token);
403 sstr_t next = token->next ? (token->next->next ?
404 token_sstr(token->next->next) : token_sstr(token->next))
405 : emptystring;
406
407 int lp = prev.length == 0 ? 0 : tokenstr.ptr-prev.ptr;
408 char *pn = tokenstr.ptr + tokenstr.length;
409 int ln = next.ptr+next.length - pn;
410
394 stmt->errorcode = errorcode; 411 stmt->errorcode = errorcode;
395 stmt->errormessage = ucx_sprintf(errormsg, 412 stmt->errormessage = ucx_sprintf(errormsg,
396 sfmtarg(token->prev?token_sstr(token->prev):emptystring), 413 lp, prev.ptr,
397 sfmtarg(token_sstr(token)), 414 sfmtarg(tokenstr),
398 sfmtarg(token->next?token_sstr(token->next):emptystring)).ptr; 415 ln, pn).ptr;
399 } 416 }
400 417
401 // special symbols are single tokens - the % sign MUST NOT be a special symbol 418 // special symbols are single tokens - the % sign MUST NOT be a special symbol
402 static const char *special_token_symbols = ",()+-*/&|^~=!<>"; 419 static const char *special_token_symbols = ",()+-*/&|^~=!<>";
403 420
755 dav_parse_multexpr, 772 dav_parse_multexpr,
756 "+-", (int[]){DAVQL_ADD, DAVQL_SUB}, 773 "+-", (int[]){DAVQL_ADD, DAVQL_SUB},
757 dav_parse_expression); 774 dav_parse_expression);
758 } 775 }
759 776
777 static int dav_parse_named_field(DavQLStatement *stmt, UcxList *token,
778 DavQLField *field) {
779 int total_consumed = 0, consumed;
780
781 // RULE: Expression, " as ", Identifier;
782 DavQLExpression * expr = calloc(sizeof(DavQLExpression), 1);
783 consumed = dav_parse_expression(stmt, token, expr);
784 if (expr->type == DAVQL_UNDEFINED_TYPE) {
785 dav_free_expression(expr);
786 dav_error_in_context(DAVQL_ERROR_INVALID_EXPR,
787 _error_invalid_expr, stmt, token);
788 return 0;
789 }
790
791 token = ucx_list_get(token, consumed);
792 total_consumed += consumed;
793
794 if (token_is(token, DAVQL_TOKEN_KEYWORD) && tokenvalue_is(token, "as")) {
795 token = token->next; total_consumed++;
796 } else {
797 free(expr);
798 dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN,
799 _error_missing_as, stmt, token);
800 return 0;
801 }
802
803 if (token_is(token, DAVQL_TOKEN_IDENTIFIER)) {
804 field->name = token_sstr(token);
805 field->expr = expr;
806 return total_consumed + 1;
807 } else {
808 free(expr);
809 dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN,
810 _error_missing_identifier, stmt, token);
811 return 0;
812 }
813 }
814
760 static int dav_parse_fieldlist(DavQLStatement *stmt, UcxList *token) { 815 static int dav_parse_fieldlist(DavQLStatement *stmt, UcxList *token) {
761 816
762 // RULE: "-" 817 // RULE: "-"
763 if (token_is(token, DAVQL_TOKEN_OPERATOR) && tokenvalue_is(token, "-")) { 818 if (token_is(token, DAVQL_TOKEN_OPERATOR) && tokenvalue_is(token, "-")) {
764 DavQLField *field = malloc(sizeof(DavQLField)); 819 DavQLField *field = malloc(sizeof(DavQLField));
767 field->expr->srctext = field->name = token_sstr(token); 822 field->expr->srctext = field->name = token_sstr(token);
768 stmt->fields = ucx_list_append(stmt->fields, field); 823 stmt->fields = ucx_list_append(stmt->fields, field);
769 return 1; 824 return 1;
770 } 825 }
771 826
772 // RULE: "*", {",", Expression, " as ", Identifier} 827 // RULE: "*", {",", NamedExpression}
773 if (token_is(token, DAVQL_TOKEN_OPERATOR) && tokenvalue_is(token, "*")) { 828 if (token_is(token, DAVQL_TOKEN_OPERATOR) && tokenvalue_is(token, "*")) {
774 DavQLField *field = malloc(sizeof(DavQLField)); 829 DavQLField *field = malloc(sizeof(DavQLField));
775 field->expr = calloc(sizeof(DavQLExpression), 1); 830 field->expr = calloc(sizeof(DavQLExpression), 1);
776 field->expr->type = DAVQL_IDENTIFIER; 831 field->expr->type = DAVQL_IDENTIFIER;
777 field->expr->srctext = field->name = token_sstr(token); 832 field->expr->srctext = field->name = token_sstr(token);
784 token = ucx_list_get(token, consumed); 839 token = ucx_list_get(token, consumed);
785 total_consumed += consumed; 840 total_consumed += consumed;
786 841
787 if (token_is(token, DAVQL_TOKEN_COMMA)) { 842 if (token_is(token, DAVQL_TOKEN_COMMA)) {
788 total_consumed++; token = token->next; 843 total_consumed++; token = token->next;
789 DavQLExpression * expr = calloc(sizeof(DavQLExpression), 1); 844 DavQLField localfield;
790 consumed = dav_parse_expression(stmt, token, expr); 845 consumed = dav_parse_named_field(stmt, token, &localfield);
791 if (expr->type == DAVQL_UNDEFINED_TYPE) { 846 if (!stmt->errorcode && consumed) {
792 dav_free_expression(expr);
793 consumed = 0;
794 dav_error_in_context(DAVQL_ERROR_INVALID_EXPR,
795 _error_invalid_expr, stmt, token);
796 } else {
797 DavQLField *field = malloc(sizeof(DavQLField)); 847 DavQLField *field = malloc(sizeof(DavQLField));
798 field->expr = expr; 848 memcpy(field, &localfield, sizeof(DavQLField));
799 field->name = expr->srctext;
800 stmt->fields = ucx_list_append(stmt->fields, field); 849 stmt->fields = ucx_list_append(stmt->fields, field);
801 } 850 }
802
803 // TODO: parse "as"
804 } else { 851 } else {
805 consumed = 0; 852 consumed = 0;
806 } 853 }
807 } while (consumed > 0); 854 } while (consumed > 0);
808 855
809 return total_consumed; 856 return total_consumed;
810 } 857 }
811 858
812 // RULE: FieldExpression, {",", FieldExpression} 859 // RULE: FieldExpression, {",", FieldExpression}
813 // TODO: make it so 860 {
814 861 int total_consumed = 0, consumed;
815 return 0; 862 do {
863 // RULE: NamedField | Identifier
864 DavQLField localfield;
865 consumed = dav_parse_named_field(stmt, token, &localfield);
866 if (consumed) {
867 DavQLField *field = malloc(sizeof(DavQLField));
868 memcpy(field, &localfield, sizeof(DavQLField));
869 stmt->fields = ucx_list_append(stmt->fields, field);
870 token = ucx_list_get(token, consumed);
871 total_consumed += consumed;
872 } else if (token_is(token, DAVQL_TOKEN_IDENTIFIER)
873 // look ahead, if the field is JUST the identifier
874 && (token_is(token->next, DAVQL_TOKEN_COMMA) ||
875 tokenvalue_is(token->next, "from"))) {
876
877 DavQLField *field = malloc(sizeof(DavQLField));
878 field->expr = calloc(sizeof(DavQLExpression), 1);
879 field->expr->type = DAVQL_IDENTIFIER;
880 field->expr->srctext = field->name = token_sstr(token);
881 stmt->fields = ucx_list_append(stmt->fields, field);
882
883 consumed = 1;
884 total_consumed++;
885 token = token->next;
886
887 // we found a valid solution, so erase any errors
888 stmt->errorcode = 0;
889 if (stmt->errormessage) {
890 free(stmt->errormessage);
891 stmt->errormessage = NULL;
892 }
893 } else {
894 // dav_parse_named_field has already thrown a good error
895 consumed = 0;
896 }
897
898 // field has been parsed, now try to get a comma
899 if (consumed) {
900 consumed = token_is(token, DAVQL_TOKEN_COMMA) ? 1 : 0;
901 if (consumed) {
902 token = token->next;
903 total_consumed++;
904 }
905 }
906 } while (consumed);
907
908 return total_consumed;
909 }
816 } 910 }
817 911
818 static int dav_parse_where_clause(DavQLStatement *stmt, UcxList *token) { 912 static int dav_parse_where_clause(DavQLStatement *stmt, UcxList *token) {
819 return 0; 913 return 0;
820 } 914 }

mercurial