davql: error handling + minor grammar changes

Sat, 04 Apr 2015 19:05:09 +0200

author
Mike Becker <universe@uap-core.de>
date
Sat, 04 Apr 2015 19:05:09 +0200
changeset 86
ecba8bdf9741
parent 85
0ab1cf261a44
child 87
ed21d95984bb

davql: error handling + minor grammar changes

libidav/davqlparser.c file | annotate | diff | comparison | revisions
libidav/davqlparser.h file | annotate | diff | comparison | revisions
ucx/utils.h file | annotate | diff | comparison | revisions
--- 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);
 }
--- a/libidav/davqlparser.h	Sat Apr 04 17:44:33 2015 +0200
+++ b/libidav/davqlparser.h	Sat Apr 04 19:05:09 2015 +0200
@@ -130,7 +130,8 @@
  * Comparison      = | "=" | "<" | ">" | "<=" | ">=" | "!=";
  * 
  * FieldExpressions = "*", {",", Expression, " as ", String}
- *                  | FieldExpression, {",", FieldExpression};
+ *                  | FieldExpression, {",", FieldExpression}
+ *                  | "-";
  * FieldExpression  = Identifier
  *                  | Expression, " as ", String;
  * SetExpressions   = SetExpression, {",", {SetExpressions};
@@ -171,6 +172,14 @@
      */
     davqltype_t type;
     /**
+     * Error code, if any error occurred. Zero otherwise.
+     */
+    int errorcode;
+    /**
+     * Error message, if any error occurred.
+     */
+    char* errormessage;
+    /**
      * The list of field expressions.
      */
     UcxList* fields;
@@ -195,11 +204,17 @@
     int depth;
 } DavQLStatement;
 
-/**
- * Infinity recursion depth for a DavQLStatement.
- */
+/** Infinity recursion depth for a DavQLStatement. */
 #define DAV_DEPTH_INFINITY -1
 
+/** No more tokens to parse, but the parser expected more. */
+#define DAVQL_ERROR_UNEXPECTED_END 1000
+
+/** A token was found, which has not been expected. */
+#define DAVQL_ERROR_UNEXPECTED_TOKEN 1010
+
+/** Nothing about the statement seems legit. */
+#define DAVQL_ERROR_INVALID -1
 
 /**
  * Starts an interactive debugger for a DavQLStatement.
--- a/ucx/utils.h	Sat Apr 04 17:44:33 2015 +0200
+++ b/ucx/utils.h	Sat Apr 04 19:05:09 2015 +0200
@@ -219,6 +219,10 @@
  */
 sstr_t ucx_asprintf(UcxAllocator *allocator, const char *fmt, ...);
 
+/** Shortcut for ucx_asprintf() with default allocator. */
+#define ucx_sprintf(fmt, ...) \
+    ucx_asprintf(ucx_default_allocator(), fmt, __VA_ARGS__)
+
 /**
  * <code>va_list</code> version of ucx_asprintf().
  * 

mercurial