fieldlist parser can now parse fields with alias

Tue, 28 Apr 2015 16:43:57 +0200

author
Mike Becker <universe@uap-core.de>
date
Tue, 28 Apr 2015 16:43:57 +0200
changeset 99
579238097973
parent 98
237844f263b4
child 101
95a215337b53

fieldlist parser can now parse fields with alias

libidav/davqlparser.c file | annotate | diff | comparison | revisions
--- a/libidav/davqlparser.c	Tue Apr 21 12:13:41 2015 +0200
+++ b/libidav/davqlparser.c	Tue Apr 28 16:43:57 2015 +0200
@@ -508,7 +508,6 @@
             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) {
@@ -544,62 +543,151 @@
 
 struct fieldlist_parser_state {
     UcxList *expr_firsttoken;
+    DavQLField *currentfield;
     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
+     *    expect "," or "from" only if expr_len is 1 (add to list and continue)
+     * 2: expect one token (identifier) for as clause
+     * 3: expect a ",": continue with step 1
+     *    or a "from": leave field list parser
+     * 4: expect end of field list (i.e. a "from" keyword)
      */
     int step;
 };
 
+static void dav_free_field(DavQLField *field) {
+    dav_free_expression(field->expr);
+    free(field);
+}
+
 static int dav_parse_fieldlist(DavQLStatement *stmt, UcxList *token,
         struct fieldlist_parser_state *state) {
     sstr_t tokendata = *token_sstr(token);
+
+    _Bool fromkeyword = !sstrcasecmp(tokendata, S("from"));
+    _Bool comma = !sstrcmp(tokendata, S(","));
     
     switch (state->step) {
     case 0:
+        if (!sstrcmp(tokendata, S("*")) || !sstrcmp(tokendata, S("-"))) {
+            DavQLField *field = malloc(sizeof(DavQLField));
+            field->name = tokendata;
+            field->expr = calloc(1, sizeof(DavQLExpression));
+            field->expr->type = DAVQL_IDENTIFIER;
+            field->expr->srctext = tokendata;
+            stmt->fields = ucx_list_append(stmt->fields, field);
+            
+            if (tokendata.ptr[0] == '-') {
+                // no further fields may follow, if dash symbol has been found
+                state->step = 4;
+            } else {
+                state->step = 3;
+            }
+            return _step_fieldlist_;
+        }
         // did not encounter special field, fall through to step 1
+        state->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(
+        if (fromkeyword || comma) {
+            // add possible identifier to list
+            if (state->expr_firsttoken) {
+                // TODO: skip comma in function call)
+                if (state->expr_len > 1) {
+                    stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN;
+                    stmt->errormessage = ucx_sprintf(_expected_token,
+                        "AS", sfmtarg(tokendata)).ptr;
+                    return 0;
+                }
+                
+                DavQLExpression *expr = dav_parse_expression(
+                    stmt, state->expr_firsttoken, state->expr_len);
+                
+                if (expr->type != DAVQL_IDENTIFIER) {
+                    dav_free_expression(expr);
+                    stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN;
+                    stmt->errormessage = ucx_sprintf(_expected_token,
+                        "AS", sfmtarg(tokendata)).ptr;
+                    return 0;
+                } // TODO: do not allow identifier when wildcard is present
+                
+                DavQLField *field = malloc(sizeof(DavQLField));
+                field->expr = expr;
+                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);
+                return 0;
+            }
+        } else if (!sstrcasecmp(tokendata, S("as"))) {
+            // TODO: return error, if expr_first_token is NULL
+            state->currentfield = malloc(sizeof(DavQLField));
+            state->currentfield->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_;
+                
+            state->step = 2;
+        } 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_;
+    case 2: {
+        DavQLExpression *expr = dav_parse_expression(stmt, token, 1);
+        if (expr->type == DAVQL_IDENTIFIER) {
+            state->currentfield->name = expr->srctext;
+            stmt->fields = ucx_list_append(stmt->fields, state->currentfield);
+            state->currentfield = NULL;
+        } else {
+            dav_free_field(state->currentfield);
+            dav_error_in_context(DAVQL_ERROR_IDENTIFIER_EXPECTED,
+                _identifier_expected, stmt, token);
+            
+        }
+        dav_free_expression(expr);
+        state->step = 3;
+        
+        return _step_fieldlist_;
+    }
+    case 3:
+        if (fromkeyword) {
+            return _step_FROM_;
+        } else if (comma) {
+            state->step = 1;
+            return _step_fieldlist_;
         } else {
             dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN,
                 _unexpected_token, stmt, token);
+            return 0;
         }
-    } else {
-        // collect tokens for field expression
-        if (state->expr_firsttoken) {
-            state->expr_len++;
+    case 4:
+        if (fromkeyword) {
+            return _step_FROM_;
         } else {
-            state->expr_firsttoken = token;
-            state->expr_len = 1;
+            stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN;
+            stmt->errormessage = ucx_sprintf(_expected_token,
+                "FROM", sfmtarg(tokendata)).ptr;
+            return 0;
         }
     }
-    
-    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) {

mercurial