aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2021-04-10 00:00:18 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2021-04-13 18:25:38 +0200
commitf7eb2ea83b2ba26032ad0f9d216dda8780165b95 (patch)
tree28b6b0bcdc377ddecc4013ac529b729c6a71c247
parent8fd2c0b489d3fe371081ceddb1637713a452eefd (diff)
downloadsparse-f7eb2ea83b2ba26032ad0f9d216dda8780165b95.tar.gz
builtin: define a symbol_op for a generic op acting on integer
This can be used to define some generic (polymorphic) builtin with a signature like: <name>(int) <name>(T, T) <name>(int, T) <name>(int, T, long, T, ... T) where T is some integer type which will be instantiated at each call. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
-rw-r--r--builtin.c63
-rw-r--r--builtin.h2
2 files changed, 65 insertions, 0 deletions
diff --git a/builtin.c b/builtin.c
index ff03dbab..8e1d2d7e 100644
--- a/builtin.c
+++ b/builtin.c
@@ -390,6 +390,69 @@ static struct symbol_op overflow_p_op = {
};
+///
+// Evaluate the arguments of 'generic' integer operators.
+//
+// Parameters with a complete type are used like in a normal prototype.
+// The first parameter with a 'dynamic' type will be consider
+// as polymorphic and for each calls will be instancied with the type
+// of its effective argument.
+// The next dynamic parameters will the use this polymorphic type.
+// This allows to declare functions with some parameters having
+// a type variably defined at call time:
+// int foo(int, T, T);
+static int evaluate_generic_int_op(struct expression *expr)
+{
+ struct symbol *fntype = expr->fn->ctype->ctype.base_type;
+ struct symbol_list *types = NULL;
+ struct symbol *ctype = NULL;
+ struct expression *arg;
+ struct symbol *t;
+ int n = 0;
+
+ PREPARE_PTR_LIST(fntype->arguments, t);
+ FOR_EACH_PTR(expr->args, arg) {
+ n++;
+
+ if (!is_dynamic_type(t)) {
+ ;
+ } else if (!ctype) {
+ // first 'dynamic' type, check that it's an integer
+ t = arg->ctype;
+ if (!t)
+ return 0;
+ if (t->type == SYM_NODE)
+ t = t->ctype.base_type;
+ if (!t)
+ return 0;
+ if (t->ctype.base_type != &int_type)
+ goto err;
+
+ // next 'dynamic' arguments will use this type
+ ctype = t;
+ } else {
+ // use the previous 'dynamic' type
+ t = ctype;
+ }
+ add_ptr_list(&types, t);
+ NEXT_PTR_LIST(t);
+ } END_FOR_EACH_PTR(arg);
+ FINISH_PTR_LIST(t);
+ return evaluate_arguments(types, expr->args);
+
+err:
+ sparse_error(arg->pos, "non-integer type for argument %d:", n);
+ info(arg->pos, " %s", show_typename(arg->ctype));
+ expr->ctype = &bad_ctype;
+ return 0;
+}
+
+struct symbol_op generic_int_op = {
+ .args = args_prototype,
+ .evaluate = evaluate_generic_int_op,
+};
+
+
static int eval_atomic_common(struct expression *expr)
{
struct symbol *fntype = expr->fn->ctype->ctype.base_type;
diff --git a/builtin.h b/builtin.h
index 9cb67284..5fe77c92 100644
--- a/builtin.h
+++ b/builtin.h
@@ -14,4 +14,6 @@ struct builtin_fn {
void declare_builtins(int stream, const struct builtin_fn tbl[]);
+extern struct symbol_op generic_int_op;
+
#endif