Sun, 20 Nov 2022 11:39:46 +0100
expression parser: add support for functions
--- 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,