libidav/davqlparser.c

changeset 86
ecba8bdf9741
parent 85
0ab1cf261a44
child 87
ed21d95984bb
--- a/libidav/davqlparser.c	Sat Apr 04 17:44:33 2015 +0200
+++ b/libidav/davqlparser.c	Sat Apr 04 19:05:09 2015 +0200
@@ -27,6 +27,7 @@
  */
 
 #include "davqlparser.h"
+#include <ucx/utils.h>
 #include <string.h>
 #include <stdio.h>
 #include <ctype.h>
@@ -58,6 +59,15 @@
     }
 }
 
+static const char* _map_specialfield(int info) {
+    switch(info) {
+    case 0: return "";
+    case 1: return "with wildcard";
+    case 2: return "(resource data only)";
+    default: return "with mysterious identifier";
+    }
+}
+
 static const char* _map_operator(davqloperator_t op) {
     // don't use string array, because enum values may change
     switch(op) {
@@ -80,22 +90,27 @@
     sstr_t empty = ST("(empty)");
     
     // Basic information
-    printf("Statement: %.*s\nType: %s\nField count: %zu",
+    size_t fieldcount = ucx_list_size(stmt->fields);
+    int specialfield = 0;
+    UCX_FOREACH(elm, stmt->fields) {
+        DavQLExpression* expr = (DavQLExpression*)elm->data;
+        if (expr->type == DAVQL_IDENTIFIER && expr->srctext.length == 1) {
+            if (expr->srctext.ptr[0] == '*') {
+                specialfield = 1;
+            } else if (expr->srctext.ptr[0] == '-') {
+                specialfield = 2;
+            }
+        }
+    }
+    if (specialfield) {
+        fieldcount--;
+    }
+    printf("Statement: %.*s\nType: %s\nField count: %zu %s\nPath: %.*s\n"
+        "Has where clause: %s\n",
         sfmtarg(stmt->srctext),
         _map_querytype(stmt->type),
-        ucx_list_size(stmt->fields));
-    
-    // Has wildcard
-    _Bool wildcard = 0;
-    UCX_FOREACH(elm, stmt->fields) {
-        DavQLExpression* expr = (DavQLExpression*)elm->data;
-        if (expr->type == DAVQL_IDENTIFIER &&
-            expr->srctext.length == 1 && expr->srctext.ptr[0] == '*') {
-            wildcard = 1;
-        }
-    }
-    printf(" %s wildcard\nPath: %.*s\nHas where clause: %s\n",
-        wildcard?"with":"without",
+        fieldcount,
+        _map_specialfield(specialfield),
         sfmtarg(stmt->path ? stmt->path->srctext : empty),
         stmt->where ? "yes" : "no");
     if (stmt->type == DAVQL_SET) {
@@ -110,6 +125,10 @@
     } else {
         printf("Depth: %d\n", stmt->depth);
     }
+    if (stmt->errorcode) {
+        printf("\nError code: %d\nError: %s\n",
+            stmt->errorcode, stmt->errormessage);
+    }
 }
 
 static int dav_debug_ql_expr_selected(DavQLExpression *expr) {
@@ -176,6 +195,10 @@
     printf("Starting DavQL debugger (type 'h' for help)...\n\n");
     dav_debug_ql_stmt_print(stmt);
     
+    if (stmt->errorcode) {
+        return;
+    }
+    
     DavQLExpression *examineexpr = NULL;
     
     while(1) {
@@ -228,6 +251,10 @@
 //                         P A R S E R
 // ------------------------------------------------------------------------
 
+#define _unexpected_end_msg "unexpected end of statement"
+#define _invalid_msg "invalid statement"
+#define _unexpected_token "unexpected token (%.*s [->]%.*s %.*s)"
+
 static UcxList* dav_parse_tokenize(sstr_t src) {
     UcxList *tokens = NULL;
     
@@ -328,6 +355,16 @@
     return expr;
 }
 
+static void dav_parse_unexpected_token(DavQLStatement *stmt, UcxList *token) {
+    sstr_t emptystring = ST("");
+    stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN;
+    sstr_t errormsg = ucx_sprintf(_unexpected_token,
+        sfmtarg(token->prev?*token_sstr(token->prev):emptystring),
+        sfmtarg(*token_sstr(token)),
+        sfmtarg(token->next?*token_sstr(token->next):emptystring));
+    stmt->errormessage = errormsg.ptr;
+}
+
 static void dav_parse_get_statement(DavQLStatement *stmt, UcxList *tokens) {
     stmt->type = DAVQL_GET;
     
@@ -339,6 +376,7 @@
      *  530: expecting WITH clause
      *   40: WITH clause
      *  500: ready to quit
+     *  999: error
      * 
      */
     int step = 10;
@@ -357,10 +395,13 @@
             if (!sstrcasecmp(tokendata, S("where"))) {
                 step = 30;
             }
-            /* no break */
+            /* no break and no else*/
         case 530:
             if (!sstrcasecmp(tokendata, S("with"))) {
                 step = 40;
+            } else {
+                dav_parse_unexpected_token(stmt, token);
+                step = 999;
             }
             break;
         // field list
@@ -407,8 +448,8 @@
     }
     
     if (step < 500) {
-        stmt->type = DAVQL_ERROR;
-        // TODO: save parse error message
+        stmt->errorcode = DAVQL_ERROR_UNEXPECTED_END;
+        stmt->errormessage = strdup(_unexpected_end_msg);
     }
 }
 
@@ -446,6 +487,8 @@
             dav_parse_set_statement(stmt, tokens);
         } else {
             stmt->type = DAVQL_ERROR;
+            stmt->errorcode = DAVQL_ERROR_INVALID;
+            stmt->errormessage = strdup(_invalid_msg);
         }
         
         // free token data
@@ -455,6 +498,8 @@
         ucx_list_free(tokens);
     } else {
         stmt->type = DAVQL_ERROR;
+        stmt->errorcode = DAVQL_ERROR_INVALID;
+        stmt->errormessage = strdup(_invalid_msg);
     }
     
     return stmt;
@@ -486,5 +531,8 @@
     if (stmt->where) {
         dav_free_expression(stmt->where);
     }
+    if (stmt->errormessage) {
+        free(stmt->errormessage);
+    }
     free(stmt);
 }

mercurial