expression parser: add support for functions

Sun, 20 Nov 2022 11:39:46 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 20 Nov 2022 11:39:46 +0100
changeset 435
713ec3da79ec
parent 434
ff576305ae6e
child 436
1260fad21be7

expression parser: add support for functions

src/server/daemon/webserver.c file | annotate | diff | comparison | revisions
src/server/test/main.c file | annotate | diff | comparison | revisions
src/server/test/object.c file | annotate | diff | comparison | revisions
src/server/test/object.h file | annotate | diff | comparison | revisions
src/server/util/object.c file | annotate | diff | comparison | revisions
src/server/util/object.h file | annotate | diff | comparison | revisions
--- a/src/server/daemon/webserver.c	Wed Nov 16 12:14:45 2022 +0100
+++ b/src/server/daemon/webserver.c	Sun Nov 20 11:39:46 2022 +0100
@@ -136,7 +136,7 @@
         }
     }
     if(!vars->Vuserpw) {
-        log_ereport(LOG_WARN, "globalvars->Vuserpw is null");
+        log_ereport(LOG_VERBOSE, "globalvars->Vuserpw is null");
     }
 
     // change uid
--- a/src/server/test/main.c	Wed Nov 16 12:14:45 2022 +0100
+++ b/src/server/test/main.c	Sun Nov 20 11:39:46 2022 +0100
@@ -79,6 +79,7 @@
     ucx_test_register(suite, test_util_uri_escape_kanji);
     
     // object tests
+    /*
     ucx_test_register(suite, test_expr_parse_expr_value);
     ucx_test_register(suite, test_expr_parse_expr_neg_value);
     ucx_test_register(suite, test_expr_parse_expr_value_str);
@@ -90,6 +91,12 @@
     ucx_test_register(suite, test_expr_parse_expr_compare2value_expr);
     ucx_test_register(suite, test_expr_parse_expr_compare2expr_value);
     ucx_test_register(suite, test_expr_parse_expr_bracket);
+    */
+    //ucx_test_register(suite, test_expr_parse_expr_func_arg0);
+    ucx_test_register(suite, test_expr_parse_expr_func_arg1);
+    ucx_test_register(suite, test_expr_parse_expr_func_arg3);
+    ucx_test_register(suite, test_expr_parse_expr_func_expr1);
+    ucx_test_register(suite, test_expr_parse_expr_func_expr2);
     
     // vfs tests
     ucx_test_register(suite, test_vfs_open);
--- a/src/server/test/object.c	Wed Nov 16 12:14:45 2022 +0100
+++ b/src/server/test/object.c	Sun Nov 20 11:39:46 2022 +0100
@@ -351,6 +351,7 @@
     NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos);
     
     UCX_TEST_ASSERT(pos == 9, "wrong token pos");
+    UCX_TEST_ASSERT(expr, "expression is null");
     UCX_TEST_ASSERT(expr->operator == NSAPI_EXPRESSION_EQ, "root: wrong operator");
     UCX_TEST_ASSERT(expr->left, "missing left expression");
     UCX_TEST_ASSERT(expr->right, "missing right expression");
@@ -366,3 +367,243 @@
     
     pool_destroy(pool);
 }
+
+UCX_TEST(test_expr_parse_expr_func_arg0) {
+    pool_handle_t *pool = pool_create();
+    
+    CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring));
+    cxstring token = cx_str("test");
+    cxListAdd(tokens, &token);
+    token = cx_str("(");
+    cxListAdd(tokens, &token);
+    token = cx_str(")");
+    cxListAdd(tokens, &token);
+    
+    UCX_TEST_BEGIN;
+    
+    size_t pos = 0;
+    NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos);
+    
+    UCX_TEST_ASSERT(pos == 3, "wrong token pos");
+    UCX_TEST_ASSERT(expr, "expression is null");
+    UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_IDENTIFIER, "wrong expression type");
+    UCX_TEST_ASSERT(expr->operator == NSAPI_EXPRESSION_CALL, "wrong expression operator");
+    UCX_TEST_ASSERT(!expr->left, "left is not null");
+    UCX_TEST_ASSERT(!expr->right, "right is not null");
+    
+    UCX_TEST_END;
+    
+    pool_destroy(pool);
+}
+
+
+int test_get_args(NSAPIExpression *arglist, size_t maxArgs, size_t *numArgs, NSAPIExpression *arg) {
+    if(!arg) {
+        return 0;
+    }
+    if(arg->operator == NSAPI_EXPRESSION_ARG) {
+        if(arg->left) {
+            if(test_get_args(arglist, maxArgs, numArgs, arg->left)) {
+                return 1;
+            }
+        }
+        if(arg->right) {
+            if(test_get_args(arglist, maxArgs, numArgs, arg->right)) {
+                return 1;
+            }
+        }
+    } else {
+        if(*numArgs >= maxArgs) {
+            return 1;
+        }
+        arglist[*numArgs] = *arg;
+        (*numArgs)++;
+    } 
+    
+    return 0;
+}
+
+
+UCX_TEST(test_expr_parse_expr_func_arg1) {
+    pool_handle_t *pool = pool_create();
+    
+    CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring));
+    cxstring token = cx_str("test");
+    cxListAdd(tokens, &token);
+    token = cx_str("(");
+    cxListAdd(tokens, &token);
+    token = cx_str("1");
+    cxListAdd(tokens, &token);
+    token = cx_str(")");
+    cxListAdd(tokens, &token);
+    
+    UCX_TEST_BEGIN;
+    
+    size_t pos = 0;
+    NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos);
+    
+    UCX_TEST_ASSERT(pos == tokens->size, "wrong token pos");
+    UCX_TEST_ASSERT(expr, "expression is null");
+    UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_IDENTIFIER, "wrong expression type");
+    UCX_TEST_ASSERT(expr->operator == NSAPI_EXPRESSION_CALL, "wrong expression operator");
+    
+    size_t numArgs = 0;
+    NSAPIExpression args[8];
+    int err = test_get_args(args, 8, &numArgs, expr->left);
+    UCX_TEST_ASSERT(err == 0, "too much args");
+    UCX_TEST_ASSERT(numArgs == 1, "wrong arg count");
+    UCX_TEST_ASSERT(args[0].value.i == 1, "wrong arg value");
+    
+    UCX_TEST_END;
+    
+    pool_destroy(pool);
+}
+
+UCX_TEST(test_expr_parse_expr_func_arg3) {
+    pool_handle_t *pool = pool_create();
+    
+    CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring));
+    cxstring token = cx_str("test");
+    cxListAdd(tokens, &token);
+    token = cx_str("(");
+    cxListAdd(tokens, &token);
+    token = cx_str("1");
+    cxListAdd(tokens, &token);
+    token = cx_str(",");
+    cxListAdd(tokens, &token);
+    token = cx_str("2");
+    cxListAdd(tokens, &token);
+    token = cx_str(",");
+    cxListAdd(tokens, &token);
+    token = cx_str("3");
+    cxListAdd(tokens, &token);
+    token = cx_str(")");
+    cxListAdd(tokens, &token);
+    
+    UCX_TEST_BEGIN;
+    
+    size_t pos = 0;
+    NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos);
+    
+    UCX_TEST_ASSERT(pos == tokens->size, "wrong token pos");
+    UCX_TEST_ASSERT(expr, "expression is null");
+    UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_IDENTIFIER, "wrong expression type");
+    UCX_TEST_ASSERT(expr->operator == NSAPI_EXPRESSION_CALL, "wrong expression operator");
+    
+    size_t numArgs = 0;
+    NSAPIExpression args[8];
+    int err = test_get_args(args, 8, &numArgs, expr->left);
+    UCX_TEST_ASSERT(err == 0, "too much args");
+    UCX_TEST_ASSERT(numArgs == 3, "wrong arg count");
+    UCX_TEST_ASSERT(args[0].value.i == 1, "arg0: wrong value");
+    UCX_TEST_ASSERT(args[1].value.i == 2, "arg1: wrong value");
+    UCX_TEST_ASSERT(args[2].value.i == 3, "arg2: wrong value");
+    
+    UCX_TEST_END;
+    
+    pool_destroy(pool);
+}
+
+UCX_TEST(test_expr_parse_expr_func_expr1) {
+    pool_handle_t *pool = pool_create();
+    
+    CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring));
+    cxstring token = cx_str("test");
+    cxListAdd(tokens, &token);
+    token = cx_str("(");
+    cxListAdd(tokens, &token);
+    token = cx_str("1");
+    cxListAdd(tokens, &token);
+    token = cx_str(",");
+    cxListAdd(tokens, &token);
+    token = cx_str("2");
+    cxListAdd(tokens, &token);
+    token = cx_str("+");
+    cxListAdd(tokens, &token);
+    token = cx_str("3");
+    cxListAdd(tokens, &token);
+    token = cx_str(")");
+    cxListAdd(tokens, &token);
+    
+    UCX_TEST_BEGIN;
+    
+    size_t pos = 0;
+    NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos);
+    
+    UCX_TEST_ASSERT(pos == tokens->size, "wrong token pos");
+    UCX_TEST_ASSERT(expr, "expression is null");
+    UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_IDENTIFIER, "wrong expression type");
+    UCX_TEST_ASSERT(expr->operator == NSAPI_EXPRESSION_CALL, "wrong expression operator");
+    
+    size_t numArgs = 0;
+    NSAPIExpression args[8];
+    int err = test_get_args(args, 8, &numArgs, expr->left);
+    UCX_TEST_ASSERT(err == 0, "too much args");
+    UCX_TEST_ASSERT(numArgs == 2, "wrong arg count");
+    UCX_TEST_ASSERT(args[0].value.i == 1, "arg0: wrong value");
+    UCX_TEST_ASSERT(args[1].operator == NSAPI_EXPRESSION_ADD, "arg1: wrong operator");
+    UCX_TEST_ASSERT(args[1].left && args[1].right, "arg1: missing operator values");
+    UCX_TEST_ASSERT(args[1].left->value.i == 2 && args[1].right->value.i == 3, "arg1: wrong operator values");
+    
+    UCX_TEST_END;
+    
+    pool_destroy(pool);
+}
+
+UCX_TEST(test_expr_parse_expr_func_expr2) {
+    pool_handle_t *pool = pool_create();
+    
+    CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring));
+    cxstring token = cx_str("test");
+    cxListAdd(tokens, &token);
+    token = cx_str("(");
+    cxListAdd(tokens, &token);
+    token = cx_str("2");
+    cxListAdd(tokens, &token);
+    token = cx_str("+");
+    cxListAdd(tokens, &token);
+    token = cx_str("3");
+    cxListAdd(tokens, &token);
+    token = cx_str(",");
+    cxListAdd(tokens, &token);
+    token = cx_str("sub");
+    cxListAdd(tokens, &token);
+    token = cx_str("(");
+    cxListAdd(tokens, &token);
+    token = cx_str("4");
+    cxListAdd(tokens, &token);
+    token = cx_str(")");
+    cxListAdd(tokens, &token);
+    token = cx_str(",");
+    cxListAdd(tokens, &token);
+    token = cx_str("6");
+    cxListAdd(tokens, &token);
+    token = cx_str(")");
+    cxListAdd(tokens, &token);
+    
+    UCX_TEST_BEGIN;
+    
+    size_t pos = 0;
+    NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos);
+    
+    UCX_TEST_ASSERT(pos == tokens->size, "wrong token pos");
+    UCX_TEST_ASSERT(expr, "expression is null");
+    UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_IDENTIFIER, "wrong expression type");
+    UCX_TEST_ASSERT(expr->operator == NSAPI_EXPRESSION_CALL, "wrong expression operator");
+    
+    size_t numArgs = 0;
+    NSAPIExpression args[8];
+    int err = test_get_args(args, 8, &numArgs, expr->left);
+    UCX_TEST_ASSERT(err == 0, "too much args");
+    UCX_TEST_ASSERT(numArgs == 3, "wrong arg count");
+    UCX_TEST_ASSERT(args[0].operator == NSAPI_EXPRESSION_ADD, "arg0: wrong operator");
+    UCX_TEST_ASSERT(args[0].left && args[0].right, "arg0: missing operator values");
+    UCX_TEST_ASSERT(args[1].operator == NSAPI_EXPRESSION_CALL, "arg1: wrong operator");
+    UCX_TEST_ASSERT(args[1].left, "arg1: missing args");
+    UCX_TEST_ASSERT(args[2].type == NSAPI_EXPRESSION_INT, "arg2: wrong type");
+    UCX_TEST_ASSERT(args[2].value.i == 6, "arg2: wrong value");
+    
+    UCX_TEST_END;
+    
+    pool_destroy(pool);
+}
--- a/src/server/test/object.h	Wed Nov 16 12:14:45 2022 +0100
+++ b/src/server/test/object.h	Sun Nov 20 11:39:46 2022 +0100
@@ -51,6 +51,13 @@
 
 UCX_TEST(test_expr_parse_expr_bracket);
 
+UCX_TEST(test_expr_parse_expr_func_arg0);
+UCX_TEST(test_expr_parse_expr_func_arg1);
+UCX_TEST(test_expr_parse_expr_func_arg3);
+UCX_TEST(test_expr_parse_expr_func_expr1);
+UCX_TEST(test_expr_parse_expr_func_expr2);
+
+
 
 #ifdef __cplusplus
 }
--- a/src/server/util/object.c	Wed Nov 16 12:14:45 2022 +0100
+++ b/src/server/util/object.c	Sun Nov 20 11:39:46 2022 +0100
@@ -128,11 +128,13 @@
   CxList *ex_stack;
   CxList *tokens;
   size_t *pos;
-  int    expect_value;
+  WSBool expect_value;
+  WSBool expect_arg;
 } ExprParser;
 
 typedef struct {
     NSAPIExpressionOperator operator;
+    cxstring identifier;
     int expect_value;
     int open_parenthesis;
 } ExprOpStackItem;
@@ -153,7 +155,9 @@
 }
 
 static NSAPIExpressionOperator expr_operator(cxstring token) {
-    if(!cx_strcmp(token, cx_str("+"))) {
+    if(!cx_strcmp(token, cx_str(","))) {
+       return NSAPI_EXPRESSION_ARG; 
+    } else if(!cx_strcmp(token, cx_str("+"))) {
         return NSAPI_EXPRESSION_ADD;
     } else if(!cx_strcmp(token, cx_str("-"))) {
         return NSAPI_EXPRESSION_SUB;
@@ -263,9 +267,18 @@
     // in that case, the - operator is a unary expression
     if(op->expect_value) {
         // We expected a value but got an operator? This must be an unary operator
+        
+        if(op->operator == NSAPI_EXPRESSION_ARG && !parser->expect_arg) {
+            // simplify unary arg
+            pool_free(parser->pool, exp);
+            parser->expect_value = TRUE;
+            parser->expect_arg = FALSE;
+            return 0;
+        }
+        
         exp->type = NSAPI_EXPRESSION_UNARY;
         exp->left = expr_parser_pop(parser);
-        exp->right = NULL;
+        exp->right = NULL; 
     } else {
         // binary operator
         exp->type = NSAPI_EXPRESSION_BINARY;
@@ -280,6 +293,33 @@
     cxListAdd(parser->ex_stack, exp);
     
     parser->expect_value = TRUE;
+    parser->expect_arg = FALSE;
+    return 0;
+}
+
+static int expr_add_func(ExprParser *parser, ExprOpStackItem *func) {
+    NSAPIExpression *exp = pool_malloc(parser->pool, sizeof(NSAPIExpression));
+    if(!exp) {
+        return 1;
+    }
+    exp->type = NSAPI_EXPRESSION_IDENTIFIER;
+    exp->operator = NSAPI_EXPRESSION_CALL;
+    exp->left = NULL;
+    exp->right = NULL;
+    exp->value.str = func->identifier;
+    
+    if(parser->ex_stack->size > 0) {
+        NSAPIExpression *top = cxListAt(parser->ex_stack, parser->ex_stack->size - 1);
+        if(top && top->operator == NSAPI_EXPRESSION_ARG) {
+            exp->left = top;
+            cxListRemove(parser->ex_stack, parser->ex_stack->size - 1);
+        }
+    }
+    
+    if(cxListAdd(parser->ex_stack, exp)) {
+        return 1;
+    }
+    parser->expect_value = FALSE;
     return 0;
 }
 
@@ -292,11 +332,46 @@
     if(expr_set_value(parser->pool, exp, token)) {
         return 1;
     }
+    
     cxListAdd(parser->ex_stack, exp);
+    if(parser->expect_arg) {
+        ExprOpStackItem argList;
+        argList.expect_value = TRUE;
+        argList.identifier = (cxstring){NULL, 0};
+        argList.open_parenthesis = FALSE;
+        argList.operator = NSAPI_EXPRESSION_ARG;
+        if(expr_add_operator(parser, &argList)) {
+            return 1;
+        }
+    }
+    
     parser->expect_value = FALSE;
+    parser->expect_arg = FALSE;
     return 0;
 }
 
+static int token_is_identifier(cxstring token) {
+    if(token.length == 0) {
+        return 0;
+    }
+    
+    if(!isalpha(token.ptr[0])) {
+        return 0;
+    }
+    
+    for(int i=1;i<token.length;i++) {
+        if(!isalnum(token.ptr[i])) {
+            return 0;
+        }
+    }
+    
+    if(!cx_strcmp(token, cx_str("true")) || !cx_strcmp(token, cx_str("false"))) {
+        return 0;
+    }
+    
+    return 1;
+}
+
 
 static NSAPIExpression* expr_parse_expr(ExprParser *parser) {
     CxList *op_stack = parser->op_stack;
@@ -309,6 +384,7 @@
         if(op != NSAPI_EXPRESSION_NOOP) {
             ExprOpStackItem new_op;
             new_op.operator = op;
+            new_op.identifier = (cxstring){NULL,0};
             new_op.expect_value = parser->expect_value;
             new_op.open_parenthesis = FALSE;
             while(op_stack->size > 0) {
@@ -327,23 +403,40 @@
             }
             cxListAdd(op_stack, &new_op);
             parser->expect_value = TRUE;
+            parser->expect_arg = FALSE;
         } else if(token.length == 1 && token.ptr[0] == '(') {
-            ExprOpStackItem new_op;
-            new_op.operator = NSAPI_EXPRESSION_NOOP;
-            new_op.expect_value = 0;
-            new_op.open_parenthesis = 1;
-            cxListAdd(op_stack, &new_op);
+            ExprOpStackItem *prev_op = NULL;
+            if(op_stack->size > 0) {
+                prev_op = cxListAt(op_stack, op_stack->size - 1);
+            }
+            
+            if(prev_op && prev_op->operator == NSAPI_EXPRESSION_CALL) {
+                // function call open parenthesis
+                // we don't need to add a new op stack item, just mark function
+                // call as open parenthesis
+                prev_op->open_parenthesis = TRUE;
+                parser->expect_arg = TRUE;
+            } else {
+                ExprOpStackItem new_op;
+                new_op.operator = NSAPI_EXPRESSION_NOOP;
+                new_op.identifier = (cxstring){NULL,0};
+                new_op.expect_value = 0;
+                new_op.open_parenthesis = TRUE;
+                cxListAdd(op_stack, &new_op);
+            }
             parser->expect_value = TRUE;
         } else if(token.length == 1 && token.ptr[0] == ')') {
             int found_open_bracket = FALSE;
+            ExprOpStackItem stack_item;
             while(op_stack->size > 0) {
-                ExprOpStackItem *stack_item = cxListAt(op_stack, op_stack->size-1);
+                ExprOpStackItem *stack_item_ptr = cxListAt(op_stack, op_stack->size-1);
+                stack_item = *stack_item_ptr;
                 cxListRemove(op_stack, op_stack->size-1);
-                if(stack_item->open_parenthesis) {
+                if(stack_item.open_parenthesis) {
                     found_open_bracket = TRUE;
                     break;
                 } else {
-                    if(expr_add_operator(parser, stack_item)) {
+                    if(expr_add_operator(parser, &stack_item)) {
                         return NULL;
                     }
                 }
@@ -351,7 +444,22 @@
             if(!found_open_bracket) {
                 return NULL;
             }
+            if(stack_item.operator == NSAPI_EXPRESSION_CALL) {
+                if(expr_add_func(parser, &stack_item)) {
+                    return NULL;
+                }
+            }
             parser->expect_value = FALSE;
+            parser->expect_arg = FALSE;
+        } else if(token_is_identifier(token)) {
+            ExprOpStackItem new_op;
+            new_op.operator = NSAPI_EXPRESSION_CALL;
+            new_op.identifier = token;
+            new_op.expect_value = 0;
+            new_op.open_parenthesis = FALSE;
+            cxListAdd(op_stack, &new_op);
+            parser->expect_value = FALSE;
+            parser->expect_arg = FALSE;
         } else {
             if(expr_add_value(parser, token)) {
                 return NULL;
@@ -388,6 +496,7 @@
     parser.tokens = tokens;
     parser.pos = pos;
     parser.expect_value = TRUE;
+    parser.expect_arg = FALSE;
     
     NSAPIExpression *ret = expr_parse_expr(&parser);
     cxListDestroy(op_stack);
--- a/src/server/util/object.h	Wed Nov 16 12:14:45 2022 +0100
+++ b/src/server/util/object.h	Sun Nov 20 11:39:46 2022 +0100
@@ -137,11 +137,14 @@
     NSAPI_EXPRESSION_VARIABLE,
     NSAPI_EXPRESSION_LOGICAL,
     NSAPI_EXPRESSION_UNARY,
-    NSAPI_EXPRESSION_BINARY
+    NSAPI_EXPRESSION_BINARY,
+    NSAPI_EXPRESSION_IDENTIFIER
 };
 
 enum NSAPIExpressionOperator {
     NSAPI_EXPRESSION_NOOP = 0,
+    NSAPI_EXPRESSION_CALL,
+    NSAPI_EXPRESSION_ARG,
     NSAPI_EXPRESSION_NOT,
     NSAPI_EXPRESSION_AND,
     NSAPI_EXPRESSION_OR,

mercurial