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 } |