# HG changeset patch # User Mike Becker # Date 1431541116 -7200 # Node ID a0903d2d8e3e1d585cd29e151f8ceedd452a4b69 # Parent 9cec78f23cbfe22ba2562982ddd672aa75254ed6 added format specifier parser diff -r 9cec78f23cbf -r a0903d2d8e3e dav/main.c --- a/dav/main.c Wed May 13 12:00:54 2015 +0200 +++ b/dav/main.c Wed May 13 20:18:36 2015 +0200 @@ -54,7 +54,7 @@ #include void test() { DavQLStatement *stmt = dav_parse_statement(S( - "get *,count(*) as count from /uap/House of Cards with depth = infinity")); + "get - from '/path/with space' with depth = %d")); dav_debug_statement(stmt); dav_free_statement(stmt); } @@ -66,6 +66,7 @@ load_config(ctx); #ifdef DO_THE_TEST test(); + return 0; #endif memcpy(ctx->http_proxy, get_http_proxy(), sizeof(Proxy)); diff -r 9cec78f23cbf -r a0903d2d8e3e libidav/davqlparser.c --- a/libidav/davqlparser.c Wed May 13 12:00:54 2015 +0200 +++ b/libidav/davqlparser.c Wed May 13 20:18:36 2015 +0200 @@ -356,11 +356,13 @@ #define _error_unhandled "unhandled error " _error_context #define _error_unexpected_token "unexpected token " _error_context #define _error_invalid_token "invalid token " _error_context -#define _error_missing_from "missing FROM keyword " _error_context -#define _error_missing_by "missing BY keyword " _error_context +#define _error_missing_path "expected path " _error_context +#define _error_missing_from "expecting FROM keyword " _error_context +#define _error_missing_by "expecting BY keyword " _error_context #define _error_invalid_depth "invalid depth " _error_context #define _error_missing_expr "missing expression " _error_context #define _error_invalid_unary_op "invalid unary operator " _error_context +#define _error_invalid_fmtspec "invalid format specifier " _error_context #define token_sstr(token) (((DavQLToken*)(token)->data)->value) @@ -539,7 +541,11 @@ DavQLExpression* expr, exprparser_f parseL, char* opc, int* opv, exprparser_f parseR) { - int total_consumed = 0, consumed; + if (!token) { + return 0; + } + + int total_consumed = 0, consumed; // save temporarily on stack (copy to heap later on) DavQLExpression left, right; @@ -553,8 +559,9 @@ total_consumed += consumed; token = ucx_list_get(token, consumed); - char *op = strchr(opc, token_sstr(token).ptr[0]); // locate operator - if (token_is(token, DAVQL_TOKEN_OPERATOR) && op) { + char *op; + if (token_is(token, DAVQL_TOKEN_OPERATOR) && + (op = strchr(opc, token_sstr(token).ptr[0]))) { expr->op = opv[op-opc]; total_consumed++; token = token->next; @@ -580,13 +587,46 @@ return total_consumed; } +static int dav_parse_literal(DavQLStatement* stmt, UcxList* token, + DavQLExpression* expr) { + + expr->srctext = token_sstr(token); + if (token_is(token, DAVQL_TOKEN_NUMBER)) { + expr->type = DAVQL_NUMBER; + } else if (token_is(token, DAVQL_TOKEN_STRING)) { + expr->type = DAVQL_STRING; + } else if (token_is(token, DAVQL_TOKEN_TIMESTAMP)) { + expr->type = DAVQL_TIMESTAMP; + } else if (token_is(token, DAVQL_TOKEN_FMTSPEC) + && expr->srctext.length == 2) { + switch (expr->srctext.ptr[1]) { + case 'd': expr->type = DAVQL_NUMBER; break; + case 's': expr->type = DAVQL_STRING; break; + case 't': expr->type = DAVQL_TIMESTAMP; break; + default: + dav_error_in_context(DAVQL_ERROR_INVALID_FMTSPEC, + _error_invalid_fmtspec, stmt, token); + return 0; + } + } else { + return 0; + } + + return 1; +} + +static int dav_parse_funccall(DavQLStatement* stmt, UcxList* token, + DavQLExpression* expr) { + + // TODO: make it so + return 0; +} static int dav_parse_unary_expr(DavQLStatement* stmt, UcxList* token, DavQLExpression* expr) { int total_consumed = 0; - DavQLExpression *litexpr = expr; - + // optional unary operator if (token_is(token, DAVQL_TOKEN_OPERATOR)) { char *op = strchr("+-~", token_sstr(token).ptr[0]); @@ -598,7 +638,7 @@ case '~': expr->op = DAVQL_NEG; break; } expr->left = calloc(sizeof(DavQLExpression), 1); - litexpr = expr->left; + expr = expr->left; total_consumed++; token = token->next; } else { @@ -613,17 +653,18 @@ // TODO: make it so (and don't forget CLOSEP) } else { // RULE: FunctionCall - // TODO: make it so - - // RULE: Identifier - /*else*/ if (token_is(token, DAVQL_TOKEN_IDENTIFIER)) { + int consumed = dav_parse_funccall(stmt, token, expr); + if (consumed) { + total_consumed += consumed; + } else if (token_is(token, DAVQL_TOKEN_IDENTIFIER)) { + // RULE: Identifier total_consumed++; - litexpr->type = DAVQL_IDENTIFIER; - litexpr->srctext = token_sstr(token); + expr->type = DAVQL_IDENTIFIER; + expr->srctext = token_sstr(token); + } else { + // RULE: Literal + total_consumed += dav_parse_literal(stmt, token, expr); } - - // RULE: Literal - // TODO: make it so } @@ -659,11 +700,6 @@ dav_parse_expression); } -static int dav_parse_format_spec(DavQLStatement* stmt, UcxList* token) { - - return 0; -} - static int dav_parse_fieldlist(DavQLStatement *stmt, UcxList *token) { // RULE: "-" @@ -819,8 +855,14 @@ stmt->path.length = toksstr.ptr-stmt->path.ptr+toksstr.length; tokens = tokens->next; } - } else if (token_is(tokens, DAVQL_TOKEN_FMTSPEC)) { - // TODO: make it so + } else if (token_is(tokens, DAVQL_TOKEN_FMTSPEC) && + tokenvalue_is(tokens, "%s")) { + stmt->path = token_sstr(tokens); + tokens = tokens->next; + } else { + dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, + _error_missing_path, stmt, tokens); + return; } // Consume with clause (if any) diff -r 9cec78f23cbf -r a0903d2d8e3e libidav/davqlparser.h --- a/libidav/davqlparser.h Wed May 13 12:00:54 2015 +0200 +++ b/libidav/davqlparser.h Wed May 13 20:18:36 2015 +0200 @@ -298,6 +298,9 @@ /** An operator has been found for a unary expression, but it is invalid. */ #define DAVQL_ERROR_INVALID_UNARY_OP 21 +/** Invalid format specifier. */ +#define DAVQL_ERROR_INVALID_FMTSPEC 22 + /** The depth is invalid. */ #define DAVQL_ERROR_INVALID_DEPTH 101