mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-25 13:11:00 +00:00
[qfcc] Parse generic function declaration
The parsed generic function declaration is for ease of matching call signatures with the appropriate implementation.
This commit is contained in:
parent
f2609b1a9b
commit
80e493e588
2 changed files with 192 additions and 3 deletions
|
@ -44,6 +44,34 @@
|
||||||
// The maximum size of a temp def, return value, or parameter value
|
// The maximum size of a temp def, return value, or parameter value
|
||||||
#define MAX_DEF_SIZE 32
|
#define MAX_DEF_SIZE 32
|
||||||
|
|
||||||
|
typedef struct function_s function_t;
|
||||||
|
|
||||||
|
typedef const type_t *(*gentype_compute_f) ();
|
||||||
|
|
||||||
|
typedef struct gentype_s {
|
||||||
|
const char *name;
|
||||||
|
gentype_compute_f compute;
|
||||||
|
// earlier types have priority over later types. null if compute valid
|
||||||
|
const type_t **valid_types;
|
||||||
|
} gentype_t;
|
||||||
|
|
||||||
|
typedef struct genparam_s {
|
||||||
|
const char *name;
|
||||||
|
const type_t *fixed_type;
|
||||||
|
int gentype; // index into function's list of types
|
||||||
|
} genparam_t;
|
||||||
|
|
||||||
|
typedef struct genfunc_s {
|
||||||
|
struct genfunc_s *next;
|
||||||
|
const char *name;
|
||||||
|
gentype_t *types;
|
||||||
|
int num_types;
|
||||||
|
int num_params;
|
||||||
|
genparam_t *params;
|
||||||
|
genparam_t *ret_type;
|
||||||
|
// only automatic (#0) builtins supported for now
|
||||||
|
} genfunc_t;
|
||||||
|
|
||||||
/** Represent an overloading of a function.
|
/** Represent an overloading of a function.
|
||||||
|
|
||||||
Every function, whether overloaded or not, has an entry in the overloaded
|
Every function, whether overloaded or not, has an entry in the overloaded
|
||||||
|
|
|
@ -68,6 +68,7 @@
|
||||||
|
|
||||||
ALLOC_STATE (param_t, params);
|
ALLOC_STATE (param_t, params);
|
||||||
ALLOC_STATE (function_t, functions);
|
ALLOC_STATE (function_t, functions);
|
||||||
|
ALLOC_STATE (genfunc_t, genfuncs);
|
||||||
static hashtab_t *overloaded_functions;
|
static hashtab_t *overloaded_functions;
|
||||||
static hashtab_t *function_map;
|
static hashtab_t *function_map;
|
||||||
|
|
||||||
|
@ -92,6 +93,163 @@ func_map_get_key (const void *_f, void *unused)
|
||||||
return f->name;
|
return f->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const type_t *
|
||||||
|
compute_type ()
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gentype_compute_f
|
||||||
|
check_compute_type (const expr_t *expr)
|
||||||
|
{
|
||||||
|
if (expr->type != ex_type) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return compute_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const type_t **
|
||||||
|
valid_type_list (const expr_t *expr)
|
||||||
|
{
|
||||||
|
if (expr->type != ex_list) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
int count = list_count (&expr->list);
|
||||||
|
const expr_t *type_refs[count];
|
||||||
|
list_scatter (&expr->list, type_refs);
|
||||||
|
const type_t **types = malloc (sizeof (type_t *[count + 1]));
|
||||||
|
types[count] = nullptr;
|
||||||
|
bool err = false;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
if (!(types[i] = resolve_type (type_refs[i]))) {
|
||||||
|
error (type_refs[i], "not a constant type ref");
|
||||||
|
err = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (err) {
|
||||||
|
free (types);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gentype_t
|
||||||
|
make_gentype (const expr_t *expr)
|
||||||
|
{
|
||||||
|
if (expr->type != ex_symbol || expr->symbol->sy_type != sy_type_param) {
|
||||||
|
internal_error (expr, "expected generic type name");
|
||||||
|
}
|
||||||
|
auto sym = expr->symbol;
|
||||||
|
gentype_t gentype = {
|
||||||
|
.name = save_string (sym->name),
|
||||||
|
.compute = check_compute_type (sym->s.expr),
|
||||||
|
.valid_types = valid_type_list (sym->s.expr),
|
||||||
|
};
|
||||||
|
if (gentype.compute && gentype.valid_types) {
|
||||||
|
internal_error (expr, "both computed type and type list");
|
||||||
|
}
|
||||||
|
if (!gentype.compute && !gentype.valid_types) {
|
||||||
|
internal_error (expr, "empty generic type");
|
||||||
|
}
|
||||||
|
return gentype;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
find_gentype (const expr_t *expr, genfunc_t *genfunc)
|
||||||
|
{
|
||||||
|
if (expr->type != ex_symbol) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
const char *name = expr->symbol->name;
|
||||||
|
for (int i = 0; i < genfunc->num_types; i++) {
|
||||||
|
auto t = &genfunc->types[i];
|
||||||
|
if (strcmp (name, t->name) == 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static genparam_t
|
||||||
|
make_genparam (param_t *param, genfunc_t *genfunc)
|
||||||
|
{
|
||||||
|
genparam_t genparam = {
|
||||||
|
.name = save_string (param->name),
|
||||||
|
.fixed_type = param->type,
|
||||||
|
.gentype = find_gentype (param->type_expr, genfunc),
|
||||||
|
};
|
||||||
|
return genparam;
|
||||||
|
}
|
||||||
|
|
||||||
|
static genfunc_t *
|
||||||
|
parse_generic_function (const char *name, specifier_t spec)
|
||||||
|
{
|
||||||
|
if (!spec.is_generic) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
// fake parameter for the return type
|
||||||
|
param_t ret_param = {
|
||||||
|
.next = spec.sym->params,
|
||||||
|
.type = spec.sym->type->t.func.ret_type,
|
||||||
|
.type_expr = spec.type_expr,
|
||||||
|
};
|
||||||
|
int num_params = 0;
|
||||||
|
int num_gentype = 0;
|
||||||
|
for (auto p = &ret_param; p; p = p->next) {
|
||||||
|
num_params++;
|
||||||
|
}
|
||||||
|
auto generic_tab = current_symtab;
|
||||||
|
for (auto s = generic_tab->symbols; s; s = s->next) {
|
||||||
|
bool found = false;
|
||||||
|
for (auto q = &ret_param; q; q = q->next) {
|
||||||
|
// FIXME check complex expressions
|
||||||
|
if (!q->type_expr || q->type_expr->type != ex_symbol) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strcmp (q->type_expr->symbol->name, s->name) == 0) {
|
||||||
|
num_gentype++;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
warning (0, "generic parameter %s not used", s->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
genfunc_t *genfunc;
|
||||||
|
ALLOC (4096, genfunc_t, genfuncs, genfunc);
|
||||||
|
*genfunc = (genfunc_t) {
|
||||||
|
.name = save_string (name),
|
||||||
|
.types = malloc (sizeof (gentype_t[num_gentype])
|
||||||
|
+ sizeof (genparam_t[num_params])),
|
||||||
|
.num_types = num_gentype,
|
||||||
|
.num_params = num_params - 1, // don't count return type
|
||||||
|
};
|
||||||
|
genfunc->params = (genparam_t *) &genfunc->types[num_gentype];
|
||||||
|
genfunc->ret_type = &genfunc->params[num_params - 1];
|
||||||
|
|
||||||
|
num_gentype = 0;
|
||||||
|
for (auto s = generic_tab->symbols; s; s = s->next) {
|
||||||
|
for (auto q = &ret_param; q; q = q->next) {
|
||||||
|
// FIXME check complex expressions
|
||||||
|
if (!q->type_expr || q->type_expr->type != ex_symbol) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strcmp (q->type_expr->symbol->name, s->name) == 0) {
|
||||||
|
genfunc->types[num_gentype++] = make_gentype (q->type_expr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
num_params = 0;
|
||||||
|
for (auto p = ret_param.next; p; p = p->next) {
|
||||||
|
genfunc->params[num_params++] = make_genparam (p, genfunc);
|
||||||
|
}
|
||||||
|
*genfunc->ret_type = make_genparam (&ret_param, genfunc);
|
||||||
|
return genfunc;
|
||||||
|
}
|
||||||
param_t *
|
param_t *
|
||||||
new_param (const char *selector, const type_t *type, const char *name)
|
new_param (const char *selector, const type_t *type, const char *name)
|
||||||
{
|
{
|
||||||
|
@ -257,8 +415,11 @@ check_params (param_t *params)
|
||||||
}
|
}
|
||||||
|
|
||||||
static overloaded_function_t *
|
static overloaded_function_t *
|
||||||
get_function (const char *name, const type_t *type, int overload)
|
get_function (const char *name, const type_t *type, specifier_t spec)
|
||||||
{
|
{
|
||||||
|
auto genfunc = parse_generic_function (name, spec);
|
||||||
|
if (genfunc) {}
|
||||||
|
bool overload = spec.is_overload;
|
||||||
const char *full_name;
|
const char *full_name;
|
||||||
overloaded_function_t *func;
|
overloaded_function_t *func;
|
||||||
|
|
||||||
|
@ -285,7 +446,7 @@ get_function (const char *name, const type_t *type, int overload)
|
||||||
full_name);
|
full_name);
|
||||||
warning (&e, "(previous function is %s)", func->full_name);
|
warning (&e, "(previous function is %s)", func->full_name);
|
||||||
}
|
}
|
||||||
overload = 1;
|
overload = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
func = calloc (1, sizeof (overloaded_function_t));
|
func = calloc (1, sizeof (overloaded_function_t));
|
||||||
|
@ -307,7 +468,7 @@ function_symbol (symbol_t *sym, specifier_t spec)
|
||||||
overloaded_function_t *func;
|
overloaded_function_t *func;
|
||||||
symbol_t *s;
|
symbol_t *s;
|
||||||
|
|
||||||
func = get_function (name, unalias_type (sym->type), spec.is_overload);
|
func = get_function (name, unalias_type (sym->type), spec);
|
||||||
|
|
||||||
if (func && func->overloaded)
|
if (func && func->overloaded)
|
||||||
name = func->full_name;
|
name = func->full_name;
|
||||||
|
|
Loading…
Reference in a new issue