diff -r 5dfbf7b45873 -r 54dbd44ac6b0 libidav/davqlparser.c --- a/libidav/davqlparser.c Thu Dec 21 16:48:58 2017 +0100 +++ b/libidav/davqlparser.c Thu Dec 21 19:42:25 2017 +0100 @@ -394,11 +394,14 @@ #define _error_invalid_token "invalid token " _error_context #define _error_missing_path "expected path " _error_context #define _error_missing_from "expecting FROM keyword " _error_context +#define _error_missing_at "expecting AT keyword " _error_context #define _error_missing_by "expecting BY keyword " _error_context #define _error_missing_as "expecting alias ('as ') " _error_context #define _error_missing_identifier "expecting identifier " _error_context #define _error_missing_par "missing closed parenthesis " _error_context #define _error_missing_assign "expecting assignment ('=') " _error_context +#define _error_missing_where "SET statements must have a WHERE clause or " \ + "explicitly use ANYWHERE " _error_context #define _error_invalid_depth "invalid depth " _error_context #define _error_missing_expr "missing expression " _error_context #define _error_invalid_expr "invalid expression " _error_context @@ -1533,6 +1536,36 @@ return total_consumed; } +static int dav_parse_path(DavQLStatement *stmt, UcxList *tokens) { + if (token_is(tokens, DAVQL_TOKEN_STRING)) { + stmt->path = token_sstr(tokens); + tokens = tokens->next; + return 1; + } else if (token_is(tokens, DAVQL_TOKEN_OPERATOR) + && tokenvalue_is(tokens, "/")) { + stmt->path = token_sstr(tokens); + tokens = tokens->next; + int consumed = 1; + while (!token_is(tokens, DAVQL_TOKEN_KEYWORD) && + !token_is(tokens, DAVQL_TOKEN_END)) { + sstr_t toksstr = token_sstr(tokens); + stmt->path.length = toksstr.ptr-stmt->path.ptr+toksstr.length; + tokens = tokens->next; + consumed++; + } + return consumed; + } else if (token_is(tokens, DAVQL_TOKEN_FMTSPEC) && + tokenvalue_is(tokens, "%s")) { + stmt->path = token_sstr(tokens); + tokens = tokens->next; + return 1; + } else { + dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, + _error_missing_path, stmt, tokens); + return 0; + } +} + /** * Parser of a select statement. * @param stmt the statement object that shall contain the syntax tree @@ -1547,7 +1580,7 @@ return; } - // Consume from keyword + // Consume FROM keyword if (token_is(tokens, DAVQL_TOKEN_KEYWORD) && tokenvalue_is(tokens, "from")) { tokens = tokens->next; @@ -1558,26 +1591,8 @@ } // Consume path - if (token_is(tokens, DAVQL_TOKEN_STRING)) { - stmt->path = token_sstr(tokens); - tokens = tokens->next; - } else if (token_is(tokens, DAVQL_TOKEN_OPERATOR) - && tokenvalue_is(tokens, "/")) { - stmt->path = token_sstr(tokens); - tokens = tokens->next; - while (!token_is(tokens, DAVQL_TOKEN_KEYWORD) && - !token_is(tokens, DAVQL_TOKEN_END)) { - sstr_t toksstr = token_sstr(tokens); - stmt->path.length = toksstr.ptr-stmt->path.ptr+toksstr.length; - tokens = tokens->next; - } - } 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); + tokens = ucx_list_get(tokens, dav_parse_path(stmt, tokens)); + if (stmt->errorcode) { return; } @@ -1643,7 +1658,47 @@ return; } - // TODO: make it so + // Consume AT keyword + if (token_is(tokens, DAVQL_TOKEN_KEYWORD) + && tokenvalue_is(tokens, "at")) { + tokens = tokens->next; + } else { + dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, + _error_missing_at, stmt, tokens); + return; + } + + // Consume path + tokens = ucx_list_get(tokens, dav_parse_path(stmt, tokens)); + if (stmt->errorcode) { + return; + } + + // Consume with clause (if any) + if (token_is(tokens, DAVQL_TOKEN_KEYWORD) + && tokenvalue_is(tokens, "with")) { + tokens = tokens->next; + tokens = ucx_list_get(tokens, + dav_parse_with_clause(stmt, tokens)); + } + if (stmt->errorcode) { + return; + } + + // Consume mandatory where clause (or anywhere keyword) + if (token_is(tokens, DAVQL_TOKEN_KEYWORD) + && tokenvalue_is(tokens, "where")) { + tokens = tokens->next; + tokens = ucx_list_get(tokens, + dav_parse_where_clause(stmt, tokens)); + } else if (token_is(tokens, DAVQL_TOKEN_KEYWORD) + && tokenvalue_is(tokens, "anywhere")) { + // no-op, but we want the user to be explicit about this + stmt->where = NULL; + } else { + dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, + _error_missing_where, stmt, tokens); + } } DavQLStatement* dav_parse_statement(sstr_t srctext) {