2002-05-08 21:24:24 +00:00
|
|
|
/*
|
|
|
|
method.c
|
|
|
|
|
|
|
|
QC method support code
|
|
|
|
|
2002-07-05 20:02:10 +00:00
|
|
|
Copyright (C) 2002 Bill Currie
|
2002-05-08 21:24:24 +00:00
|
|
|
|
|
|
|
Author: Bill Currie <bill@taniwha.org>
|
|
|
|
Date: 2002/5/7
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to:
|
|
|
|
|
|
|
|
Free Software Foundation, Inc.
|
|
|
|
59 Temple Place - Suite 330
|
|
|
|
Boston, MA 02111-1307, USA
|
|
|
|
|
|
|
|
*/
|
2002-06-01 04:41:25 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
2003-01-15 15:31:36 +00:00
|
|
|
|
2002-06-01 04:41:25 +00:00
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
# include <string.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
# include <strings.h>
|
|
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2002-05-08 21:24:24 +00:00
|
|
|
#include "QF/dstring.h"
|
2002-05-09 20:12:28 +00:00
|
|
|
#include "QF/hash.h"
|
2002-05-15 23:24:19 +00:00
|
|
|
#include "QF/va.h"
|
2002-05-08 21:24:24 +00:00
|
|
|
|
2022-01-08 15:26:52 +00:00
|
|
|
#include "QF/progs/pr_obj.h"
|
|
|
|
|
2020-06-21 14:15:17 +00:00
|
|
|
#include "tools/qfcc/include/qfcc.h"
|
|
|
|
|
|
|
|
#include "tools/qfcc/include/expr.h"
|
|
|
|
#include "tools/qfcc/include/class.h"
|
|
|
|
#include "tools/qfcc/include/def.h"
|
|
|
|
#include "tools/qfcc/include/defspace.h"
|
|
|
|
#include "tools/qfcc/include/diagnostic.h"
|
|
|
|
#include "tools/qfcc/include/emit.h"
|
|
|
|
#include "tools/qfcc/include/method.h"
|
|
|
|
#include "tools/qfcc/include/options.h"
|
|
|
|
#include "tools/qfcc/include/reloc.h"
|
|
|
|
#include "tools/qfcc/include/shared.h"
|
|
|
|
#include "tools/qfcc/include/strpool.h"
|
|
|
|
#include "tools/qfcc/include/struct.h"
|
|
|
|
#include "tools/qfcc/include/symtab.h"
|
|
|
|
#include "tools/qfcc/include/type.h"
|
|
|
|
#include "tools/qfcc/include/value.h"
|
2002-05-08 21:24:24 +00:00
|
|
|
|
2003-07-29 17:38:29 +00:00
|
|
|
static hashtab_t *known_methods;
|
|
|
|
|
|
|
|
static const char *
|
2012-07-18 13:34:37 +00:00
|
|
|
method_get_key (const void *meth, void *unused)
|
2003-07-29 17:38:29 +00:00
|
|
|
{
|
|
|
|
return ((method_t *) meth)->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
method_free (void *_meth, void *unused)
|
|
|
|
{
|
2012-11-01 11:32:25 +00:00
|
|
|
method_t *meth = (method_t *) _meth;
|
2003-07-29 17:38:29 +00:00
|
|
|
|
|
|
|
free (meth->name);
|
|
|
|
free (meth->types);
|
|
|
|
free (meth);
|
|
|
|
}
|
|
|
|
|
2002-05-08 21:24:24 +00:00
|
|
|
method_t *
|
2011-01-09 10:41:24 +00:00
|
|
|
new_method (type_t *ret_type, param_t *selector, param_t *opt_params)
|
2002-05-08 21:24:24 +00:00
|
|
|
{
|
|
|
|
method_t *meth = malloc (sizeof (method_t));
|
2002-05-22 05:03:36 +00:00
|
|
|
param_t *cmd = new_param (0, &type_SEL, "_cmd");
|
2002-05-08 21:24:24 +00:00
|
|
|
param_t *self = new_param (0, &type_id, "self");
|
2002-05-16 20:20:23 +00:00
|
|
|
dstring_t *name = dstring_newstr ();
|
|
|
|
dstring_t *types = dstring_newstr ();
|
2002-05-08 21:24:24 +00:00
|
|
|
|
2020-07-04 03:39:11 +00:00
|
|
|
if (!ret_type) {
|
|
|
|
ret_type = &type_id;
|
|
|
|
}
|
|
|
|
|
2020-03-06 08:14:14 +00:00
|
|
|
selector = reverse_params (selector);
|
|
|
|
selector = append_params (selector, opt_params);
|
2002-05-08 21:24:24 +00:00
|
|
|
cmd->next = selector;
|
|
|
|
self->next = cmd;
|
|
|
|
|
|
|
|
meth->next = 0;
|
2011-02-04 10:50:24 +00:00
|
|
|
meth->func = 0;
|
2002-05-08 21:24:24 +00:00
|
|
|
meth->instance = 0;
|
|
|
|
meth->selector = selector;
|
|
|
|
meth->params = self;
|
|
|
|
meth->type = parse_params (ret_type, meth->params);
|
2011-02-04 10:50:24 +00:00
|
|
|
meth->type = find_type (meth->type);
|
2002-05-16 20:20:23 +00:00
|
|
|
|
|
|
|
selector_name (name, (keywordarg_t *)selector);
|
2004-11-10 05:37:00 +00:00
|
|
|
method_types (types, meth);
|
2002-05-16 20:20:23 +00:00
|
|
|
meth->name = name->str;
|
|
|
|
meth->types = types->str;
|
|
|
|
free (name);
|
|
|
|
free (types);
|
|
|
|
|
2020-03-06 08:14:14 +00:00
|
|
|
//print_type (meth->type);
|
2002-05-08 21:24:24 +00:00
|
|
|
meth->def = 0;
|
2003-07-29 17:38:29 +00:00
|
|
|
|
|
|
|
if (!known_methods)
|
2020-03-25 06:43:16 +00:00
|
|
|
known_methods = Hash_NewTable (1021, method_get_key,
|
|
|
|
method_free, 0, 0);
|
2003-07-29 17:38:29 +00:00
|
|
|
Hash_Add (known_methods, meth);
|
|
|
|
|
2002-05-08 21:24:24 +00:00
|
|
|
return meth;
|
|
|
|
}
|
|
|
|
|
2010-12-31 09:26:42 +00:00
|
|
|
const char *
|
|
|
|
method_name (method_t *method)
|
|
|
|
{
|
|
|
|
return nva ("%c%s", method->instance ? '-' : '+', method->name);
|
|
|
|
}
|
|
|
|
|
2003-08-01 05:08:15 +00:00
|
|
|
method_t *
|
|
|
|
copy_method (method_t *method)
|
|
|
|
{
|
|
|
|
method_t *meth = calloc (sizeof (method_t), 1);
|
|
|
|
param_t *self = copy_params (method->params);
|
|
|
|
|
|
|
|
meth->next = 0;
|
|
|
|
meth->instance = method->instance;
|
|
|
|
meth->selector = self->next->next;
|
|
|
|
meth->params = self;
|
2004-11-10 05:37:00 +00:00
|
|
|
meth->type = method->type;
|
2003-08-01 05:08:15 +00:00
|
|
|
meth->name = method->name;
|
|
|
|
meth->types = method->types;
|
|
|
|
return meth;
|
|
|
|
}
|
|
|
|
|
2002-05-08 21:24:24 +00:00
|
|
|
void
|
|
|
|
add_method (methodlist_t *methodlist, method_t *method)
|
|
|
|
{
|
2012-10-26 10:02:02 +00:00
|
|
|
if (method->next)
|
|
|
|
internal_error (0, "add_method: method loop detected");
|
2002-05-08 21:24:24 +00:00
|
|
|
|
2020-03-02 12:15:21 +00:00
|
|
|
for (method_t *m = methodlist->head; m; m = m->next) {
|
|
|
|
if (method_compare (m, method)) {
|
|
|
|
debug (0, "dropping duplicate method: %s", method->name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2002-05-08 21:24:24 +00:00
|
|
|
*methodlist->tail = method;
|
|
|
|
methodlist->tail = &method->next;
|
|
|
|
}
|
|
|
|
|
2011-02-04 10:50:24 +00:00
|
|
|
symbol_t *
|
|
|
|
method_symbol (class_type_t *class_type, method_t *method)
|
2002-05-08 21:24:24 +00:00
|
|
|
{
|
|
|
|
dstring_t *str = dstring_newstr ();
|
2011-02-04 10:50:24 +00:00
|
|
|
symbol_t *sym;
|
2002-05-09 20:12:28 +00:00
|
|
|
char *s;
|
2002-11-14 18:17:43 +00:00
|
|
|
const char *class_name;
|
|
|
|
|
2010-12-31 06:44:54 +00:00
|
|
|
class_name = get_class_name (class_type, 0);
|
2002-05-09 20:12:28 +00:00
|
|
|
|
2010-12-31 06:44:54 +00:00
|
|
|
dsprintf (str, "_%c_%s_%s",
|
2002-05-09 20:12:28 +00:00
|
|
|
method->instance ? 'i' : 'c',
|
2002-11-14 18:17:43 +00:00
|
|
|
class_name,
|
2002-05-16 20:20:23 +00:00
|
|
|
method->name);
|
2002-05-09 20:12:28 +00:00
|
|
|
for (s = str->str; *s; s++)
|
|
|
|
if (*s == ':')
|
|
|
|
*s = '_';
|
2011-01-24 06:41:43 +00:00
|
|
|
//printf ("%s %s %s %ld\n", method->name, method->types, str->str,
|
|
|
|
// str->size);
|
2011-02-04 10:50:24 +00:00
|
|
|
sym = new_symbol_type (str->str, method->type);
|
2011-02-15 03:38:29 +00:00
|
|
|
sym = function_symbol (sym, 0, 1);
|
2011-02-06 06:14:42 +00:00
|
|
|
sym->params = method->params;
|
2002-05-09 20:12:28 +00:00
|
|
|
dstring_delete (str);
|
2011-02-04 10:50:24 +00:00
|
|
|
return sym;
|
2002-05-08 21:24:24 +00:00
|
|
|
}
|
2002-05-08 23:12:49 +00:00
|
|
|
|
2004-11-02 23:54:00 +00:00
|
|
|
void
|
|
|
|
method_set_param_names (method_t *dst, method_t *src)
|
|
|
|
{
|
|
|
|
param_t *dp, *sp;
|
|
|
|
|
|
|
|
for (dp = dst->params, sp = src->params; dp && sp;
|
|
|
|
dp = dp->next, sp = sp->next) {
|
|
|
|
dp->name = sp->name;
|
|
|
|
}
|
2012-10-26 10:02:02 +00:00
|
|
|
if (dp || sp)
|
|
|
|
internal_error (0, "missmatched method params");
|
2004-11-02 23:54:00 +00:00
|
|
|
}
|
|
|
|
|
2002-05-10 00:00:23 +00:00
|
|
|
methodlist_t *
|
|
|
|
new_methodlist (void)
|
|
|
|
{
|
|
|
|
methodlist_t *l = malloc (sizeof (methodlist_t));
|
|
|
|
l->head = 0;
|
|
|
|
l->tail = &l->head;
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
2020-03-05 03:52:37 +00:00
|
|
|
static uintptr_t
|
|
|
|
methodset_get_hash (const void *_method, void *unused)
|
|
|
|
{
|
|
|
|
method_t *method = (method_t *) _method;
|
|
|
|
uintptr_t hash;
|
|
|
|
|
|
|
|
hash = Hash_String (method->name);
|
|
|
|
return hash ^ (method->instance << 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
methodset_compare (const void *_m1, const void *_m2, void *unused)
|
|
|
|
{
|
|
|
|
method_t *m1 = (method_t *) _m1;
|
|
|
|
method_t *m2 = (method_t *) _m2;
|
|
|
|
int cmp;
|
|
|
|
|
|
|
|
cmp = strcmp (m1->name, m2->name) == 0;
|
|
|
|
return cmp && m1->instance == m2->instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
methodset_t *
|
|
|
|
new_methodset (void)
|
|
|
|
{
|
|
|
|
methodset_t *s = malloc (sizeof (*s));
|
2020-03-25 06:43:16 +00:00
|
|
|
s->tab = Hash_NewTable (31, 0, 0, 0, 0);
|
2020-03-05 03:52:37 +00:00
|
|
|
Hash_SetHashCompare (s->tab, methodset_get_hash, methodset_compare);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
methodset_add_methods (methodset_t *methodset, methodlist_t *methods)
|
|
|
|
{
|
|
|
|
method_t *m;
|
|
|
|
|
|
|
|
for (m = methods->head; m; m = m->next) {
|
|
|
|
Hash_AddElement (methodset->tab, m);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
methodset_contains_method (methodset_t *methodset, method_t *method)
|
|
|
|
{
|
|
|
|
return Hash_FindElement (methodset->tab, method) != 0;
|
|
|
|
}
|
|
|
|
|
2020-03-03 01:59:01 +00:00
|
|
|
static int __attribute__((pure))
|
2020-03-02 15:11:54 +00:00
|
|
|
method_in_list (methodlist_t *method_list, method_t *method)
|
|
|
|
{
|
|
|
|
method_t *m;
|
|
|
|
|
|
|
|
for (m = method_list->head; m; m = m->next) {
|
|
|
|
if (method_compare (m, method)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
merge_method_lists (methodlist_t *dst, methodlist_t *src)
|
|
|
|
{
|
|
|
|
while (src->head) {
|
|
|
|
method_t *s = src->head;
|
|
|
|
src->head = s->next;
|
|
|
|
s->next = 0;
|
|
|
|
if (method_in_list (dst, s)) {
|
|
|
|
debug (0, "dropping duplicate method: %s", s->name);
|
2022-09-19 15:39:25 +00:00
|
|
|
//FIXME this free is currently erroneous as it remains in
|
|
|
|
//known_methods, but it may also be a leak, thus only
|
|
|
|
//commented out for now.
|
|
|
|
//free (s);
|
2020-03-02 15:11:54 +00:00
|
|
|
} else {
|
|
|
|
// add_method does the duplicate check
|
|
|
|
*dst->tail = s;
|
|
|
|
dst->tail = &s->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free (src);
|
|
|
|
}
|
|
|
|
|
2002-05-10 00:00:23 +00:00
|
|
|
void
|
2020-03-05 03:52:37 +00:00
|
|
|
copy_methods (methodlist_t *dst, methodlist_t *src, methodset_t *except)
|
2002-05-10 00:00:23 +00:00
|
|
|
{
|
[qfcc] Copy self param when copying methods
Copying methods is done when adding protocols to classes (the current
use for adding regular methods is an incorrect solution to a different
problem). However, when a method is added to a class, the type of its
self parameter is set to be a pointer to the class. Thus, not only does
the method need to be copied, the self parameter does too, otherwise
the self parameter of methods added via protocols will have their type
set to be a pointer to the last class seen adding the protocol.
That is, if, while compiling the implementation for class A, but the
interface for class B is comes after the interface for class A, and both
A and B add protocol P, then all methods in protocol P will have self
pointing to B rather than A.
@protocol P
-method;
@end
@interface A <P>
@end
@interface B <P>
@end
@implementation A
-method {} // self is B, not A!
@end
2020-03-02 14:38:04 +00:00
|
|
|
method_t *s, *d;
|
|
|
|
param_t *self;
|
2002-05-10 00:00:23 +00:00
|
|
|
|
2002-08-13 21:17:20 +00:00
|
|
|
for (s = src->head; s; s = s->next) {
|
2020-03-05 03:52:37 +00:00
|
|
|
if (methodset_contains_method (except, s) || method_in_list (dst, s)) {
|
2020-03-02 15:11:54 +00:00
|
|
|
debug (0, "skipping duplicate method: %s", s->name);
|
|
|
|
continue;
|
|
|
|
}
|
2002-05-10 00:00:23 +00:00
|
|
|
d = malloc (sizeof (method_t));
|
|
|
|
*d = *s;
|
[qfcc] Copy self param when copying methods
Copying methods is done when adding protocols to classes (the current
use for adding regular methods is an incorrect solution to a different
problem). However, when a method is added to a class, the type of its
self parameter is set to be a pointer to the class. Thus, not only does
the method need to be copied, the self parameter does too, otherwise
the self parameter of methods added via protocols will have their type
set to be a pointer to the last class seen adding the protocol.
That is, if, while compiling the implementation for class A, but the
interface for class B is comes after the interface for class A, and both
A and B add protocol P, then all methods in protocol P will have self
pointing to B rather than A.
@protocol P
-method;
@end
@interface A <P>
@end
@interface B <P>
@end
@implementation A
-method {} // self is B, not A!
@end
2020-03-02 14:38:04 +00:00
|
|
|
// The above is only a shallow copy and thus even though the methods
|
|
|
|
// are not shared between the source and destination lists, the
|
|
|
|
// parameters are. Thus, duplicate the self (first) parameter so
|
|
|
|
// changing its type to match the class into which it is inserted does
|
|
|
|
// not affect the source list. The rest of the parameters do not need
|
|
|
|
// to be copied as they will not be altered.
|
|
|
|
self = malloc (sizeof (param_t));
|
|
|
|
*self = *d->params;
|
|
|
|
d->params = self;
|
2002-05-10 00:00:23 +00:00
|
|
|
d->next = 0;
|
2020-03-02 15:11:54 +00:00
|
|
|
// add_method does the duplicate check
|
|
|
|
*dst->tail = d;
|
|
|
|
dst->tail = &d->next;
|
2002-05-10 00:00:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-09 03:35:01 +00:00
|
|
|
__attribute__((pure)) int
|
2002-05-15 23:24:19 +00:00
|
|
|
method_compare (method_t *m1, method_t *m2)
|
|
|
|
{
|
2002-05-16 20:48:41 +00:00
|
|
|
if (m1->instance != m2->instance)
|
|
|
|
return 0;
|
2010-11-18 01:44:25 +00:00
|
|
|
return strcmp (m1->name, m2->name) == 0 && m1->type == m2->type;
|
2002-05-15 23:24:19 +00:00
|
|
|
}
|
|
|
|
|
2002-05-08 23:12:49 +00:00
|
|
|
keywordarg_t *
|
|
|
|
new_keywordarg (const char *selector, struct expr_s *expr)
|
|
|
|
{
|
|
|
|
keywordarg_t *k = malloc (sizeof (keywordarg_t));
|
|
|
|
|
|
|
|
k->next = 0;
|
|
|
|
k->selector = selector;
|
|
|
|
k->expr = expr;
|
|
|
|
return k;
|
|
|
|
}
|
|
|
|
|
2002-08-20 02:09:34 +00:00
|
|
|
keywordarg_t *
|
|
|
|
copy_keywordargs (const keywordarg_t *kwargs)
|
|
|
|
{
|
|
|
|
keywordarg_t *n_kwargs = 0, **kw = &n_kwargs;
|
|
|
|
|
|
|
|
while (kwargs) {
|
|
|
|
*kw = new_keywordarg (kwargs->selector, kwargs->expr);
|
|
|
|
kwargs = kwargs->next;
|
|
|
|
kw = &(*kw)->next;
|
|
|
|
}
|
|
|
|
return n_kwargs;
|
|
|
|
}
|
|
|
|
|
2002-05-08 23:12:49 +00:00
|
|
|
expr_t *
|
2004-02-04 04:49:46 +00:00
|
|
|
send_message (int super)
|
2002-05-08 23:12:49 +00:00
|
|
|
{
|
2011-02-04 14:49:25 +00:00
|
|
|
symbol_t *sym;
|
|
|
|
const char *sm_name = "obj_msgSend";
|
|
|
|
type_t *sm_type = &type_IMP;
|
|
|
|
|
|
|
|
if (super) {
|
|
|
|
sm_name = "obj_msgSend_super";
|
2011-02-11 02:29:25 +00:00
|
|
|
sm_type = &type_supermsg;
|
2011-02-04 14:49:25 +00:00
|
|
|
}
|
|
|
|
sym = symtab_lookup (pr.symtab, sm_name);
|
|
|
|
if (!sym) {
|
2011-03-02 03:35:10 +00:00
|
|
|
symtab_t *save = current_symtab;
|
|
|
|
current_symtab = pr.symtab;
|
2011-02-04 14:49:25 +00:00
|
|
|
sym = new_symbol_type (sm_name, sm_type);
|
|
|
|
sym = function_symbol (sym, 0, 1);
|
2012-12-02 01:11:30 +00:00
|
|
|
make_function (sym, 0, sym->table->space, sc_extern);
|
2011-03-02 03:35:10 +00:00
|
|
|
current_symtab = save;
|
2011-02-04 14:49:25 +00:00
|
|
|
}
|
|
|
|
return new_symbol_expr (sym);
|
2002-05-08 23:12:49 +00:00
|
|
|
}
|
2002-05-09 20:12:28 +00:00
|
|
|
|
2003-07-29 17:38:29 +00:00
|
|
|
method_t *
|
|
|
|
find_method (const char *sel_name)
|
|
|
|
{
|
|
|
|
if (!known_methods)
|
|
|
|
return 0;
|
|
|
|
return Hash_Find (known_methods, sel_name);
|
|
|
|
}
|
|
|
|
|
2020-03-15 14:30:57 +00:00
|
|
|
method_t *
|
|
|
|
methodlist_find_method (methodlist_t *methodlist, selector_t *selector,
|
|
|
|
int instance)
|
|
|
|
{
|
|
|
|
method_t *m;
|
|
|
|
|
|
|
|
for (m = methodlist->head; m; m = m->next) {
|
|
|
|
if (m->instance == instance && strcmp (selector->name, m->name) == 0) {
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-05-09 20:12:28 +00:00
|
|
|
void
|
|
|
|
selector_name (dstring_t *sel_id, keywordarg_t *selector)
|
|
|
|
{
|
|
|
|
dstring_clearstr (sel_id);
|
|
|
|
while (selector && selector->selector) {
|
|
|
|
dstring_appendstr (sel_id, selector->selector);
|
2003-07-27 19:13:13 +00:00
|
|
|
if (selector->expr)
|
|
|
|
dstring_appendstr (sel_id, ":");
|
2002-05-09 20:12:28 +00:00
|
|
|
selector = selector->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2004-11-10 05:37:00 +00:00
|
|
|
method_types (dstring_t *sel_types, method_t *method)
|
2002-05-09 20:12:28 +00:00
|
|
|
{
|
2002-05-15 23:24:19 +00:00
|
|
|
dstring_clearstr (sel_types);
|
2004-11-10 05:37:00 +00:00
|
|
|
encode_type (sel_types, method->type);
|
2002-05-09 20:12:28 +00:00
|
|
|
}
|
|
|
|
|
2003-08-23 06:15:19 +00:00
|
|
|
static hashtab_t *sel_hash;
|
|
|
|
static hashtab_t *sel_index_hash;
|
|
|
|
static int sel_index;
|
2002-05-09 20:12:28 +00:00
|
|
|
|
2007-04-04 11:22:48 +00:00
|
|
|
static uintptr_t
|
2012-07-18 13:34:37 +00:00
|
|
|
sel_get_hash (const void *_sel, void *unused)
|
2002-05-09 20:12:28 +00:00
|
|
|
{
|
2003-08-23 06:15:19 +00:00
|
|
|
selector_t *sel = (selector_t *) _sel;
|
2007-04-04 11:22:48 +00:00
|
|
|
uintptr_t hash;
|
2002-05-09 20:12:28 +00:00
|
|
|
|
2004-11-10 05:37:00 +00:00
|
|
|
hash = Hash_String (sel->name);
|
2002-05-09 20:12:28 +00:00
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-07-18 13:34:37 +00:00
|
|
|
sel_compare (const void *_s1, const void *_s2, void *unused)
|
2002-05-09 20:12:28 +00:00
|
|
|
{
|
2003-08-23 06:15:19 +00:00
|
|
|
selector_t *s1 = (selector_t *) _s1;
|
|
|
|
selector_t *s2 = (selector_t *) _s2;
|
2002-05-09 20:12:28 +00:00
|
|
|
int cmp;
|
|
|
|
|
2003-08-23 06:15:19 +00:00
|
|
|
cmp = strcmp (s1->name, s2->name) == 0;
|
2002-05-09 20:12:28 +00:00
|
|
|
return cmp;
|
|
|
|
}
|
|
|
|
|
2007-04-04 11:22:48 +00:00
|
|
|
static uintptr_t
|
2012-07-18 13:34:37 +00:00
|
|
|
sel_index_get_hash (const void *_sel, void *unused)
|
2003-08-23 06:15:19 +00:00
|
|
|
{
|
|
|
|
selector_t *sel = (selector_t *) _sel;
|
|
|
|
return sel->index;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-07-18 13:34:37 +00:00
|
|
|
sel_index_compare (const void *_s1, const void *_s2, void *unused)
|
2003-08-23 06:15:19 +00:00
|
|
|
{
|
|
|
|
selector_t *s1 = (selector_t *) _s1;
|
|
|
|
selector_t *s2 = (selector_t *) _s2;
|
|
|
|
return s1->index == s2->index;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2004-11-10 05:37:00 +00:00
|
|
|
selector_index (const char *sel_id)
|
2003-08-23 06:15:19 +00:00
|
|
|
{
|
2004-11-10 05:37:00 +00:00
|
|
|
selector_t _sel = {save_string (sel_id), 0, 0};
|
2003-08-23 06:15:19 +00:00
|
|
|
selector_t *sel = &_sel;
|
|
|
|
|
|
|
|
if (!sel_hash) {
|
2020-03-25 06:43:16 +00:00
|
|
|
sel_hash = Hash_NewTable (1021, 0, 0, 0, 0);
|
2003-08-23 06:15:19 +00:00
|
|
|
Hash_SetHashCompare (sel_hash, sel_get_hash, sel_compare);
|
2020-03-25 06:43:16 +00:00
|
|
|
sel_index_hash = Hash_NewTable (1021, 0, 0, 0, 0);
|
2003-08-23 06:15:19 +00:00
|
|
|
Hash_SetHashCompare (sel_index_hash, sel_index_get_hash,
|
|
|
|
sel_index_compare);
|
|
|
|
}
|
|
|
|
sel = Hash_FindElement (sel_hash, sel);
|
|
|
|
if (sel)
|
|
|
|
return sel->index;
|
|
|
|
sel = malloc (sizeof (selector_t));
|
|
|
|
sel->name = _sel.name;
|
|
|
|
sel->types = _sel.types;
|
|
|
|
sel->index = sel_index++;
|
|
|
|
Hash_AddElement (sel_hash, sel);
|
|
|
|
Hash_AddElement (sel_index_hash, sel);
|
|
|
|
return sel->index;
|
|
|
|
}
|
|
|
|
|
|
|
|
selector_t *
|
|
|
|
get_selector (expr_t *sel)
|
|
|
|
{
|
2011-02-15 01:48:05 +00:00
|
|
|
selector_t _sel = {0, 0, 0};
|
|
|
|
|
2021-12-24 04:22:01 +00:00
|
|
|
if (sel->type == ex_selector) {
|
|
|
|
return sel->e.selector.sel;
|
|
|
|
}
|
2022-01-08 07:52:24 +00:00
|
|
|
if (sel->type != ex_address && !sel->e.address.offset
|
|
|
|
&& !is_SEL(sel->e.address.type)) {
|
2011-02-15 01:48:05 +00:00
|
|
|
error (sel, "not a selector");
|
|
|
|
return 0;
|
|
|
|
}
|
2022-01-19 15:42:29 +00:00
|
|
|
_sel.index = expr_short (sel->e.address.offset);
|
2011-01-09 10:41:24 +00:00
|
|
|
_sel.index /= type_size (type_SEL.t.fldptr.type);
|
2003-08-23 06:15:19 +00:00
|
|
|
return (selector_t *) Hash_FindElement (sel_index_hash, &_sel);
|
|
|
|
}
|
|
|
|
|
2002-05-09 20:12:28 +00:00
|
|
|
def_t *
|
2003-08-23 06:15:19 +00:00
|
|
|
emit_selectors (void)
|
2002-05-09 20:12:28 +00:00
|
|
|
{
|
2011-02-06 07:56:19 +00:00
|
|
|
symbol_t *sel_sym;
|
2003-08-23 06:15:19 +00:00
|
|
|
def_t *sel_def;
|
|
|
|
type_t *sel_type;
|
|
|
|
pr_sel_t *sel;
|
|
|
|
selector_t **selectors, **s;
|
2012-05-21 23:23:22 +00:00
|
|
|
|
2003-08-23 06:15:19 +00:00
|
|
|
if (!sel_index)
|
|
|
|
return 0;
|
2002-05-09 20:12:28 +00:00
|
|
|
|
2011-01-09 10:41:24 +00:00
|
|
|
sel_type = array_type (type_SEL.t.fldptr.type, sel_index);
|
2011-02-15 03:09:39 +00:00
|
|
|
sel_sym = make_symbol ("_OBJ_SELECTOR_TABLE", sel_type,
|
2012-12-02 01:11:30 +00:00
|
|
|
pr.far_data, sc_static);
|
2011-02-06 07:56:19 +00:00
|
|
|
if (!sel_sym->table)
|
|
|
|
symtab_addsymbol (pr.symtab, sel_sym);
|
|
|
|
sel_def = sel_sym->s.def;
|
2011-01-24 06:41:43 +00:00
|
|
|
sel_def->initialized = sel_def->constant = 1;
|
|
|
|
sel_def->nosave = 1;
|
|
|
|
|
|
|
|
sel = D_POINTER (pr_sel_t, sel_def);
|
|
|
|
|
2003-08-23 06:15:19 +00:00
|
|
|
selectors = (selector_t **) Hash_GetList (sel_hash);
|
2012-05-21 23:23:22 +00:00
|
|
|
|
2003-08-23 06:15:19 +00:00
|
|
|
for (s = selectors; *s; s++) {
|
2011-01-24 06:41:43 +00:00
|
|
|
EMIT_STRING (sel_def->space, sel[(*s)->index].sel_id, (*s)->name);
|
|
|
|
EMIT_STRING (sel_def->space, sel[(*s)->index].sel_types, (*s)->types);
|
2002-05-09 20:12:28 +00:00
|
|
|
}
|
2003-08-23 06:15:19 +00:00
|
|
|
free (selectors);
|
|
|
|
return sel_def;
|
2002-05-09 20:12:28 +00:00
|
|
|
}
|
2002-05-15 23:24:19 +00:00
|
|
|
|
2011-01-24 06:41:43 +00:00
|
|
|
static void
|
|
|
|
emit_methods_next (def_t *def, void *data, int index)
|
|
|
|
{
|
2022-01-19 08:48:46 +00:00
|
|
|
if (!is_ptr(def->type))
|
2011-01-24 06:41:43 +00:00
|
|
|
internal_error (0, "%s: expected pointer def", __FUNCTION__);
|
|
|
|
D_INT (def) = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
emit_methods_count (def_t *def, void *data, int index)
|
|
|
|
{
|
|
|
|
methodlist_t *methods = (methodlist_t *) data;
|
|
|
|
|
2022-01-18 04:21:06 +00:00
|
|
|
if (!is_int(def->type))
|
|
|
|
internal_error (0, "%s: expected int def", __FUNCTION__);
|
2011-01-24 06:41:43 +00:00
|
|
|
D_INT (def) = methods->count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
emit_methods_list_item (def_t *def, void *data, int index)
|
|
|
|
{
|
|
|
|
methodlist_t *methods = (methodlist_t *) data;
|
|
|
|
method_t *m;
|
|
|
|
pr_method_t *meth;
|
|
|
|
|
2020-03-27 06:16:41 +00:00
|
|
|
if (!is_array (def->type) || !is_method(def->type->t.array.type))
|
2011-02-15 13:26:44 +00:00
|
|
|
internal_error (0, "%s: expected array of method def",
|
2011-01-24 06:41:43 +00:00
|
|
|
__FUNCTION__);
|
|
|
|
if (index < 0 || index >= methods->count)
|
|
|
|
internal_error (0, "%s: out of bounds index: %d %d",
|
|
|
|
__FUNCTION__, index, methods->count);
|
|
|
|
|
|
|
|
meth = D_POINTER (pr_method_t, def);
|
|
|
|
|
|
|
|
for (m = methods->head; m; m = m->next) {
|
|
|
|
if (!m->instance != !methods->instance || !m->def)
|
|
|
|
continue;
|
|
|
|
if (!index--)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
EMIT_STRING (def->space, meth->method_name, m->name);
|
|
|
|
EMIT_STRING (def->space, meth->method_types, m->types);
|
|
|
|
meth->method_imp = D_FUNCTION (m->def);
|
2011-02-12 13:34:38 +00:00
|
|
|
if (m->func) {
|
|
|
|
def_t loc;
|
|
|
|
loc.space = def->space;
|
|
|
|
loc.offset = POINTER_OFS (def->space, &meth->method_imp);
|
|
|
|
reloc_def_func (m->func, &loc);
|
|
|
|
}
|
2011-01-24 06:41:43 +00:00
|
|
|
}
|
|
|
|
|
2002-07-13 06:09:03 +00:00
|
|
|
def_t *
|
2011-01-24 06:41:43 +00:00
|
|
|
emit_methods (methodlist_t *methods, const char *name, int instance)
|
2002-05-15 23:24:19 +00:00
|
|
|
{
|
2011-01-17 13:33:33 +00:00
|
|
|
static struct_def_t methods_struct[] = {
|
2022-01-18 13:34:52 +00:00
|
|
|
{"method_next", &type_ptr, emit_methods_next},
|
|
|
|
{"method_count", &type_int, emit_methods_count},
|
|
|
|
{"method_list", 0, emit_methods_list_item},
|
2011-01-17 13:33:33 +00:00
|
|
|
{0, 0}
|
|
|
|
};
|
2002-05-15 23:24:19 +00:00
|
|
|
const char *type = instance ? "INSTANCE" : "CLASS";
|
2011-01-24 06:41:43 +00:00
|
|
|
method_t *m;
|
|
|
|
int count;
|
2002-05-15 23:24:19 +00:00
|
|
|
|
2011-01-24 06:41:43 +00:00
|
|
|
if (!methods)
|
2002-05-16 21:57:03 +00:00
|
|
|
return 0;
|
2004-11-18 06:08:20 +00:00
|
|
|
|
2020-03-01 04:53:18 +00:00
|
|
|
for (count = 0, m = methods->head; m; m = m->next) {
|
2011-01-24 06:41:43 +00:00
|
|
|
if (!m->instance == !instance) {
|
|
|
|
if (!m->def && options.warnings.unimplemented) {
|
2004-11-18 06:08:20 +00:00
|
|
|
warning (0, "Method `%c%s' not implemented",
|
2011-01-24 06:41:43 +00:00
|
|
|
m->instance ? '-' : '+', m->name);
|
2002-05-21 22:51:46 +00:00
|
|
|
}
|
2011-02-03 23:26:16 +00:00
|
|
|
if (m->def)
|
|
|
|
count++;
|
2002-05-21 22:51:46 +00:00
|
|
|
}
|
2020-03-01 04:53:18 +00:00
|
|
|
}
|
2002-05-16 21:57:03 +00:00
|
|
|
if (!count)
|
|
|
|
return 0;
|
2011-01-24 06:41:43 +00:00
|
|
|
methods->count = count;
|
2011-02-04 10:50:24 +00:00
|
|
|
methods->instance = instance;
|
2011-01-24 06:41:43 +00:00
|
|
|
|
2020-03-27 06:33:53 +00:00
|
|
|
methods_struct[2].type = array_type (&type_method, count);
|
2021-01-31 07:01:20 +00:00
|
|
|
return emit_structure (va (0, "_OBJ_%s_METHODS_%s", type, name), 's',
|
2020-04-03 05:16:16 +00:00
|
|
|
methods_struct, 0, methods, 0, sc_static);
|
2011-01-24 06:41:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
emit_method_list_count (def_t *def, void *data, int index)
|
|
|
|
{
|
|
|
|
methodlist_t *methods = (methodlist_t *) data;
|
|
|
|
|
2022-01-18 04:21:06 +00:00
|
|
|
if (!is_int(def->type))
|
|
|
|
internal_error (0, "%s: expected int def", __FUNCTION__);
|
2011-01-24 06:41:43 +00:00
|
|
|
D_INT (def) = methods->count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
emit_method_list_item (def_t *def, void *data, int index)
|
|
|
|
{
|
|
|
|
methodlist_t *methods = (methodlist_t *) data;
|
|
|
|
method_t *m;
|
|
|
|
pr_method_description_t *desc;
|
|
|
|
|
2020-03-02 01:52:09 +00:00
|
|
|
if (!is_array (def->type)
|
2020-03-27 06:16:41 +00:00
|
|
|
|| !is_method_description(def->type->t.array.type)) {
|
2020-03-02 01:52:09 +00:00
|
|
|
internal_error (0, "%s: expected array of method_description def",
|
2011-01-24 06:41:43 +00:00
|
|
|
__FUNCTION__);
|
2020-03-02 01:52:09 +00:00
|
|
|
}
|
2011-01-24 06:41:43 +00:00
|
|
|
if (index < 0 || index >= methods->count)
|
|
|
|
internal_error (0, "%s: out of bounds index: %d %d",
|
|
|
|
__FUNCTION__, index, methods->count);
|
|
|
|
|
|
|
|
desc = D_POINTER (pr_method_description_t, def);
|
|
|
|
|
|
|
|
for (m = methods->head; m; m = m->next) {
|
2020-03-02 01:52:09 +00:00
|
|
|
if (!m->instance != !methods->instance)
|
2002-05-15 23:24:19 +00:00
|
|
|
continue;
|
2011-01-24 06:41:43 +00:00
|
|
|
if (!index--)
|
|
|
|
break;
|
2002-05-15 23:24:19 +00:00
|
|
|
}
|
2011-01-24 06:41:43 +00:00
|
|
|
EMIT_STRING (def->space, desc->name, m->name);
|
|
|
|
EMIT_STRING (def->space, desc->types, m->types);
|
2002-05-15 23:24:19 +00:00
|
|
|
}
|
2002-06-28 16:00:01 +00:00
|
|
|
|
2004-11-10 05:37:00 +00:00
|
|
|
def_t *
|
2011-01-24 06:41:43 +00:00
|
|
|
emit_method_descriptions (methodlist_t *methods, const char *name,
|
2004-11-10 05:37:00 +00:00
|
|
|
int instance)
|
|
|
|
{
|
2011-01-24 06:41:43 +00:00
|
|
|
static struct_def_t method_list_struct[] = {
|
2022-01-18 04:21:06 +00:00
|
|
|
{"count", &type_int, emit_method_list_count},
|
2011-01-24 06:41:43 +00:00
|
|
|
{"method_list", 0, emit_method_list_item},
|
|
|
|
{0, 0}
|
|
|
|
};
|
2004-11-10 05:37:00 +00:00
|
|
|
const char *type = instance ? "PROTOCOL_INSTANCE" : "PROTOCOL_CLASS";
|
2011-01-24 06:41:43 +00:00
|
|
|
method_t *m;
|
|
|
|
int count;
|
|
|
|
|
|
|
|
if (!methods)
|
2004-11-10 05:37:00 +00:00
|
|
|
return 0;
|
|
|
|
|
2011-01-24 06:41:43 +00:00
|
|
|
for (count = 0, m = methods->head; m; m = m->next)
|
2020-03-02 01:52:09 +00:00
|
|
|
if (!m->instance == !instance)
|
2004-11-10 05:37:00 +00:00
|
|
|
count++;
|
|
|
|
if (!count)
|
|
|
|
return 0;
|
2011-01-24 06:41:43 +00:00
|
|
|
|
2004-11-10 05:37:00 +00:00
|
|
|
methods->count = count;
|
2011-01-24 06:41:43 +00:00
|
|
|
methods->instance = instance;
|
|
|
|
|
2020-03-27 06:33:53 +00:00
|
|
|
method_list_struct[1].type = array_type (&type_method_description, count);
|
2021-01-31 07:01:20 +00:00
|
|
|
return emit_structure (va (0, "_OBJ_%s_METHODS_%s", type, name), 's',
|
2020-04-03 05:16:16 +00:00
|
|
|
method_list_struct, 0, methods, 0, sc_static);
|
2004-11-10 05:37:00 +00:00
|
|
|
}
|
|
|
|
|
2002-06-28 16:00:01 +00:00
|
|
|
void
|
|
|
|
clear_selectors (void)
|
|
|
|
{
|
2003-08-23 06:15:19 +00:00
|
|
|
if (sel_hash) {
|
|
|
|
Hash_FlushTable (sel_hash);
|
|
|
|
Hash_FlushTable (sel_index_hash);
|
|
|
|
}
|
|
|
|
sel_index = 0;
|
2003-07-29 17:38:29 +00:00
|
|
|
if (known_methods)
|
|
|
|
Hash_FlushTable (known_methods);
|
2002-06-28 16:00:01 +00:00
|
|
|
}
|
2003-08-22 05:26:47 +00:00
|
|
|
|
|
|
|
expr_t *
|
|
|
|
method_check_params (method_t *method, expr_t *args)
|
|
|
|
{
|
2011-01-09 10:41:24 +00:00
|
|
|
int i, count, param_count;
|
2003-08-22 05:26:47 +00:00
|
|
|
expr_t *a, **arg_list, *err = 0;
|
|
|
|
type_t *mtype = method->type;
|
|
|
|
|
2011-01-09 10:41:24 +00:00
|
|
|
if (mtype->t.func.num_params == -1)
|
2003-08-22 05:26:47 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (count = 0, a = args; a; a = a->next)
|
|
|
|
count++;
|
|
|
|
|
2022-01-23 05:17:25 +00:00
|
|
|
if (count > PR_MAX_PARAMS)
|
|
|
|
return error (args, "more than %d parameters", PR_MAX_PARAMS);
|
2003-08-22 05:26:47 +00:00
|
|
|
|
2011-01-09 10:41:24 +00:00
|
|
|
if (mtype->t.func.num_params >= 0)
|
|
|
|
param_count = mtype->t.func.num_params;
|
2003-08-22 05:26:47 +00:00
|
|
|
else
|
2011-01-09 10:41:24 +00:00
|
|
|
param_count = -mtype->t.func.num_params - 1;
|
2003-08-22 05:26:47 +00:00
|
|
|
|
2011-01-09 10:41:24 +00:00
|
|
|
if (count < param_count)
|
2003-08-22 05:26:47 +00:00
|
|
|
return error (args, "too few arguments");
|
2011-01-09 10:41:24 +00:00
|
|
|
if (mtype->t.func.num_params >= 0 && count > mtype->t.func.num_params)
|
2003-08-22 05:26:47 +00:00
|
|
|
return error (args, "too many arguments");
|
|
|
|
|
|
|
|
arg_list = malloc (count * sizeof (expr_t *));
|
|
|
|
for (i = count - 1, a = args; a; a = a->next)
|
|
|
|
arg_list[i--] = a;
|
|
|
|
for (i = 2; i < count; i++) {
|
|
|
|
expr_t *e = arg_list[i];
|
2020-03-13 00:46:36 +00:00
|
|
|
type_t *arg_type = mtype->t.func.param_types[i];
|
|
|
|
type_t *t;
|
2003-08-22 05:48:19 +00:00
|
|
|
|
2020-03-13 00:46:36 +00:00
|
|
|
if (e->type == ex_compound) {
|
|
|
|
e = expr_file_line (initialized_temp_expr (arg_type, e), e);
|
|
|
|
}
|
|
|
|
t = get_type (e);
|
|
|
|
if (!t) {
|
2003-08-22 05:48:19 +00:00
|
|
|
return e;
|
2020-03-13 00:46:36 +00:00
|
|
|
}
|
2012-05-21 23:23:22 +00:00
|
|
|
|
2011-01-09 10:41:24 +00:00
|
|
|
if (i < param_count) {
|
2020-03-13 00:46:36 +00:00
|
|
|
if (e->type != ex_nil) {
|
|
|
|
if (!type_assignable (arg_type, t)) {
|
|
|
|
err = param_mismatch (e, i - 1, method->name, arg_type, t);
|
2003-08-22 05:26:47 +00:00
|
|
|
}
|
2020-03-13 00:46:36 +00:00
|
|
|
}
|
2003-08-22 05:26:47 +00:00
|
|
|
} else {
|
2022-01-18 04:21:06 +00:00
|
|
|
if (is_int_val (e) && options.warnings.vararg_integer) {
|
|
|
|
warning (e, "passing int consant into ... function");
|
2020-03-13 00:46:36 +00:00
|
|
|
}
|
2003-08-22 05:26:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
free (arg_list);
|
|
|
|
return err;
|
|
|
|
}
|