X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Fecoli_node_expr.c;h=eb7bff30651cd22b3912c0b31e26a425d283e05f;hb=7c07e2a8b3b5851de0c238da830291f041185778;hp=9207e4d4d15a8ee49eeeeb1912e77e54a84ba59e;hpb=a936ea741c1135e46e04b4dd75b95adc2ac201cb;p=protos%2Flibecoli.git diff --git a/lib/ecoli_node_expr.c b/lib/ecoli_node_expr.c index 9207e4d..eb7bff3 100644 --- a/lib/ecoli_node_expr.c +++ b/lib/ecoli_node_expr.c @@ -1,28 +1,5 @@ -/* - * Copyright (c) 2016-2017, Olivier MATZ - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of the University of California, Berkeley nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS AND 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. +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright 2016, Olivier MATZ */ #include @@ -39,12 +16,11 @@ #include #include #include -#include -#include +#include +#include #include #include #include -#include #include EC_LOG_TYPE_REGISTER(node_expr); @@ -69,23 +45,32 @@ struct ec_node_expr { }; static int ec_node_expr_parse(const struct ec_node *gen_node, - struct ec_parsed *state, + struct ec_parse *state, const struct ec_strvec *strvec) { struct ec_node_expr *node = (struct ec_node_expr *)gen_node; + if (node->child == NULL) { + errno = ENOENT; + return -1; + } + return ec_node_parse_child(node->child, state, strvec); } static int ec_node_expr_complete(const struct ec_node *gen_node, - struct ec_completed *completed, - struct ec_parsed *parsed, + struct ec_comp *comp, const struct ec_strvec *strvec) { struct ec_node_expr *node = (struct ec_node_expr *)gen_node; - return ec_node_complete_child(node->child, completed, parsed, strvec); + if (node->child == NULL) { + errno = ENOENT; + return -1; + } + + return ec_node_complete_child(node->child, comp, strvec); } static void ec_node_expr_free_priv(struct ec_node *gen_node) @@ -93,7 +78,7 @@ static void ec_node_expr_free_priv(struct ec_node *gen_node) struct ec_node_expr *node = (struct ec_node_expr *)gen_node; unsigned int i; - EC_LOG(EC_LOG_DEBUG, "free %p %p %p\n", node, node->child, node->val_node); + ec_node_free(node->child); ec_node_free(node->val_node); for (i = 0; i < node->bin_ops_len; i++) @@ -111,30 +96,46 @@ static void ec_node_expr_free_priv(struct ec_node *gen_node) } ec_free(node->open_ops); ec_free(node->close_ops); - - ec_node_free(node->child); } -static int ec_node_expr_build(struct ec_node *gen_node) +static int ec_node_expr_build(struct ec_node_expr *node) { - struct ec_node_expr *node = (struct ec_node_expr *)gen_node; struct ec_node *term = NULL, *expr = NULL, *next = NULL, - *pre_op = NULL, *post_op = NULL, - *post = NULL, *weak = NULL; + *pre_op = NULL, *post_op = NULL, *ref = NULL, + *post = NULL; unsigned int i; - int ret; - if (node->val_node == NULL) - return -EINVAL; + ec_node_free(node->child); + node->child = NULL; + + if (node->val_node == NULL) { + errno = EINVAL; + return -1; + } + if (node->bin_ops_len == 0 && node->pre_ops_len == 0 && - node->post_ops_len == 0) - return -EINVAL; - - /* create the object, we will initialize it later: this is - * needed because we have a circular dependency */ - ret = -ENOMEM; - weak = ec_node("weakref", "weak"); - if (weak == NULL) + node->post_ops_len == 0) { + errno = EINVAL; + return -1; + } + + /* + * Example of created grammar: + * + * pre_op = "!" + * post_op = "^" + * post = val | + * pre_op expr | + * "(" expr ")" + * term = post post_op* + * prod = term ( "*" term )* + * sum = prod ( "+" prod )* + * expr = sum + */ + + /* we use this as a ref, will be set later */ + ref = ec_node("seq", "ref"); + if (ref == NULL) return -1; /* prefix unary operators */ @@ -161,20 +162,20 @@ static int ec_node_expr_build(struct ec_node *gen_node) if (ec_node_or_add(post, ec_node_clone(node->val_node)) < 0) goto fail; if (ec_node_or_add(post, - EC_NODE_SEQ(NULL, + EC_NODE_SEQ(EC_NO_ID, ec_node_clone(pre_op), - ec_node_clone(weak))) < 0) + ec_node_clone(ref))) < 0) goto fail; for (i = 0; i < node->paren_len; i++) { - if (ec_node_or_add(post, EC_NODE_SEQ(NULL, + if (ec_node_or_add(post, EC_NODE_SEQ(EC_NO_ID, ec_node_clone(node->open_ops[i]), - ec_node_clone(weak), + ec_node_clone(ref), ec_node_clone(node->close_ops[i]))) < 0) goto fail; } term = EC_NODE_SEQ("term", ec_node_clone(post), - ec_node_many(NULL, ec_node_clone(post_op), 0, 0) + ec_node_many(EC_NO_ID, ec_node_clone(post_op), 0, 0) ); if (term == NULL) goto fail; @@ -182,8 +183,8 @@ static int ec_node_expr_build(struct ec_node *gen_node) for (i = 0; i < node->bin_ops_len; i++) { next = EC_NODE_SEQ("next", ec_node_clone(term), - ec_node_many(NULL, - EC_NODE_SEQ(NULL, + ec_node_many(EC_NO_ID, + EC_NODE_SEQ(EC_NO_ID, ec_node_clone(node->bin_ops[i]), ec_node_clone(term) ), @@ -206,14 +207,12 @@ static int ec_node_expr_build(struct ec_node *gen_node) ec_node_free(post); post = NULL; - /* no need to clone here, the node is not consumed */ - if (ec_node_weakref_set(weak, expr) < 0) + if (ec_node_seq_add(ref, ec_node_clone(expr)) < 0) goto fail; - ec_node_free(weak); - weak = NULL; + ec_node_free(ref); + ref = NULL; node->child = expr; - //ec_node_dump(stdout, node->child); //XXX return 0; @@ -223,18 +222,40 @@ fail: ec_node_free(pre_op); ec_node_free(post_op); ec_node_free(post); - ec_node_free(weak); + ec_node_free(ref); + + return -1; +} + +static size_t +ec_node_expr_get_children_count(const struct ec_node *gen_node) +{ + struct ec_node_expr *node = (struct ec_node_expr *)gen_node; - return ret; + if (node->child) + return 1; + return 0; +} + +static struct ec_node * +ec_node_expr_get_child(const struct ec_node *gen_node, size_t i) +{ + struct ec_node_expr *node = (struct ec_node_expr *)gen_node; + + if (i >= 1) + return NULL; + + return node->child; } static struct ec_node_type ec_node_expr_type = { .name = "expr", - .build = ec_node_expr_build, .parse = ec_node_expr_parse, .complete = ec_node_expr_complete, .size = sizeof(struct ec_node_expr), .free_priv = ec_node_expr_free_priv, + .get_children_count = ec_node_expr_get_children_count, + .get_child = ec_node_expr_get_child, }; EC_NODE_TYPE_REGISTER(ec_node_expr_type); @@ -242,26 +263,24 @@ EC_NODE_TYPE_REGISTER(ec_node_expr_type); int ec_node_expr_set_val_node(struct ec_node *gen_node, struct ec_node *val_node) { struct ec_node_expr *node = (struct ec_node_expr *)gen_node; - int ret; - ret = -EINVAL; - if (val_node == NULL) + if (ec_node_check_type(gen_node, &ec_node_expr_type) < 0) goto fail; - ret = -EPERM; - if (gen_node->flags & EC_NODE_F_BUILT) - goto fail; - ret = -EEXIST; - if (node->val_node != NULL) + + if (val_node == NULL) { + errno = EINVAL; goto fail; + } + ec_node_free(node->val_node); node->val_node = val_node; - gen_node->flags &= ~EC_NODE_F_BUILT; + ec_node_expr_build(node); return 0; fail: ec_node_free(val_node); - return ret; + return -1; } /* add a binary operator */ @@ -269,18 +288,15 @@ int ec_node_expr_add_bin_op(struct ec_node *gen_node, struct ec_node *op) { struct ec_node_expr *node = (struct ec_node_expr *)gen_node; struct ec_node **bin_ops; - int ret; - - // XXX check node type - ret = -EINVAL; - if (node == NULL || op == NULL) + if (ec_node_check_type(gen_node, &ec_node_expr_type) < 0) goto fail; - ret = -EPERM; - if (gen_node->flags & EC_NODE_F_BUILT) + + if (node == NULL || op == NULL) { + errno = EINVAL; goto fail; + } - ret = -ENOMEM; bin_ops = ec_realloc(node->bin_ops, (node->bin_ops_len + 1) * sizeof(*node->bin_ops)); if (bin_ops == NULL) @@ -289,13 +305,13 @@ int ec_node_expr_add_bin_op(struct ec_node *gen_node, struct ec_node *op) node->bin_ops = bin_ops; bin_ops[node->bin_ops_len] = op; node->bin_ops_len++; - gen_node->flags &= ~EC_NODE_F_BUILT; + ec_node_expr_build(node); return 0; fail: ec_node_free(op); - return ret; + return -1; } /* add a unary pre-operator */ @@ -303,18 +319,15 @@ int ec_node_expr_add_pre_op(struct ec_node *gen_node, struct ec_node *op) { struct ec_node_expr *node = (struct ec_node_expr *)gen_node; struct ec_node **pre_ops; - int ret; - // XXX check node type - - ret = -EINVAL; - if (node == NULL || op == NULL) + if (ec_node_check_type(gen_node, &ec_node_expr_type) < 0) goto fail; - ret = -EPERM; - if (gen_node->flags & EC_NODE_F_BUILT) + + if (node == NULL || op == NULL) { + errno = EINVAL; goto fail; + } - ret = -ENOMEM; pre_ops = ec_realloc(node->pre_ops, (node->pre_ops_len + 1) * sizeof(*node->pre_ops)); if (pre_ops == NULL) @@ -323,13 +336,13 @@ int ec_node_expr_add_pre_op(struct ec_node *gen_node, struct ec_node *op) node->pre_ops = pre_ops; pre_ops[node->pre_ops_len] = op; node->pre_ops_len++; - gen_node->flags &= ~EC_NODE_F_BUILT; + ec_node_expr_build(node); return 0; fail: ec_node_free(op); - return ret; + return -1; } /* add a unary post-operator */ @@ -337,18 +350,15 @@ int ec_node_expr_add_post_op(struct ec_node *gen_node, struct ec_node *op) { struct ec_node_expr *node = (struct ec_node_expr *)gen_node; struct ec_node **post_ops; - int ret; - - // XXX check node type - ret = -EINVAL; - if (node == NULL || op == NULL) + if (ec_node_check_type(gen_node, &ec_node_expr_type) < 0) goto fail; - ret = -EPERM; - if (gen_node->flags & EC_NODE_F_BUILT) + + if (node == NULL || op == NULL) { + errno = EINVAL; goto fail; + } - ret = -ENOMEM; post_ops = ec_realloc(node->post_ops, (node->post_ops_len + 1) * sizeof(*node->post_ops)); if (post_ops == NULL) @@ -357,13 +367,13 @@ int ec_node_expr_add_post_op(struct ec_node *gen_node, struct ec_node *op) node->post_ops = post_ops; post_ops[node->post_ops_len] = op; node->post_ops_len++; - gen_node->flags &= ~EC_NODE_F_BUILT; + ec_node_expr_build(node); return 0; fail: ec_node_free(op); - return ret; + return -1; } /* add parenthesis symbols */ @@ -372,18 +382,15 @@ int ec_node_expr_add_parenthesis(struct ec_node *gen_node, { struct ec_node_expr *node = (struct ec_node_expr *)gen_node; struct ec_node **open_ops, **close_ops; - int ret; - // XXX check node type + if (ec_node_check_type(gen_node, &ec_node_expr_type) < 0) + goto fail; - ret = -EINVAL; - if (node == NULL || open == NULL || close == NULL) + if (node == NULL || open == NULL || close == NULL) { + errno = EINVAL; goto fail; - ret = -EPERM; - if (gen_node->flags & EC_NODE_F_BUILT) - goto fail;; + } - ret = -ENOMEM; open_ops = ec_realloc(node->open_ops, (node->paren_len + 1) * sizeof(*node->open_ops)); if (open_ops == NULL) @@ -398,14 +405,14 @@ int ec_node_expr_add_parenthesis(struct ec_node *gen_node, open_ops[node->paren_len] = open; close_ops[node->paren_len] = close; node->paren_len++; - gen_node->flags &= ~EC_NODE_F_BUILT; + ec_node_expr_build(node); return 0; fail: ec_node_free(open); ec_node_free(close); - return ret; + return -1; } enum expr_node_type { @@ -417,6 +424,7 @@ enum expr_node_type { PAREN_OPEN, PAREN_CLOSE, }; + static enum expr_node_type get_node_type(const struct ec_node *expr_gen_node, const struct ec_node *check) { @@ -454,7 +462,7 @@ static enum expr_node_type get_node_type(const struct ec_node *expr_gen_node, struct result { bool has_val; void *val; - const struct ec_parsed *op; + const struct ec_parse *op; enum expr_node_type op_type; }; @@ -463,8 +471,6 @@ static int merge_results(void *userctx, const struct ec_node_expr_eval_ops *ops, struct result *x, const struct result *y) { - int ret; - if (y->has_val == 0 && y->op == NULL) return 0; if (x->has_val == 0 && x->op == NULL) { @@ -474,10 +480,9 @@ static int merge_results(void *userctx, if (x->has_val && y->has_val && y->op != NULL) { if (y->op_type == BIN_OP) { - ret = ops->eval_bin_op(&x->val, userctx, x->val, - y->op, y->val); - if (ret < 0) - return ret; + if (ops->eval_bin_op(&x->val, userctx, x->val, + y->op, y->val) < 0) + return -1; return 0; } @@ -485,9 +490,9 @@ static int merge_results(void *userctx, if (x->has_val == 0 && x->op != NULL && y->has_val && y->op == NULL) { if (x->op_type == PRE_OP) { - ret = ops->eval_pre_op(&x->val, userctx, y->val, x->op); - if (ret < 0) - return ret; + if (ops->eval_pre_op(&x->val, userctx, y->val, + x->op) < 0) + return -1; x->has_val = true; x->op_type = NONE; x->op = NULL; @@ -500,47 +505,44 @@ static int merge_results(void *userctx, } if (x->has_val && x->op == NULL && y->has_val == 0 && y->op != NULL) { - ret = ops->eval_post_op(&x->val, userctx, x->val, y->op); - if (ret < 0) - return ret; + if (ops->eval_post_op(&x->val, userctx, x->val, y->op) < 0) + return -1; return 0; } assert(false); /* we should not get here */ - return -EINVAL; + return -1; } static int eval_expression(struct result *result, void *userctx, const struct ec_node_expr_eval_ops *ops, const struct ec_node *expr_gen_node, - const struct ec_parsed *parsed) + const struct ec_parse *parse) { - struct ec_parsed *open = NULL, *close = NULL; + struct ec_parse *open = NULL, *close = NULL; struct result child_result; - struct ec_parsed *child; + struct ec_parse *child; enum expr_node_type type; - int ret; memset(result, 0, sizeof(*result)); memset(&child_result, 0, sizeof(child_result)); - type = get_node_type(expr_gen_node, parsed->node); + type = get_node_type(expr_gen_node, ec_parse_get_node(parse)); if (type == VAL) { - ret = ops->eval_var(&result->val, userctx, parsed); - if (ret < 0) + if (ops->eval_var(&result->val, userctx, parse) < 0) goto fail; result->has_val = 1; } else if (type == PRE_OP || type == POST_OP || type == BIN_OP) { - result->op = parsed; + result->op = parse; result->op_type = type; } - TAILQ_FOREACH(child, &parsed->children, next) { + EC_PARSE_FOREACH_CHILD(child, parse) { - type = get_node_type(expr_gen_node, child->node); + type = get_node_type(expr_gen_node, ec_parse_get_node(child)); if (type == PAREN_OPEN) { open = child; continue; @@ -549,22 +551,19 @@ static int eval_expression(struct result *result, continue; } - ret = eval_expression(&child_result, userctx, ops, - expr_gen_node, child); - if (ret < 0) + if (eval_expression(&child_result, userctx, ops, + expr_gen_node, child) < 0) goto fail; - ret = merge_results(userctx, ops, result, &child_result); - if (ret < 0) + if (merge_results(userctx, ops, result, &child_result) < 0) goto fail; memset(&child_result, 0, sizeof(child_result)); } if (open != NULL && close != NULL) { - ret = ops->eval_parenthesis(&result->val, userctx, open, close, - result->val); - if (ret < 0) + if (ops->eval_parenthesis(&result->val, userctx, open, close, + result->val) < 0) goto fail; } @@ -577,28 +576,33 @@ fail: ops->eval_free(child_result.val, userctx); memset(result, 0, sizeof(*result)); - return ret; + return -1; } int ec_node_expr_eval(void **user_result, const struct ec_node *node, - struct ec_parsed *parsed, const struct ec_node_expr_eval_ops *ops, + struct ec_parse *parse, const struct ec_node_expr_eval_ops *ops, void *userctx) { struct result result; - int ret; if (ops == NULL || ops->eval_var == NULL || ops->eval_pre_op == NULL || ops->eval_post_op == NULL || ops->eval_bin_op == NULL || - ops->eval_parenthesis == NULL || ops->eval_free == NULL) - return -EINVAL; + ops->eval_parenthesis == NULL || + ops->eval_free == NULL) { + errno = EINVAL; + return -1; + } + + if (ec_node_check_type(node, &ec_node_expr_type) < 0) + return -1; - if (!ec_parsed_matches(parsed)) - return -EINVAL; + if (!ec_parse_matches(parse)) { + errno = EINVAL; + return -1; + } - //ec_parsed_dump(stdout, parsed); //XXX - ret = eval_expression(&result, userctx, ops, node, parsed); - if (ret < 0) - return ret; + if (eval_expression(&result, userctx, ops, node, parse) < 0) + return -1; assert(result.has_val); assert(result.op == NULL);