libidav/davqlparser.c

changeset 358
54dbd44ac6b0
parent 357
5dfbf7b45873
child 359
bacb54502b24
--- 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 <identifier>') " _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) {

mercurial