add obj.conf expression parser

Sat, 12 Nov 2022 11:01:11 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sat, 12 Nov 2022 11:01:11 +0100
changeset 423
bb7cff720dd0
parent 422
76f2f5d532d0
child 424
3df9258cd3cc

add obj.conf expression parser

src/server/config/serverconfig.c file | annotate | diff | comparison | revisions
src/server/daemon/config.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/test/objs.mk 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/config/serverconfig.c	Wed Nov 09 11:51:19 2022 +0100
+++ b/src/server/config/serverconfig.c	Sat Nov 12 11:01:11 2022 +0100
@@ -96,6 +96,15 @@
     return root;
 }
 
+static int scfg_char_is_delim(char c) {
+    static const char *scfg_tokenizer_delim = "()+-/*%";
+    for(int i=0;i<sizeof(scfg_tokenizer_delim)-1;i++) {
+        if(c == scfg_tokenizer_delim[i]) {
+            return 1;
+        }
+    }
+    return 0;
+}
 
 static CFGToken get_next_token(cxstring content, int *pos) {
     CFGToken token = { {NULL, 0}, CFG_NO_TOKEN };
@@ -155,7 +164,7 @@
             if(token_begin < 0) {
                 token_begin = i;
             }
-        } else if(c == '(' || c == ')') {
+        } else if(scfg_char_is_delim(c)) {
             if(token_begin >= 0) {
                 token_end = i;
                 i--;
--- a/src/server/daemon/config.c	Wed Nov 09 11:51:19 2022 +0100
+++ b/src/server/daemon/config.c	Sat Nov 12 11:01:11 2022 +0100
@@ -844,18 +844,40 @@
     return 0;
 }
 
-static int set_if_condition(pool_handle_t *pool, ConfigNode *node, Condition *condition) {
-    printf("\n");
+static int set_if_condition(pool_handle_t *pool, ConfigNode *node, Condition *condition) { 
+    // convert to parameters to a list of tokens
+    // usually, one parameter is one token, however the config parser
+    // converts name=value pairs to one ConfigParam
     
-    ConfigParam *token = node->args;
-    while(token) {
-        printf("token: %s  %s\n", token->name.ptr, token->value.ptr);
-        token = token->next;
+    // list of cxmutstr, however the expression parser will use this
+    // as list of cxstring, but that is totally fine
+    CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxmutstr));
+    ConfigParam *arg = node->args;
+    while(arg) {
+        if(arg->name.length > 0) {
+            // arg text is name=value, therefore we add 3 tokens
+            // name, "=", value
+            cxListAdd(tokens, &arg->name);
+            cxmutstr op = (cxmutstr){ "=", 1 };
+            cxListAdd(tokens, &op);
+        }
+        if(cxListAdd(tokens, &arg->value)) {
+            cxListDestroy(tokens);
+            return 1; // OOM
+        }
+        arg = arg->next;
     }
-    printf("\n");
-    fflush(stdout);
     
-    return 0;
+    int ret = 0;
+    condition->expression = condition_create(pool, tokens);
+    if(!condition->expression) {
+        ret = 1;
+    }
+    
+    // don't need the token list anymore
+    cxListDestroy(tokens);
+    
+    return ret;
 }
 
 // convert a condition 
--- a/src/server/test/main.c	Wed Nov 09 11:51:19 2022 +0100
+++ b/src/server/test/main.c	Sat Nov 12 11:01:11 2022 +0100
@@ -47,6 +47,7 @@
 #include "xml.h"
 #include "webdav.h"
 #include "uri.h"
+#include "object.h"
 
 void register_pg_tests(int argc, char **argv, UcxTestSuite *suite);
 
@@ -77,6 +78,18 @@
     ucx_test_register(suite, test_util_uri_escape_latin);
     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_value_str);
+    //ucx_test_register(suite, test_expr_parse_expr_value_bool);
+    //ucx_test_register(suite, test_expr_parse_expr_value_var);
+    //ucx_test_register(suite, test_expr_parse_expr_not_value);
+    //ucx_test_register(suite, test_expr_parse_expr_sign_value);
+    //ucx_test_register(suite, test_expr_parse_expr_compare2values);
+    //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);
+    
     // vfs tests
     ucx_test_register(suite, test_vfs_open);
     ucx_test_register(suite, test_vfs_mkdir);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/test/object.c	Sat Nov 12 11:01:11 2022 +0100
@@ -0,0 +1,346 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2022 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "object.h"
+
+#include "../util/object.h"
+
+#include <cx/linked_list.h>
+#include <cx/compare.h>
+
+#include "object.h"
+
+
+UCX_TEST(test_expr_parse_expr_value) {
+    pool_handle_t *pool = pool_create();
+    
+    CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring));
+    cxstring token = cx_str("123");
+    cxListAdd(tokens, &token);
+    
+    UCX_TEST_BEGIN;
+    
+    size_t pos = 0;
+    NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos);
+    
+    UCX_TEST_ASSERT(pos == 1, "wrong token pos");
+    UCX_TEST_ASSERT(expr, "expression is null");
+    UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_INT, "wrong type");
+    
+    UCX_TEST_END;
+    
+    pool_destroy(pool);
+}
+
+UCX_TEST(test_expr_parse_expr_value_str) {
+    pool_handle_t *pool = pool_create();
+    
+    CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring));
+    cxstring token = cx_str("\"hello world\"");
+    cxListAdd(tokens, &token);
+    
+    UCX_TEST_BEGIN;
+    
+    size_t pos = 0;
+    NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos);
+    
+    UCX_TEST_ASSERT(pos == 1, "wrong token pos");
+    UCX_TEST_ASSERT(expr, "expression is null");
+    UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_STRING, "wrong type");
+    UCX_TEST_ASSERT(!cx_strcmp(expr->value.str, cx_str("hello world")), "wrong value");
+    
+    UCX_TEST_END;
+    
+    pool_destroy(pool);
+}
+
+UCX_TEST(test_expr_parse_expr_value_bool) {
+    pool_handle_t *pool = pool_create();
+    
+    CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring));
+    cxstring token = cx_str("true");
+    cxListAdd(tokens, &token);
+    
+    UCX_TEST_BEGIN;
+    
+    size_t pos = 0;
+    NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos);
+    
+    UCX_TEST_ASSERT(pos == 1, "wrong token pos");
+    UCX_TEST_ASSERT(expr, "expression is null");
+    UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_BOOL, "wrong type");
+    UCX_TEST_ASSERT(expr->value.b == 1, "wrong value");
+    
+    UCX_TEST_END;
+    
+    pool_destroy(pool);
+}
+
+UCX_TEST(test_expr_parse_expr_value_var) {
+    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);
+    
+    UCX_TEST_BEGIN;
+    
+    size_t pos = 0;
+    NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos);
+    
+    UCX_TEST_ASSERT(pos == 1, "wrong token pos");
+    UCX_TEST_ASSERT(expr, "expression is null");
+    UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_VARIABLE, "wrong type");
+    UCX_TEST_ASSERT(!cx_strcmp(expr->value.var, cx_str("test")), "wrong var name");
+    
+    UCX_TEST_END;
+    
+    pool_destroy(pool);
+}
+
+UCX_TEST(test_expr_parse_expr_not_value) {
+    pool_handle_t *pool = pool_create();
+    
+    CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring));
+    cxstring token = cx_str("not");
+    cxListAdd(tokens, &token);
+    token = cx_str("true");
+    cxListAdd(tokens, &token);
+    
+    UCX_TEST_BEGIN;
+    
+    size_t pos = 0;
+    NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos);
+    
+    UCX_TEST_ASSERT(pos == 2, "wrong token pos");
+    UCX_TEST_ASSERT(expr, "expression is null");
+    
+    UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_UNARY, "wrong root expression type");
+    UCX_TEST_ASSERT(expr->left, "missing left expression");
+    UCX_TEST_ASSERT(!expr->right, "right expression should be null");
+    UCX_TEST_ASSERT(expr->left->type == NSAPI_EXPRESSION_BOOL, "left expression has wrong type");
+    UCX_TEST_ASSERT(expr->left->value.b == 1, "left expression has wrong value");
+    
+    UCX_TEST_END;
+    
+    pool_destroy(pool);
+}
+
+UCX_TEST(test_expr_parse_expr_sign_value) {
+    pool_handle_t *pool = pool_create();
+    
+    CxList *tokens1 = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring));
+    cxstring token = cx_str("+");
+    cxListAdd(tokens1, &token);
+    token = cx_str("123");
+    cxListAdd(tokens1, &token);
+    
+    CxList *tokens2 = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring));
+    token = cx_str("-");
+    cxListAdd(tokens2, &token);
+    token = cx_str("123");
+    cxListAdd(tokens2, &token);
+    
+    UCX_TEST_BEGIN;
+    
+    size_t pos = 0;
+    NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens1, &pos);
+    
+    UCX_TEST_ASSERT(pos == 2, "test1: wrong token pos");
+    UCX_TEST_ASSERT(expr, "test1: expression is null");
+    
+    pos = 0;
+    expr = expr_parse_logical_expr(pool, tokens2, &pos);
+    
+    UCX_TEST_ASSERT(pos == 2, "test2: wrong token pos");
+    UCX_TEST_ASSERT(expr, "test2: expression is null");
+    
+    UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_UNARY, "wrong expression type");
+    UCX_TEST_ASSERT(expr->operator == NSAPI_EXPRESSION_SUB, "wrong expression operator");
+    UCX_TEST_ASSERT(expr->left, "missing left expresion");
+    UCX_TEST_ASSERT(expr->left->type == NSAPI_EXPRESSION_INT, "left expression has wrong type");
+    UCX_TEST_ASSERT(expr->left->value.i == 123, "left expression has wrong value");
+    
+    UCX_TEST_END;
+    
+    pool_destroy(pool);
+}
+
+
+
+UCX_TEST(test_expr_parse_expr_compare2values) {
+    pool_handle_t *pool = pool_create();
+    
+    CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring));
+    cxstring token = cx_str("2");
+    cxListAdd(tokens, &token);
+    token = cx_str("==");
+    cxListAdd(tokens, &token);
+    token = cx_str("2");
+    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_BINARY, "wrong expression type");
+    UCX_TEST_ASSERT(expr->left, "left expression is null");
+    UCX_TEST_ASSERT(expr->right, "right expression is null");
+    
+    UCX_TEST_ASSERT(expr->left->operator == NSAPI_EXPRESSION_NOOP, "left should be a literal with no operator");
+    UCX_TEST_ASSERT(expr->right->operator == NSAPI_EXPRESSION_NOOP, "right should be a literal with no operator");
+    
+    UCX_TEST_END;
+    
+    pool_destroy(pool);
+}
+
+UCX_TEST(test_expr_parse_expr_compare2value_expr) {
+    pool_handle_t *pool = pool_create();
+    
+    CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring));
+    cxstring token = cx_str("2");
+    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("1");
+    cxListAdd(tokens, &token);
+    
+    UCX_TEST_BEGIN;
+    
+    size_t pos = 0;
+    NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos);
+    
+    UCX_TEST_ASSERT(pos == 5, "wrong token pos");
+    UCX_TEST_ASSERT(expr, "expression is null");
+    
+    UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_BINARY, "wrong expression type");
+    UCX_TEST_ASSERT(expr->left, "left expression is null");
+    UCX_TEST_ASSERT(expr->right, "right expression is null");
+    
+    UCX_TEST_ASSERT(expr->left->operator == NSAPI_EXPRESSION_NOOP, "left should be a literal with no operator");
+    UCX_TEST_ASSERT(expr->right->operator == NSAPI_EXPRESSION_ADD, "right should be a binary expression");
+    
+    UCX_TEST_END;
+    
+    pool_destroy(pool);
+}
+
+UCX_TEST(test_expr_parse_expr_compare2expr_value) {
+    pool_handle_t *pool = pool_create();
+    
+    CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring));
+    cxstring token = cx_str("1");
+    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);
+    
+    UCX_TEST_BEGIN;
+    
+    size_t pos = 0;
+    NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos);
+    
+    UCX_TEST_ASSERT(pos == 5, "wrong token pos");
+    UCX_TEST_ASSERT(expr, "expression is null");
+    
+    UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_BINARY, "wrong expression type");
+    UCX_TEST_ASSERT(expr->left, "left expression is null");
+    UCX_TEST_ASSERT(expr->right, "right expression is null");
+    UCX_TEST_ASSERT(expr->right->value.i == 2, "right wrong value");
+    
+    UCX_TEST_ASSERT(expr->left->operator == NSAPI_EXPRESSION_ADD, "left should be a binary operation");
+    UCX_TEST_ASSERT(expr->right->operator == NSAPI_EXPRESSION_NOOP, "right should be NOOP");
+    UCX_TEST_ASSERT(expr->left->left, "ADD-op missing left");
+    UCX_TEST_ASSERT(expr->left->right, "ADD-op missing right");
+    UCX_TEST_ASSERT(expr->left->left->value.i == 1, "ADD-op: wrong left value");
+    UCX_TEST_ASSERT(expr->left->right->value.i == 1, "ADD-op: wrong right value");
+    
+    UCX_TEST_END;
+    
+    pool_destroy(pool);
+}
+
+UCX_TEST(test_expr_parse_expr_bracket) {
+    pool_handle_t *pool = pool_create();
+    
+    // expression: 2 * (1 + 2) == 6
+    CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring));
+    cxstring token = cx_str("2");
+    cxListAdd(tokens, &token);
+    token = cx_str("*");
+    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("==");
+    cxListAdd(tokens, &token);
+    token = cx_str("6");
+    cxListAdd(tokens, &token);
+    
+    UCX_TEST_BEGIN;
+    
+    size_t pos = 0;
+    NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos);
+    
+    UCX_TEST_ASSERT(pos == 9, "wrong token pos");
+    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");
+    UCX_TEST_ASSERT(expr->right->type == NSAPI_EXPRESSION_INT, "right expression has wrong type");
+    UCX_TEST_ASSERT(expr->left->operator == NSAPI_EXPRESSION_MUL, "left expression has wrong operator");
+    UCX_TEST_ASSERT(expr->left->left, "mul: missing left");
+    UCX_TEST_ASSERT(expr->left->right, "mul: missing right");
+    UCX_TEST_ASSERT(expr->left->right->operator == NSAPI_EXPRESSION_ADD, "missing add operator");
+    UCX_TEST_ASSERT(expr->left->right->left, "add: missing left");
+    UCX_TEST_ASSERT(expr->left->right->left, "add: missing right");
+    
+    UCX_TEST_END;
+    
+    pool_destroy(pool);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/test/object.h	Sat Nov 12 11:01:11 2022 +0100
@@ -0,0 +1,59 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2022 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TEST_OBJECT_H
+#define TEST_OBJECT_H
+
+#include "../public/nsapi.h"
+
+#include "test.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+UCX_TEST(test_expr_parse_expr_value);
+UCX_TEST(test_expr_parse_expr_value_str);
+UCX_TEST(test_expr_parse_expr_value_bool);
+UCX_TEST(test_expr_parse_expr_value_var);
+UCX_TEST(test_expr_parse_expr_not_value);
+UCX_TEST(test_expr_parse_expr_sign_value);
+
+UCX_TEST(test_expr_parse_expr_compare2values);
+UCX_TEST(test_expr_parse_expr_compare2value_expr);
+UCX_TEST(test_expr_parse_expr_compare2expr_value);
+
+UCX_TEST(test_expr_parse_expr_bracket);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TEST_OBJECT_H */
+
--- a/src/server/test/objs.mk	Wed Nov 09 11:51:19 2022 +0100
+++ b/src/server/test/objs.mk	Sat Nov 12 11:01:11 2022 +0100
@@ -38,6 +38,7 @@
 TESTOBJ += xml.o
 TESTOBJ += writer.o
 TESTOBJ += uri.o
+TESTOBJ += object.o
 
 TESTOBJS = $(TESTOBJ:%=$(TEST_OBJPRE)%)
 TESTSOURCE = $(TESTOBJ:%.o=test/%.c)
--- a/src/server/util/object.c	Wed Nov 09 11:51:19 2022 +0100
+++ b/src/server/util/object.c	Sat Nov 12 11:01:11 2022 +0100
@@ -27,11 +27,13 @@
  */
 
 #include <cx/string.h>
+#include <cx/linked_list.h>
+#include <cx/compare.h>
 
 #include "../public/nsapi.h"
 
 #include "object.h"
-
+#include "util.h"
 #include "pool.h"
 #include "../daemon/func.h"
 
@@ -106,6 +108,281 @@
     context->last_req_code = REQ_NOACTION;
 }
 
+
+/* ------------------------------ Expression ------------------------------ */
+
+Expression* condition_create(pool_handle_t *pool, CxList *tokens) {
+    
+    
+    
+    return NULL;
+}
+
+
+typedef struct {
+  pool_handle_t *pool;
+  CxList *op_stack;
+  CxList *ex_stack;
+  CxList *tokens;
+  size_t *pos;
+  int    expect_value;
+} ExprParser;
+
+typedef struct {
+    NSAPIExpressionOperator operator;
+    int expect_value;
+    int open_parenthesis;
+} ExprOpStackItem;
+
+static void expr_free(pool_handle_t *pool, NSAPIExpression *expr) {
+    if(expr->left) {
+        expr_free(pool, expr->left);
+    }
+    if(expr->right) {
+        expr_free(pool, expr->right);
+    }
+    if(expr->type == NSAPI_EXPRESSION_STRING && expr->value.str.ptr) {
+        pool_free(pool, (char*)expr->value.str.ptr);
+    } else if(expr->type == NSAPI_EXPRESSION_VARIABLE && expr->value.var.ptr) {
+        pool_free(pool, (char*)expr->value.var.ptr);
+    }
+    pool_free(pool, expr);
+}
+
+static NSAPIExpressionOperator expr_operator(cxstring token) {
+    if(!cx_strcmp(token, cx_str("+"))) {
+        return NSAPI_EXPRESSION_ADD;
+    } else if(!cx_strcmp(token, cx_str("-"))) {
+        return NSAPI_EXPRESSION_SUB;
+    } else if(!cx_strcmp(token, cx_str("*"))) {
+        return NSAPI_EXPRESSION_MUL;
+    } else if(!cx_strcmp(token, cx_str("/"))) {
+        return NSAPI_EXPRESSION_DIV;
+    } else if(!cx_strcmp(token, cx_str("%"))) {
+        return NSAPI_EXPRESSION_MOD;
+    } else if(!cx_strcmp(token, cx_str("not"))) {
+        return NSAPI_EXPRESSION_NOT;
+    } else if(!cx_strcmp(token, cx_str("and"))) {
+        return NSAPI_EXPRESSION_AND;
+    } else if(!cx_strcmp(token, cx_str("or"))) {
+        return NSAPI_EXPRESSION_OR;
+    } else if(!cx_strcmp(token, cx_str("xor"))) {
+        return NSAPI_EXPRESSION_XOR;
+    } else if(!cx_strcmp(token, cx_str("=="))) {
+        return NSAPI_EXPRESSION_EQ;
+    } else if(!cx_strcmp(token, cx_str("!="))) {
+        return NSAPI_EXPRESSION_NEQ;
+    } else if(!cx_strcmp(token, cx_str(">"))) {
+        return NSAPI_EXPRESSION_GT;
+    } else if(!cx_strcmp(token, cx_str("<"))) {
+        return NSAPI_EXPRESSION_LT;
+    } else if(!cx_strcmp(token, cx_str(">="))) {
+        return NSAPI_EXPRESSION_GE;
+    } else if(!cx_strcmp(token, cx_str("<="))) {
+        return NSAPI_EXPRESSION_LE;
+    }
+    return NSAPI_EXPRESSION_NOOP;
+}
+
+static int token_is_int(cxstring token) {
+    for(size_t i=0;i<token.length;i++) {
+        if(!isdigit(token.ptr[i])) {
+            return 0;
+        }
+    }
+    return 1;
+}
+
+static int expr_set_value(pool_handle_t *pool, NSAPIExpression *expr, cxstring token) {
+    if(token.length >= 2 && token.ptr[0] == '\"' && token.ptr[token.length-1] == '\"') {
+        expr->value.str = cx_strcast(cx_strdup_a(pool_allocator(pool), cx_strsubsl(token, 1, token.length-2)));
+        expr->type = NSAPI_EXPRESSION_STRING;
+    } else if(token.length >= 2 && token.ptr[0] == '$' && isalpha(token.ptr[1])) {
+        expr->value.var = cx_strcast(cx_strdup_a(pool_allocator(pool), cx_strsubs(token, 1)));
+        expr->type = NSAPI_EXPRESSION_VARIABLE;
+    } else if(token_is_int(token)) {
+        if(!util_strtoint(token.ptr, &expr->value.i)) {
+            return 1;
+        }
+        expr->type = NSAPI_EXPRESSION_INT;
+    } else if(!strcmp(token.ptr, "true")) {
+        expr->type = NSAPI_EXPRESSION_BOOL;
+        expr->value.b = 1;
+    } else if(!strcmp(token.ptr, "false")) {
+        expr->type = NSAPI_EXPRESSION_BOOL;
+        expr->value.b = 0;
+    } else {
+        return 1;
+    }
+    // TODO: double
+    return 0;
+}
+
+cxstring expr_next_token(CxList *tokens, size_t *pos) {
+    cxstring *token = cxListAt(tokens, *pos);
+    if(token) {
+        (*pos)++;
+        return *token;
+    }
+    return (cxstring){NULL, 0};
+}
+
+NSAPIExpression* expr_parser_pop(ExprParser *parser) {
+    CxList *stack = parser->ex_stack;
+    if(stack->size == 0) {
+        return NULL;
+    }
+    NSAPIExpression *ret = cxListAt(stack, stack->size-1);
+    cxListRemove(stack, stack->size-1);
+    return ret;
+}
+
+// takes items from ex_stack and adds a new operator expression to ex_stack
+static int expr_add_operator(ExprParser *parser, ExprOpStackItem *op) {
+    NSAPIExpression *exp = pool_malloc(parser->pool, sizeof(NSAPIExpression));
+    exp->operator = op->operator;
+    // op->expect_value == TRUE means, that the operator was found in a case
+    // a value was expected.
+    // For example: 1 + - 2
+    // After + a value is expected, but there is the - operator
+    // 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
+        exp->type = NSAPI_EXPRESSION_UNARY;
+        exp->left = expr_parser_pop(parser);
+        exp->right = NULL;
+    } else {
+        // binary operator
+        exp->type = NSAPI_EXPRESSION_BINARY;
+        exp->right = expr_parser_pop(parser);
+        exp->left = expr_parser_pop(parser);
+    }
+    
+    if(!exp->left && !exp->right) {
+        return 1; // error
+    }
+    
+    cxListAdd(parser->ex_stack, exp);
+    
+    parser->expect_value = TRUE;
+    return 0;
+}
+
+// converts the token to a value expression (int, bool, str, ...)
+// and adds it to parser->ex_stack
+// sets parser->expect_value to false
+static int expr_add_value(ExprParser *parser, cxstring token) {
+    NSAPIExpression *exp = pool_malloc(parser->pool, sizeof(NSAPIExpression));
+    ZERO(exp, sizeof(NSAPIExpression));
+    if(expr_set_value(parser->pool, exp, token)) {
+        return 1;
+    }
+    cxListAdd(parser->ex_stack, exp);
+    parser->expect_value = FALSE;
+    return 0;
+}
+
+
+static NSAPIExpression* expr_parse_expr(ExprParser *parser) {
+    CxList *op_stack = parser->op_stack;
+    CxList *ex_stack = parser->ex_stack;
+    
+    // Shunting yard algorithm
+    cxstring token = expr_next_token(parser->tokens, parser->pos);
+    for(;token.ptr;token=expr_next_token(parser->tokens, parser->pos)) {
+        NSAPIExpressionOperator op = expr_operator(token);
+        if(op != NSAPI_EXPRESSION_NOOP) {
+            ExprOpStackItem new_op;
+            new_op.operator = op;
+            new_op.expect_value = parser->expect_value;
+            new_op.open_parenthesis = FALSE;
+            while(op_stack->size > 0) {
+                ExprOpStackItem *stack_item = cxListAt(op_stack, op_stack->size-1);
+                if(stack_item->operator == NSAPI_EXPRESSION_NOOP) {
+                    break;
+                }
+                // check presedence
+                if(op >= stack_item->operator) {
+                    break;
+                }
+                if(expr_add_operator(parser, stack_item)) {
+                    return NULL;
+                }
+                cxListRemove(op_stack, op_stack->size-1);
+            }
+            cxListAdd(op_stack, &new_op);
+            parser->expect_value = TRUE;
+        } 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);
+            parser->expect_value = TRUE;
+        } else if(token.length == 1 && token.ptr[0] == ')') {
+            int found_open_bracket = FALSE;
+            while(op_stack->size > 0) {
+                ExprOpStackItem *stack_item = cxListAt(op_stack, op_stack->size-1);
+                cxListRemove(op_stack, op_stack->size-1);
+                if(stack_item->open_parenthesis) {
+                    found_open_bracket = TRUE;
+                    break;
+                } else {
+                    if(expr_add_operator(parser, stack_item)) {
+                        return NULL;
+                    }
+                }
+            }
+            if(!found_open_bracket) {
+                return NULL;
+            }
+            parser->expect_value = FALSE;
+        } else {
+            if(expr_add_value(parser, token)) {
+                return NULL;
+            }
+        }
+    }
+    
+    while(op_stack->size > 0) {
+        ExprOpStackItem *stack_item = cxListAt(op_stack, op_stack->size-1);
+        if(stack_item->open_parenthesis) {
+            return NULL;
+        }
+        if(expr_add_operator(parser, stack_item)) {
+            return NULL;
+        }
+        cxListRemove(op_stack, op_stack->size-1);
+    }
+    
+    if(ex_stack->size != 1) {
+        return NULL;
+    }
+    
+    return cxListAt(ex_stack, 0);
+}
+
+NSAPIExpression* expr_parse_logical_expr(pool_handle_t *pool, CxList *tokens, size_t *pos) {  
+    CxList *op_stack = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(ExprOpStackItem));
+    CxList *ex_stack = cxPointerLinkedListCreate(pool_allocator(pool), cx_cmp_ptr);
+    
+    ExprParser parser;
+    parser.pool = pool;
+    parser.op_stack = op_stack;
+    parser.ex_stack = ex_stack;
+    parser.tokens = tokens;
+    parser.pos = pos;
+    parser.expect_value = TRUE;
+    
+    NSAPIExpression *ret = expr_parse_expr(&parser);
+    cxListDestroy(op_stack);
+    cxListDestroy(ex_stack);
+    
+    return ret;
+}
+
+
+
 int condition_evaluate(Condition *condition, Session *sn, Request *rq) {
     return 1;
 }
--- a/src/server/util/object.h	Wed Nov 09 11:51:19 2022 +0100
+++ b/src/server/util/object.h	Sat Nov 12 11:01:11 2022 +0100
@@ -32,6 +32,9 @@
 #include "../public/nsapi.h"
 #include "pool.h"
 
+#include <inttypes.h>
+#include <cx/list.h>
+
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -120,6 +123,73 @@
     uint32_t      ref; // reference counter
 };
 
+
+
+typedef struct NSAPIExpression         NSAPIExpression;
+typedef enum NSAPIExpressionType       NSAPIExpressionType;
+typedef enum NSAPIExpressionOperator   NSAPIExpressionOperator;
+
+enum NSAPIExpressionType {
+    NSAPI_EXPRESSION_BOOL = 0,
+    NSAPI_EXPRESSION_INT,
+    NSAPI_EXPRESSION_DOUBLE,
+    NSAPI_EXPRESSION_STRING,
+    NSAPI_EXPRESSION_VARIABLE,
+    NSAPI_EXPRESSION_LOGICAL,
+    NSAPI_EXPRESSION_UNARY,
+    NSAPI_EXPRESSION_BINARY
+};
+
+enum NSAPIExpressionOperator {
+    NSAPI_EXPRESSION_NOOP = 0,
+    NSAPI_EXPRESSION_NOT,
+    NSAPI_EXPRESSION_AND,
+    NSAPI_EXPRESSION_OR,
+    NSAPI_EXPRESSION_XOR,
+    NSAPI_EXPRESSION_EQ,
+    NSAPI_EXPRESSION_NEQ,
+    NSAPI_EXPRESSION_GT,
+    NSAPI_EXPRESSION_LT,
+    NSAPI_EXPRESSION_GE,
+    NSAPI_EXPRESSION_LE,
+    NSAPI_EXPRESSION_ADD,
+    NSAPI_EXPRESSION_SUB,
+    NSAPI_EXPRESSION_MUL,
+    NSAPI_EXPRESSION_DIV,
+    NSAPI_EXPRESSION_MOD
+};
+
+union NSAPIExpressionValue {
+    cxstring str;
+    cxstring var;
+    int64_t  i;
+    double   f;
+    int      b;
+};
+
+struct NSAPIExpression {
+    // value.ptr is not null if
+    // type is one of (bool, int, string): literal text
+    // type is variable: variable name
+    union NSAPIExpressionValue value;
+    
+    NSAPIExpressionType type;
+    
+    NSAPIExpressionOperator operator;
+    
+    /*
+     * left/single operand
+     */
+    NSAPIExpression *left;
+    
+    /*
+     * right operand or NULL
+     */
+    NSAPIExpression *right;
+};
+
+
+
 /*
  * creates a new httpd_object
  */
@@ -171,6 +241,16 @@
 void nsapi_context_next_stage(NSAPIContext *context);
 
 
+/*
+ * parses an expression from a list of cxstring tokens and compiles the
+ * expression into an Expression object
+ * 
+ * tokens: CxList that contains cxstring
+ */
+Expression* condition_create(pool_handle_t *pool, CxList *tokens);
+
+NSAPIExpression* expr_parse_logical_expr(pool_handle_t *pool, CxList *tokens, size_t *pos);
+
 int condition_evaluate(Condition *condition, Session *sn, Request *rq);
 
 

mercurial