2012-07-10 16:35:17 +02:00
|
|
|
/***************************************************************************
|
|
|
|
|
|
|
|
gbx_exec_operator.c
|
|
|
|
|
2018-02-12 02:53:46 +01:00
|
|
|
(c) 2000-2017 Benoît Minisini <g4mba5@gmail.com>
|
2012-07-10 16:35:17 +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.
|
|
|
|
|
|
|
|
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., 51 Franklin Street, Fifth Floor, Boston,
|
|
|
|
MA 02110-1301, USA.
|
|
|
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#define __GBX_EXEC_OPERATOR_C
|
|
|
|
|
|
|
|
#include "gb_common.h"
|
2012-07-14 04:49:57 +02:00
|
|
|
#include "gbx_type.h"
|
|
|
|
#include "gbx_api.h"
|
2012-07-10 16:35:17 +02:00
|
|
|
#include "gbx_exec.h"
|
|
|
|
|
|
|
|
typedef
|
2012-07-14 04:49:57 +02:00
|
|
|
void *(*FUNC_O_OF)(void *, double, bool);
|
2012-07-10 16:35:17 +02:00
|
|
|
|
|
|
|
typedef
|
2012-07-14 04:49:57 +02:00
|
|
|
void *(*FUNC_O_OO)(void *, void *, bool);
|
2012-07-10 16:35:17 +02:00
|
|
|
|
|
|
|
typedef
|
2012-07-14 04:49:57 +02:00
|
|
|
int (*FUNC_I_OF)(void *, double, bool);
|
2012-07-10 16:35:17 +02:00
|
|
|
|
|
|
|
typedef
|
2012-07-14 04:49:57 +02:00
|
|
|
int (*FUNC_I_OO)(void *, void *, bool);
|
2012-07-10 16:35:17 +02:00
|
|
|
|
|
|
|
typedef
|
|
|
|
void *(*FUNC_O_O)(void *);
|
|
|
|
|
|
|
|
typedef
|
2013-09-03 23:11:55 +02:00
|
|
|
int (*FUNC_I_O)(void *);
|
2012-07-10 16:35:17 +02:00
|
|
|
|
2013-09-08 01:09:01 +02:00
|
|
|
typedef
|
|
|
|
double (*FUNC_F_O)(void *);
|
|
|
|
|
2012-07-14 17:18:22 +02:00
|
|
|
static void raise_error(void *o1, void *o2)
|
2012-07-14 04:49:57 +02:00
|
|
|
{
|
2013-09-03 23:11:55 +02:00
|
|
|
if (o2 && OBJECT_class(o2) == OBJECT_class(o1))
|
2012-07-14 17:18:22 +02:00
|
|
|
GB_Error((char *)E_TYPE, "Number", TYPE_get_name((TYPE)OBJECT_class(o1)));
|
|
|
|
else
|
|
|
|
GB_Error((char *)E_TYPE, TYPE_get_name((TYPE)OBJECT_class(o1)), o2 ? TYPE_get_name((TYPE)OBJECT_class(o2)) : "Number");
|
2012-07-14 04:49:57 +02:00
|
|
|
}
|
|
|
|
|
2012-07-14 17:18:22 +02:00
|
|
|
bool EXEC_check_operator_single(VALUE *P1, uchar op)
|
2012-07-10 16:35:17 +02:00
|
|
|
{
|
2012-07-14 17:18:22 +02:00
|
|
|
return (TYPE_is_object(P1->type) && P1->_object.object && OBJECT_class(P1->_object.object)->has_operators
|
|
|
|
&& CLASS_has_operator(OBJECT_class(P1->_object.object), op));
|
2012-07-10 16:35:17 +02:00
|
|
|
}
|
|
|
|
|
2012-07-14 17:18:22 +02:00
|
|
|
int EXEC_check_operator(VALUE *P1, VALUE *P2, uchar op)
|
2012-07-10 16:35:17 +02:00
|
|
|
{
|
2012-07-14 17:18:22 +02:00
|
|
|
CLASS *class1, *class2;
|
|
|
|
|
2012-07-10 16:35:17 +02:00
|
|
|
if (TYPE_is_number(P1->type) && TYPE_is_object(P2->type))
|
|
|
|
{
|
2012-07-14 17:18:22 +02:00
|
|
|
if (P2->_object.object && OBJECT_class(P2->_object.object)->has_operators && CLASS_has_operator(OBJECT_class(P2->_object.object), op + 1))
|
2012-07-10 16:35:17 +02:00
|
|
|
{
|
|
|
|
//*dynamic = P2->type == T_OBJECT;
|
|
|
|
return OP_FLOAT_OBJECT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (TYPE_is_number(P2->type) && TYPE_is_object(P1->type))
|
|
|
|
{
|
2012-07-14 17:18:22 +02:00
|
|
|
if (P1->_object.object && OBJECT_class(P1->_object.object)->has_operators && CLASS_has_operator(OBJECT_class(P1->_object.object), op + 1))
|
2012-07-10 16:35:17 +02:00
|
|
|
{
|
|
|
|
//*dynamic = P1->type == T_OBJECT;
|
|
|
|
return OP_OBJECT_FLOAT;
|
|
|
|
}
|
|
|
|
}
|
2012-07-10 21:57:43 +02:00
|
|
|
else if (TYPE_are_objects(P1->type, P2->type) && OBJECT_are_not_null(P1->_object.object, P2->_object.object))
|
2012-07-10 16:35:17 +02:00
|
|
|
{
|
2012-07-14 17:18:22 +02:00
|
|
|
class1 = OBJECT_class(P1->_object.object);
|
|
|
|
class2 = OBJECT_class(P2->_object.object);
|
2012-07-10 16:35:17 +02:00
|
|
|
|
|
|
|
//*dynamic = P1->type == T_OBJECT || P2->type = T_OBJECT;
|
|
|
|
|
2012-07-14 17:18:22 +02:00
|
|
|
if (class1->has_operators)
|
2012-07-10 16:35:17 +02:00
|
|
|
{
|
2012-07-14 17:18:22 +02:00
|
|
|
if (class1 == class2 && CLASS_has_operator(class1, op))
|
2012-07-10 16:35:17 +02:00
|
|
|
return OP_OBJECT_OBJECT;
|
|
|
|
|
2012-07-14 17:18:22 +02:00
|
|
|
if (class2->has_operators)
|
2012-07-14 04:49:57 +02:00
|
|
|
{
|
2012-07-14 17:18:22 +02:00
|
|
|
if (CLASS_get_operator_strength(class1) > CLASS_get_operator_strength(class2) && CLASS_has_operator(class1, op + 2))
|
2012-07-14 04:49:57 +02:00
|
|
|
return OP_OBJECT_OTHER;
|
2012-07-14 17:18:22 +02:00
|
|
|
else if (CLASS_has_operator(class2, op + 2))
|
2012-07-14 04:49:57 +02:00
|
|
|
return OP_OTHER_OBJECT;
|
|
|
|
}
|
2012-07-14 17:18:22 +02:00
|
|
|
else if (CLASS_has_operator(class1, op))
|
|
|
|
return OP_OBJECT_OTHER;
|
2012-07-10 16:35:17 +02:00
|
|
|
}
|
2012-07-14 17:18:22 +02:00
|
|
|
else if (class2->has_operators && CLASS_has_operator(class2, op + 2))
|
|
|
|
return OP_OTHER_OBJECT;
|
2012-07-10 16:35:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return OP_NOTHING;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EXEC_operator(uchar what, uchar op, VALUE *P1, VALUE *P2)
|
|
|
|
{
|
2012-07-14 04:49:57 +02:00
|
|
|
static void *jump[] = { NULL, &&__OBJECT_FLOAT, &&__FLOAT_OBJECT, &&__OBJECT_OTHER, &&__OTHER_OBJECT, &&__OBJECT_OBJECT };
|
2012-07-10 16:35:17 +02:00
|
|
|
|
|
|
|
void *func;
|
|
|
|
void *result;
|
2012-07-14 04:49:57 +02:00
|
|
|
bool invert;
|
|
|
|
void *o1, *o2;
|
2012-07-10 16:35:17 +02:00
|
|
|
|
|
|
|
goto *jump[what];
|
|
|
|
|
|
|
|
__OBJECT_FLOAT:
|
|
|
|
|
2012-07-14 04:49:57 +02:00
|
|
|
o1 = P1->_object.object;
|
|
|
|
if (!o1)
|
2016-03-20 02:27:31 +01:00
|
|
|
THROW_NULL();
|
2012-07-10 16:35:17 +02:00
|
|
|
|
2012-07-14 04:49:57 +02:00
|
|
|
func = OBJECT_class(o1)->operators[op];
|
2012-07-10 16:35:17 +02:00
|
|
|
VALUE_conv_float(P2);
|
2012-07-14 04:49:57 +02:00
|
|
|
result = (*(FUNC_O_OF)func)(o1, P2->_float.value, FALSE);
|
2013-03-30 14:51:10 +01:00
|
|
|
OBJECT_REF(result);
|
|
|
|
OBJECT_UNREF(o1);
|
2012-07-14 17:18:22 +02:00
|
|
|
|
|
|
|
if (!result)
|
|
|
|
{
|
|
|
|
if (op != CO_DIVF)
|
|
|
|
raise_error(o1, NULL);
|
|
|
|
}
|
|
|
|
|
2012-07-10 16:35:17 +02:00
|
|
|
goto __END;
|
|
|
|
|
|
|
|
__FLOAT_OBJECT:
|
|
|
|
|
2012-07-14 17:18:22 +02:00
|
|
|
o1 = P2->_object.object;
|
|
|
|
if (!o1)
|
2016-03-20 02:27:31 +01:00
|
|
|
THROW_NULL();
|
2012-07-10 16:35:17 +02:00
|
|
|
|
2012-07-14 17:18:22 +02:00
|
|
|
func = OBJECT_class(o1)->operators[op];
|
2012-07-10 16:35:17 +02:00
|
|
|
VALUE_conv_float(P1);
|
2012-07-14 17:18:22 +02:00
|
|
|
result = (*(FUNC_O_OF)func)(o1, P1->_float.value, TRUE);
|
2013-03-30 14:51:10 +01:00
|
|
|
OBJECT_REF(result);
|
2012-07-10 16:35:17 +02:00
|
|
|
P1->_object.class = P2->_object.class;
|
2013-03-30 14:51:10 +01:00
|
|
|
OBJECT_UNREF(o1);
|
2012-07-14 17:18:22 +02:00
|
|
|
|
|
|
|
if (!result && !EXEC_has_native_error())
|
|
|
|
raise_error(o1, NULL);
|
|
|
|
|
2012-07-10 16:35:17 +02:00
|
|
|
goto __END;
|
|
|
|
|
2012-07-14 04:49:57 +02:00
|
|
|
__OTHER_OBJECT:
|
2012-07-10 16:35:17 +02:00
|
|
|
|
2012-07-14 04:49:57 +02:00
|
|
|
o2 = P1->_object.object;
|
|
|
|
o1 = P2->_object.object;
|
2012-07-10 16:35:17 +02:00
|
|
|
|
2012-07-14 04:49:57 +02:00
|
|
|
invert = TRUE;
|
|
|
|
goto __OTHER;
|
2012-07-10 16:35:17 +02:00
|
|
|
|
2012-07-14 04:49:57 +02:00
|
|
|
__OBJECT_OTHER:
|
2012-07-10 16:35:17 +02:00
|
|
|
__OBJECT_OBJECT:
|
|
|
|
|
2012-07-14 04:49:57 +02:00
|
|
|
o1 = P1->_object.object;
|
|
|
|
o2 = P2->_object.object;
|
|
|
|
|
|
|
|
invert = FALSE;
|
|
|
|
goto __OTHER;
|
|
|
|
|
|
|
|
__OTHER:
|
|
|
|
|
|
|
|
if (!OBJECT_are_not_null(o1, o2))
|
2016-03-20 02:27:31 +01:00
|
|
|
THROW_NULL();
|
2012-07-10 16:35:17 +02:00
|
|
|
|
2012-07-14 04:49:57 +02:00
|
|
|
func = OBJECT_class(o1)->operators[op];
|
|
|
|
result = (*(FUNC_O_OO)func)(o1, o2, invert);
|
2013-03-30 14:51:10 +01:00
|
|
|
OBJECT_REF(result);
|
|
|
|
OBJECT_UNREF(o1);
|
|
|
|
OBJECT_UNREF(o2);
|
2012-07-10 16:35:17 +02:00
|
|
|
|
2012-07-14 17:18:22 +02:00
|
|
|
if (!result && !EXEC_has_native_error())
|
|
|
|
raise_error(o1, o2);
|
|
|
|
|
2012-07-10 16:35:17 +02:00
|
|
|
__END:
|
|
|
|
|
|
|
|
P1->_object.object = result;
|
2012-07-14 04:49:57 +02:00
|
|
|
|
|
|
|
if (EXEC_has_native_error())
|
|
|
|
{
|
|
|
|
EXEC_set_native_error(FALSE);
|
|
|
|
PROPAGATE();
|
|
|
|
}
|
2012-07-10 16:35:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void EXEC_operator_object_add_quick(VALUE *P1, double val)
|
|
|
|
{
|
|
|
|
if (P1->_object.object)
|
|
|
|
{
|
2012-07-14 04:49:57 +02:00
|
|
|
void *func = OBJECT_class(P1->_object.object)->operators[CO_ADDF];
|
|
|
|
void *result = (*(FUNC_O_OF)func)(P1->_object.object, val, FALSE);
|
2013-03-30 14:51:10 +01:00
|
|
|
OBJECT_REF(result);
|
|
|
|
OBJECT_UNREF(P1->_object.object);
|
2012-07-10 16:35:17 +02:00
|
|
|
P1->_object.object = result;
|
|
|
|
}
|
|
|
|
else
|
2016-03-20 02:27:31 +01:00
|
|
|
THROW_NULL();
|
2012-07-14 04:49:57 +02:00
|
|
|
|
|
|
|
if (EXEC_has_native_error())
|
|
|
|
{
|
|
|
|
EXEC_set_native_error(FALSE);
|
|
|
|
PROPAGATE();
|
|
|
|
}
|
2012-07-10 16:35:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-03 23:11:55 +02:00
|
|
|
int EXEC_comparator(uchar what, uchar op, VALUE *P1, VALUE *P2)
|
2012-07-10 16:35:17 +02:00
|
|
|
{
|
2012-07-14 04:49:57 +02:00
|
|
|
static void *jump[] = { NULL, &&__OBJECT_FLOAT, &&__FLOAT_OBJECT, &&__OBJECT_OTHER, &&__OTHER_OBJECT, &&__OBJECT_OBJECT };
|
2012-07-10 16:35:17 +02:00
|
|
|
|
|
|
|
void *func;
|
|
|
|
int result;
|
2012-07-14 04:49:57 +02:00
|
|
|
bool invert;
|
|
|
|
void *o1, *o2;
|
2012-07-10 16:35:17 +02:00
|
|
|
|
|
|
|
goto *jump[what];
|
|
|
|
|
|
|
|
__OBJECT_FLOAT:
|
|
|
|
|
2012-07-14 04:49:57 +02:00
|
|
|
o1 = P1->_object.object;
|
2012-08-06 22:14:41 +02:00
|
|
|
if (!o1)
|
2016-03-20 02:27:31 +01:00
|
|
|
THROW_NULL();
|
2012-08-06 22:14:41 +02:00
|
|
|
|
2012-07-14 04:49:57 +02:00
|
|
|
func = OBJECT_class(o1)->operators[op];
|
2012-07-10 16:35:17 +02:00
|
|
|
VALUE_conv_float(P2);
|
2012-07-14 04:49:57 +02:00
|
|
|
result = (*(FUNC_I_OF)func)(o1, P2->_float.value, FALSE);
|
2013-03-30 14:51:10 +01:00
|
|
|
OBJECT_UNREF(o1);
|
2012-07-16 18:30:55 +02:00
|
|
|
|
2013-09-03 23:11:55 +02:00
|
|
|
if (result < (-1))
|
2012-07-16 18:30:55 +02:00
|
|
|
raise_error(o1, NULL);
|
|
|
|
|
2012-07-14 04:49:57 +02:00
|
|
|
goto __END;
|
2012-07-10 16:35:17 +02:00
|
|
|
|
|
|
|
__FLOAT_OBJECT:
|
|
|
|
|
2012-07-14 04:49:57 +02:00
|
|
|
o2 = P2->_object.object;
|
2012-08-06 22:14:41 +02:00
|
|
|
if (!o2)
|
2016-03-20 02:27:31 +01:00
|
|
|
THROW_NULL();
|
2012-08-06 22:14:41 +02:00
|
|
|
|
2012-07-14 04:49:57 +02:00
|
|
|
func = OBJECT_class(o2)->operators[op];
|
2012-07-10 16:35:17 +02:00
|
|
|
VALUE_conv_float(P1);
|
2012-07-14 04:49:57 +02:00
|
|
|
result = (*(FUNC_I_OF)func)(o2, P1->_float.value, TRUE);
|
2013-03-30 14:51:10 +01:00
|
|
|
OBJECT_UNREF(o2);
|
2012-07-16 18:30:55 +02:00
|
|
|
|
2013-09-03 23:11:55 +02:00
|
|
|
if (result < (-1))
|
2012-07-16 18:30:55 +02:00
|
|
|
raise_error(o2, NULL);
|
|
|
|
|
2012-07-14 04:49:57 +02:00
|
|
|
goto __END;
|
2012-07-10 16:35:17 +02:00
|
|
|
|
2012-07-14 04:49:57 +02:00
|
|
|
__OTHER_OBJECT:
|
2012-07-10 16:35:17 +02:00
|
|
|
|
2012-07-14 04:49:57 +02:00
|
|
|
o2 = P1->_object.object;
|
|
|
|
o1 = P2->_object.object;
|
|
|
|
invert = TRUE;
|
|
|
|
goto __OTHER;
|
2012-07-10 16:35:17 +02:00
|
|
|
|
2012-07-14 04:49:57 +02:00
|
|
|
__OBJECT_OTHER:
|
2012-07-10 16:35:17 +02:00
|
|
|
__OBJECT_OBJECT:
|
|
|
|
|
2012-07-14 04:49:57 +02:00
|
|
|
o1 = P1->_object.object;
|
|
|
|
o2 = P2->_object.object;
|
|
|
|
invert = FALSE;
|
|
|
|
goto __OTHER;
|
|
|
|
|
|
|
|
__OTHER:
|
|
|
|
|
2012-08-06 22:14:41 +02:00
|
|
|
if (!OBJECT_are_not_null(o1, o2))
|
2016-03-20 02:27:31 +01:00
|
|
|
THROW_NULL();
|
2012-08-06 22:14:41 +02:00
|
|
|
|
2012-07-14 04:49:57 +02:00
|
|
|
func = OBJECT_class(o1)->operators[op];
|
|
|
|
result = (*(FUNC_I_OO)func)(o1, o2, invert);
|
2013-03-30 14:51:10 +01:00
|
|
|
OBJECT_UNREF(o1);
|
|
|
|
OBJECT_UNREF(o2);
|
2012-07-16 18:30:55 +02:00
|
|
|
//result = !!result; // result != 0;
|
|
|
|
|
2013-09-03 23:11:55 +02:00
|
|
|
if (result < (-1))
|
2012-07-16 18:30:55 +02:00
|
|
|
raise_error(o1, o2);
|
2012-07-14 04:49:57 +02:00
|
|
|
|
|
|
|
__END:
|
|
|
|
|
|
|
|
if (EXEC_has_native_error())
|
|
|
|
{
|
|
|
|
EXEC_set_native_error(FALSE);
|
|
|
|
PROPAGATE();
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
2012-07-10 16:35:17 +02:00
|
|
|
}
|
|
|
|
|
2013-09-03 23:11:55 +02:00
|
|
|
void EXEC_operator_object_sgn(VALUE *P1)
|
2012-07-10 16:35:17 +02:00
|
|
|
{
|
|
|
|
if (P1->_object.object)
|
|
|
|
{
|
2013-09-03 23:11:55 +02:00
|
|
|
void *func = OBJECT_class(P1->_object.object)->operators[CO_SGN];
|
|
|
|
int result = (*(FUNC_I_O)func)(P1->_object.object);
|
2013-03-30 14:51:10 +01:00
|
|
|
OBJECT_UNREF(P1->_object.object);
|
2013-09-03 23:11:55 +02:00
|
|
|
P1->type = T_INTEGER;
|
|
|
|
P1->_integer.value = result;
|
2012-07-10 16:35:17 +02:00
|
|
|
}
|
|
|
|
else
|
2016-03-20 02:27:31 +01:00
|
|
|
THROW_NULL();
|
2012-07-14 04:49:57 +02:00
|
|
|
|
|
|
|
if (EXEC_has_native_error())
|
|
|
|
{
|
|
|
|
EXEC_set_native_error(FALSE);
|
|
|
|
PROPAGATE();
|
|
|
|
}
|
2012-07-10 16:35:17 +02:00
|
|
|
}
|
|
|
|
|
2013-09-08 01:09:01 +02:00
|
|
|
void EXEC_operator_object_fabs(VALUE *P1)
|
|
|
|
{
|
|
|
|
if (P1->_object.object)
|
|
|
|
{
|
|
|
|
void *func = OBJECT_class(P1->_object.object)->operators[CO_FABS];
|
|
|
|
double result = (*(FUNC_F_O)func)(P1->_object.object);
|
|
|
|
OBJECT_UNREF(P1->_object.object);
|
|
|
|
P1->type = T_FLOAT;
|
|
|
|
P1->_float.value = result;
|
|
|
|
}
|
|
|
|
else
|
2016-03-20 02:27:31 +01:00
|
|
|
THROW_NULL();
|
2013-09-08 01:09:01 +02:00
|
|
|
|
|
|
|
if (EXEC_has_native_error())
|
|
|
|
{
|
|
|
|
EXEC_set_native_error(FALSE);
|
|
|
|
PROPAGATE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-10 16:35:17 +02:00
|
|
|
void EXEC_operator_object_single(uchar op, VALUE *P1)
|
|
|
|
{
|
|
|
|
if (P1->_object.object)
|
|
|
|
{
|
2012-07-14 04:49:57 +02:00
|
|
|
void *func = OBJECT_class(P1->_object.object)->operators[op];
|
2012-07-10 16:35:17 +02:00
|
|
|
void *result = (*(FUNC_O_O)func)(P1->_object.object);
|
2013-03-30 14:51:10 +01:00
|
|
|
OBJECT_REF(result);
|
|
|
|
OBJECT_UNREF(P1->_object.object);
|
2012-07-10 16:35:17 +02:00
|
|
|
P1->_object.object = result;
|
|
|
|
}
|
|
|
|
else
|
2016-03-20 02:27:31 +01:00
|
|
|
THROW_NULL();
|
2012-07-14 04:49:57 +02:00
|
|
|
|
|
|
|
if (EXEC_has_native_error())
|
|
|
|
{
|
|
|
|
EXEC_set_native_error(FALSE);
|
|
|
|
PROPAGATE();
|
|
|
|
}
|
2012-07-10 16:35:17 +02:00
|
|
|
}
|