run in fear, function overloading is here

This is an imperfect revision of history.
This commit is contained in:
Bill Currie 2004-11-13 11:50:00 +00:00 committed by Jeff Teunissen
parent 9b81bc5ea6
commit 66257e3a88
7 changed files with 274 additions and 37 deletions

View file

@ -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);

View file

@ -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,

View file

@ -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)

View file

@ -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)

View file

@ -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)
{

View file

@ -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 *

View file

@ -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
;