On 12/04/2021 22:21, Luc Van Oostenryck wrote: > 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@xxxxxxxxx> > --- > builtin.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > builtin.h | 2 ++ > 2 files changed, 63 insertions(+) > > diff --git a/builtin.c b/builtin.c > index ff03dbab9a06..928e03050375 100644 > --- a/builtin.c > +++ b/builtin.c > @@ -390,6 +390,67 @@ 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) { Hmm, now n is always 0 in the error message, so: n++; here? > + if (!is_dynamic_type(t)) { > + ; > + } else if (!ctype) { > + // fist 'dynamic' type, chat that it is an integer s/chat/check/ > + 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); Hmm, does this do the usual argument promotions, so e.g. an 'generic' 'short' gets promoted to 'int' in the prototype? I guess not, that would have to be done above, while adding to the types list, right? Hmm, I would have to study evaluate_arguments(), but it may be worth a comment here? > + > +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; > +} So, this certainly looks better. Thanks! ;-) ATB, Ramsay Jones > + > +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 9cb6728444fe..5fe77c926244 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 >