2007-12-30 17:41:49 +01:00
|
|
|
/***************************************************************************
|
|
|
|
|
2009-08-17 12:41:51 +02:00
|
|
|
gbx_class.c
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-12-31 03:39:20 +01:00
|
|
|
(c) 2000-2012 Benoît Minisini <gambas@users.sourceforge.net>
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-08-17 12:41:51 +02:00
|
|
|
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, or (at your option)
|
|
|
|
any later version.
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-08-17 12:41:51 +02:00
|
|
|
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.
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-08-17 12:41:51 +02:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
2011-06-03 02:51:09 +02:00
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
2011-12-31 03:39:20 +01:00
|
|
|
MA 02110-1301, USA.
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#define __GBX_CLASS_C
|
|
|
|
|
|
|
|
#include "gb_common.h"
|
|
|
|
#include "gb_common_buffer.h"
|
2010-05-27 15:51:09 +02:00
|
|
|
#include "gb_common_case.h"
|
2007-12-30 17:41:49 +01:00
|
|
|
#include "gb_alloc.h"
|
|
|
|
#include "gb_error.h"
|
|
|
|
#include "gb_limit.h"
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
#include "gb_buffer.h"
|
|
|
|
#include "gb_file.h"
|
|
|
|
#include "gbx_type.h"
|
|
|
|
#include "gbx_exec.h"
|
|
|
|
#include "gbx_debug.h"
|
|
|
|
#include "gb_magic.h"
|
|
|
|
#include "gbx_stream.h"
|
2010-05-27 00:01:28 +02:00
|
|
|
#include "gbx_struct.h"
|
2007-12-30 17:41:49 +01:00
|
|
|
#include "gbx_string.h"
|
|
|
|
#include "gbx_object.h"
|
|
|
|
#include "gbx_variant.h"
|
|
|
|
#include "gbx_number.h"
|
|
|
|
#include "gbx_c_array.h"
|
|
|
|
|
|
|
|
#include "gambas.h"
|
|
|
|
|
|
|
|
#include "gbx_class.h"
|
|
|
|
|
|
|
|
//#define DEBUG_COMP 1
|
|
|
|
//#define DEBUG_LOAD 1
|
|
|
|
//#define DEBUG_DESC 1
|
|
|
|
|
|
|
|
/* Global class table */
|
|
|
|
static TABLE _global_table;
|
|
|
|
/* List of all classes */
|
|
|
|
static CLASS *_classes = NULL;
|
|
|
|
/* First created class (must be 'Class' class) */
|
|
|
|
static CLASS *_first = NULL;
|
|
|
|
/* This flag forces CLASS_find() to only register in the global table */
|
|
|
|
static bool _global = FALSE;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
static CLASS *Class;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
void CLASS_init(void)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
TABLE_create_static(&_global_table, sizeof(CLASS_SYMBOL), TF_IGNORE_CASE);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
CLASS_init_native();
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TABLE *CLASS_get_table(void)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
return &_global_table;
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void exit_class(CLASS *class, bool native)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
//CLASS_DESC *desc;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
/*if (!class->ready && !CLASS_is_virtual(class))
|
|
|
|
printf("WARNING: class %s was never loaded.\n", class->name);*/
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
#if DEBUG_LOAD
|
|
|
|
fprintf(stderr, "Exiting class %s...\n", class->name);
|
|
|
|
#endif
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
/* Est-ce que _exit marche pour les classes gambas ? */
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
if (CLASS_is_native(class) != native)
|
|
|
|
return;
|
2010-09-14 15:01:47 +02:00
|
|
|
|
|
|
|
if (class->state < CS_LOADED)
|
|
|
|
return;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
EXEC_public(class, NULL, "_exit", 0);
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void unload_class(CLASS *class)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
#if DEBUG_LOAD
|
|
|
|
fprintf(stderr, "Unloading class %s...\n", class->name);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (class->free_name)
|
|
|
|
FREE(&class->name, "unload_class");
|
|
|
|
|
2010-05-23 13:07:14 +02:00
|
|
|
if (class->is_struct)
|
|
|
|
{
|
|
|
|
FREE(&class->load->dyn, "unload_class");
|
|
|
|
if (class->debug)
|
|
|
|
FREE(&class->load->global, "unload_class");
|
|
|
|
FREE(&class->load, "unload_class");
|
|
|
|
FREE(&class->data, "unload_class");
|
|
|
|
}
|
|
|
|
else if (!CLASS_is_native(class))
|
2009-01-01 14:42:17 +01:00
|
|
|
{
|
|
|
|
#ifdef OS_64BITS
|
|
|
|
|
2009-02-02 15:53:45 +01:00
|
|
|
if (class->load)
|
2009-01-01 14:42:17 +01:00
|
|
|
{
|
2009-02-02 15:53:45 +01:00
|
|
|
FREE(&class->load->desc, "unload_class");
|
|
|
|
FREE(&class->load->cst, "unload_class");
|
|
|
|
FREE(&class->load->class_ref, "unload_class");
|
|
|
|
FREE(&class->load->unknown, "unload_class");
|
|
|
|
FREE(&class->load->event, "unload_class");
|
|
|
|
FREE(&class->load->ext, "unload_class");
|
|
|
|
FREE(&class->load->local, "unload_class");
|
|
|
|
FREE(&class->load->array, "unload_class");
|
2009-01-01 14:42:17 +01:00
|
|
|
|
2009-02-02 15:53:45 +01:00
|
|
|
if (class->debug)
|
2008-01-17 22:39:26 +01:00
|
|
|
{
|
2009-02-02 15:53:45 +01:00
|
|
|
int i;
|
|
|
|
FUNCTION *func;
|
|
|
|
|
|
|
|
for (i = 0; i < class->load->n_func; i++)
|
|
|
|
{
|
|
|
|
func = &class->load->func[i];
|
|
|
|
FREE(&func->debug->local, "unload_class");
|
|
|
|
}
|
|
|
|
|
|
|
|
FREE(&class->load->global, "unload_class");
|
|
|
|
FREE(&class->load->debug, "unload_class");
|
2008-01-17 22:39:26 +01:00
|
|
|
}
|
|
|
|
|
2009-02-02 15:53:45 +01:00
|
|
|
FREE(&class->load->func, "unload_class");
|
2009-01-01 14:42:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
FREE(&class->load, "unload_class");
|
|
|
|
if (!class->mmapped)
|
|
|
|
FREE(&class->data, "unload_class");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-04-26 11:36:47 +02:00
|
|
|
FREE(&class->signature, "unload_class");
|
|
|
|
FREE(&class->data, "unload_class");
|
2009-01-01 14:42:17 +01:00
|
|
|
}
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
if (class->free_event)
|
|
|
|
FREE(&class->event, "unload_class");
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2010-04-26 11:36:47 +02:00
|
|
|
FREE(&class->stat, "unload_class");
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2010-04-26 11:36:47 +02:00
|
|
|
FREE(&class->table, "unload_class");
|
2010-05-27 15:51:09 +02:00
|
|
|
FREE(&class->sort, "unload_class");
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
class->state = CS_NULL;
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
2010-04-26 11:36:47 +02:00
|
|
|
static CLASS *class_replace_global(const char *name)
|
|
|
|
{
|
|
|
|
CLASS_SYMBOL *csym;
|
|
|
|
char *new_name;
|
|
|
|
CLASS *class, *parent;
|
|
|
|
CLASS *new_class;
|
|
|
|
int len;
|
2010-05-25 13:19:00 +02:00
|
|
|
int index;
|
2010-04-26 11:36:47 +02:00
|
|
|
|
|
|
|
class = CLASS_find_global(name);
|
|
|
|
if (class->state)
|
|
|
|
{
|
|
|
|
len = strlen(name);
|
|
|
|
|
|
|
|
ALLOC(&new_name, len + 2, "class_replace_global");
|
|
|
|
snprintf(new_name, len + 2, ">%s", name);
|
|
|
|
new_class = class_replace_global(new_name);
|
|
|
|
FREE(&new_name, "class_replace_global");
|
|
|
|
|
|
|
|
new_name = (char *)new_class->name;
|
|
|
|
|
2010-12-05 21:17:24 +01:00
|
|
|
if (TABLE_find_symbol(&_global_table, name, len, &index))
|
|
|
|
{
|
|
|
|
csym = (CLASS_SYMBOL *)TABLE_get_symbol(&_global_table, index);
|
|
|
|
csym->class = new_class;
|
|
|
|
}
|
2010-04-26 11:36:47 +02:00
|
|
|
|
2010-12-05 21:17:24 +01:00
|
|
|
if (TABLE_find_symbol(&_global_table, new_name, len + 1, &index))
|
|
|
|
{
|
|
|
|
csym = (CLASS_SYMBOL *)TABLE_get_symbol(&_global_table, index);
|
|
|
|
csym->class = class;
|
|
|
|
}
|
2010-04-26 11:36:47 +02:00
|
|
|
|
|
|
|
new_class->name = class->name;
|
|
|
|
class->name = new_name;
|
|
|
|
|
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
class->override = new_class;
|
|
|
|
parent = class->parent;
|
|
|
|
if (!parent || parent->override != class)
|
|
|
|
break;
|
|
|
|
class = parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
class = new_class;
|
|
|
|
}
|
|
|
|
|
|
|
|
return class;
|
|
|
|
}
|
|
|
|
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2008-07-16 12:12:13 +02:00
|
|
|
void CLASS_clean_up(bool silent)
|
2007-12-30 17:41:49 +01:00
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
int n, nc, nb;
|
|
|
|
//CLASS_SYMBOL *csym;
|
|
|
|
CLASS *class;
|
|
|
|
|
|
|
|
#if DEBUG_LOAD
|
|
|
|
fprintf(stderr, "\n------------------- CLASS_exit -------------------\n\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if DEBUG_LOAD
|
|
|
|
fprintf(stderr, "Freeing auto-creatable objects...\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Count how many classes should be freed
|
|
|
|
// And free automatic instances
|
|
|
|
|
|
|
|
nc = 0;
|
|
|
|
|
|
|
|
for (class = _classes; class; class = class->next)
|
|
|
|
{
|
|
|
|
if (class->instance)
|
|
|
|
OBJECT_UNREF(class->instance, "CLASS_exit");
|
|
|
|
if (!CLASS_is_native(class) && class->state)
|
|
|
|
{
|
|
|
|
/*printf("Must free: %s\n", class->name);*/
|
|
|
|
nc++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if DEBUG_LOAD
|
|
|
|
fprintf(stderr, "Calling _exit on loaded classes...\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (class = _classes; class; class = class->next)
|
|
|
|
exit_class(class, FALSE);
|
|
|
|
|
|
|
|
#if DEBUG_LOAD
|
|
|
|
fprintf(stderr, "Freeing classes with no instance...\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Free classes having no instance
|
|
|
|
|
|
|
|
n = 0;
|
|
|
|
while (n < nc)
|
|
|
|
{
|
|
|
|
nb = n;
|
|
|
|
|
|
|
|
for (class = _classes; class; class = class->next)
|
|
|
|
{
|
|
|
|
/*if (!CLASS_is_native(class) && class->ready && !class->exit)
|
|
|
|
printf("%s: %d ready = %d\n", class->name, class->count, class->ready);*/
|
|
|
|
|
|
|
|
if (class->count == 0 && !CLASS_is_native(class) && class->state && !class->exit)
|
|
|
|
{
|
|
|
|
/*printf("Freeing %s\n", class->name);*/
|
2010-03-12 02:18:20 +01:00
|
|
|
#if DEBUG_LOAD
|
|
|
|
fprintf(stderr, "Freeing %s\n", class->name);
|
|
|
|
#endif
|
2009-01-01 14:42:17 +01:00
|
|
|
OBJECT_release(class, NULL);
|
|
|
|
class->exit = TRUE;
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (n == nb) /* On n'a rien pu faire */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if DEBUG_LOAD
|
|
|
|
fprintf(stderr, "Freeing other classes...\n");
|
|
|
|
#endif
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2008-07-16 12:12:13 +02:00
|
|
|
// Remaining objects are circular references
|
|
|
|
// Everything is forced to be freed
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
if (n < nc)
|
|
|
|
{
|
|
|
|
if (!silent)
|
2010-12-21 15:05:42 +01:00
|
|
|
ERROR_warning("circular references detected:");
|
2009-01-01 14:42:17 +01:00
|
|
|
for (class = _classes; class; class = class->next)
|
|
|
|
{
|
|
|
|
if (!CLASS_is_native(class) && class->state && !class->exit)
|
|
|
|
{
|
|
|
|
if (!silent)
|
2011-02-08 02:35:04 +01:00
|
|
|
fprintf(stderr, "gbx" GAMBAS_VERSION_STRING ": % 5d %s\n", class->count, class->name);
|
2009-01-01 14:42:17 +01:00
|
|
|
OBJECT_release(class, NULL);
|
|
|
|
class->exit = TRUE;
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#if DEBUG_LOAD
|
|
|
|
fprintf(stderr, "Calling _exit on native classes...\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (class = _classes; class; class = class->next)
|
|
|
|
exit_class(class, TRUE);
|
2008-07-16 12:12:13 +02:00
|
|
|
}
|
|
|
|
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2008-07-16 12:12:13 +02:00
|
|
|
void CLASS_exit()
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
CLASS *class, *next;
|
|
|
|
|
|
|
|
#if DEBUG_LOAD
|
|
|
|
fprintf(stderr, "Unloading classes...\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (class = _classes; class; class = class->next)
|
|
|
|
unload_class(class);
|
|
|
|
|
|
|
|
#if DEBUG_LOAD
|
|
|
|
fprintf(stderr, "Destroying classes...\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
class = _classes;
|
|
|
|
while (class)
|
|
|
|
{
|
|
|
|
next = class->next;
|
|
|
|
FREE(&class, "CLASS_exit");
|
|
|
|
class = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
TABLE_delete_static(&_global_table);
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CLASS *CLASS_look(const char *name, int len)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
CLASS_SYMBOL *csym;
|
|
|
|
ARCHIVE *arch = NULL;
|
2007-12-30 17:41:49 +01:00
|
|
|
int index;
|
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
#if DEBUG_COMP
|
|
|
|
fprintf(stderr, "CLASS_look: %s in %s\n", name, _global ? "global" : "local");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//if (CP && CP->component && CP->component->archive)
|
|
|
|
if (!_global && !ARCHIVE_get_current(&arch))
|
|
|
|
{
|
2010-05-25 13:19:00 +02:00
|
|
|
if (TABLE_find_symbol(arch->classes, name, len, &index))
|
2009-01-01 14:42:17 +01:00
|
|
|
{
|
|
|
|
#if DEBUG_COMP
|
|
|
|
fprintf(stderr, " -> in %s\n", arch->name ? arch->name : "main");
|
|
|
|
#endif
|
2010-05-25 13:19:00 +02:00
|
|
|
csym = (CLASS_SYMBOL *)TABLE_get_symbol(arch->classes, index);
|
2009-01-01 14:42:17 +01:00
|
|
|
return csym->class;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-25 13:19:00 +02:00
|
|
|
if (TABLE_find_symbol(&_global_table, name, len, &index))
|
2009-01-01 14:42:17 +01:00
|
|
|
{
|
|
|
|
#if DEBUG_COMP
|
|
|
|
fprintf(stderr, " -> %d in global\n", index);
|
|
|
|
#endif
|
2010-05-25 13:19:00 +02:00
|
|
|
csym = (CLASS_SYMBOL *)TABLE_get_symbol(&_global_table, index);
|
2009-01-01 14:42:17 +01:00
|
|
|
return csym->class;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#if DEBUG_COMP
|
|
|
|
fprintf(stderr, " -> ?\n");
|
|
|
|
#endif
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
CLASS *CLASS_find(const char *name)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
CLASS_SYMBOL *csym;
|
|
|
|
CLASS *class;
|
|
|
|
int index;
|
|
|
|
int len;
|
|
|
|
ARCHIVE *arch = NULL;
|
|
|
|
bool global;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
if (name == NULL)
|
|
|
|
name = COMMON_buffer;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
len = strlen(name);
|
|
|
|
|
|
|
|
#if DEBUG_LOAD
|
2009-01-01 14:42:17 +01:00
|
|
|
fprintf(stderr, "CLASS_find: %s (%d)\n", name, _global);
|
2007-12-30 17:41:49 +01:00
|
|
|
#endif
|
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
class = CLASS_look(name, len);
|
|
|
|
if (class)
|
|
|
|
return class;
|
|
|
|
|
|
|
|
//if (CP && CP->component && CP->component->archive)
|
|
|
|
if (!_global && !ARCHIVE_get_current(&arch))
|
|
|
|
{
|
|
|
|
global = FALSE;
|
2010-05-25 13:19:00 +02:00
|
|
|
TABLE_add_symbol(arch->classes, name, len, &index);
|
2009-01-01 14:42:17 +01:00
|
|
|
#if DEBUG_LOAD || DEBUG_COMP
|
|
|
|
fprintf(stderr, "Not found -> creating new one in %s\n", arch->name ? arch->name : "main");
|
|
|
|
#endif
|
2010-05-25 13:19:00 +02:00
|
|
|
csym = (CLASS_SYMBOL *)TABLE_get_symbol(arch->classes, index);
|
2009-01-01 14:42:17 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
global = TRUE;
|
2010-05-25 13:19:00 +02:00
|
|
|
TABLE_add_symbol(&_global_table, name, len, &index);
|
2009-01-01 14:42:17 +01:00
|
|
|
#if DEBUG_LOAD || DEBUG_COMP
|
|
|
|
fprintf(stderr, "Not found -> creating new one in global\n");
|
|
|
|
#endif
|
2010-05-25 13:19:00 +02:00
|
|
|
csym = (CLASS_SYMBOL *)TABLE_get_symbol(&_global_table, index);
|
2009-01-01 14:42:17 +01:00
|
|
|
}
|
|
|
|
|
2009-02-02 14:04:04 +01:00
|
|
|
ALLOC_ZERO(&class, sizeof(CLASS), "CLASS_find");
|
2009-01-01 14:42:17 +01:00
|
|
|
csym->class = class;
|
2010-04-26 11:36:47 +02:00
|
|
|
//class->state = CS_NULL;
|
|
|
|
//class->count = 0;
|
2009-01-01 14:42:17 +01:00
|
|
|
class->ref = 1;
|
|
|
|
|
|
|
|
class->next = _classes;
|
|
|
|
_classes = class;
|
|
|
|
|
|
|
|
ALLOC(&class->name, len + 1, "CLASS_find");
|
|
|
|
strcpy((char *)class->name, name);
|
|
|
|
|
|
|
|
csym->sym.name = class->name;
|
|
|
|
|
|
|
|
class->free_name = TRUE;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2008-09-22 01:22:07 +02:00
|
|
|
// The first class must be the Class class!
|
2009-01-01 14:42:17 +01:00
|
|
|
if (_first == NULL)
|
|
|
|
_first = class;
|
|
|
|
class->class = _first;
|
|
|
|
|
|
|
|
class->global = global;
|
|
|
|
|
|
|
|
return class;
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int CLASS_count(void)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
return TABLE_count(&_global_table);
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CLASS *CLASS_get(const char *name)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
CLASS *class = CLASS_find(name);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
if (class->state == CS_NULL)
|
|
|
|
CLASS_load(class);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
return class;
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CLASS *CLASS_look_global(const char *name, int len)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
CLASS *class;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
_global = TRUE;
|
|
|
|
class = CLASS_look(name, len);
|
|
|
|
_global = FALSE;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
return class;
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CLASS *CLASS_find_global(const char *name)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
CLASS *class;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
_global = TRUE;
|
|
|
|
class = CLASS_find(name);
|
|
|
|
_global = FALSE;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
return class;
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-07-08 21:57:50 +02:00
|
|
|
bool CLASS_inherits(CLASS *class, CLASS *parent)
|
2007-12-30 17:41:49 +01:00
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
class = class->parent;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
if (class == NULL)
|
|
|
|
return FALSE;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
if (class == parent)
|
|
|
|
return TRUE;
|
|
|
|
}
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CLASS_find_symbol_with_prefix(CLASS *class, const char *name, const char *prefix)
|
|
|
|
{
|
2010-06-05 01:48:53 +02:00
|
|
|
return SYMBOL_find(class->table, class->sort, class->n_desc, sizeof(CLASS_DESC_SYMBOL), TF_IGNORE_CASE, name, strlen(name), prefix);
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CLASS_DESC_SYMBOL *CLASS_get_symbol(CLASS *class, const char *name)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
int index;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
index = CLASS_find_symbol(class, name);
|
|
|
|
if (index == NO_SYMBOL)
|
|
|
|
return NULL;
|
|
|
|
else
|
|
|
|
return &class->table[index];
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CLASS_DESC *CLASS_get_symbol_desc(CLASS *class, const char *name)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
CLASS_DESC_SYMBOL *cds = CLASS_get_symbol(class, name);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
if (cds == NULL)
|
|
|
|
return NULL;
|
|
|
|
else
|
|
|
|
return cds->desc;
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
short CLASS_get_symbol_index_kind(CLASS *class, const char *name, int kind, int kind2)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
CLASS_DESC *desc;
|
|
|
|
int index;
|
|
|
|
|
|
|
|
index = CLASS_find_symbol(class, name);
|
|
|
|
if (index != NO_SYMBOL)
|
|
|
|
{
|
|
|
|
desc = CLASS_get_desc(class, index);
|
|
|
|
if (desc)
|
|
|
|
if ((CLASS_DESC_get_type(desc) == kind) || (CLASS_DESC_get_type(desc) == kind2))
|
|
|
|
return (short)index;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (short)NO_SYMBOL;
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CLASS_DESC *CLASS_get_symbol_desc_kind(CLASS *class, const char *name, int kind, int kind2)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
short index;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
index = CLASS_get_symbol_index_kind(class, name, kind, kind2);
|
|
|
|
if (index == NO_SYMBOL)
|
|
|
|
return NULL;
|
|
|
|
else
|
|
|
|
return CLASS_get_desc(class, index);
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CLASS_DESC_EVENT *CLASS_get_event_desc(CLASS *class, const char *name)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
int index;
|
|
|
|
CLASS_DESC *cd;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
index = CLASS_find_symbol_with_prefix(class, name, ":");
|
|
|
|
if (index == NO_SYMBOL)
|
|
|
|
return NULL;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
cd = class->table[index].desc;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
if (CLASS_DESC_get_type(cd) != CD_EVENT)
|
|
|
|
return NULL;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
return &cd->event;
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-07-19 14:33:57 +02:00
|
|
|
char *CLASS_DESC_get_signature(CLASS_DESC *cd)
|
2007-12-30 17:41:49 +01:00
|
|
|
{
|
2010-07-19 14:33:57 +02:00
|
|
|
char *res = NULL;
|
|
|
|
TYPE *sign;
|
|
|
|
int i, n;
|
|
|
|
TYPE type;
|
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
switch (CLASS_DESC_get_type(cd))
|
|
|
|
{
|
|
|
|
case CD_METHOD:
|
|
|
|
case CD_STATIC_METHOD:
|
2010-07-19 14:33:57 +02:00
|
|
|
|
|
|
|
sign = cd->method.signature;
|
|
|
|
n = cd->method.npmax;
|
|
|
|
break;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
case CD_EVENT:
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2010-07-19 14:33:57 +02:00
|
|
|
sign = cd->event.signature;
|
|
|
|
n = cd->event.npmax;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CD_EXTERN:
|
|
|
|
|
|
|
|
sign = cd->ext.signature;
|
|
|
|
n = cd->ext.npmax;
|
|
|
|
break;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
default:
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
2010-07-19 14:33:57 +02:00
|
|
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
type = sign[i];
|
2011-09-07 14:38:29 +02:00
|
|
|
res = STRING_add(res, TYPE_to_string(type), 0);
|
2010-07-19 14:33:57 +02:00
|
|
|
if (TYPE_is_object(type))
|
2011-09-07 14:38:29 +02:00
|
|
|
res = STRING_add_char(res, ';');
|
2010-07-19 14:33:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
2010-06-18 02:14:53 +02:00
|
|
|
// The _free method can be called during a conversion, so we must save the EXEC structure
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2012-02-25 04:16:08 +01:00
|
|
|
static void *_CLASS_free_object;
|
|
|
|
static EXEC_GLOBAL *_CLASS_free_exec;
|
|
|
|
|
|
|
|
static void error_CLASS_free()
|
|
|
|
{
|
|
|
|
void *object = _CLASS_free_object;
|
|
|
|
((OBJECT *)object)->ref = 0;
|
|
|
|
OBJECT_release(OBJECT_class(object), object);
|
|
|
|
EXEC = *_CLASS_free_exec;
|
|
|
|
}
|
|
|
|
|
2008-08-14 21:42:27 +02:00
|
|
|
void CLASS_free(void *object)
|
2007-12-30 17:41:49 +01:00
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
CLASS *class = OBJECT_class(object);
|
2010-06-18 02:14:53 +02:00
|
|
|
EXEC_GLOBAL save = EXEC;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2012-02-25 04:16:08 +01:00
|
|
|
void *save_object = _CLASS_free_object;
|
|
|
|
void *save_exec = _CLASS_free_exec;
|
2010-03-12 02:18:20 +01:00
|
|
|
|
2012-02-25 04:16:08 +01:00
|
|
|
_CLASS_free_object = object;
|
|
|
|
_CLASS_free_exec = &save;
|
2010-06-18 02:14:53 +02:00
|
|
|
|
2012-02-25 04:16:08 +01:00
|
|
|
ON_ERROR(error_CLASS_free)
|
|
|
|
{
|
|
|
|
((OBJECT *)object)->ref = 1; /* Prevents anybody from freeing the object ! */
|
|
|
|
EXEC_special_inheritance(SPEC_FREE, class, object, 0, TRUE);
|
|
|
|
((OBJECT *)object)->ref = 0;
|
|
|
|
EXEC = save;
|
|
|
|
OBJECT_release(class, object);
|
|
|
|
}
|
|
|
|
END_ERROR
|
|
|
|
|
|
|
|
_CLASS_free_object = save_object;
|
|
|
|
_CLASS_free_exec = save_exec;
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#if DEBUG_REF
|
|
|
|
void CLASS_ref(void *object)
|
|
|
|
{
|
2010-07-21 13:45:28 +02:00
|
|
|
char *name;
|
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
((OBJECT *)object)->ref++;
|
2010-05-27 00:01:28 +02:00
|
|
|
|
2010-07-21 13:45:28 +02:00
|
|
|
if (OBJECT_class(object) == FREE_MARK)
|
|
|
|
name = "*ALREADY FREED*";
|
|
|
|
else
|
|
|
|
name = OBJECT_class(object)->name;
|
|
|
|
|
2009-06-16 02:17:25 +02:00
|
|
|
#if DEBUG_MEMORY
|
2010-07-21 13:45:28 +02:00
|
|
|
fprintf(stderr, "%s: %s: ref(%s <%d>) -> %ld\n", OBJECT_ref_where,
|
2009-06-16 02:17:25 +02:00
|
|
|
DEBUG_get_current_position(),
|
2010-07-21 13:45:28 +02:00
|
|
|
name, GET_ALLOC_ID(object), ((OBJECT *)object)->ref);
|
2009-06-16 02:17:25 +02:00
|
|
|
#else
|
2010-07-21 13:45:28 +02:00
|
|
|
fprintf(stderr, "%s: %s: ref(%s %p) -> %ld\n", OBJECT_ref_where,
|
2009-01-01 14:42:17 +01:00
|
|
|
DEBUG_get_current_position(),
|
2010-07-21 13:45:28 +02:00
|
|
|
name, object, ((OBJECT *)object)->ref);
|
2009-06-16 02:17:25 +02:00
|
|
|
#endif
|
2009-01-01 14:42:17 +01:00
|
|
|
fflush(stdout);
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
2009-07-08 21:57:50 +02:00
|
|
|
bool CLASS_unref(void *ob, bool can_free)
|
2007-12-30 17:41:49 +01:00
|
|
|
{
|
2010-07-21 13:45:28 +02:00
|
|
|
char *name;
|
|
|
|
|
2008-09-22 01:22:07 +02:00
|
|
|
OBJECT *object = (OBJECT *)ob;
|
|
|
|
|
2010-07-21 13:45:28 +02:00
|
|
|
if (OBJECT_class(object) == FREE_MARK)
|
|
|
|
name = "*ALREADY FREED*";
|
|
|
|
else
|
|
|
|
name = OBJECT_class(object)->name;
|
2010-05-27 00:01:28 +02:00
|
|
|
|
2009-06-16 02:17:25 +02:00
|
|
|
#if DEBUG_MEMORY
|
|
|
|
if (object->ref <= 0)
|
2010-07-21 13:45:28 +02:00
|
|
|
fprintf(stderr, "*** <%d> REF = %ld !\n", GET_ALLOC_ID(object), object->ref);
|
2009-06-16 02:17:25 +02:00
|
|
|
|
2010-07-21 13:45:28 +02:00
|
|
|
fprintf(stderr, "%s: %s: unref(%s <%d>) -> %ld\n", OBJECT_ref_where,
|
2009-06-16 02:17:25 +02:00
|
|
|
DEBUG_get_current_position(),
|
2010-07-21 13:45:28 +02:00
|
|
|
name, GET_ALLOC_ID(object), object->ref - 1);
|
2009-06-16 02:17:25 +02:00
|
|
|
#else
|
2009-01-01 14:42:17 +01:00
|
|
|
if (object->ref <= 0)
|
|
|
|
fprintf(stderr, "*** %p REF = %d !\n", object, object->ref);
|
|
|
|
|
2010-07-21 13:45:28 +02:00
|
|
|
fprintf(stderr, "%s, %s: unref(%s %p) -> %ld\n", OBJECT_ref_where,
|
2009-01-01 14:42:17 +01:00
|
|
|
DEBUG_get_current_position(),
|
2010-07-21 13:45:28 +02:00
|
|
|
name, object, object->ref - 1);
|
2009-06-16 02:17:25 +02:00
|
|
|
#endif
|
2009-01-01 14:42:17 +01:00
|
|
|
fflush(stdout);
|
|
|
|
|
|
|
|
/*if (strcmp(OBJECT_class(object)->name, "Class") == 0)
|
|
|
|
fprintf(stderr, "Class ?\n");*/
|
|
|
|
|
|
|
|
if ((--(object->ref) <= 0) && can_free)
|
|
|
|
{
|
2009-06-16 02:17:25 +02:00
|
|
|
#if DEBUG_MEMORY
|
|
|
|
fprintf(stderr, "FREE <%d> !\n", GET_ALLOC_ID(object));
|
|
|
|
#else
|
2009-01-01 14:42:17 +01:00
|
|
|
fprintf(stderr, "FREE %p !\n", object);
|
2009-06-16 02:17:25 +02:00
|
|
|
#endif
|
2009-01-01 14:42:17 +01:00
|
|
|
CLASS_free(object);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void CLASS_do_nothing()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
int CLASS_return_zero()
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
return 0;
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
2011-08-07 21:48:08 +02:00
|
|
|
static CLASS *_sorted_class;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2010-06-09 01:08:04 +02:00
|
|
|
static int partition(CLASS_DESC_SYMBOL *cds, ushort *sym, const int start, const int end)
|
2007-12-30 17:41:49 +01:00
|
|
|
{
|
2010-06-09 01:08:04 +02:00
|
|
|
int pos = start;
|
|
|
|
short pivot = sym[start];
|
|
|
|
int i;
|
|
|
|
ushort val;
|
|
|
|
int len;
|
|
|
|
const char *s1, *s2;
|
2010-05-27 15:51:09 +02:00
|
|
|
int result;
|
|
|
|
|
2010-06-09 01:08:04 +02:00
|
|
|
for (i = start + 1; i <= end; i++)
|
|
|
|
{
|
|
|
|
len = cds[sym[i]].len;
|
|
|
|
result = len - cds[pivot].len;
|
2010-05-27 15:51:09 +02:00
|
|
|
|
2010-06-09 01:08:04 +02:00
|
|
|
if (result > 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (result == 0)
|
|
|
|
{
|
|
|
|
s1 = cds[sym[i]].name;
|
|
|
|
s2 = cds[pivot].name;
|
2010-05-27 15:51:09 +02:00
|
|
|
|
2010-06-09 01:08:04 +02:00
|
|
|
while (len)
|
|
|
|
{
|
|
|
|
result = tolower(*s1++) - tolower(*s2++);
|
|
|
|
if (result)
|
|
|
|
break;
|
|
|
|
len--;
|
|
|
|
}
|
|
|
|
|
2011-08-07 21:48:08 +02:00
|
|
|
if (result == 0)
|
|
|
|
{
|
|
|
|
if (*cds[pivot].name != '.')
|
|
|
|
ERROR_panic("Symbol '%s' declared twice in class '%s'\n", cds[sym[i]].name, _sorted_class->name);
|
|
|
|
}
|
2010-06-09 01:08:04 +02:00
|
|
|
if (result >= 0)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
pos++; // incrémente compteur cad la place finale du pivot
|
|
|
|
//echanger(tableau, compteur, i); // élément positionné
|
|
|
|
val = sym[pos];
|
|
|
|
sym[pos] = sym[i];
|
|
|
|
sym[i] = val;
|
2010-05-27 15:51:09 +02:00
|
|
|
}
|
|
|
|
|
2010-06-09 01:08:04 +02:00
|
|
|
//echanger(tableau, compteur, debut); // le pivot est placé
|
|
|
|
val = sym[pos];
|
|
|
|
sym[pos] = sym[start];
|
|
|
|
sym[start] = val;
|
|
|
|
|
|
|
|
return pos; // et sa position est retournée
|
|
|
|
}
|
|
|
|
|
|
|
|
static void my_qsort(CLASS_DESC_SYMBOL *cds, ushort *sym, const int start, const int end)
|
|
|
|
{
|
|
|
|
if (start < end) // cas d'arrêt pour la récursivité
|
|
|
|
{
|
|
|
|
int pivot = partition(cds, sym, start, end); // division du tableau
|
|
|
|
my_qsort(cds, sym, start, pivot - 1); // trie partie1
|
|
|
|
my_qsort(cds, sym, pivot + 1, end); // trie partie2
|
|
|
|
}
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CLASS_sort(CLASS *class)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
ushort *sym;
|
|
|
|
ushort i;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2010-04-26 11:36:47 +02:00
|
|
|
if (!class->n_desc)
|
2009-01-01 14:42:17 +01:00
|
|
|
return;
|
2010-04-26 11:36:47 +02:00
|
|
|
|
2011-08-07 21:48:08 +02:00
|
|
|
_sorted_class = class;
|
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
ALLOC(&sym, sizeof(ushort) * class->n_desc, "CLASS_sort");
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
for (i = 0; i < class->n_desc; i++)
|
|
|
|
sym[i] = i;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2010-06-09 01:08:04 +02:00
|
|
|
//qsort(sym, class->n_desc, sizeof(ushort), (int (*)(const void *, const void *))sort_desc);
|
|
|
|
my_qsort(class->table, sym, 0, class->n_desc - 1);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2010-05-27 15:51:09 +02:00
|
|
|
class->sort = sym;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
#if DEBUG_DESC
|
|
|
|
{
|
2010-06-09 01:08:04 +02:00
|
|
|
SYMBOL *s;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
fprintf(stderr, "\nSORT %s\n", class->name);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
for (i = 0; i < class->n_desc; i++)
|
|
|
|
{
|
2010-06-09 01:08:04 +02:00
|
|
|
s = (SYMBOL *)&class->table[sym[i]];
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2010-06-09 01:08:04 +02:00
|
|
|
fprintf(stderr, "[%d] %.*s\n", i, (int)s->len, s->name);
|
2009-01-01 14:42:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CLASS_inheritance(CLASS *class, CLASS *parent)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
if (class->parent != NULL)
|
|
|
|
THROW(E_CLASS, class->name, "Multiple inheritance", "");
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
class->parent = parent;
|
2012-01-15 09:54:57 +01:00
|
|
|
parent->has_child = TRUE;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
TRY
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
CLASS_load(class->parent);
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
CATCH
|
|
|
|
{
|
2011-08-20 03:31:42 +02:00
|
|
|
THROW(E_CLASS, class->name, "Cannot load parent class: ", STRING_new_temp_zero(ERROR_current->info.msg));
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
END_TRY
|
|
|
|
|
2010-08-02 21:36:37 +02:00
|
|
|
if (!class->check)
|
|
|
|
{
|
|
|
|
class->check = class->parent->check;
|
|
|
|
class->must_check = class->parent->must_check;
|
|
|
|
}
|
2007-12-30 17:41:49 +01:00
|
|
|
// CREATE STATIC is inherited, but not CREATE PRIVATE
|
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
if (parent->auto_create)
|
|
|
|
class->auto_create = TRUE;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2010-07-29 12:19:10 +02:00
|
|
|
if (!class->array_type)
|
|
|
|
class->array_type = parent->array_type;
|
|
|
|
|
2007-12-30 17:41:49 +01:00
|
|
|
//fprintf(stderr, "CLASS_inheritance: %s %s\n", class->name, class->auto_create ? "AUTO CREATE" : "");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-08-20 02:33:36 +02:00
|
|
|
const char *CLASS_DESC_get_type_name(const CLASS_DESC *desc)
|
2008-07-18 01:45:32 +02:00
|
|
|
{
|
|
|
|
switch (desc->gambas.val4)
|
|
|
|
{
|
2009-02-02 15:53:45 +01:00
|
|
|
case CD_PROPERTY_ID: return desc->gambas.val2 < 0 ? "r" : "p";
|
2008-07-18 01:45:32 +02:00
|
|
|
case CD_VARIABLE_ID: return "v";
|
|
|
|
case CD_METHOD_ID: return "m";
|
2009-02-02 15:53:45 +01:00
|
|
|
case CD_STATIC_PROPERTY_ID: return desc->gambas.val2 < 0 ? "R" : "P";
|
2008-07-18 01:45:32 +02:00
|
|
|
case CD_STATIC_VARIABLE_ID: return "V";
|
|
|
|
case CD_STATIC_METHOD_ID: return "M";
|
|
|
|
case CD_CONSTANT_ID: return "C";
|
|
|
|
case CD_EVENT_ID: return ":";
|
|
|
|
case CD_EXTERN_ID: return "X";
|
2011-08-20 02:33:36 +02:00
|
|
|
default:
|
2011-11-06 01:26:37 +01:00
|
|
|
//fprintf(stderr, "CLASS_DESC_get_type_name: %s: %ld\n", desc->gambas.name, desc->gambas.val4);
|
2011-08-20 02:33:36 +02:00
|
|
|
return "?";
|
2008-07-18 01:45:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-20 02:33:36 +02:00
|
|
|
static bool check_signature(char type, const CLASS_DESC *desc, const CLASS_DESC *pdesc)
|
2009-01-01 14:42:17 +01:00
|
|
|
{
|
2011-08-31 01:50:38 +02:00
|
|
|
TYPE *sd, *sp;
|
|
|
|
int nsd, nsp;
|
2011-08-20 02:33:36 +02:00
|
|
|
|
|
|
|
if (desc->property.type != pdesc->property.type)
|
|
|
|
{
|
|
|
|
//fprintf(stderr, "type! %ld / %ld\n", desc->property.type, pdesc->property.type);
|
|
|
|
return TRUE;
|
|
|
|
}
|
2011-08-31 01:50:38 +02:00
|
|
|
//else
|
|
|
|
// return FALSE;
|
2009-01-01 14:42:17 +01:00
|
|
|
|
2011-08-20 02:33:36 +02:00
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case CD_METHOD:
|
|
|
|
case CD_STATIC_METHOD:
|
|
|
|
|
|
|
|
sd = desc->method.signature;
|
|
|
|
nsd = desc->method.npmax;
|
|
|
|
sp = pdesc->method.signature;
|
|
|
|
nsp = pdesc->method.npmax;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CD_EVENT:
|
|
|
|
|
|
|
|
sd = desc->event.signature;
|
|
|
|
nsd = desc->event.npmax;
|
|
|
|
sp = pdesc->event.signature;
|
|
|
|
nsp = pdesc->event.npmax;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CD_EXTERN:
|
|
|
|
|
|
|
|
sd = desc->ext.signature;
|
|
|
|
nsd = desc->ext.npmax;
|
|
|
|
sp = pdesc->ext.signature;
|
|
|
|
nsp = pdesc->ext.npmax;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TYPE_compare_signature(sd, nsd, sp, nsp))
|
|
|
|
return TRUE;
|
|
|
|
else
|
|
|
|
return FALSE;
|
2009-01-01 14:42:17 +01:00
|
|
|
}
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2011-08-20 02:33:36 +02:00
|
|
|
void CLASS_make_description(CLASS *class, const CLASS_DESC *desc, int n_desc, int *first)
|
2007-12-30 17:41:49 +01:00
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
static const char *nonher[] = { "_new", "_free", "_init", "_exit", NULL };
|
|
|
|
|
|
|
|
int ind;
|
|
|
|
int i, j;
|
|
|
|
const char *name;
|
|
|
|
const char **pnonher;
|
|
|
|
CLASS *parent;
|
|
|
|
char type, parent_type;
|
|
|
|
CLASS_DESC_SYMBOL *cds;
|
2011-11-06 01:26:37 +01:00
|
|
|
bool check;
|
2009-01-01 14:42:17 +01:00
|
|
|
|
2007-12-30 17:41:49 +01:00
|
|
|
#if DEBUG_DESC
|
2009-01-01 14:42:17 +01:00
|
|
|
fprintf(stderr, "\n---- %s\n", class->name);
|
|
|
|
#endif
|
|
|
|
|
2011-08-30 00:57:39 +02:00
|
|
|
// Compute number of public descriptions
|
2009-01-01 14:42:17 +01:00
|
|
|
|
|
|
|
class->n_desc = n_desc;
|
|
|
|
if (class->parent)
|
|
|
|
class->n_desc += class->parent->n_desc;
|
|
|
|
|
2011-08-30 00:57:39 +02:00
|
|
|
// Make the description symbol table
|
2009-01-01 14:42:17 +01:00
|
|
|
|
|
|
|
if (class->n_desc)
|
|
|
|
ALLOC(&class->table, sizeof(CLASS_DESC_SYMBOL) * class->n_desc, "CLASS_make_description");
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
if (class->parent && class->parent->n_desc)
|
|
|
|
{
|
|
|
|
for (j = 0; j < class->parent->n_desc; j++)
|
|
|
|
{
|
|
|
|
class->table[i] = class->parent->table[j];
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j = 0; j < n_desc; j++)
|
|
|
|
{
|
|
|
|
if (CLASS_is_native(class))
|
|
|
|
{
|
|
|
|
name = &(desc[j].gambas.name[1]);
|
|
|
|
type = CLASS_DESC_get_type(&desc[j]);
|
2011-08-20 02:33:36 +02:00
|
|
|
//ptype = (const char*)desc[j].gambas.type;
|
|
|
|
//fprintf(stderr, "%s -> ", ptype);
|
|
|
|
//desc[j].gambas.type = TYPE_from_string(&ptype);
|
|
|
|
//fprintf(stderr, "%p\n", (void *)desc[j].gambas.type);
|
2009-01-01 14:42:17 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
name = desc[j].gambas.name;
|
|
|
|
type = *CLASS_DESC_get_type_name(&desc[j]);
|
|
|
|
}
|
|
|
|
|
|
|
|
//fprintf(stderr, "%s.%s\n", class->name, name);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2010-03-18 07:05:17 +01:00
|
|
|
// An inherited symbol has two or more entries in the table. Only the first one
|
2007-12-30 17:41:49 +01:00
|
|
|
// will be used, and so it must point at the new description, not the inherited one.
|
2011-11-06 01:26:37 +01:00
|
|
|
check = FALSE;
|
2008-04-12 00:36:53 +02:00
|
|
|
parent = class;
|
2008-05-10 17:17:07 +02:00
|
|
|
while ((parent = parent->parent))
|
2007-12-30 17:41:49 +01:00
|
|
|
{
|
2008-04-12 00:36:53 +02:00
|
|
|
ind = CLASS_find_symbol(parent, name);
|
2011-08-20 02:33:36 +02:00
|
|
|
if (ind == NO_SYMBOL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
cds = &parent->table[ind];
|
2009-01-01 14:42:17 +01:00
|
|
|
|
2011-08-20 02:33:36 +02:00
|
|
|
// The parent class public symbols of non-native classes were replaced by the symbol kind returned by CLASS_DESC_get_type_name()
|
2011-11-06 01:26:37 +01:00
|
|
|
// Only the first inheritance level is tested against signature compatibility
|
2011-08-20 02:33:36 +02:00
|
|
|
|
2011-11-06 01:26:37 +01:00
|
|
|
if (cds->desc && !check)
|
2011-08-20 02:33:36 +02:00
|
|
|
{
|
|
|
|
parent_type = CLASS_DESC_get_type(cds->desc);
|
2009-01-01 14:42:17 +01:00
|
|
|
|
2011-08-20 02:33:36 +02:00
|
|
|
if (parent_type != type)
|
2008-04-12 00:36:53 +02:00
|
|
|
{
|
2008-07-18 01:45:32 +02:00
|
|
|
#if DEBUG_DESC
|
2011-08-20 02:33:36 +02:00
|
|
|
fprintf(stderr, "type = '%c' parent_type = '%c'\n", type, parent_type);
|
2008-07-18 01:45:32 +02:00
|
|
|
#endif
|
2011-08-20 02:33:36 +02:00
|
|
|
THROW(E_OVERRIDE, parent->name, cds->name, class->name);
|
2008-04-12 00:36:53 +02:00
|
|
|
}
|
2011-08-20 02:33:36 +02:00
|
|
|
|
2011-11-06 01:26:37 +01:00
|
|
|
if (!CLASS_is_native(class) && strcasecmp(name, "_new"))
|
|
|
|
{
|
|
|
|
//fprintf(stderr, "check_signature: %s\n", name);
|
|
|
|
if (check_signature(type, &desc[j], cds->desc))
|
|
|
|
THROW(E_OVERRIDE, parent->name, cds->name, class->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
check = TRUE;
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
2011-08-20 02:33:36 +02:00
|
|
|
|
|
|
|
cds = &class->table[ind];
|
|
|
|
|
|
|
|
#if DEBUG_DESC
|
|
|
|
fprintf(stderr, "%s: [%d] (%p %ld) := (%p %ld)\n", name, ind, cds->desc, cds->desc ? cds->desc->gambas.val1 : 0, &desc[j], desc[j].gambas.val1);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
cds->desc = (CLASS_DESC *)&desc[j];
|
|
|
|
cds->name = ".";
|
|
|
|
cds->len = 1;
|
|
|
|
|
|
|
|
/*if (!desc[j].gambas.val1 && index(CD_CALL_SOMETHING_LIST, type) != NULL)
|
|
|
|
{
|
|
|
|
//#if DEBUG_DESC
|
|
|
|
fprintf(stderr, "CLASS_make_description: '%s.%s' gambas.val1: %ld -> %ld\n", class->name, desc[j].gambas.name, desc[j].gambas.val1, class->parent->table[ind].desc->gambas.val1);
|
|
|
|
//#endif
|
|
|
|
((CLASS_DESC *)desc)[j].gambas.val1 = class->parent->table[ind].desc->gambas.val1;
|
|
|
|
}*/
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
2009-01-01 14:42:17 +01:00
|
|
|
}
|
2010-04-26 11:36:47 +02:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
for (pnonher = nonher; *pnonher; pnonher++)
|
|
|
|
{
|
|
|
|
ind = CLASS_find_symbol(class->parent, *pnonher);
|
|
|
|
if (ind != NO_SYMBOL)
|
|
|
|
{
|
|
|
|
cds = &class->table[ind];
|
|
|
|
cds->desc = NULL;
|
|
|
|
cds->name = ".";
|
|
|
|
cds->len = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*first = i;
|
|
|
|
|
|
|
|
for (j = 0; j < n_desc; j++, i++)
|
|
|
|
{
|
2011-08-20 02:33:36 +02:00
|
|
|
class->table[i].desc = (CLASS_DESC *)&desc[j];
|
2011-09-08 18:01:36 +02:00
|
|
|
name = desc[j].gambas.name;
|
2009-01-01 14:42:17 +01:00
|
|
|
|
|
|
|
/* On saute le caractère de type de symbole */
|
|
|
|
if (CLASS_is_native(class))
|
2011-09-08 18:01:36 +02:00
|
|
|
{
|
|
|
|
name++;
|
|
|
|
if (*name == '!')
|
|
|
|
name++;
|
|
|
|
}
|
2009-01-01 14:42:17 +01:00
|
|
|
|
2011-09-08 18:01:36 +02:00
|
|
|
class->table[i].name = (char *)name;
|
|
|
|
class->table[i].len = strlen(name);
|
2009-01-01 14:42:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#if DEBUG_DESC
|
|
|
|
{
|
|
|
|
CLASS_DESC_SYMBOL *cds;
|
|
|
|
|
2007-12-30 17:41:49 +01:00
|
|
|
for (i = 0; i < class->n_desc; i++)
|
|
|
|
{
|
|
|
|
cds = &class->table[i];
|
2010-05-27 15:51:09 +02:00
|
|
|
fprintf(stderr, "%d: %.*s %p\n", i, cds->len, cds->name, cds->desc);
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 'all' means that size_dynamic is the entire size of the object, not just the size of the data */
|
2008-03-11 14:29:47 +01:00
|
|
|
/* And check if the class is a stream */
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-07-08 21:57:50 +02:00
|
|
|
void CLASS_calc_info(CLASS *class, int n_event, int size_dynamic, bool all, int size_static)
|
2007-12-30 17:41:49 +01:00
|
|
|
{
|
2010-02-25 00:47:46 +01:00
|
|
|
// If the class is native and static, then size_dynamic == 0. But if we want to inherit
|
|
|
|
// the static class, and make the inherited class dynamic, then class->off_event must
|
|
|
|
// start after the object header. So we fix size_dynamic accordingly.
|
|
|
|
|
|
|
|
if (all && size_dynamic == 0)
|
|
|
|
size_dynamic = sizeof(OBJECT);
|
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
if (class->parent)
|
|
|
|
{
|
|
|
|
if (all)
|
|
|
|
class->off_event = size_dynamic;
|
|
|
|
else
|
|
|
|
class->off_event = class->parent->off_event + size_dynamic;
|
|
|
|
|
|
|
|
class->n_event = class->parent->n_event + n_event;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (all)
|
|
|
|
class->off_event = size_dynamic;
|
|
|
|
else
|
|
|
|
class->off_event = sizeof(OBJECT) + size_dynamic;
|
|
|
|
|
|
|
|
class->n_event = n_event;
|
|
|
|
}
|
|
|
|
|
2010-05-27 00:01:28 +02:00
|
|
|
if (class->n_event)
|
|
|
|
class->size = class->off_event + sizeof(OBJECT_EVENT) + class->n_event * sizeof(ushort);
|
|
|
|
else
|
|
|
|
class->size = class->off_event;
|
2009-01-01 14:42:17 +01:00
|
|
|
|
|
|
|
class->size_stat = size_static;
|
|
|
|
if (size_static)
|
|
|
|
ALLOC_ZERO(&class->stat, class->size_stat, "CLASS_calc_info");
|
|
|
|
else
|
|
|
|
class->stat = NULL;
|
|
|
|
|
|
|
|
class->is_stream = (class == CLASS_Stream) || (class->parent && class->parent->is_stream);
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CLASS_make_event(CLASS *class, int *first)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
int i, ev;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
*first = 0;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
if (class->n_event == 0)
|
|
|
|
return;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
if (!CLASS_is_native(class))
|
|
|
|
{
|
|
|
|
if (class->parent == NULL)
|
|
|
|
{
|
|
|
|
class->event = class->load->event;
|
|
|
|
class->free_event = FALSE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
ALLOC_ZERO(&class->event, sizeof(CLASS_EVENT) * class->n_event, "CLASS_make_event");
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
if (class->parent != NULL)
|
|
|
|
{
|
|
|
|
ev = class->parent->n_event;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
for (i = 0; i < ev; i++)
|
|
|
|
class->event[i] = class->parent->event[i];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ev = 0;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
class->free_event = TRUE;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
*first = ev;
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CLASS_get_inheritance(CLASS *class, CLASS **her)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
int nher = 0;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
while ((nher < MAX_INHERITANCE) && (class != NULL))
|
|
|
|
{
|
|
|
|
*her++ = class;
|
|
|
|
nher++;
|
|
|
|
class = class->parent;
|
|
|
|
}
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
return nher;
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void *CLASS_auto_create(CLASS *class, int nparam)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
void *ob = class->instance;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-06-16 02:17:25 +02:00
|
|
|
//fprintf(stderr, ">>> CLASS_auto_create: %s (%p)\n", class->name, ob);
|
|
|
|
|
2010-09-16 13:27:51 +02:00
|
|
|
// We automatically release invalid automatic instances
|
2010-09-14 15:01:47 +02:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
if (ob)
|
|
|
|
{
|
2010-09-16 13:27:51 +02:00
|
|
|
if (OBJECT_is_valid(ob))
|
2009-01-01 14:42:17 +01:00
|
|
|
{
|
|
|
|
RELEASE_MANY(SP, nparam);
|
2009-06-16 02:17:25 +02:00
|
|
|
//fprintf(stderr, "<<< CLASS_auto_create: %s (%p): valid=1\n", class->name, ob);
|
2009-01-01 14:42:17 +01:00
|
|
|
return ob;
|
|
|
|
}
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2010-09-16 13:27:51 +02:00
|
|
|
OBJECT_UNREF(class->instance, "CLASS_auto_create");
|
|
|
|
class->instance = NULL;
|
2009-01-01 14:42:17 +01:00
|
|
|
}
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
/*fprintf(stderr, "CLASS_auto_create: create %s\n", class->name);*/
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2010-12-24 13:20:11 +01:00
|
|
|
OBJECT_create_and_set(&class->instance, class, NULL, NULL, nparam);
|
2011-04-18 15:57:46 +02:00
|
|
|
//ob = class->instance;
|
|
|
|
//OBJECT_REF(ob, "CLASS_auto_create");
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-06-16 02:17:25 +02:00
|
|
|
//fprintf(stderr, "<<< CLASS_auto_create: %s (%p) valid=%d\n", class->name, ob, OBJECT_is_valid(ob));
|
|
|
|
|
2011-04-18 15:57:46 +02:00
|
|
|
return class->instance;
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CLASS_search_special(CLASS *class)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
class->special[SPEC_NEW] = CLASS_get_symbol_index_kind(class, "_new", CD_METHOD, 0);
|
|
|
|
class->special[SPEC_FREE] = CLASS_get_symbol_index_kind(class, "_free", CD_METHOD, 0);
|
|
|
|
class->special[SPEC_GET] = CLASS_get_symbol_index_kind(class, "_get", CD_METHOD, CD_STATIC_METHOD);
|
|
|
|
class->special[SPEC_PUT] = CLASS_get_symbol_index_kind(class, "_put", CD_METHOD, CD_STATIC_METHOD);
|
|
|
|
class->special[SPEC_FIRST] = CLASS_get_symbol_index_kind(class, "_first", CD_METHOD, CD_STATIC_METHOD);
|
|
|
|
class->special[SPEC_NEXT] = CLASS_get_symbol_index_kind(class, "_next", CD_METHOD, CD_STATIC_METHOD);
|
|
|
|
class->special[SPEC_CALL] = CLASS_get_symbol_index_kind(class, "_call", CD_METHOD, CD_STATIC_METHOD);
|
|
|
|
class->special[SPEC_UNKNOWN] = CLASS_get_symbol_index_kind(class, "_unknown", CD_METHOD, CD_STATIC_METHOD);
|
2011-07-03 04:46:15 +02:00
|
|
|
class->special[SPEC_PROPERTY] = CLASS_get_symbol_index_kind(class, "_property", CD_METHOD, CD_STATIC_METHOD);
|
2009-01-01 14:42:17 +01:00
|
|
|
class->special[SPEC_COMPARE] = CLASS_get_symbol_index_kind(class, "_compare", CD_METHOD, 0);
|
2009-07-12 23:49:13 +02:00
|
|
|
class->special[SPEC_ATTACH] = CLASS_get_symbol_index_kind(class, "_attach", CD_METHOD, 0);
|
2010-11-27 02:27:23 +01:00
|
|
|
|
|
|
|
class->special[SPEC_CONVERT] = CLASS_get_symbol_index_kind(class, "_@_convert", CD_CONSTANT, 0);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
if (class->special[SPEC_NEXT] != NO_SYMBOL)
|
2009-01-01 14:42:17 +01:00
|
|
|
class->enum_static = CLASS_DESC_get_type(CLASS_get_desc(class, class->special[SPEC_NEXT])) == CD_STATIC_METHOD;
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CLASS *CLASS_check_global(char *name)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
CLASS *class, *parent;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
class = CLASS_find_global(name);
|
|
|
|
if (class->state)
|
|
|
|
{
|
|
|
|
if (COMPONENT_current && class->component == COMPONENT_current)
|
|
|
|
ERROR_panic("Class '%s' declared twice in the component '%s'.", class->name, class->component->name);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
parent = class;
|
2010-04-26 11:36:47 +02:00
|
|
|
class = class_replace_global(name);
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
CLASS_inheritance(class, parent);
|
|
|
|
}
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
return class;
|
2007-12-30 17:41:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CLASS_DESC_METHOD *CLASS_get_special_desc(CLASS *class, int spec)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
short index = class->special[spec];
|
2007-12-30 17:41:49 +01:00
|
|
|
|
2009-01-01 14:42:17 +01:00
|
|
|
if (index == NO_SYMBOL)
|
|
|
|
return NULL;
|
2007-12-30 17:41:49 +01:00
|
|
|
else
|
|
|
|
return &CLASS_get_desc(class, index)->method;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CLASS_DESC_SYMBOL *CLASS_get_next_sorted_symbol(CLASS *class, int *index)
|
|
|
|
{
|
2009-01-01 14:42:17 +01:00
|
|
|
CLASS_DESC_SYMBOL *old = NULL;
|
|
|
|
CLASS_DESC_SYMBOL *cur;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
if (*index >= class->n_desc)
|
|
|
|
return NULL;
|
|
|
|
|
2010-05-27 15:51:09 +02:00
|
|
|
cur = &class->table[class->sort[*index]];
|
2009-01-01 14:42:17 +01:00
|
|
|
if (*index > 0)
|
2010-05-27 15:51:09 +02:00
|
|
|
old = &class->table[class->sort[*index - 1]];
|
2009-01-01 14:42:17 +01:00
|
|
|
|
|
|
|
(*index)++;
|
|
|
|
|
2007-12-30 17:41:49 +01:00
|
|
|
if (!cur->desc)
|
|
|
|
continue;
|
2009-01-01 14:42:17 +01:00
|
|
|
|
|
|
|
if (old && !TABLE_compare_ignore_case(cur->name, cur->len, old->name, old->len))
|
|
|
|
continue;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
return cur;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CLASS_create_array_class(CLASS *class)
|
|
|
|
{
|
2008-08-31 02:32:21 +02:00
|
|
|
void *save = TYPE_joker;
|
|
|
|
char *name_joker;
|
2007-12-30 17:41:49 +01:00
|
|
|
GB_DESC *desc;
|
2010-07-08 00:06:05 +02:00
|
|
|
CLASS *array_type = (CLASS *)class->array_type;
|
2008-08-31 02:32:21 +02:00
|
|
|
|
2008-10-23 16:09:48 +02:00
|
|
|
//fprintf(stderr, "CLASS_create_array_class: create %s\n", class->name);
|
2008-09-01 01:45:47 +02:00
|
|
|
|
2010-06-05 01:48:53 +02:00
|
|
|
name_joker = STRING_new(class->name, strlen(class->name) - 2);
|
2008-08-31 02:32:21 +02:00
|
|
|
|
2010-07-08 00:06:05 +02:00
|
|
|
if (!array_type)
|
|
|
|
{
|
|
|
|
array_type = class->global ? CLASS_find_global(name_joker) : CLASS_find(name_joker);
|
|
|
|
class->array_type = (TYPE)array_type;
|
|
|
|
}
|
|
|
|
|
2010-05-19 14:43:57 +02:00
|
|
|
TYPE_joker = array_type;
|
|
|
|
array_type->array_class = class;
|
2007-12-30 17:41:49 +01:00
|
|
|
|
|
|
|
ALLOC(&desc, sizeof(GB_DESC) * ARRAY_TEMPLATE_NDESC, "CLASS_create_array_class");
|
|
|
|
memcpy(desc, NATIVE_TemplateArray, sizeof(GB_DESC) * ARRAY_TEMPLATE_NDESC);
|
|
|
|
((CLASS_DESC_GAMBAS *)desc)->name = class->name;
|
|
|
|
|
|
|
|
CLASS_register_class(desc, class);
|
|
|
|
|
2010-07-09 13:16:49 +02:00
|
|
|
class->is_array = TRUE;
|
|
|
|
class->quick_array = CQA_ARRAY;
|
2007-12-30 17:41:49 +01:00
|
|
|
class->data = (char *)desc;
|
2009-01-05 12:38:03 +01:00
|
|
|
|
2008-08-31 02:32:21 +02:00
|
|
|
STRING_free(&name_joker);
|
2007-12-30 17:41:49 +01:00
|
|
|
TYPE_joker = save;
|
|
|
|
}
|
2009-01-05 12:38:03 +01:00
|
|
|
|
|
|
|
|
|
|
|
CLASS *CLASS_get_array_class(CLASS *class)
|
|
|
|
{
|
|
|
|
if (!class->array_class)
|
|
|
|
{
|
|
|
|
char name[strlen(class->name) + 3];
|
|
|
|
strcpy(name, class->name);
|
|
|
|
strcat(name, "[]");
|
|
|
|
class->array_class = class->global ? CLASS_find_global(name) : CLASS_find(name);
|
|
|
|
CLASS_create_array_class(class->array_class);
|
|
|
|
}
|
|
|
|
|
|
|
|
return class->array_class;
|
|
|
|
}
|
2010-05-27 00:01:28 +02:00
|
|
|
|
|
|
|
|
2010-07-08 00:06:05 +02:00
|
|
|
void CLASS_create_array_of_struct_class(CLASS *class)
|
|
|
|
{
|
|
|
|
void *save = TYPE_joker;
|
|
|
|
char *name_joker;
|
|
|
|
GB_DESC *desc;
|
|
|
|
CLASS *array_type = (CLASS *)class->array_type;
|
|
|
|
|
|
|
|
//fprintf(stderr, "CLASS_create_array_class: create %s\n", class->name);
|
|
|
|
|
|
|
|
name_joker = STRING_new(&class->name[1], strlen(class->name) - 3);
|
|
|
|
|
|
|
|
if (!array_type)
|
|
|
|
{
|
|
|
|
array_type = class->global ? CLASS_find_global(name_joker) : CLASS_find(name_joker);
|
|
|
|
class->array_type = (TYPE)array_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
TYPE_joker = array_type;
|
|
|
|
array_type->astruct_class = class;
|
|
|
|
|
|
|
|
ALLOC(&desc, sizeof(GB_DESC) * ARRAY_OF_STRUCT_TEMPLATE_NDESC, "CLASS_create_array_of_struct_class");
|
|
|
|
memcpy(desc, NATIVE_TemplateArrayOfStruct, sizeof(GB_DESC) * ARRAY_OF_STRUCT_TEMPLATE_NDESC);
|
|
|
|
((CLASS_DESC_GAMBAS *)desc)->name = class->name;
|
|
|
|
|
|
|
|
CLASS_register_class(desc, class);
|
|
|
|
|
2010-07-09 13:16:49 +02:00
|
|
|
class->is_array = TRUE;
|
2010-11-26 21:30:58 +01:00
|
|
|
class->is_array_of_struct = TRUE;
|
2010-07-08 00:06:05 +02:00
|
|
|
class->data = (char *)desc;
|
|
|
|
|
|
|
|
STRING_free(&name_joker);
|
|
|
|
TYPE_joker = save;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CLASS *CLASS_get_array_of_struct_class(CLASS *class)
|
|
|
|
{
|
|
|
|
if (!class->astruct_class)
|
|
|
|
{
|
|
|
|
char name[strlen(class->name) + 4];
|
|
|
|
sprintf(name, "$%s[]", class->name);
|
|
|
|
class->astruct_class = class->global ? CLASS_find_global(name) : CLASS_find(name);
|
|
|
|
CLASS_create_array_of_struct_class(class->astruct_class);
|
|
|
|
}
|
|
|
|
|
|
|
|
return class->astruct_class;
|
|
|
|
}
|
|
|
|
|
2010-05-27 00:01:28 +02:00
|
|
|
int CLASS_sizeof(CLASS *class)
|
|
|
|
{
|
|
|
|
if (CLASS_is_struct(class))
|
|
|
|
return class->size - sizeof(CSTRUCT);
|
|
|
|
else
|
|
|
|
return class->size - sizeof(OBJECT);
|
|
|
|
}
|