added function call parser + fixed some memory management mistakes

Sun, 24 May 2015 20:27:51 +0200

author
Mike Becker <universe@uap-core.de>
date
Sun, 24 May 2015 20:27:51 +0200
changeset 114
943548492a47
parent 113
412b06dc0162
child 115
5744a3dee766

added function call parser + fixed some memory management mistakes

libidav/davqlparser.c file | annotate | diff | comparison | revisions
libidav/davqlparser.h file | annotate | diff | comparison | revisions
--- a/libidav/davqlparser.c	Wed May 20 11:14:33 2015 +0200
+++ b/libidav/davqlparser.c	Sun May 24 20:27:51 2015 +0200
@@ -75,6 +75,7 @@
     // don't use string array, because enum values may change
     switch(op) {
     case DAVQL_NOOP: return "no operator";
+    case DAVQL_CALL: return "function call"; case DAVQL_ARGLIST: return ",";
     case DAVQL_ADD: return "+"; case DAVQL_SUB: return "-";
     case DAVQL_MUL: return "*"; case DAVQL_DIV: return "/";
     case DAVQL_AND: return "&"; case DAVQL_OR: return "|";
@@ -422,7 +423,7 @@
     sstr_t keywords[] = {ST("get"), ST("set"), ST("from"), ST("at"), ST("as"),
         ST("where"), ST("with"), ST("order"), ST("by"), ST("asc"), ST("desc")
     };
-    for (int i = 0 ; i < sizeof(keywords)/sizeof(char*) ; i++) {
+    for (int i = 0 ; i < sizeof(keywords)/sizeof(sstr_t) ; i++) {
         if (!sstrcasecmp(token->value, keywords[i])) {
             return 1;
         }
@@ -547,13 +548,15 @@
 }
 
 static void dav_free_expression(DavQLExpression *expr) {
-    if (expr->left) {
-        dav_free_expression(expr->left);
+    if (expr) {
+        if (expr->left) {
+            dav_free_expression(expr->left);
+        }
+        if (expr->right) {
+            dav_free_expression(expr->right);
+        }
+        free(expr);
     }
-    if (expr->right) {
-        dav_free_expression(expr->right);
-    }
-    free(expr);
 }
 
 static void dav_free_field(DavQLField *field) {
@@ -592,7 +595,7 @@
     // RULE:    LEFT, [Operator, RIGHT]
     memset(&left, 0, sizeof(DavQLExpression));
     consumed = parseL(stmt, token, &left);
-    if (!consumed) {
+    if (!consumed || stmt->errorcode) {
         return 0;
     }
     total_consumed += consumed;
@@ -607,6 +610,9 @@
         token = token->next;
         memset(&right, 0, sizeof(DavQLExpression));
         consumed = parseR(stmt, token, &right);
+        if (stmt->errorcode) {
+            return 0;
+        }
         if (!consumed) {
             dav_error_in_context(DAVQL_ERROR_MISSING_EXPR,
                 _error_missing_expr, stmt, token);
@@ -660,16 +666,106 @@
     return 1;
 }
 
+// forward declaration
+static int dav_parse_expression(DavQLStatement* stmt, UcxList* token,
+        DavQLExpression* expr);
+
+static int dav_parse_arglist(DavQLStatement* stmt, UcxList* token,
+        DavQLExpression* expr) {
+    
+    expr->srctext.ptr = token_sstr(token).ptr;
+    expr->srctext.length = 0;
+    expr->left = expr->right = NULL; // in case we fail, we want them to be sane
+    
+    int total_consumed = 0;
+    
+    // RULE:    Expression, {",", Expression};
+    DavQLExpression *arglist = expr;
+    DavQLExpression arg;
+    char *lastchar = expr->srctext.ptr;
+    int consumed;
+    do {
+        memset(&arg, 0, sizeof(DavQLExpression));
+        consumed = dav_parse_expression(stmt, token, &arg);
+        if (consumed) {
+            lastchar = arg.srctext.ptr + arg.srctext.length;
+            total_consumed += consumed;
+            token = ucx_list_get(token, consumed);
+            // look ahead for a comma
+            if (token_is(token, DAVQL_TOKEN_COMMA)) {
+                total_consumed++;
+                token = token->next;
+                /* we have more arguments, so put the current argument to the
+                 * left subtree and create a new node to the right
+                 */
+                arglist->left = malloc(sizeof(DavQLExpression));
+                memcpy(arglist->left, &arg, sizeof(DavQLExpression));
+                arglist->srctext.ptr = arg.srctext.ptr;
+                arglist->op = DAVQL_ARGLIST;
+                arglist->type = DAVQL_FUNCCALL;
+                arglist->right = calloc(1, sizeof(DavQLExpression));
+                arglist = arglist->right;
+            } else {
+                // this was the last argument, so write it to the current node
+                memcpy(arglist, &arg, sizeof(DavQLExpression));
+                consumed = 0;
+            }
+        }
+    } while (consumed && !stmt->errorcode);
+    
+    // recover source text
+    arglist = expr;
+    while (arglist && arglist->type == DAVQL_FUNCCALL) {
+        arglist->srctext.length = lastchar - arglist->srctext.ptr;
+        arglist = arglist->right;
+    }
+    
+    return total_consumed;
+}
+
 static int dav_parse_funccall(DavQLStatement* stmt, UcxList* token,
         DavQLExpression* expr) {
     
-    // TODO: make it so
-    return 0;
-}
+    // RULE:    Identifier, "(", ArgumentList, ")";
+    if (token_is(token, DAVQL_TOKEN_IDENTIFIER) &&
+            token_is(token->next, DAVQL_TOKEN_OPENP)) {
 
-// forward declaration
-static int dav_parse_expression(DavQLStatement* stmt, UcxList* token,
-        DavQLExpression* expr);
+        expr->type = DAVQL_FUNCCALL;
+        expr->op = DAVQL_CALL;
+        
+        expr->left = calloc(1, sizeof(DavQLExpression));
+        expr->left->type = DAVQL_IDENTIFIER;
+        expr->left->srctext = token_sstr(token);
+        expr->right = NULL;
+        
+        token = token->next->next;
+        
+        DavQLExpression arg;
+        int argtokens = dav_parse_arglist(stmt, token, &arg);
+        if (stmt->errorcode) {
+            // if an error occurred while parsing the arglist, return now
+            return 2;
+        }
+        if (argtokens) {
+            token = ucx_list_get(token, argtokens);
+            expr->right = malloc(sizeof(DavQLExpression));
+            memcpy(expr->right, &arg, sizeof(DavQLExpression));
+        } else {
+            // arg list may be empty
+            expr->right = NULL;
+        }
+        
+        if (token_is(token, DAVQL_TOKEN_CLOSEP)) {
+            return 3 + argtokens;
+        } else {
+            dav_error_in_context(DAVQL_ERROR_MISSING_PAR, _error_missing_par,
+                stmt, token);
+            return 2; // it MUST be a function call, but it is invalid
+        }
+    } else {
+        return 0;
+    }
+}
 
 static int dav_parse_unary_expr(DavQLStatement* stmt, UcxList* token,
         DavQLExpression* expr) {
@@ -689,7 +785,7 @@
             case '-': expr->op = DAVQL_SUB; break;
             case '~': expr->op = DAVQL_NEG; break;
             }
-            expr->left = calloc(sizeof(DavQLExpression), 1);
+            expr->left = calloc(1, sizeof(DavQLExpression));
             atom = expr->left;
             total_consumed++;
             token = token->next;
@@ -740,8 +836,15 @@
     
     // recover source text
     expr->srctext.ptr = token_sstr(firsttoken).ptr;
-    sstr_t lasttoken = token_sstr(ucx_list_get(firsttoken, total_consumed-1));
-    expr->srctext.length = lasttoken.ptr - expr->srctext.ptr + lasttoken.length;
+    if (total_consumed > 0) {
+        sstr_t lasttoken =
+            token_sstr(ucx_list_get(firsttoken, total_consumed-1));
+        expr->srctext.length =
+            lasttoken.ptr - expr->srctext.ptr + lasttoken.length;
+    } else {
+        // the expression should not be used anyway, but we want to be safe
+        expr->srctext.length = 0;
+    }
     
     
     return total_consumed;
@@ -779,8 +882,12 @@
     int total_consumed = 0, consumed;
     
     // RULE:    Expression, " as ", Identifier;
-    DavQLExpression * expr = calloc(sizeof(DavQLExpression), 1);
+    DavQLExpression *expr = calloc(1, sizeof(DavQLExpression));
     consumed = dav_parse_expression(stmt, token, expr);
+    if (stmt->errorcode) {
+        dav_free_expression(expr);
+        return 0;
+    }
     if (expr->type == DAVQL_UNDEFINED_TYPE) {
         dav_free_expression(expr);
         dav_error_in_context(DAVQL_ERROR_INVALID_EXPR,
@@ -794,7 +901,7 @@
     if (token_is(token, DAVQL_TOKEN_KEYWORD) && tokenvalue_is(token, "as")) {
         token = token->next; total_consumed++;
     } else {
-        free(expr);
+        dav_free_expression(expr);
         dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN,
             _error_missing_as, stmt, token);
         return 0;
@@ -805,7 +912,7 @@
         field->expr = expr;
         return total_consumed + 1;
     } else {
-        free(expr);
+        dav_free_expression(expr);
         dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN,
             _error_missing_identifier, stmt, token);
         return 0;
@@ -817,7 +924,7 @@
     // RULE:    "-"
     if (token_is(token, DAVQL_TOKEN_OPERATOR) && tokenvalue_is(token, "-")) {
         DavQLField *field = malloc(sizeof(DavQLField));
-        field->expr = calloc(sizeof(DavQLExpression), 1);
+        field->expr = calloc(1, sizeof(DavQLExpression));
         field->expr->type = DAVQL_IDENTIFIER;
         field->expr->srctext = field->name = token_sstr(token);
         stmt->fields = ucx_list_append(stmt->fields, field);
@@ -827,7 +934,7 @@
     // RULE:    "*", {",", NamedExpression}
     if (token_is(token, DAVQL_TOKEN_OPERATOR) && tokenvalue_is(token, "*")) {
         DavQLField *field = malloc(sizeof(DavQLField));
-        field->expr = calloc(sizeof(DavQLExpression), 1);
+        field->expr = calloc(1, sizeof(DavQLExpression));
         field->expr->type = DAVQL_IDENTIFIER;
         field->expr->srctext = field->name = token_sstr(token);
         stmt->fields = ucx_list_append(stmt->fields, field);
@@ -875,7 +982,7 @@
                     tokenvalue_is(token->next, "from"))) {
                 
                 DavQLField *field = malloc(sizeof(DavQLField));
-                field->expr = calloc(sizeof(DavQLExpression), 1);
+                field->expr = calloc(1, sizeof(DavQLExpression));
                 field->expr->type = DAVQL_IDENTIFIER;
                 field->expr->srctext = field->name = token_sstr(token);
                 stmt->fields = ucx_list_append(stmt->fields, field);
@@ -926,7 +1033,7 @@
                 stmt->depth = DAV_DEPTH_INFINITY;
                 token = token->next; total_consumed++;
             } else {
-                DavQLExpression *depthexpr = calloc(sizeof(DavQLExpression), 1);
+                DavQLExpression *depthexpr = calloc(1, sizeof(DavQLExpression));
                 
                 int consumed = dav_parse_expression(stmt, token, depthexpr);
 
--- a/libidav/davqlparser.h	Wed May 20 11:14:33 2015 +0200
+++ b/libidav/davqlparser.h	Sun May 24 20:27:51 2015 +0200
@@ -171,7 +171,7 @@
  * AddOperator     = "+" | "-";
  * UnaryOperator   = "+" | "-" | "~";
  * 
- * FunctionCall    = Identifier, "(", ArgumentList, ")";
+ * FunctionCall    = Identifier, "(", [ArgumentList], ")";
  * ArgumentList    = Expression, {",", Expression};
  * Identifier      = IdentifierChar - ?Digit?, {IdentifierChar}
  *                 | "`", ?Character? - "`", {?Character? - "`"}, "`";

mercurial