gambas-source-code/main/gbx/gbx_c_class.c
Benoît Minisini b3db598050 [DEVELOPMENT ENVIRONMENT]
* BUG: Breakpoints are correctly reset when opening a new project.

[INTERPRETER]
* BUG: The GB.NewString(), GB.NewZeroString() and GB.TempString() API 
  signature has changed. All components have been updated accordingly.
* OPT: Many optimizations to speed up the interpreter.

[GB.EVAL]
* NEW: During syntax highlighting, the first character of class names is
  automatically converted to uppercase.


git-svn-id: svn://localhost/gambas/trunk@2992 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2010-06-04 23:48:53 +00:00

934 lines
18 KiB
C

/***************************************************************************
gbx_c_class.c
(c) 2000-2009 Benoît Minisini <gambas@users.sourceforge.net>
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.
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 the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
***************************************************************************/
#define __GBX_C_CLASS_C
#include "gbx_info.h"
#ifndef GBX_INFO
#include <ctype.h>
#include "gb_common.h"
#include "gbx_api.h"
#include "gbx_component.h"
#include "gbx_project.h"
#include "gbx_class.h"
#include "gbx_class_desc.h"
#include "gbx_exec.h"
#include "gbx_event.h"
#include "gbx_object.h"
#include "gbx_c_array.h"
#include "gbx_c_gambas.h"
#include "gbx_c_class.h"
static CLASS_DESC_SYMBOL *_current_symbol = NULL;
static CLASS_DESC *get_desc(CLASS *class, const char *name)
{
int index;
index = CLASS_find_symbol(class, name);
//fprintf(stderr, "CLASS_find_symbol('%s', '%s') = %ld\n", class->name, name, index);
if (index == NO_SYMBOL)
{
GB_Error((char *)E_NSYMBOL, name, class->name);
return NULL;
}
else
return class->table[index].desc;
}
/**** Components ***********************************************************/
BEGIN_METHOD(Components_get, GB_STRING name)
const char *name = GB_ToZeroString(ARG(name));
COMPONENT *comp;
comp = COMPONENT_find(name);
GB_ReturnObject(comp);
END_METHOD
BEGIN_PROPERTY(Components_Count)
GB_ReturnInt(COMPONENT_count);
END_PROPERTY
BEGIN_METHOD_VOID(Components_next)
COMPONENT **plib = (COMPONENT **)GB_GetEnum();
*plib = COMPONENT_next(*plib);
if (*plib == NULL)
GB_StopEnum();
else
GB_ReturnObject(*plib);
END_METHOD
BEGIN_PROPERTY(Component_Name)
GB_ReturnConstZeroString(OBJECT(COMPONENT)->name);
END_PROPERTY
BEGIN_PROPERTY(Component_Path)
GB_ReturnString(COMPONENT_path);
END_PROPERTY
BEGIN_METHOD(Component_Load, GB_STRING name)
const char *name = GB_ToZeroString(ARG(name));
COMPONENT *comp;
comp = COMPONENT_find(name);
if (!comp)
comp = COMPONENT_create(name);
COMPONENT_load(comp);
GB_ReturnObject(comp);
END_METHOD
BEGIN_METHOD(Component_IsLoaded, GB_STRING name)
const char *name = GB_ToZeroString(ARG(name));
COMPONENT *comp;
comp = COMPONENT_find(name);
GB_ReturnBoolean(comp && comp->loaded);
END_METHOD
/**** Classes **************************************************************/
BEGIN_METHOD(Classes_get, GB_STRING name)
const char *name = GB_ToZeroString(ARG(name));
CLASS *class = NULL;
if (name != NULL)
class = CLASS_look(name, LENGTH(name));
if (class == NULL)
{
GB_Error("Unknown class '&1'", name);
return;
}
if (!class->state)
{
GB_Error("Class is not loaded");
return;
}
GB_ReturnObject(class);
END_METHOD
BEGIN_METHOD(Class_Load, GB_STRING name)
CLASS *class;
class = CLASS_get(GB_ToZeroString(ARG(name)));
GB_ReturnObject(class);
END_METHOD
BEGIN_PROPERTY(Class_Name)
GB_ReturnConstZeroString(OBJECT(CLASS)->name);
END_PROPERTY
BEGIN_METHOD_VOID(Classes_next)
TABLE *table = CLASS_get_table();
int *index = (int *)GB_GetEnum();
CLASS *class;
for(;;)
{
if (*index >= TABLE_count(table))
{
GB_StopEnum();
break;
}
class = ((CLASS_SYMBOL *)TABLE_get_symbol(table, *index))->class;
(*index)++;
if (class->state)
{
GB_ReturnObject(class);
break;
}
}
END_METHOD
BEGIN_PROPERTY(Classes_count)
GB_ReturnInt(CLASS_count());
END_PROPERTY
/**** Class ****************************************************************/
BEGIN_PROPERTY(Class_Count)
GB_ReturnInt(OBJECT(CLASS)->count);
END_PROPERTY
BEGIN_PROPERTY(Class_Hidden)
GB_ReturnBoolean(*(OBJECT(CLASS)->name) == '.');
END_PROPERTY
BEGIN_PROPERTY(Class_Native)
GB_ReturnBoolean(CLASS_is_native(OBJECT(CLASS)));
END_PROPERTY
BEGIN_PROPERTY(Class_Component)
GB_ReturnObject(OBJECT(CLASS)->component);
END_PROPERTY
BEGIN_PROPERTY(Class_Parent)
GB_ReturnObject(OBJECT(CLASS)->parent);
END_PROPERTY
BEGIN_PROPERTY(Class_Symbols)
CLASS *class = OBJECT(CLASS);
GB_ARRAY array;
CLASS_DESC_SYMBOL *cds;
int index = 0;
GB_ArrayNew(&array, T_STRING, 0);
for(;;)
{
cds = CLASS_get_next_sorted_symbol(class, &index);
if (!cds)
break;
*((char **)GB_ArrayAdd(array)) = STRING_new(cds->name, cds->len);
}
GB_ReturnObject(array);
END_PROPERTY
BEGIN_METHOD(Class_get, GB_STRING name)
CLASS *class = OBJECT(CLASS);
CLASS_DESC_SYMBOL *cd = NULL;
const char *name = GB_ToZeroString(ARG(name));
if (name != NULL)
cd = CLASS_get_symbol(class, name);
if (cd == NULL)
{
GB_Error("Unknown symbol '&1'", name);
return;
}
_current_symbol = cd;
GB_ReturnObject(class);
END_METHOD
BEGIN_PROPERTY(Class_Instance)
GB_ReturnObject(OBJECT(CLASS)->instance);
END_PROPERTY
BEGIN_METHOD_VOID(Class_AutoCreate)
CLASS *class = OBJECT(CLASS);
if (!class->auto_create)
GB_ReturnNull();
else
GB_ReturnObject(CLASS_auto_create(class, 0));
END_METHOD
/**** Symbol ***************************************************************/
BEGIN_PROPERTY(Symbol_Name)
GB_ReturnConstString(_current_symbol->name, _current_symbol->len);
END_PROPERTY
BEGIN_PROPERTY(Symbol_Kind)
CLASS_DESC_SYMBOL *cds = _current_symbol;
switch(CLASS_DESC_get_type(cds->desc))
{
case CD_VARIABLE:
case CD_STATIC_VARIABLE:
GB_ReturnInt(1);
return;
case CD_PROPERTY:
case CD_PROPERTY_READ:
case CD_STATIC_PROPERTY:
case CD_STATIC_PROPERTY_READ:
GB_ReturnInt(2);
return;
case CD_METHOD:
case CD_STATIC_METHOD:
GB_ReturnInt(3);
return;
case CD_EVENT:
GB_ReturnInt(4);
return;
case CD_CONSTANT:
GB_ReturnInt(5);
return;
default:
GB_ReturnInt(0);
return;
}
END_PROPERTY
BEGIN_PROPERTY(Symbol_Static)
CLASS_DESC_SYMBOL *cds = _current_symbol;
GB_ReturnBoolean(index(CD_STATIC_LIST, CLASS_DESC_get_type(cds->desc)) != NULL);
END_PROPERTY
BEGIN_PROPERTY(Symbol_Hidden)
CLASS_DESC_SYMBOL *cds = _current_symbol;
GB_ReturnBoolean(*cds->name == '_');
END_PROPERTY
BEGIN_PROPERTY(Symbol_ReadOnly)
CLASS_DESC_SYMBOL *cds = _current_symbol;
switch (CLASS_DESC_get_type(cds->desc))
{
case CD_PROPERTY:
case CD_STATIC_PROPERTY:
GB_ReturnBoolean(FALSE);
break;
default:
GB_ReturnBoolean(TRUE);
break;
}
END_PROPERTY
BEGIN_PROPERTY(Symbol_Type)
CLASS_DESC_SYMBOL *cds = _current_symbol;
GB_ReturnConstZeroString(TYPE_to_string(cds->desc->property.type)); /* Valable pour tout symbole */
END_PROPERTY
BEGIN_PROPERTY(Symbol_Signature)
CLASS_DESC_SYMBOL *cds = _current_symbol;
GB_ReturnConstZeroString(CLASS_DESC_get_signature(cds->desc));
END_METHOD
BEGIN_PROPERTY(Symbol_Value)
CLASS_DESC *desc = _current_symbol->desc;
if (CLASS_DESC_get_type(desc) != CD_CONSTANT)
{
GB_ReturnNull();
return;
}
if (desc->constant.type == T_STRING)
GB_ReturnConstZeroString(desc->constant.value._string);
else
GB_ReturnPtr(desc->constant.type, (void *)&desc->constant.value);
END_PROPERTY
/**** Object ***************************************************************/
BEGIN_METHOD(Object_GetProperty, GB_OBJECT object; GB_STRING property)
const char *name;
CLASS_DESC *desc;
CLASS *class;
char type;
void *object = VARG(object);
if (GB_CheckObject(object))
return;
if (OBJECT_is_class(object))
{
class = (CLASS *)object;
object = NULL;
}
else
{
class = OBJECT_class(object);
}
name = GB_ToZeroString(ARG(property));
desc = get_desc(class, name);
if (!desc)
return;
type = CLASS_DESC_get_type(desc);
if (type == CD_PROPERTY || type == CD_PROPERTY_READ || type == CD_VARIABLE)
{
if (!object)
{
GB_Error((char *)E_DYNAMIC, class->name, name);
return;
}
}
else if (type == CD_STATIC_PROPERTY || type == CD_STATIC_PROPERTY_READ || type == CD_STATIC_VARIABLE || type == CD_CONSTANT)
{
if (object)
{
GB_Error((char *)E_STATIC, class->name, name);
return;
}
}
else
{
GB_Error((char *)E_NPROPERTY, class->name, name);
return;
}
if (type == CD_VARIABLE)
VALUE_read(&TEMP, (char *)object + desc->variable.offset, desc->property.type);
else if (type == CD_STATIC_VARIABLE)
VALUE_read(&TEMP, (char *)class->stat + desc->variable.offset, desc->property.type);
else if (type == CD_CONSTANT)
VALUE_read(&TEMP, (void *)&desc->constant.value, desc->constant.type);
else
{
if (desc->property.native)
{
if (EXEC_call_native(desc->property.read, object, desc->property.type, 0))
{
GAMBAS_Error = TRUE;
return;
}
}
else
{
EXEC.class = desc->property.class;
EXEC.object = object;
EXEC.drop = FALSE;
EXEC.nparam = 0;
EXEC.native = FALSE;
EXEC.index = (int)(intptr_t)desc->property.read;
//EXEC.func = &class->load->func[(long)desc->property.read];
EXEC_function_keep();
TEMP = *RP;
UNBORROW(RP);
RP->type = T_VOID;
}
}
END_METHOD
BEGIN_METHOD(Object_SetProperty, GB_OBJECT object; GB_STRING property; GB_VARIANT value)
const char *name;
CLASS_DESC *desc;
CLASS *class;
char type;
void *object = VARG(object);
VALUE *value = (VALUE *)ARG(value);
if (GB_CheckObject(object))
return;
if (OBJECT_is_class(object))
{
class = (CLASS *)object;
object = NULL;
}
else
{
class = OBJECT_class(object);
}
name = GB_ToZeroString(ARG(property));
desc = get_desc(class, name);
if (!desc)
return;
type = CLASS_DESC_get_type(desc);
if (type == CD_PROPERTY || type == CD_VARIABLE)
{
if (!object)
{
if (!class->auto_create)
{
GB_Error((char *)E_DYNAMIC, class->name, name);
return;
}
object = EXEC_auto_create(class, TRUE);
}
}
else if (type == CD_STATIC_PROPERTY || type == CD_STATIC_VARIABLE)
{
if (object)
{
GB_Error((char *)E_STATIC, class->name, name);
return;
}
}
else if (type == CD_PROPERTY_READ || type == CD_STATIC_PROPERTY_READ)
{
GB_Error((char *)E_NWRITE, class->name, name);
return;
}
else
{
GB_Error((char *)E_NPROPERTY, class->name, name);
return;
}
if (type == CD_VARIABLE)
VALUE_write(value, (char *)object + desc->variable.offset, desc->variable.type);
else if (type == CD_STATIC_VARIABLE)
VALUE_write(value, (char *)class->stat + desc->variable.offset, desc->variable.type);
else
{
if (desc->property.native)
{
VALUE_conv(value, desc->property.type);
if (EXEC_call_native(desc->property.write, object, 0, value))
{
GAMBAS_Error = TRUE;
return;
}
}
else
{
*SP = *value;
BORROW(SP);
SP++;
EXEC.class = desc->property.class;
EXEC.object = object;
EXEC.drop = FALSE;
EXEC.nparam = 1;
EXEC.native = FALSE;
EXEC.index = (int)(intptr_t)desc->property.write;
//EXEC.func = &class->load->func[(long)desc->property.write];
EXEC_function();
/*VALUE_write(value, OBJECT_get_prop_addr(object, desc), desc->property.type);*/
}
}
END_METHOD
BEGIN_METHOD(Object_Attach, GB_OBJECT object; GB_OBJECT parent; GB_STRING name)
void *object = VARG(object);
void *parent = VARG(parent);
char *name = GB_ToZeroString(ARG(name));
if (GB_CheckObject(object))
return;
if (!parent || !name || !*name)
{
OBJECT_detach(object);
return;
}
if (GB_CheckObject(parent))
return;
OBJECT_attach(object, parent, name);
/*if (OBJECT_is(object, CLASS_Observer))
COBSERVER_attach((COBSERVER *)object, parent, GB_ToZeroString(ARG(name)));*/
END_METHOD
BEGIN_METHOD(Object_Detach, GB_OBJECT object)
void *object = VARG(object);
if (GB_CheckObject(object))
return;
if (OBJECT_is(object, CLASS_Observer))
COBSERVER_detach((COBSERVER *)object);
OBJECT_detach(object);
END_METHOD
BEGIN_METHOD(Object_Parent, GB_OBJECT object)
void *object = VARG(object);
if (GB_CheckObject(object))
return;
GB_ReturnObject(OBJECT_parent(object));
END_METHOD
BEGIN_METHOD(Object_Class, GB_OBJECT object)
void *object = VARG(object);
if (GB_CheckObject(object))
return;
GB_ReturnObject(OBJECT_class(object));
END_METHOD
BEGIN_METHOD(Object_Type, GB_OBJECT object)
void *object = VARG(object);
if (GB_CheckObject(object))
return;
GB_ReturnConstZeroString(OBJECT_class(object)->name);
END_METHOD
BEGIN_METHOD(Object_Is, GB_OBJECT object; GB_STRING class)
void *object = VARG(object);
CLASS *class = CLASS_look(STRING(class), LENGTH(class));
if (GB_CheckObject(object))
return;
if (!class)
{
GB_ReturnBoolean(FALSE);
return;
}
GB_ReturnBoolean(OBJECT_class(object) == class || CLASS_inherits(OBJECT_class(object), class));
END_METHOD
BEGIN_METHOD(Object_Call, GB_OBJECT object; GB_STRING method; GB_OBJECT params)
int i;
int np = 0;
char *name = GB_ToZeroString(ARG(method));
void *object = VARG(object);
GB_FUNCTION func;
GB_ARRAY params = VARGOPT(params, NULL);
if (GB_CheckObject(object))
return;
if (GB_GetFunction(&func, object, name, NULL, NULL))
{
GB_Error((char *)E_NSYMBOL, name, OBJECT_class(object)->name);
return;
}
if (params)
np = GB_ArrayCount(params);
if (np)
{
STACK_check(np);
for (i = 0; i < np; i++)
{
CARRAY_get_value(params, i, SP);
PUSH();
}
}
GB_Call(&func, np, FALSE);
END_METHOD
BEGIN_METHOD(Object_IsValid, GB_OBJECT object)
GB_ReturnBoolean(OBJECT_is_valid(VARG(object)));
END_METHOD
BEGIN_METHOD(Object_Lock, GB_OBJECT object)
void *object = VARG(object);
if (GB_CheckObject(object))
return;
OBJECT_lock(object, TRUE);
END_METHOD
BEGIN_METHOD(Object_Unlock, GB_OBJECT object)
void *object = VARG(object);
if (GB_CheckObject(object))
return;
OBJECT_lock(object, FALSE);
END_METHOD
BEGIN_METHOD(Object_IsLocked, GB_OBJECT object)
void *object = VARG(object);
if (GB_CheckObject(object))
return;
GB_ReturnBoolean(OBJECT_is_locked(object));
END_METHOD
BEGIN_METHOD(Object_Count, GB_OBJECT object)
void *object = VARG(object);
if (GB_CheckObject(object))
return;
// We substract one because the object is referenced on the stack
GB_ReturnInteger(OBJECT_count(object) - 1);
END_METHOD
BEGIN_METHOD(Object_New, GB_STRING class; GB_OBJECT params)
CLASS *class = CLASS_find(GB_ToZeroString(ARG(class)));
GB_ARRAY params = VARGOPT(params, NULL);
int i, np = 0;
void *object;
if (!class)
{
GB_Error("Unknown class");
return;
}
if (params)
np = GB_ArrayCount(params);
if (np)
{
STACK_check(np);
for (i = 0; i < np; i++)
{
CARRAY_get_value(params, i, SP);
PUSH();
}
}
object = EXEC_create_object(class, np, NULL);
OBJECT_UNREF_KEEP(object, "Object_New");
GB_ReturnObject(object);
END_METHOD
BEGIN_PROPERTY(Object_LastEventName)
GB_ReturnString(EVENT_Name);
END_PROPERTY
#endif
/***************************************************************************/
GB_DESC NATIVE_Symbol[] =
{
GB_DECLARE(".Symbol", 0), GB_VIRTUAL_CLASS(),
GB_PROPERTY_READ("Name", "s", Symbol_Name),
GB_PROPERTY_READ("Kind", "i", Symbol_Kind),
GB_PROPERTY_READ("Type", "s", Symbol_Type),
GB_PROPERTY_READ("ReadOnly", "b", Symbol_ReadOnly),
GB_PROPERTY_READ("Hidden", "b", Symbol_Hidden),
GB_PROPERTY_READ("Signature", "s", Symbol_Signature),
GB_PROPERTY_READ("Static", "b", Symbol_Static),
GB_PROPERTY_READ("Value", "v", Symbol_Value),
GB_END_DECLARE
};
GB_DESC NATIVE_Components[] =
{
GB_DECLARE("Components", 0), GB_VIRTUAL_CLASS(),
GB_STATIC_METHOD("_next", "Component", Components_next, NULL),
GB_STATIC_METHOD("_get", "Component", Components_get, "(Name)s"),
GB_STATIC_PROPERTY_READ("Count", "i", Components_Count),
GB_END_DECLARE
};
GB_DESC NATIVE_Component[] =
{
GB_DECLARE("Component", 0), GB_VIRTUAL_CLASS(),
//GB_STATIC_METHOD("_get", "Component", library_get, "(Name)s"),
GB_STATIC_METHOD("Load", "Component", Component_Load, "(Name)s"),
GB_STATIC_METHOD("IsLoaded", "b", Component_IsLoaded, "(Name)s"),
GB_STATIC_PROPERTY_READ("Path", "s", Component_Path),
GB_PROPERTY_READ("Name", "s", Component_Name),
GB_END_DECLARE
};
GB_DESC NATIVE_Classes[] =
{
GB_DECLARE("Classes", 0), GB_VIRTUAL_CLASS(),
GB_STATIC_METHOD("_next", "Class", Classes_next, NULL),
GB_STATIC_METHOD("_get", "Class", Classes_get, "(Name)s"),
GB_STATIC_PROPERTY_READ("Count", "i", Classes_count),
GB_END_DECLARE
};
GB_DESC NATIVE_Class[] =
{
GB_DECLARE("Class", 0), GB_VIRTUAL_CLASS(),
GB_STATIC_METHOD("Load", "Class", Class_Load, "(Name)s"),
GB_METHOD("_get", ".Symbol", Class_get, "(Name)s"),
GB_PROPERTY_READ("Name", "s", Class_Name),
GB_PROPERTY_READ("Hidden", "b", Class_Hidden),
GB_PROPERTY_READ("Native", "b", Class_Native),
GB_PROPERTY_READ("Parent", "Class", Class_Parent),
GB_PROPERTY_READ("Component", "Component", Class_Component),
GB_PROPERTY_READ("Count", "i", Class_Count),
GB_PROPERTY_READ("Instance", "o", Class_Instance),
GB_PROPERTY_READ("Symbols", "String[]", Class_Symbols),
GB_METHOD("AutoCreate", "o", Class_AutoCreate, NULL),
GB_CONSTANT("Variable", "i", 1),
GB_CONSTANT("Property", "i", 2),
GB_CONSTANT("Method", "i", 3),
GB_CONSTANT("Event", "i", 4),
GB_CONSTANT("Constant", "i", 5),
GB_END_DECLARE
};
GB_DESC NATIVE_Object[] =
{
GB_DECLARE("Object", 0), GB_VIRTUAL_CLASS(),
GB_STATIC_METHOD("GetProperty", "v", Object_GetProperty, "(Object)o(Property)s"),
GB_STATIC_METHOD("SetProperty", NULL, Object_SetProperty, "(Object)o(Property)s(Value)v"),
GB_STATIC_METHOD("Attach", NULL, Object_Attach, "(Object)o(Parent)o(Name)s"),
GB_STATIC_METHOD("Detach", NULL, Object_Detach, "(Object)o"),
GB_STATIC_METHOD("Class", "Class", Object_Class, "(Object)o"),
GB_STATIC_METHOD("Type", "s", Object_Type, "(Object)o"),
GB_STATIC_METHOD("Is", "b", Object_Is, "(Object)o(Class)s"),
GB_STATIC_METHOD("Parent", "o", Object_Parent, "(Object)o"),
GB_STATIC_METHOD("Call", "v", Object_Call, "(Object)o(Method)s[(Arguments)Array;]"),
GB_STATIC_METHOD("New", "o", Object_New, "(Class)s[(Arguments)Array;]"),
GB_STATIC_METHOD("IsValid", "b", Object_IsValid, "(Object)o"),
GB_STATIC_METHOD("Lock", NULL, Object_Lock, "(Object)o"),
GB_STATIC_METHOD("Unlock", NULL, Object_Unlock, "(Object)o"),
GB_STATIC_METHOD("IsLocked", "b", Object_IsLocked, "(Object)o"),
GB_STATIC_METHOD("Count", "i", Object_Count, "(Object)o"),
GB_STATIC_PROPERTY_READ("LastEventName", "s", Object_LastEventName),
GB_END_DECLARE
};