minor grammar fix (alias name is now identifier and not string) + completed debugger (so far) + separated field list parser (currently unable to parse alias names) + new structure for fields

Tue, 21 Apr 2015 12:13:41 +0200

author
Mike Becker <universe@uap-core.de>
date
Tue, 21 Apr 2015 12:13:41 +0200
changeset 98
237844f263b4
parent 97
f82cb65a78ec
child 99
579238097973

minor grammar fix (alias name is now identifier and not string) + completed debugger (so far) + separated field list parser (currently unable to parse alias names) + new structure for fields

libidav/davqlparser.c file | annotate | diff | comparison | revisions
libidav/davqlparser.h file | annotate | diff | comparison | revisions
--- a/libidav/davqlparser.c	Fri Apr 17 16:26:53 2015 +0200
+++ b/libidav/davqlparser.c	Tue Apr 21 12:13:41 2015 +0200
@@ -49,6 +49,7 @@
 
 static const char* _map_exprtype(davqlexprtype_t type) {
     switch(type) {
+    case DAVQL_UNDEFINED_TYP: return "undefined";
     case DAVQL_NUMBER: return "NUMBER";
     case DAVQL_STRING: return "STRING";
     case DAVQL_TIMESTAMP: return "TIMESTAMP";
@@ -92,13 +93,12 @@
     // Basic information
     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 (stmt->fields) {
+        DavQLField* firstfield = (DavQLField*)stmt->fields->data;
+        if (firstfield->expr->type == DAVQL_IDENTIFIER) {
+            switch (firstfield->expr->srctext.ptr[0]) {
+            case '*': specialfield = 1; break;
+            case '-': specialfield = 2; break;
             }
         }
     }
@@ -113,11 +113,6 @@
         _map_specialfield(specialfield),
         sfmtarg(stmt->path),
         stmt->where ? "yes" : "no");
-    if (stmt->type == DAVQL_SET) {
-        printf("Value list size matches: %s",
-            ucx_list_size(stmt->fields) == ucx_list_size(stmt->setvalues)
-            ? "yes" : "no");
-    }
     
     // WITH attributes
     if (stmt->depth == DAV_DEPTH_INFINITY) {
@@ -161,29 +156,41 @@
     if (dav_debug_ql_expr_selected(expr)) {
         sstr_t empty = ST("(empty)");
         printf(
-            "Text: %.*s\nType: %s\nOperator: %s\n"
-            "Left hand: %.*s\nRight hand: %.*s\n",
+            "Text: %.*s\nType: %s\nOperator: %s\n",
             sfmtarg(expr->srctext),
             _map_exprtype(expr->type),
-            _map_operator(expr->op),
-            sfmtarg(expr->left?expr->left->srctext:empty),
-            sfmtarg(expr->right?expr->right->srctext:empty));
+            _map_operator(expr->op));
+        if (expr->left || expr->right) {
+            printf("Left hand: %.*s\nRight hand: %.*s\n",
+                sfmtarg(expr->left?expr->left->srctext:empty),
+                sfmtarg(expr->right?expr->right->srctext:empty));
+        }
     }
 }
 
 #define DQLD_CMD_Q     0
 #define DQLD_CMD_PS    1
 #define DQLD_CMD_PE    2
-#define DQLD_CMD_P    10
+#define DQLD_CMD_F    10
+#define DQLD_CMD_W    11
+#define DQLD_CMD_O    12
 #define DQLD_CMD_L    21
 #define DQLD_CMD_R    22
+#define DQLD_CMD_N    23
+#define DQLD_CMD_P    24
 #define DQLD_CMD_H   100
 
 static int dav_debug_ql_command() {
     printf("> ");
     
-    char buffer[16];
-    fgets(buffer, 16, stdin);
+    char buffer[8];
+    fgets(buffer, 8, stdin);
+     // discard remaining chars
+    if (!strchr(buffer, '\n')) {
+        int chr;
+        while ((chr = fgetc(stdin) != '\n') && chr != EOF);
+    }
+    
     if (!strcmp(buffer, "q\n")) {
         return DQLD_CMD_Q;
     } else if (!strcmp(buffer, "ps\n")) {
@@ -196,6 +203,16 @@
         return DQLD_CMD_R;
     } else if (!strcmp(buffer, "h\n")) {
         return DQLD_CMD_H;
+    } else if (!strcmp(buffer, "f\n")) {
+        return DQLD_CMD_F;
+    } else if (!strcmp(buffer, "w\n")) {
+        return DQLD_CMD_W;
+    } else if (!strcmp(buffer, "o\n")) {
+        return DQLD_CMD_O;
+    } else if (!strcmp(buffer, "n\n")) {
+        return DQLD_CMD_N;
+    } else if (!strcmp(buffer, "p\n")) {
+        return DQLD_CMD_P;
     } else {
         return -1;
     }
@@ -215,6 +232,8 @@
     }
     
     DavQLExpression *examineexpr = NULL;
+    UcxList *examineelem = NULL;
+    int examineclause = 0;
     
     while(1) {
         int cmd = dav_debug_ql_command();
@@ -222,6 +241,52 @@
         case DQLD_CMD_Q: return;
         case DQLD_CMD_PS: dav_debug_ql_stmt_print(stmt); break;
         case DQLD_CMD_PE: dav_debug_ql_expr_print(examineexpr); break;
+        case DQLD_CMD_F:
+            if (examineclause != DQLD_CMD_F) {
+                examineclause = DQLD_CMD_F;
+                examineelem = stmt->fields;
+                examineexpr = stmt->fields ?
+                    ((DavQLField*)stmt->fields->data)->expr : NULL;
+                dav_debug_ql_expr_print(examineexpr);
+            }
+            break;
+        case DQLD_CMD_W:
+            examineclause = 0; examineelem = NULL;
+            examineexpr = stmt->where;
+            dav_debug_ql_expr_print(examineexpr);
+            break;
+        case DQLD_CMD_O:
+            if (examineclause != DQLD_CMD_O) {
+                examineclause = DQLD_CMD_O;
+                examineelem = stmt->orderby;
+                examineexpr = stmt->orderby ?
+                    ((DavQLOrderCriterion*)stmt->orderby->data)->column : NULL;
+                dav_debug_ql_expr_print(examineexpr);
+            }
+            break;
+        case DQLD_CMD_N:
+        case DQLD_CMD_P:
+            if (examineelem) {
+                UcxList *newelem = (cmd == DQLD_CMD_N ?
+                    examineelem->next : examineelem->prev);
+                if (newelem) {
+                    examineelem = newelem;
+                    if (examineclause == DQLD_CMD_O) {
+                        examineexpr = ((DavQLOrderCriterion*)
+                            examineelem->data)->column;
+                    } else if (examineclause == DQLD_CMD_F) {
+                        examineexpr = ((DavQLField*)examineelem->data)->expr;
+                    } else {
+                        printf("Examining unknown clause type.");
+                    }
+                    dav_debug_ql_expr_print(examineexpr);
+                } else {
+                    printf("Reached end of list.\n");
+                }
+            } else {
+                printf("Currently not examining an expression list.\n");
+            }
+            break;
         case DQLD_CMD_L:
             if (dav_debug_ql_expr_selected(examineexpr)) {
                 if (examineexpr->left) {
@@ -246,6 +311,13 @@
             printf(
                 "\nCommands:\n"
                 "ps:  print statement information\n"
+                "o:   examine order by clause\n"
+                "f:   examine field list\n"
+                "w:   examine where clause\n"
+                "n:   examine next expression "
+                    "(in order by clause or field list)\n"
+                "p:   examine previous expression "
+                    "(in order by clause or field list)\n"
                 "q:   quit\n\n"
                 "\nExpression examination:\n"
                 "pe:  print expression information\n"
@@ -433,8 +505,10 @@
 
         // process tokens        
         for (size_t i = 0 ; i < n ; i++) {
+            sstr_t tokendata = *token_sstr(token);
             
             // TODO: make it so
+            printf("Processing %.*s...\n", sfmtarg(tokendata));
 
             // go to next token (if this is not the last token)
             if (i < n-1) {
@@ -468,6 +542,66 @@
 #define _step_ORDER_BY_     50 // ORDER BY clause
 #define _step_end_         500 // expect end
 
+struct fieldlist_parser_state {
+    UcxList *expr_firsttoken;
+    size_t expr_len;
+    /*
+     * 0: begin of field list - may encounter "*" or "-" special fields
+     * 1: collect expression token
+     *    switch to step 2 on keyword "as"
+     *    expect "," only if expr_len is 1 (add expr to list and continue)
+     * 2: expect one token (identifier) and a "," - continue with step 1
+     */
+    int step;
+};
+
+static int dav_parse_fieldlist(DavQLStatement *stmt, UcxList *token,
+        struct fieldlist_parser_state *state) {
+    sstr_t tokendata = *token_sstr(token);
+    
+    switch (state->step) {
+    case 0:
+        // did not encounter special field, fall through to step 1
+    case 1:
+        break;
+    }
+    
+    _Bool fromkeyword = !sstrcasecmp(tokendata, S("from"));
+    if (fromkeyword || !sstrcmp(tokendata, S(","))) {
+        if (state->expr_firsttoken) {
+            DavQLField *field = malloc(sizeof(DavQLField));
+            field->expr = dav_parse_expression(
+                stmt, state->expr_firsttoken, state->expr_len);
+            field->name = field->expr->srctext;
+            stmt->fields = ucx_list_append(stmt->fields, field);
+            state->expr_firsttoken = NULL;
+            state->expr_len = 0;
+
+            if (fromkeyword) {
+                return _step_FROM_;
+            }
+        } else {
+            dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN,
+                _unexpected_token, stmt, token);
+        }
+    } else {
+        // collect tokens for field expression
+        if (state->expr_firsttoken) {
+            state->expr_len++;
+        } else {
+            state->expr_firsttoken = token;
+            state->expr_len = 1;
+        }
+    }
+    
+    return _step_fieldlist_;
+}
+
+static void dav_free_field(DavQLField *field) {
+    dav_free_expression(field->expr);
+    free(field);
+}
+
 static int dav_parse_from(DavQLStatement *stmt, UcxList *token) {
     sstr_t tokendata = *token_sstr(token);
     
@@ -693,16 +827,11 @@
     memset(&state_with, 0, sizeof(struct with_parser_state));
     struct orderby_parser_state state_orderby;
     memset(&state_orderby, 0, sizeof(struct orderby_parser_state));
-    
-    // Variables for token sublists for expressions
-    // TODO: this is deprecated and won't work with function calls
-    UcxList *exprstart = NULL;
-    size_t exprlen = 0;
+    struct fieldlist_parser_state state_fieldlist;
+    memset(&state_fieldlist, 0, sizeof(struct fieldlist_parser_state));
     
     // Process tokens
     UCX_FOREACH(token, tokens) {
-        sstr_t tokendata = *token_sstr(token);
-        
         switch (step) {
         // too much input data
         case _step_end_:
@@ -711,30 +840,7 @@
             break;
         // field list
         case _step_fieldlist_: {
-            _Bool fromkeyword = !sstrcasecmp(tokendata, S("from"));
-            if (fromkeyword || !sstrcmp(tokendata, S(","))) {
-                if (exprstart) {
-                    stmt->fields = ucx_list_append(stmt->fields,
-                        dav_parse_expression(stmt, exprstart, exprlen));
-                    exprstart = NULL;
-                    exprlen = 0;
-                    
-                    if (fromkeyword) {
-                        step = _step_FROM_;
-                    }
-                } else {
-                    dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN,
-                        _unexpected_token, stmt, token);
-                }
-            } else {
-                // collect tokens for field expression
-                if (exprstart) {
-                    exprlen++;
-                } else {
-                    exprstart = token;
-                    exprlen = 1;
-                }
-            }
+            step = dav_parse_fieldlist(stmt, token, &state_fieldlist);
             break;
         }
         // from clause
@@ -828,13 +934,9 @@
 
 void dav_free_statement(DavQLStatement *stmt) {
     UCX_FOREACH(expr, stmt->fields) {
-        dav_free_expression(expr->data);
+        dav_free_field(expr->data);
     }
     ucx_list_free(stmt->fields);
-    UCX_FOREACH(expr, stmt->setvalues) {
-        dav_free_expression(expr->data);
-    }
-    ucx_list_free(stmt->setvalues);
     
     if (stmt->where) {
         dav_free_expression(stmt->where);
--- a/libidav/davqlparser.h	Fri Apr 17 16:26:53 2015 +0200
+++ b/libidav/davqlparser.h	Tue Apr 21 12:13:41 2015 +0200
@@ -46,6 +46,7 @@
  * Enumeration of possible expression types.
  */
 typedef enum {
+    DAVQL_UNDEFINED_TYP,
     DAVQL_NUMBER, DAVQL_STRING, DAVQL_TIMESTAMP, DAVQL_IDENTIFIER,
     DAVQL_UNARY, DAVQL_BINARY, DAVQL_LOGICAL, DAVQL_FUNCCALL
 } davqlexprtype_t;
@@ -111,6 +112,27 @@
     _Bool descending;
 } DavQLOrderCriterion;
 
+/**
+ * A tuple representing a field.
+ */
+typedef struct {
+    /**
+     * The field name.
+     * <ul>
+     * <li>GET: the identifier or an alias name</li>
+     * <li>SET: the identifier</li>
+     * </ul>
+     */
+    sstr_t name;
+    /**
+     * The field expression.
+     * <ul>
+     * <li>GET: the queried property (identifier) or an expression</li>
+     * <li>SET: the expression for the value to be set</li>
+     * </ul>
+     */
+    DavQLExpression *expr;
+} DavQLField;
 
 /**
  * Query statement object.
@@ -145,11 +167,11 @@
  * LogicalOperator = " and " | " or " | " xor ";
  * Comparison      = | "=" | "<" | ">" | "<=" | ">=" | "!=";
  * 
- * FieldExpressions = "*", {",", Expression, " as ", String}
+ * FieldExpressions = "*", {",", Expression, " as ", Identifier}
  *                  | FieldExpression, {",", FieldExpression}
  *                  | "-";
  * FieldExpression  = Identifier
- *                  | Expression, " as ", String;
+ *                  | Expression, " as ", Identifier;
  * SetExpressions   = SetExpression, {",", SetExpressions};
  * SetExpression    = Identifier, "=", Expression;
  * 
@@ -204,15 +226,10 @@
      */
     char* errormessage;
     /**
-     * The list of field expressions.
+     * The list of DavQLFields.
      */
     UcxList* fields;
     /**
-     * The list of DavQLExpressions for the new DAV property values.
-     * This is <code>NULL</code> for GET queries.
-     */
-    UcxList* setvalues;
-    /**
      * A string that denotes the queried path.
      */
     sstr_t path;

mercurial