mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-23 04:42:32 +00:00
run in fear, function overloading is here
This is an imperfect revision of history.
This commit is contained in:
parent
9b81bc5ea6
commit
66257e3a88
7 changed files with 274 additions and 37 deletions
|
@ -212,6 +212,8 @@ expr_t *bool_expr (int op, expr_t *label, expr_t *e1, expr_t *e2);
|
|||
expr_t *binary_expr (int op, expr_t *e1, expr_t *e2);
|
||||
expr_t *asx_expr (int op, expr_t *e1, expr_t *e2);
|
||||
expr_t *unary_expr (int op, expr_t *e);
|
||||
expr_t *build_function_call (expr_t *fexpr, struct type_s *ftype,
|
||||
expr_t *params);
|
||||
expr_t *function_expr (expr_t *e1, expr_t *e2);
|
||||
struct function_s;
|
||||
expr_t *return_expr (struct function_s *f, expr_t *e);
|
||||
|
|
|
@ -34,6 +34,14 @@
|
|||
|
||||
#include "QF/pr_comp.h"
|
||||
|
||||
typedef struct overloaded_function_s {
|
||||
struct overloaded_function_s *next;
|
||||
const char *name;
|
||||
const char *full_name;
|
||||
struct type_s *type;
|
||||
int overloaded;
|
||||
} overloaded_function_t;
|
||||
|
||||
typedef struct function_s {
|
||||
struct function_s *next;
|
||||
pr_auxfunction_t *aux; // debug info;
|
||||
|
@ -67,6 +75,12 @@ param_t *_reverse_params (param_t *params, param_t *next);
|
|||
param_t *reverse_params (param_t *params);
|
||||
param_t *copy_params (param_t *params);
|
||||
struct type_s *parse_params (struct type_s *type, param_t *params);
|
||||
overloaded_function_t *get_function (const char *name, struct type_s *type,
|
||||
int overload, int create);
|
||||
struct def_s *get_function_def (const char *name, struct type_s *type,
|
||||
struct scope_s *scope, storage_class_t storage,
|
||||
int overload, int create);
|
||||
struct expr_s *find_function (struct expr_s *fexpr, struct expr_s *params);
|
||||
void build_scope (function_t *f, struct def_s *func, param_t *params);
|
||||
function_t *new_function (const char *name);
|
||||
function_t *build_code_function (function_t *f, struct expr_s *state_expr,
|
||||
|
|
|
@ -105,8 +105,6 @@ check_for_name (type_t *type, const char *name, scope_t *scope,
|
|||
if (def) {
|
||||
if (storage != st_none && scope == def->scope)
|
||||
if (type && def->type != type) {
|
||||
print_type (type);
|
||||
print_type (def->type);
|
||||
error (0, "Type mismatch on redeclaration of %s", name);
|
||||
}
|
||||
if (storage == st_none || def->scope == scope)
|
||||
|
|
|
@ -1881,7 +1881,7 @@ bitnot_expr:
|
|||
abort ();
|
||||
}
|
||||
|
||||
static expr_t *
|
||||
expr_t *
|
||||
build_function_call (expr_t *fexpr, type_t *ftype, expr_t *params)
|
||||
{
|
||||
expr_t *e;
|
||||
|
@ -1938,8 +1938,8 @@ build_function_call (expr_t *fexpr, type_t *ftype, expr_t *params)
|
|||
if (e->type == ex_error)
|
||||
return e;
|
||||
if (!type_assignable (ftype->parm_types[i], t)) {
|
||||
//print_type (ftype->parm_types[i]); puts ("");
|
||||
//print_type (t); puts ("");
|
||||
print_type (ftype->parm_types[i]); puts ("");
|
||||
print_type (t); puts ("");
|
||||
err = error (e, "type mismatch for parameter %d of %s",
|
||||
i + 1, fexpr->e.def->name);
|
||||
}
|
||||
|
@ -2005,6 +2005,7 @@ function_expr (expr_t *fexpr, expr_t *params)
|
|||
{
|
||||
type_t *ftype;
|
||||
|
||||
find_function (fexpr, params);
|
||||
ftype = get_type (fexpr);
|
||||
|
||||
if (fexpr->type == ex_error)
|
||||
|
|
|
@ -43,6 +43,8 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "QF/dstring.h"
|
||||
#include "QF/hash.h"
|
||||
#include "QF/va.h"
|
||||
|
||||
#include "qfcc.h"
|
||||
|
||||
|
@ -59,6 +61,22 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
|
||||
static param_t *free_params;
|
||||
static function_t *free_functions;
|
||||
static hashtab_t *overloaded_functions;
|
||||
static hashtab_t *function_map;
|
||||
|
||||
static const char *
|
||||
ol_func_get_key (void *_f, void *unused)
|
||||
{
|
||||
overloaded_function_t *f = (overloaded_function_t *) _f;
|
||||
return f->full_name;
|
||||
}
|
||||
|
||||
static const char *
|
||||
func_map_get_key (void *_f, void *unused)
|
||||
{
|
||||
overloaded_function_t *f = (overloaded_function_t *) _f;
|
||||
return f->name;
|
||||
}
|
||||
|
||||
param_t *
|
||||
new_param (const char *selector, type_t *type, const char *name)
|
||||
|
@ -136,6 +154,194 @@ parse_params (type_t *type, param_t *parms)
|
|||
return find_type (&new);
|
||||
}
|
||||
|
||||
overloaded_function_t *
|
||||
get_function (const char *name, type_t *type, int overload, int create)
|
||||
{
|
||||
const char *full_name;
|
||||
overloaded_function_t *func;
|
||||
|
||||
if (!overloaded_functions) {
|
||||
overloaded_functions = Hash_NewTable (1021, ol_func_get_key, 0, 0);
|
||||
function_map = Hash_NewTable (1021, func_map_get_key, 0, 0);
|
||||
}
|
||||
|
||||
name = save_string (name);
|
||||
|
||||
full_name = save_string (va ("%s|%s", name, encode_params (type)));
|
||||
|
||||
func = Hash_Find (overloaded_functions, full_name);
|
||||
if (func) {
|
||||
if (func->type != type) {
|
||||
error (0, "can't overload on return types");
|
||||
return func;
|
||||
}
|
||||
return func;
|
||||
}
|
||||
|
||||
if (!create)
|
||||
return 0;
|
||||
|
||||
func = Hash_Find (function_map, name);
|
||||
if (func) {
|
||||
if (!overload && !func->overloaded) {
|
||||
warning (0, "creating overloaded function %s without @overload",
|
||||
full_name);
|
||||
warning (0, "(previous function is %s)",
|
||||
func->full_name);
|
||||
}
|
||||
overload = 1;
|
||||
}
|
||||
|
||||
func = calloc (1, sizeof (overloaded_function_t));
|
||||
func->name = name;
|
||||
func->full_name = full_name;
|
||||
func->type = type;
|
||||
func->overloaded = overload;
|
||||
|
||||
Hash_Add (overloaded_functions, func);
|
||||
Hash_Add (function_map, func);
|
||||
return func;
|
||||
}
|
||||
|
||||
def_t *
|
||||
get_function_def (const char *name, struct type_s *type,
|
||||
scope_t *scope, storage_class_t storage,
|
||||
int overload, int create)
|
||||
{
|
||||
overloaded_function_t *func;
|
||||
|
||||
func = get_function (name, type, overload, create);
|
||||
|
||||
if (func && func->overloaded)
|
||||
name = func->full_name;
|
||||
return get_def (type, name, scope, storage);
|
||||
}
|
||||
|
||||
// NOTE sorts the list in /reverse/ order
|
||||
static int
|
||||
func_compare (const void *a, const void *b)
|
||||
{
|
||||
overloaded_function_t *fa = *(overloaded_function_t **) a;
|
||||
overloaded_function_t *fb = *(overloaded_function_t **) b;
|
||||
type_t *ta = fa->type;
|
||||
type_t *tb = fb->type;
|
||||
int na = ta->num_parms;
|
||||
int nb = tb->num_parms;
|
||||
int ret, i;
|
||||
|
||||
if (na < 0)
|
||||
na = ~na;
|
||||
if (nb < 0)
|
||||
nb = ~nb;
|
||||
if (na != nb)
|
||||
return nb - na;
|
||||
if ((ret = (fb->type->num_parms - fa->type->num_parms)))
|
||||
return ret;
|
||||
for (i = 0; i < na && i < nb; i++)
|
||||
if (ta->parm_types[i] != tb->parm_types[i])
|
||||
return (long)(tb->parm_types[i] - ta->parm_types[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
expr_t *
|
||||
find_function (expr_t *fexpr, expr_t *params)
|
||||
{
|
||||
expr_t *e;
|
||||
int i, j, func_count, parm_count, reported = 0;
|
||||
overloaded_function_t *f, dummy, *best = 0;
|
||||
type_t type;
|
||||
void **funcs, *dummy_p = &dummy;
|
||||
|
||||
if (fexpr->type != ex_name)
|
||||
return fexpr;
|
||||
|
||||
memset (&type, 0, sizeof (type));
|
||||
|
||||
for (e = params; e; e = e->next) {
|
||||
if (e->type == ex_error)
|
||||
return e;
|
||||
type.num_parms++;
|
||||
}
|
||||
if (type.num_parms > MAX_PARMS)
|
||||
return fexpr;
|
||||
for (i = 0, e = params; e; i++, e = e->next) {
|
||||
type.parm_types[type.num_parms - 1 - i] = get_type (e);
|
||||
if (e->type == ex_error)
|
||||
return e;
|
||||
}
|
||||
funcs = Hash_FindList (function_map, fexpr->e.string_val);
|
||||
if (!funcs)
|
||||
return fexpr;
|
||||
for (func_count = 0; funcs[func_count]; func_count++)
|
||||
;
|
||||
if (func_count < 2) {
|
||||
free (funcs);
|
||||
return fexpr;
|
||||
}
|
||||
type.aux_type = ((overloaded_function_t *) funcs[0])->type->aux_type;
|
||||
dummy.type = find_type (&type);
|
||||
|
||||
qsort (funcs, func_count, sizeof (void *), func_compare);
|
||||
dummy.full_name = save_string (va ("%s|%s", fexpr->e.string_val,
|
||||
encode_params (&type)));
|
||||
dummy_p = bsearch (&dummy_p, funcs, func_count, sizeof (void *),
|
||||
func_compare);
|
||||
if (dummy_p) {
|
||||
f = (overloaded_function_t *) *(void **) dummy_p;
|
||||
if (f->overloaded)
|
||||
fexpr->e.string_val = f->full_name;
|
||||
free (funcs);
|
||||
return fexpr;
|
||||
}
|
||||
for (i = 0; i < func_count; i++) {
|
||||
f = (overloaded_function_t *) funcs[i];
|
||||
parm_count = f->type->num_parms;
|
||||
if ((parm_count >= 0 && parm_count != type.num_parms)
|
||||
|| (parm_count < 0 && ~parm_count > type.num_parms)) {
|
||||
funcs[i] = 0;
|
||||
continue;
|
||||
}
|
||||
if (parm_count < 0)
|
||||
parm_count = ~parm_count;
|
||||
for (j = 0; j < parm_count; j++) {
|
||||
if (!type_assignable (f->type->parm_types[j],
|
||||
type.parm_types[j])) {
|
||||
funcs[i] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j < parm_count)
|
||||
continue;
|
||||
}
|
||||
for (i = 0; i < func_count; i++) {
|
||||
f = (overloaded_function_t *) funcs[i];
|
||||
if (f) {
|
||||
if (!best) {
|
||||
best = f;
|
||||
} else {
|
||||
if (!reported) {
|
||||
reported = 1;
|
||||
error (fexpr, "unable to disambiguate %s",
|
||||
dummy.full_name);
|
||||
error (fexpr, "possible match: %s", best->full_name);
|
||||
}
|
||||
error (fexpr, "possible match: %s", f->full_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (reported)
|
||||
return fexpr;
|
||||
if (best) {
|
||||
if (best->overloaded)
|
||||
fexpr->e.string_val = best->full_name;
|
||||
free (funcs);
|
||||
return fexpr;
|
||||
}
|
||||
error (fexpr, "unable to find function matching %s", dummy.full_name);
|
||||
free (funcs);
|
||||
return fexpr;
|
||||
}
|
||||
|
||||
void
|
||||
build_scope (function_t *f, def_t *func, param_t *params)
|
||||
{
|
||||
|
|
|
@ -344,6 +344,7 @@ static keyword_t keywords[] = {
|
|||
{"@static", STATIC, 0, 1, PROG_ID_VERSION},
|
||||
{"@system", SYSTEM, 0, 1, PROG_ID_VERSION},
|
||||
{"@sizeof", SIZEOF, 0, 0, PROG_VERSION},
|
||||
{"@overload", OVERLOAD, 0, 0, PROG_VERSION},
|
||||
};
|
||||
|
||||
static const char *
|
||||
|
|
|
@ -148,7 +148,7 @@ expr_t *argv_expr (void);
|
|||
%token LOCAL RETURN WHILE DO IF ELSE FOR BREAK CONTINUE ELLIPSIS NIL
|
||||
%token IFBE IFB IFAE IFA
|
||||
%token SWITCH CASE DEFAULT STRUCT UNION ENUM TYPEDEF SUPER SELF THIS
|
||||
%token ARGS ARGC ARGV EXTERN STATIC SYSTEM SIZEOF
|
||||
%token ARGS ARGC ARGV EXTERN STATIC SYSTEM SIZEOF OVERLOAD
|
||||
%token <type> TYPE
|
||||
%token <typename> TYPE_NAME
|
||||
%token CLASS DEFS ENCODE END IMPLEMENTATION INTERFACE PRIVATE PROTECTED
|
||||
|
@ -157,8 +157,8 @@ expr_t *argv_expr (void);
|
|||
%type <type> type non_field_type type_name def simple_def struct_def
|
||||
%type <type> struct_def_item ivar_decl ivar_declarator def_item def_list
|
||||
%type <type> struct_def_list ivars func_type non_func_type
|
||||
%type <type> non_code_func code_func func_def func_defs func_def_list
|
||||
%type <def> fdef_name
|
||||
%type <type> non_code_func code_func func_init func_defs func_def_list
|
||||
%type <def> fdef_name cfunction_def func_def
|
||||
%type <param> function_decl
|
||||
%type <param> param param_list
|
||||
%type <def> def_name opt_initializer methoddef var_initializer
|
||||
|
@ -237,6 +237,11 @@ def
|
|||
}
|
||||
;
|
||||
|
||||
opt_eq
|
||||
: /* empty */
|
||||
| '='
|
||||
;
|
||||
|
||||
opt_semi
|
||||
: /* empty */
|
||||
| ';'
|
||||
|
@ -254,41 +259,38 @@ simple_def
|
|||
;
|
||||
|
||||
cfunction
|
||||
: non_func_type NAME function_decl ';'
|
||||
: cfunction_def ';'
|
||||
{
|
||||
type_t *type;
|
||||
def_t *def;
|
||||
|
||||
type = parse_params ($1, $3);
|
||||
def = get_def (type, $2, current_scope, current_storage);
|
||||
}
|
||||
| non_func_type NAME function_decl '=' '#' fexpr ';'
|
||||
| cfunction_def '=' '#' fexpr ';'
|
||||
{
|
||||
type_t *type;
|
||||
def_t *def;
|
||||
|
||||
type = parse_params ($1, $3);
|
||||
def = get_def (type, $2, current_scope, current_storage);
|
||||
$6 = constant_expr ($6);
|
||||
build_builtin_function (def, $6);
|
||||
build_builtin_function ($1, $4);
|
||||
}
|
||||
| non_func_type NAME function_decl
|
||||
opt_state_expr
|
||||
| cfunction_def opt_state_expr
|
||||
{ $<op>$ = current_storage; }
|
||||
{
|
||||
type_t *type;
|
||||
|
||||
current_params = $3;
|
||||
type = parse_params ($1, $3);
|
||||
$<def>$ = get_def (type, $2, current_scope, current_storage);
|
||||
}
|
||||
begin_function statement_block { $<op>$ = $<op>5; } end_function
|
||||
{ $<def>$ = $1; }
|
||||
begin_function statement_block { $<op>$ = $<op>3; } end_function
|
||||
{
|
||||
build_code_function ($7, $4, $8);
|
||||
build_code_function ($5, $2, $6);
|
||||
current_func = 0;
|
||||
}
|
||||
;
|
||||
|
||||
cfunction_def
|
||||
: OVERLOAD non_func_type identifier function_decl
|
||||
{
|
||||
type_t *type = parse_params ($2, current_params = $4);
|
||||
$$ = get_function_def ($3, type, current_scope,
|
||||
current_storage, 1, 1);
|
||||
}
|
||||
| non_func_type identifier function_decl
|
||||
{
|
||||
type_t *type = parse_params ($1, current_params = $3);
|
||||
$$ = get_function_def ($2, type, current_scope,
|
||||
current_storage, 0, 1);
|
||||
}
|
||||
;
|
||||
|
||||
storage_class
|
||||
: EXTERN { current_storage = st_extern; }
|
||||
| STATIC { current_storage = st_static; }
|
||||
|
@ -461,7 +463,7 @@ def_item
|
|||
|
||||
func_defs
|
||||
: func_def_list ',' fdef_name func_term
|
||||
| def_name func_term {}
|
||||
| func_def func_term {}
|
||||
;
|
||||
|
||||
func_term
|
||||
|
@ -470,15 +472,28 @@ func_term
|
|||
;
|
||||
|
||||
func_def_list
|
||||
: func_def_list ',' fdef_name func_def
|
||||
| def_name func_def { $$ = $<type>0; }
|
||||
: func_def_list ',' fdef_name func_init
|
||||
| func_def func_init { $$ = $<type>0; }
|
||||
;
|
||||
|
||||
fdef_name
|
||||
: { $<type>$ = $<type>-1; } def_name { $$ = $2; }
|
||||
: { $<type>$ = $<type>-1; } func_def { $$ = $2; }
|
||||
;
|
||||
|
||||
func_def
|
||||
: identifier
|
||||
{
|
||||
$$ = get_function_def ($1, $<type>0, current_scope,
|
||||
current_storage, 0, 1);
|
||||
}
|
||||
| OVERLOAD identifier
|
||||
{
|
||||
$$ = get_function_def ($2, $<type>0, current_scope,
|
||||
current_storage, 1, 1);
|
||||
}
|
||||
;
|
||||
|
||||
func_init
|
||||
: non_code_func
|
||||
| code_func
|
||||
;
|
||||
|
|
Loading…
Reference in a new issue