gambas-source-code/main/gbx/gbx_exec_operator.c
Benoît Minisini df89e09b2e [INTERPRETER]
* NEW: '_operators' interface has been renamed as '_operator'.
* NEW: Arithmetic operators now can be applied on two objects with
  different classes. One at least must implement the '_operator' interface.
* NEW: Each class that implements the '_operator' interface has now an 
  automatic priority that follows the load order. When a binary operator 
  has two objects that implement two different '_operator' interface, the
  one having the highest priority is used.
* NEW: Implementing all methods in the '_operators' interface is not 
  mandatory anymore. If one method is not implemented, then it is replaced
  by a function that raises a 'Type mismatch' error.

[GB.GSL]
* NEW: Matrix arithmetic has been implemented.
* NEW: Matrix.Determinant() method.
* NEW: Matrix.Invert() method.
* NEW: Matrix.Transpose() method.
* NEW: Matrix _call special method multiplies a matrix by a vector.
* NEW: Vector <-> Array conversion.


git-svn-id: svn://localhost/gambas/trunk@4946 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2012-07-14 02:49:57 +00:00

309 lines
6.9 KiB
C

/***************************************************************************
gbx_exec_operator.c
(c) 2000-2012 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., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
***************************************************************************/
#define __GBX_EXEC_OPERATOR_C
#include "gb_common.h"
#include "gbx_type.h"
#include "gbx_api.h"
#include "gbx_exec.h"
typedef
void *(*FUNC_O_OF)(void *, double, bool);
typedef
void *(*FUNC_O_OO)(void *, void *, bool);
typedef
int (*FUNC_I_OF)(void *, double, bool);
typedef
int (*FUNC_I_OO)(void *, void *, bool);
typedef
void *(*FUNC_O_O)(void *);
typedef
double (*FUNC_F_O)(void *);
void *EXEC_no_operator_O_OO(void *a, void *b, bool invert)
{
GB_Error((char *)E_TYPE, TYPE_get_name((TYPE)OBJECT_class(a)), TYPE_get_name((TYPE)OBJECT_class(b)));
return NULL;
}
void *EXEC_no_operator_O_OF(void *a, double b, bool invert)
{
GB_Error((char *)E_TYPE, TYPE_get_name((TYPE)OBJECT_class(a)), "Number");
return NULL;
}
bool EXEC_check_operator_single(VALUE *P1)
{
return (TYPE_is_object(P1->type) && P1->_object.object && OBJECT_class(P1->_object.object)->has_operators);
}
int EXEC_check_operator(VALUE *P1, VALUE *P2)
{
if (TYPE_is_number(P1->type) && TYPE_is_object(P2->type))
{
if (P2->_object.object && OBJECT_class(P2->_object.object)->has_operators)
{
//*dynamic = P2->type == T_OBJECT;
return OP_FLOAT_OBJECT;
}
}
else if (TYPE_is_number(P2->type) && TYPE_is_object(P1->type))
{
if (P1->_object.object && OBJECT_class(P1->_object.object)->has_operators)
{
//*dynamic = P1->type == T_OBJECT;
return OP_OBJECT_FLOAT;
}
}
else if (TYPE_are_objects(P1->type, P2->type) && OBJECT_are_not_null(P1->_object.object, P2->_object.object))
{
CLASS *class1 = OBJECT_class(P1->_object.object);
CLASS *class2 = OBJECT_class(P2->_object.object);
//*dynamic = P1->type == T_OBJECT || P2->type = T_OBJECT;
if (class1 && class1->has_operators)
{
if (class1 == class2)
return OP_OBJECT_OBJECT;
if (class2 && class2->has_operators)
{
if (CLASS_get_operator_strength(class1) > CLASS_get_operator_strength(class2))
return OP_OBJECT_OTHER;
else
return OP_OTHER_OBJECT;
}
}
}
return OP_NOTHING;
}
void EXEC_operator(uchar what, uchar op, VALUE *P1, VALUE *P2)
{
static void *jump[] = { NULL, &&__OBJECT_FLOAT, &&__FLOAT_OBJECT, &&__OBJECT_OTHER, &&__OTHER_OBJECT, &&__OBJECT_OBJECT };
void *func;
void *result;
bool invert;
void *o1, *o2;
goto *jump[what];
__OBJECT_FLOAT:
o1 = P1->_object.object;
if (!o1)
THROW(E_NULL);
func = OBJECT_class(o1)->operators[op];
VALUE_conv_float(P2);
result = (*(FUNC_O_OF)func)(o1, P2->_float.value, FALSE);
OBJECT_REF(result, "EXEC_operator");
OBJECT_UNREF(o1, "EXEC_operator");
goto __END;
__FLOAT_OBJECT:
o2 = P2->_object.object;
if (!o2)
THROW(E_NULL);
func = OBJECT_class(o2)->operators[op];
VALUE_conv_float(P1);
result = (*(FUNC_O_OF)func)(o2, P1->_float.value, TRUE);
OBJECT_REF(result, "EXEC_operator");
P1->_object.class = P2->_object.class;
OBJECT_UNREF(o2, "EXEC_operator");
goto __END;
__OTHER_OBJECT:
o2 = P1->_object.object;
o1 = P2->_object.object;
invert = TRUE;
goto __OTHER;
__OBJECT_OTHER:
__OBJECT_OBJECT:
o1 = P1->_object.object;
o2 = P2->_object.object;
invert = FALSE;
goto __OTHER;
__OTHER:
if (!OBJECT_are_not_null(o1, o2))
THROW(E_NULL);
func = OBJECT_class(o1)->operators[op];
result = (*(FUNC_O_OO)func)(o1, o2, invert);
OBJECT_REF(result, "EXEC_operator");
OBJECT_UNREF(o1, "EXEC_operator");
OBJECT_UNREF(o2, "EXEC_operator");
__END:
P1->_object.object = result;
if (EXEC_has_native_error())
{
EXEC_set_native_error(FALSE);
PROPAGATE();
}
}
void EXEC_operator_object_add_quick(VALUE *P1, double val)
{
if (P1->_object.object)
{
void *func = OBJECT_class(P1->_object.object)->operators[CO_ADDF];
void *result = (*(FUNC_O_OF)func)(P1->_object.object, val, FALSE);
OBJECT_REF(result, "EXEC_operator_object_float_direct");
OBJECT_UNREF(P1->_object.object, "EXEC_operator_object_float_direct");
P1->_object.object = result;
}
else
THROW(E_NULL);
if (EXEC_has_native_error())
{
EXEC_set_native_error(FALSE);
PROPAGATE();
}
}
bool EXEC_comparator(uchar what, uchar op, VALUE *P1, VALUE *P2)
{
static void *jump[] = { NULL, &&__OBJECT_FLOAT, &&__FLOAT_OBJECT, &&__OBJECT_OTHER, &&__OTHER_OBJECT, &&__OBJECT_OBJECT };
void *func;
int result;
bool invert;
void *o1, *o2;
goto *jump[what];
__OBJECT_FLOAT:
o1 = P1->_object.object;
func = OBJECT_class(o1)->operators[op];
VALUE_conv_float(P2);
result = (*(FUNC_I_OF)func)(o1, P2->_float.value, FALSE);
OBJECT_UNREF(o1, "EXEC_comparator");
goto __END;
__FLOAT_OBJECT:
o2 = P2->_object.object;
func = OBJECT_class(o2)->operators[op];
VALUE_conv_float(P1);
result = (*(FUNC_I_OF)func)(o2, P1->_float.value, TRUE);
OBJECT_UNREF(o2, "EXEC_comparator");
goto __END;
__OTHER_OBJECT:
o2 = P1->_object.object;
o1 = P2->_object.object;
invert = TRUE;
goto __OTHER;
__OBJECT_OTHER:
__OBJECT_OBJECT:
o1 = P1->_object.object;
o2 = P2->_object.object;
invert = FALSE;
goto __OTHER;
__OTHER:
func = OBJECT_class(o1)->operators[op];
result = (*(FUNC_I_OO)func)(o1, o2, invert);
OBJECT_UNREF(o1, "EXEC_comparator");
OBJECT_UNREF(o2, "EXEC_comparator");
result = !!result; // result != 0;
__END:
if (EXEC_has_native_error())
{
EXEC_set_native_error(FALSE);
PROPAGATE();
}
return result;
}
void EXEC_operator_object_abs(VALUE *P1)
{
if (P1->_object.object)
{
void *func = OBJECT_class(P1->_object.object)->operators[CO_ABS];
double result = (*(FUNC_F_O)func)(P1->_object.object);
OBJECT_UNREF(P1->_object.object, "EXEC_operator_object_abs");
P1->type = T_FLOAT;
P1->_float.value = result;
}
else
THROW(E_NULL);
if (EXEC_has_native_error())
{
EXEC_set_native_error(FALSE);
PROPAGATE();
}
}
void EXEC_operator_object_single(uchar op, VALUE *P1)
{
if (P1->_object.object)
{
void *func = OBJECT_class(P1->_object.object)->operators[op];
void *result = (*(FUNC_O_O)func)(P1->_object.object);
OBJECT_REF(result, "EXEC_operator_object_single");
OBJECT_UNREF(P1->_object.object, "EXEC_operator_object_single");
P1->_object.object = result;
}
else
THROW(E_NULL);
if (EXEC_has_native_error())
{
EXEC_set_native_error(FALSE);
PROPAGATE();
}
}