diff --git a/gb.gsl/src/c_complex.c b/gb.gsl/src/c_complex.c index 1028b0685..2b2271433 100644 --- a/gb.gsl/src/c_complex.c +++ b/gb.gsl/src/c_complex.c @@ -38,20 +38,228 @@ #define THIS ((GSLCOMPLEX *)_object) +//---- Complex number creation ---------------------------------------------- -/*********************************** - Complex Utility Methods -***********************************/ -GSLCOMPLEX *GSLComplex_create() +GSLCOMPLEX *COMPLEX_create() { + static GB_CLASS _klass = (GB_CLASS)NULL; + GSLCOMPLEX *c; - c = (GSLCOMPLEX *)GB.New(GB.FindClass("Complex"), NULL, NULL); + + if (!_klass) + _klass = GB.FindClass("Complex"); + + c = (GSLCOMPLEX *)GB.New(_klass, NULL, NULL); c->number.dat[0] = 0.0; c->number.dat[1] = 0.0; return c; } +//---- Arithmetic operators ------------------------------------------------- + +static GSLCOMPLEX *_addf(GSLCOMPLEX *a, double f) +{ + GSLCOMPLEX *r = COMPLEX_create(); + r->number = gsl_complex_add_real(a->number, f); + return r; +} + +static GSLCOMPLEX *_add(GSLCOMPLEX *a, GSLCOMPLEX *b) +{ + GSLCOMPLEX *r = COMPLEX_create(); + r->number = gsl_complex_add(a->number, b->number); + return r; +} + +static GSLCOMPLEX *_subf(GSLCOMPLEX *a, double f) +{ + GSLCOMPLEX *r = COMPLEX_create(); + r->number = gsl_complex_sub_real(a->number, f); + return r; +} + +static GSLCOMPLEX *_sub(GSLCOMPLEX *a, GSLCOMPLEX *b) +{ + GSLCOMPLEX *r = COMPLEX_create(); + r->number = gsl_complex_sub(a->number, b->number); + return r; +} + +static GSLCOMPLEX *_mulf(GSLCOMPLEX *a, double f) +{ + GSLCOMPLEX *r = COMPLEX_create(); + r->number = gsl_complex_mul_real(a->number, f); + return r; +} + +static GSLCOMPLEX *_mul(GSLCOMPLEX *a, GSLCOMPLEX *b) +{ + GSLCOMPLEX *r = COMPLEX_create(); + r->number = gsl_complex_mul(a->number, b->number); + return r; +} + +static GSLCOMPLEX *_divf(GSLCOMPLEX *a, double f) +{ + gsl_complex c = gsl_complex_div_real(a->number, f); + + if (isfinite(c.dat[0]) && isfinite(c.dat[1])) + { + GSLCOMPLEX *r = COMPLEX_create(); + r->number = c; + return r; + } + else + return NULL; +} + +static GSLCOMPLEX *_idivf(GSLCOMPLEX *a, double f) +{ + GSLCOMPLEX *r = COMPLEX_create(); + r->number = gsl_complex_mul_real(gsl_complex_inverse(a->number), f); + return r; +} + +static GSLCOMPLEX *_div(GSLCOMPLEX *a, GSLCOMPLEX *b) +{ + gsl_complex c = gsl_complex_div(a->number, b->number); + + if (isfinite(c.dat[0]) && isfinite(c.dat[1])) + { + GSLCOMPLEX *r = COMPLEX_create(); + r->number = c; + return r; + } + else + return NULL; +} + +static int _equal(GSLCOMPLEX *a, GSLCOMPLEX *b) +{ + return a->number.dat[0] == b->number.dat[0] && a->number.dat[1] == b->number.dat[1]; +} + +static int _equalf(GSLCOMPLEX *a, double f) +{ + return a->number.dat[0] == f && a->number.dat[1] == 0.0; +} + +static GSLCOMPLEX *_neg(GSLCOMPLEX *a) +{ + GSLCOMPLEX *r = COMPLEX_create(); + r->number = gsl_complex_negative(a->number); + return r; +} + +static double _abs(GSLCOMPLEX *a) +{ + return gsl_complex_abs(a->number); +} + +static GB_OPERATOR_DESC _operators = +{ + add: (void *)_add, + addf: (void *)_addf, + sub: (void *)_sub, + subf: (void *)_subf, + mul: (void *)_mul, + mulf: (void *)_mulf, + div: (void *)_div, + divf: (void *)_divf, + idivf: (void *)_idivf, + equal: (void *)_equal, + equalf: (void *)_equalf, + abs: (void *)_abs, + neg: (void *)_neg +}; + +//---- Conversions ---------------------------------------------------------- + +static char *_to_string(GSLCOMPLEX *_object, bool local) +{ + char buffer[64]; + char *p; + char *str; + int len; + double real, imag; + + if (!THIS) + return NULL; + + real = THIS->number.dat[0]; + imag = THIS->number.dat[1]; + + if (real == 0.0 && imag == 0.0) + return GB.NewString("0", 1); + + p = buffer; + + if (real != 0.0) + { + GB.NumberToString(local, real, NULL, &str, &len); + strncpy(p, str, len); + p += len; + } + + if (imag != 0.0) + { + if (imag < 0.0) + { + *p++ = '-'; + imag = (-imag); + } + else if (p != buffer) + *p++ = '+'; + + if (imag != 1.0) + { + GB.NumberToString(local, imag, NULL, &str, &len); + strncpy(p, str, len); + p += len; + } + *p++ = 'i'; + } + + return GB.NewString(buffer, p - buffer); +} + +static bool _convert(GSLCOMPLEX *a, GB_TYPE type, GB_VALUE *conv) +{ + switch (type) + { + case GB_T_FLOAT: + conv->_float.value = gsl_complex_abs(a->number); + return FALSE; + + case GB_T_SINGLE: + conv->_single.value = gsl_complex_abs(a->number); + return FALSE; + + case GB_T_INTEGER: + case GB_T_SHORT: + case GB_T_BYTE: + conv->_integer.value = gsl_complex_abs(a->number); + return FALSE; + + case GB_T_LONG: + conv->_long.value = gsl_complex_abs(a->number); + return FALSE; + + case GB_T_STRING: + case GB_T_CSTRING: + conv->_string.value.addr = _to_string(a, type == GB_T_CSTRING); + conv->_string.value.start = 0; + conv->_string.value.len = GB.StringLength(conv->_string.value.addr); + return FALSE; + + default: + return TRUE; + } +} + +//--------------------------------------------------------------------------- + BEGIN_METHOD(GslComplex_new, GB_FLOAT real; GB_FLOAT imag) THIS->number.dat[0] = VARGOPT(real, 0.0); @@ -62,7 +270,7 @@ END_METHOD BEGIN_METHOD(GslComplex_call, GB_FLOAT real; GB_FLOAT imag) - GSLCOMPLEX *c = GSLComplex_create(); + GSLCOMPLEX *c = COMPLEX_create(); c->number.dat[0] = VARG(real); c->number.dat[1] = VARG(imag); @@ -73,7 +281,7 @@ END_METHOD BEGIN_METHOD_VOID(GslComplex_Copy) - GSLCOMPLEX *c = GSLComplex_create(); + GSLCOMPLEX *c = COMPLEX_create(); c->number = THIS->number; GB.ReturnObject(c); @@ -110,15 +318,11 @@ BEGIN_METHOD_VOID(GslComplex_ToString) { if (imag < 0.0) { - *p++ = ' '; *p++ = '-'; - *p++ = ' '; imag = (-imag); } else if (p != buffer) - *p++ = ' '; *p++ = '+'; - *p++ = ' '; if (imag != 1.0) { @@ -233,7 +437,7 @@ BEGIN_METHOD(GslComplex_Add, GB_OBJECT x) return; // Create new object - obj = GSLComplex_create(); + obj = COMPLEX_create(); // Add two complex numbers obj->number = gsl_complex_add(THIS->number, x->number); @@ -251,7 +455,7 @@ BEGIN_METHOD(GslComplex_Sub, GB_OBJECT x) if (GB.CheckObject(x)) return; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_sub(THIS->number, x->number); @@ -268,7 +472,7 @@ BEGIN_METHOD(GslComplex_Mul, GB_OBJECT x) if (GB.CheckObject(x)) return; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_mul(THIS->number, x->number); @@ -285,7 +489,7 @@ BEGIN_METHOD(GslComplex_Div, GB_OBJECT x) if (GB.CheckObject(x)) return; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_div(THIS->number, x->number); @@ -301,7 +505,7 @@ BEGIN_METHOD(GslComplex_Add_Real, GB_FLOAT x) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_add_real(THIS->number, VARG(x)); @@ -314,7 +518,7 @@ BEGIN_METHOD(GslComplex_Sub_Real, GB_FLOAT x) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_sub_real(THIS->number, VARG(x)); @@ -327,7 +531,7 @@ BEGIN_METHOD(GslComplex_Mul_Real, GB_FLOAT x) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_mul_real(THIS->number, VARG(x)); @@ -340,7 +544,7 @@ BEGIN_METHOD(GslComplex_Div_Real, GB_FLOAT x) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_div_real(THIS->number, VARG(x)); @@ -356,7 +560,7 @@ BEGIN_METHOD(GslComplex_Add_Imag, GB_FLOAT x) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_add_imag(THIS->number, VARG(x)); @@ -369,7 +573,7 @@ BEGIN_METHOD(GslComplex_Sub_Imag, GB_FLOAT x) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_sub_imag(THIS->number, VARG(x)); @@ -382,7 +586,7 @@ BEGIN_METHOD(GslComplex_Mul_Imag, GB_FLOAT x) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_mul_imag(THIS->number, VARG(x)); @@ -395,7 +599,7 @@ BEGIN_METHOD(GslComplex_Div_Imag, GB_FLOAT x) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_div_imag(THIS->number, VARG(x)); @@ -408,7 +612,7 @@ BEGIN_METHOD_VOID(GslComplex_Conjugate) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_conjugate(THIS->number); @@ -420,7 +624,7 @@ BEGIN_METHOD_VOID(GslComplex_Inverse) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_inverse(THIS->number); @@ -433,7 +637,7 @@ BEGIN_METHOD_VOID(GslComplex_Negative) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_negative(THIS->number); @@ -449,7 +653,7 @@ BEGIN_METHOD_VOID(GslComplex_Sqrt) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_sqrt(THIS->number); @@ -462,7 +666,7 @@ BEGIN_METHOD(GslComplex_SqrtReal, GB_FLOAT x;) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_sqrt_real(VARG(x)); @@ -479,7 +683,7 @@ BEGIN_METHOD(GslComplex_Pow, GB_OBJECT x;) if (GB.CheckObject(x)) return; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_pow(THIS->number, x->number); @@ -492,7 +696,7 @@ BEGIN_METHOD(GslComplex_PowReal, GB_FLOAT x;) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_pow_real(THIS->number, VARG(x)); @@ -505,7 +709,7 @@ BEGIN_METHOD_VOID(GslComplex_Exp) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_exp(THIS->number); @@ -518,7 +722,7 @@ BEGIN_METHOD_VOID(GslComplex_Log) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_log(THIS->number); @@ -531,7 +735,7 @@ BEGIN_METHOD_VOID(GslComplex_Log10) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_log10(THIS->number); @@ -548,7 +752,7 @@ BEGIN_METHOD(GslComplex_Log_b, GB_OBJECT x;) if (GB.CheckObject(x)) return; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_log_b(THIS->number, x->number); @@ -566,7 +770,7 @@ BEGIN_METHOD_VOID(GslComplex_Sin) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_sin(THIS->number); @@ -579,7 +783,7 @@ BEGIN_METHOD_VOID(GslComplex_Cos) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_cos(THIS->number); @@ -592,7 +796,7 @@ BEGIN_METHOD_VOID(GslComplex_Tan) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_tan(THIS->number); @@ -605,7 +809,7 @@ BEGIN_METHOD_VOID(GslComplex_Sec) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_sec(THIS->number); @@ -618,7 +822,7 @@ BEGIN_METHOD_VOID(GslComplex_Csc) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_csc(THIS->number); @@ -631,7 +835,7 @@ BEGIN_METHOD_VOID(GslComplex_Cot) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_cot(THIS->number); @@ -648,7 +852,7 @@ END_METHOD BEGIN_METHOD_VOID(GslComplex_Arcsin) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_arcsin(THIS->number); @@ -661,7 +865,7 @@ BEGIN_METHOD(GslComplex_Arcsin_Real, GB_FLOAT x;) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_arcsin_real(VARG(x)); @@ -673,7 +877,7 @@ END_METHOD BEGIN_METHOD_VOID(GslComplex_Arccos) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_arccos(THIS->number); @@ -686,7 +890,7 @@ BEGIN_METHOD(GslComplex_Arccos_Real, GB_FLOAT x;) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_arccos_real(VARG(x)); @@ -698,7 +902,7 @@ END_METHOD BEGIN_METHOD_VOID(GslComplex_Arctan) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_arctan(THIS->number); @@ -710,7 +914,7 @@ END_METHOD BEGIN_METHOD_VOID(GslComplex_Arcsec) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_arcsec(THIS->number); @@ -723,7 +927,7 @@ BEGIN_METHOD(GslComplex_Arcsec_Real, GB_FLOAT x;) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_arcsec_real(VARG(x)); @@ -735,7 +939,7 @@ END_METHOD BEGIN_METHOD_VOID(GslComplex_Arccsc) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_arccsc(THIS->number); @@ -748,7 +952,7 @@ BEGIN_METHOD(GslComplex_Arccsc_Real, GB_FLOAT x;) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_arccsc_real(VARG(x)); @@ -760,7 +964,7 @@ END_METHOD BEGIN_METHOD_VOID(GslComplex_Arccot) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_arccot(THIS->number); @@ -777,7 +981,7 @@ END_METHOD BEGIN_METHOD_VOID(GslComplex_Sinh) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_sinh(THIS->number); @@ -789,7 +993,7 @@ END_METHOD BEGIN_METHOD_VOID(GslComplex_Cosh) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_cosh(THIS->number); @@ -801,7 +1005,7 @@ END_METHOD BEGIN_METHOD_VOID(GslComplex_Tanh) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_tanh(THIS->number); @@ -813,7 +1017,7 @@ END_METHOD BEGIN_METHOD_VOID(GslComplex_Sech) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_sech(THIS->number); @@ -825,7 +1029,7 @@ END_METHOD BEGIN_METHOD_VOID(GslComplex_Csch) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_csch(THIS->number); @@ -837,7 +1041,7 @@ END_METHOD BEGIN_METHOD_VOID(GslComplex_Coth) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_coth(THIS->number); @@ -854,7 +1058,7 @@ END_METHOD BEGIN_METHOD_VOID(GslComplex_Arcsinh) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_arcsinh(THIS->number); @@ -866,7 +1070,7 @@ END_METHOD BEGIN_METHOD_VOID(GslComplex_Arccosh) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_arccosh(THIS->number); @@ -879,7 +1083,7 @@ BEGIN_METHOD(GslComplex_Arccosh_Real, GB_FLOAT x;) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_arccosh_real(VARG(x)); @@ -891,7 +1095,7 @@ END_METHOD BEGIN_METHOD_VOID(GslComplex_Arctanh) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_arctanh(THIS->number); @@ -904,7 +1108,7 @@ BEGIN_METHOD(GslComplex_Arctanh_Real, GB_FLOAT x;) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_arctanh_real(VARG(x)); @@ -917,7 +1121,7 @@ END_METHOD BEGIN_METHOD_VOID(GslComplex_Arcsech) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_arcsech(THIS->number); @@ -929,7 +1133,7 @@ END_METHOD BEGIN_METHOD_VOID(GslComplex_Arccsch) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_arccsch(THIS->number); @@ -941,7 +1145,7 @@ END_METHOD BEGIN_METHOD_VOID(GslComplex_Arccoth) GSLCOMPLEX *obj; - obj = GSLComplex_create(); + obj = COMPLEX_create(); obj->number = gsl_complex_arccoth(THIS->number); @@ -967,15 +1171,17 @@ GB_DESC CComplexDesc[] = GB_METHOD("Rect", NULL, GslComplex_Rect, "[(Real)f(Imag)f]"), GB_METHOD("Polar", NULL, GslComplex_Polar, "[(Real)f(Imag)f]"), GB_METHOD("Arg", "f", GslComplex_Arg, NULL), + + GB_INTERFACE("_operators", &_operators), + GB_INTERFACE("_convert", &_convert), + GB_METHOD("Abs", "f", GslComplex_Abs, NULL), GB_METHOD("Abs2", "f", GslComplex_Abs2, NULL), GB_METHOD("LogAbs", "f", GslComplex_LogAbs, NULL), - // Properties GB_PROPERTY("Real", "f", GslComplex_Real), GB_PROPERTY("Imag", "f", GslComplex_Imagined), - /* Operations on gsl_complex */ // Elementary Math Functions diff --git a/gb.gsl/src/c_complex.h b/gb.gsl/src/c_complex.h index 0245fea68..4c7ff4d6c 100644 --- a/gb.gsl/src/c_complex.h +++ b/gb.gsl/src/c_complex.h @@ -1,25 +1,25 @@ /*************************************************************************** - c_complex.h + c_complex.h - gb.gsl component + gb.gsl component - (c) 2012 Randall Morgan + (c) 2012 Randall Morgan - 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 1, or (at your option) - any later version. + 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 1, 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. + 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. + 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. ***************************************************************************/ @@ -38,14 +38,13 @@ GB_INTERFACE GB EXPORT; extern GB_DESC CComplexDesc[]; typedef - struct __GSLCOMPLEX - { - GB_BASE ob; - gsl_complex number; - } - GSLCOMPLEX; - -GSLCOMPLEX *GSLComplex_create(); + struct + { + GB_BASE ob; + gsl_complex number; + } + GSLCOMPLEX; +GSLCOMPLEX *COMPLEX_create(); #endif /* __C_GSL_COMPLEX_H */ diff --git a/gb.gsl/src/c_complexpolynomial.c b/gb.gsl/src/c_complexpolynomial.c index bc2ebd66b..76043062f 100644 --- a/gb.gsl/src/c_complexpolynomial.c +++ b/gb.gsl/src/c_complexpolynomial.c @@ -228,7 +228,7 @@ BEGIN_METHOD_VOID(CComplexPolynomial_ComplexSolve) for(i = 0; i < THIS->len-1; i++) { printf ("z%d = %+.18f %+.18f\n", i, GSL_REAL(z[i]), GSL_IMAG(z[i])); - cx = GSLComplex_create(); + cx = COMPLEX_create(); if(cx) { GSLCOMPLEX *elt; diff --git a/main/gbx/gbx_c_array.c b/main/gbx/gbx_c_array.c index e6d37b31a..1dde899b7 100644 --- a/main/gbx/gbx_c_array.c +++ b/main/gbx/gbx_c_array.c @@ -1400,15 +1400,15 @@ static void error_array_convert() OBJECT_UNREF(_converted_array, "error_array_convert"); } -static void *array_convert(CARRAY *src, CLASS *class) +static bool array_convert(CARRAY *src, CLASS *class, VALUE *conv) { CARRAY *array; int i; void *data; VALUE temp; - if (!CLASS_inherits(class, CLASS_Array)) - return NULL; + if (!TYPE_is_pure_object((TYPE)class) || !CLASS_inherits(class, CLASS_Array)) + return TRUE; _converted_array = array = OBJECT_create(class, NULL, NULL, 0); @@ -1429,7 +1429,9 @@ static void *array_convert(CARRAY *src, CLASS *class) } END_ERROR - return array; + conv->_object.object = array; + OBJECT_REF(array, "array_convert"); + return FALSE; } #else diff --git a/main/gbx/gbx_class.c b/main/gbx/gbx_class.c index 9351a9d09..525f549b5 100644 --- a/main/gbx/gbx_class.c +++ b/main/gbx/gbx_class.c @@ -1266,6 +1266,8 @@ void *CLASS_auto_create(CLASS *class, int nparam) void CLASS_search_special(CLASS *class) { + int sym; + 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); @@ -1279,7 +1281,15 @@ void CLASS_search_special(CLASS *class) class->special[SPEC_ATTACH] = CLASS_get_symbol_index_kind(class, "_attach", CD_METHOD, 0); class->special[SPEC_CONVERT] = CLASS_get_symbol_index_kind(class, "_@_convert", CD_CONSTANT, 0); + class->has_convert = class->special[SPEC_CONVERT] != NO_SYMBOL; + sym = CLASS_get_symbol_index_kind(class, "_@_operators", CD_CONSTANT, 0); + if (sym != NO_SYMBOL) + { + class->has_operators = TRUE; + class->operators = CLASS_get_desc(class, sym)->constant.value._pointer; + } + if (class->special[SPEC_NEXT] != NO_SYMBOL) class->enum_static = CLASS_DESC_get_type(CLASS_get_desc(class, class->special[SPEC_NEXT])) == CD_STATIC_METHOD; if (class->special[SPEC_UNKNOWN] != NO_SYMBOL) diff --git a/main/gbx/gbx_class.h b/main/gbx/gbx_class.h index 269f3d730..2464e3326 100644 --- a/main/gbx/gbx_class.h +++ b/main/gbx/gbx_class.h @@ -238,6 +238,28 @@ enum CS_READY = 2 }; +enum { + CO_EQUAL, + CO_EQUALF, + CO_COMP, + CO_COMPF, + CO_ADD, + CO_ADDF, + CO_SUB, + CO_SUBF, + CO_MUL, + CO_MULF, + CO_DIV, + CO_DIVF, + CO_IDIVF, + CO_NEG, + CO_POW, + CO_POWF, + CO_ABS, + CO_MAX, + CO_MIN +}; + typedef struct _CLASS { // 32b 64b struct _CLASS *class; // 4 8 Points at the 'Class' class ! @@ -271,9 +293,11 @@ typedef unsigned init_dynamic : 1; // If there is a special function to call at instanciation unsigned must_check : 1; // The class has a check function unsigned has_child : 1; // The class has an inherited child class - unsigned unknown_static : 1; // if _unknown is static + unsigned unknown_static : 1; // if _unknown is static unsigned property_static : 1; // if _property is static - unsigned _reserved : 3; // 24 36 + unsigned has_convert : 1; // if the _convert interface is implemented + unsigned has_operators : 1; // if the _operators interface is implemented + unsigned _reserved : 1; // 24 36 short n_desc; // 26 38 number of descriptions short n_event; // 28 40 number of events @@ -309,17 +333,18 @@ typedef struct _CLASS *astruct_class; // 112 176 array of struct class void *instance; // 116 184 automatically created instance + void *operators; // 120 192 arithmetic interface - COMPONENT *component; // 120 192 The component the class belongs to + COMPONENT *component; // 124 200 The component the class belongs to - struct _CLASS *override; // 124 200 The overridden class + struct _CLASS *override; // 128 208 The overridden class - struct _CLASS *next; // 128 208 next class + struct _CLASS *next; // 132 216 next class - void (**jit_functions)(void); // 132 216 array of jit functions + void (**jit_functions)(void); // 136 224 array of jit functions } CLASS; - + typedef struct { SYMBOL sym; diff --git a/main/gbx/gbx_exec_loop.c b/main/gbx/gbx_exec_loop.c index 0e3d7d5ac..18e3d872c 100644 --- a/main/gbx/gbx_exec_loop.c +++ b/main/gbx/gbx_exec_loop.c @@ -73,6 +73,8 @@ static void _SUBR_sub(ushort code); static void _SUBR_mul(ushort code); static void _SUBR_div(ushort code); +//---- Subroutine dispatch table -------------------------------------------- + static void *SubrTable[] = { /* 28 */ NULL, _SUBR_compn, _SUBR_compi, _SUBR_compi, @@ -181,6 +183,139 @@ static void *SubrTable[] = }; +//---- Object arithmetic helpers -------------------------------------------- + +#define OP_NONE 0 +#define OP_OBJECT_FLOAT 1 +#define OP_FLOAT_OBJECT 2 +#define OP_OBJECT_CONV 3 +#define OP_CONV_OBJECT 4 +#define OP_OBJECT 5 + +static int check_operators(VALUE *P1, VALUE *P2) +{ + if (TYPE_is_number(P1->type) && TYPE_is_object(P2->type)) + { + if (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 (OBJECT_class(P1->_object.object)->has_operators) + { + //*dynamic = P1->type == T_OBJECT; + return OP_OBJECT_FLOAT; + } + } + else if (TYPE_is_object(P1->type) && TYPE_is_object(P2->type)) + { + 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; + + if (class2 && class2->has_operators) + return OP_OBJECT_CONV; + } + } + + return OP_NONE; +} + +static void operator_object_float(VALUE *P1, VALUE *P2, uchar op) +{ + void *(*func)(void *, double) = (void *(*)(void *, double))((void **)(OBJECT_class(P1->_object.object)->operators))[op]; + VALUE_conv_float(P2); + void *result = (*func)(P1->_object.object, P2->_float.value); + OBJECT_REF(result, "operator_object_float"); + OBJECT_UNREF(P1->_object.object, "operator_object_float"); + P1->_object.object = result; +} + +static void operator_float_object(VALUE *P1, VALUE *P2, uchar op) +{ + void *(*func)(void *, double) = (void *(*)(void *, double))((void **)(OBJECT_class(P2->_object.object)->operators))[op]; + VALUE_conv_float(P1); + void *result = (*func)(P2->_object.object, P1->_float.value); + OBJECT_REF(result, "operator_float_object"); + P1->_object.class = P2->_object.class; + OBJECT_UNREF(P2->_object.object, "operator_float_object"); + P1->_object.object = result; +} + +static void operator_object(VALUE *P1, VALUE *P2, uchar op) +{ + void *(*func)(void *, void *) = (void *(*)(void *, void *))((void **)(OBJECT_class(P1->_object.object)->operators))[op]; + void *result = (*func)(P1->_object.object, P2->_object.object); + OBJECT_REF(result, "operator_object"); + OBJECT_UNREF(P1->_object.object, "operator_object"); + OBJECT_UNREF(P2->_object.object, "operator_object"); + P1->_object.object = result; +} + +static void operator_object_conv(VALUE *P1, VALUE *P2, char op) +{ + VALUE_conv(P2, (TYPE)P1->_object.class); + operator_object(P1, P2, op); +} + +static void operator_conv_object(VALUE *P1, VALUE *P2, char op) +{ + VALUE_conv(P1, (TYPE)P2->_object.class); + operator_object(P1, P2, op); +} + +static int comparator_object_float(VALUE *P1, VALUE *P2, uchar op) +{ + int (*func)(void *, double) = (int (*)(void *, double))((void **)(OBJECT_class(P1->_object.object)->operators))[op]; + VALUE_conv_float(P2); + int result = (*func)(P1->_object.object, P2->_float.value); + OBJECT_UNREF(P1->_object.object, "comparator_object_float"); + return result; +} + +static int comparator_float_object(VALUE *P1, VALUE *P2, uchar op) +{ + int (*func)(void *, double) = (int (*)(void *, double))((void **)(OBJECT_class(P2->_object.object)->operators))[op]; + VALUE_conv_float(P1); + int result = (*func)(P2->_object.object, P1->_float.value); + OBJECT_UNREF(P2->_object.object, "comparator_float_object"); + return result; +} + +static int comparator_object(VALUE *P1, VALUE *P2, uchar op) +{ + int (*func)(void *, void *) = (int (*)(void *, void *))((void **)(OBJECT_class(P1->_object.object)->operators))[op]; + int result = (*func)(P1->_object.object, P2->_object.object); + OBJECT_UNREF(P1->_object.object, "comparator_object"); + OBJECT_UNREF(P2->_object.object, "comparator_object"); + return result; +} + +static int comparator_object_conv(VALUE *P1, VALUE *P2, char op) +{ + VALUE_conv(P2, (TYPE)P1->_object.class); + return comparator_object(P1, P2, op); +} + +static int comparator_conv_object(VALUE *P1, VALUE *P2, char op) +{ + VALUE_conv(P1, (TYPE)P2->_object.class); + return comparator_object(P1, P2, op); +} + + + +//---- Main interpreter loop ------------------------------------------------ + void EXEC_loop(void) { static const void *jump_table[256] = @@ -1707,14 +1842,14 @@ _ADD_QUICK: if (LIKELY(type <= T_POINTER)) goto *_aq_jump[type]; - __AQ_VOID: - - THROW(E_NRETURN); - __AQ_BOOLEAN: THROW(E_TYPE, "Number", TYPE_get_name(type)); + __AQ_VOID: + + THROW(E_NRETURN); + __AQ_BYTE: P1->_integer.value = (unsigned char)(P1->_integer.value + value); @@ -2041,9 +2176,10 @@ _SUBR_LEN: _SUBR_COMP: { - static void *jump[17] = { + static void *jump[] = { &&__SC_VARIANT, &&__SC_BOOLEAN, &&__SC_BYTE, &&__SC_SHORT, &&__SC_INTEGER, &&__SC_LONG, &&__SC_SINGLE, &&__SC_FLOAT, &&__SC_DATE, - &&__SC_STRING, &&__SC_STRING, &&__SC_POINTER, &&__SC_ERROR, &&__SC_ERROR, &&__SC_ERROR, &&__SC_NULL, &&__SC_OBJECT + &&__SC_STRING, &&__SC_STRING, &&__SC_POINTER, &&__SC_ERROR, &&__SC_ERROR, &&__SC_ERROR, &&__SC_NULL, &&__SC_OBJECT, + &&__SC_OBJECT_FLOAT, &&__SC_FLOAT_OBJECT, &&__SC_OBJECT_CONV, &&__SC_CONV_OBJECT, &&__SC_OBJECT_OBJECT }; char NO_WARNING(result); @@ -2137,6 +2273,31 @@ _SUBR_COMP: //RELEASE_OBJECT(P2); goto __SC_END_RELEASE; + __SC_OBJECT_FLOAT: + + result = comparator_object_float(P1, P2, CO_EQUALF); + goto __SC_END; + + __SC_FLOAT_OBJECT: + + result = comparator_float_object(P1, P2, CO_EQUALF); + goto __SC_END; + + __SC_OBJECT_CONV: + + result = comparator_object_conv(P1, P2, CO_EQUAL); + goto __SC_END; + + __SC_CONV_OBJECT: + + result = comparator_conv_object(P1, P2, CO_EQUAL); + goto __SC_END; + + __SC_OBJECT_OBJECT: + + result = comparator_object(P1, P2, CO_EQUAL); + goto __SC_END; + __SC_VARIANT: { @@ -2155,6 +2316,15 @@ _SUBR_COMP: variant = TRUE; } + code = check_operators(P1, P2); + if (code) + { + code += T_OBJECT; + if (!(variant || P1->type == T_OBJECT || P2->type == T_OBJECT)) + *PC |= code; + goto *jump[code]; + } + type = Max(P1->type, P2->type); if (TYPE_is_object_null(P1->type) && TYPE_is_object_null(P2->type)) @@ -2345,9 +2515,10 @@ __END: static void _SUBR_compn(ushort code) { - static void *jump[17] = { + static void *jump[] = { &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__DATE, - &&__STRING, &&__STRING, &&__POINTER, &&__ERROR, &&__ERROR, &&__ERROR, &&__NULL, &&__OBJECT + &&__STRING, &&__STRING, &&__POINTER, &&__ERROR, &&__ERROR, &&__ERROR, &&__NULL, &&__OBJECT, + &&__OBJECT_FLOAT, &&__FLOAT_OBJECT, &&__OBJECT_CONV, &&__CONV_OBJECT, &&__OBJECT_OBJECT }; //static void *test[] = { &&__EQ, &&__NE, &&__GT, &&__LE, &&__LT, &&__GE }; @@ -2443,6 +2614,31 @@ __OBJECT: //RELEASE_OBJECT(P2); goto __END_RELEASE; +__OBJECT_FLOAT: + + result = comparator_object_float(P1, P2, CO_EQUALF); + goto __END; + +__FLOAT_OBJECT: + + result = comparator_float_object(P1, P2, CO_EQUALF); + goto __END; + +__OBJECT_CONV: + + result = comparator_object_conv(P1, P2, CO_EQUAL); + goto __END; + +__CONV_OBJECT: + + result = comparator_conv_object(P1, P2, CO_EQUAL); + goto __END; + +__OBJECT_OBJECT: + + result = comparator_object(P1, P2, CO_EQUAL); + goto __END; + __VARIANT: { @@ -2461,6 +2657,15 @@ __VARIANT: variant = TRUE; } + code = check_operators(P1, P2); + if (code) + { + code += T_OBJECT; + if (!(variant || P1->type == T_OBJECT || P2->type == T_OBJECT)) + *PC |= code; + goto *jump[code]; + } + type = Max(P1->type, P2->type); if (TYPE_is_object_null(P1->type) && TYPE_is_object_null(P2->type)) @@ -2493,7 +2698,7 @@ __END: P1->_boolean.value = result - 1; // ? 0 : -1; } -#define sgn(_x) \ +/*#define sgn(_x) \ ({ \ int x = _x; \ int minusOne = x >> 31; \ @@ -2501,13 +2706,653 @@ __END: int plusOne = (int)(negateX >> 31); \ int result = minusOne | plusOne; \ result; \ -}) +})*/ static void my_VALUE_class_constant(CLASS *class, VALUE *value, int ind) { VALUE_class_constant_inline(class, value, ind); } -#define STATIC_SUBR -#include "gbx_subr_common.h" +#define MANAGE_VARIANT_OBJECT(_func) \ +({ \ + type = Max(P1->type, P2->type); \ + if (TYPE_is_void(P1->type) || TYPE_is_void(P2->type)) \ + THROW(E_NRETURN); \ + \ + if (TYPE_is_number_date(type)) \ + { \ + *PC |= type; \ + goto *jump[type]; \ + } \ + \ + code = check_operators(P1, P2); \ + if (code) \ + { \ + code += T_DATE; \ + if (!(P1->type == T_OBJECT || P2->type == T_OBJECT)) \ + *PC |= code; \ + goto *jump[code]; \ + } \ + \ + VARIANT_undo(P1); \ + VARIANT_undo(P2); \ + \ + if (TYPE_is_string(P1->type)) \ + VALUE_conv_float(P1); \ + \ + if (TYPE_is_string(P2->type)) \ + VALUE_conv_float(P2); \ + \ + if (TYPE_is_null(P1->type) || TYPE_is_null(P2->type)) \ + type = T_NULL; \ + else \ + type = Max(P1->type, P2->type); \ + \ + if (TYPE_is_number_date(type)) \ + { \ + (_func)(code | type); \ + VALUE_conv_variant(P1); \ + return; \ + } \ + \ + code = check_operators(P1, P2); \ + if (code) \ + { \ + (_func)(code + T_DATE); \ + VALUE_conv_variant(P1); \ + return; \ + } \ +}) + +#define MANAGE_VARIANT_POINTER_OBJECT(_func) \ +({ \ + type = Max(P1->type, P2->type); \ + if (TYPE_is_void(P1->type) || TYPE_is_void(P2->type)) \ + THROW(E_NRETURN); \ + \ + if (TYPE_is_number_date(type) || TYPE_is_pointer(type)) \ + { \ + *PC |= type; \ + goto *jump[type]; \ + } \ + \ + code = check_operators(P1, P2); \ + if (code) \ + { \ + code += T_POINTER; \ + *PC |= code; \ + goto *jump[code]; \ + } \ + \ + VARIANT_undo(P1); \ + VARIANT_undo(P2); \ + \ + if (TYPE_is_string(P1->type)) \ + VALUE_conv_float(P1); \ + \ + if (TYPE_is_string(P2->type)) \ + VALUE_conv_float(P2); \ + \ + if (TYPE_is_null(P1->type) || TYPE_is_null(P2->type)) \ + type = T_NULL; \ + else \ + type = Max(P1->type, P2->type); \ + \ + if (TYPE_is_number_date(type) || TYPE_is_pointer(type)) \ + { \ + (_func)(code | type); \ + VALUE_conv_variant(P1); \ + return; \ + } \ + \ + code = check_operators(P1, P2); \ + if (code) \ + { \ + (_func)(code + T_POINTER); \ + VALUE_conv_variant(P1); \ + return; \ + } \ +}) + + +static void _SUBR_add(ushort code) +{ + static void *jump[] = { + &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__DATE, NULL, NULL, &&__POINTER, + &&__OBJECT_FLOAT, &&__FLOAT_OBJECT, &&__OBJECT_CONV, &&__CONV_OBJECT, &&__OBJECT + }; + + TYPE type; + VALUE *P1, *P2; + + P1 = SP - 2; + P2 = P1 + 1; + + type = code & 0x0F; + goto *jump[type]; + +__BOOLEAN: + + P1->type = T_BOOLEAN; + P1->_integer.value = P1->_integer.value | P2->_integer.value; goto __END; + +__BYTE: + + P1->type = T_BYTE; + P1->_integer.value = (unsigned char)(P1->_integer.value + P2->_integer.value); goto __END; + +__SHORT: + + P1->type = T_SHORT; + P1->_integer.value = (short)(P1->_integer.value + P2->_integer.value); goto __END; + +__INTEGER: + + P1->type = T_INTEGER; + P1->_integer.value += P2->_integer.value; goto __END; + +__LONG: + + VALUE_conv(P1, T_LONG); + VALUE_conv(P2, T_LONG); + + P1->_long.value += P2->_long.value; goto __END; + +__SINGLE: + + VALUE_conv(P1, T_SINGLE); + VALUE_conv(P2, T_SINGLE); + + P1->_single.value += P2->_single.value; goto __END; + +__DATE: +__FLOAT: + + VALUE_conv_float(P1); + VALUE_conv_float(P2); + + P1->_float.value += P2->_float.value; + //fprintf(stderr, "+: %.24g\n", P1->_float.value); + goto __END; + +__POINTER: + + VALUE_conv(P1, T_POINTER); + VALUE_conv(P2, T_POINTER); + + P1->_pointer.value += (intptr_t)P2->_pointer.value; goto __END; + +__OBJECT_FLOAT: + + operator_object_float(P1, P2, CO_ADDF); + goto __END; + +__FLOAT_OBJECT: + + operator_float_object(P1, P2, CO_ADDF); + goto __END; + +__OBJECT_CONV: + + operator_object_conv(P1, P2, CO_ADD); + goto __END; + +__CONV_OBJECT: + + operator_conv_object(P1, P2, CO_ADD); + goto __END; + +__OBJECT: + + operator_object(P1, P2, CO_ADD); + goto __END; + +__VARIANT: + + MANAGE_VARIANT_POINTER_OBJECT(_SUBR_add); + goto __ERROR; + +__ERROR: + + THROW(E_TYPE, "Number", TYPE_get_name(type)); + +__END: + + SP--; +} + +static void _SUBR_sub(ushort code) +{ + static void *jump[] = { + &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__DATE, NULL, NULL, &&__POINTER, + &&__OBJECT_FLOAT, &&__FLOAT_OBJECT, &&__OBJECT_CONV, &&__CONV_OBJECT, &&__OBJECT + }; + + TYPE type; + VALUE *P1, *P2; + + P1 = SP - 2; + P2 = P1 + 1; + + type = code & 0x0F; + goto *jump[type]; + +__BOOLEAN: + + P1->type = T_BOOLEAN; + P1->_integer.value = P1->_integer.value ^ P2->_integer.value; goto __END; + +__BYTE: + + P1->type = T_BYTE; + P1->_integer.value = (unsigned char)(P1->_integer.value - P2->_integer.value); goto __END; + +__SHORT: + + P1->type = T_SHORT; + P1->_integer.value = (short)(P1->_integer.value - P2->_integer.value); goto __END; + +__INTEGER: + + P1->type = T_INTEGER; + P1->_integer.value -= P2->_integer.value; goto __END; + +__LONG: + + VALUE_conv(P1, T_LONG); + VALUE_conv(P2, T_LONG); + + P1->_long.value -= P2->_long.value; goto __END; + +__SINGLE: + + VALUE_conv(P1, T_SINGLE); + VALUE_conv(P2, T_SINGLE); + + P1->_single.value -= P2->_single.value; goto __END; + +__DATE: +__FLOAT: + + VALUE_conv_float(P1); + VALUE_conv_float(P2); + + P1->_float.value -= P2->_float.value; goto __END; + +__POINTER: + + VALUE_conv(P1, T_POINTER); + VALUE_conv(P2, T_POINTER); + + P1->_pointer.value -= (intptr_t)P2->_pointer.value; goto __END; + +__OBJECT_FLOAT: + + operator_object_float(P1, P2, CO_SUBF); + goto __END; + +__FLOAT_OBJECT: + + operator_float_object(P1, P2, CO_SUBF); + goto __END; + +__OBJECT_CONV: + + operator_object_conv(P1, P2, CO_SUB); + goto __END; + +__CONV_OBJECT: + + operator_conv_object(P1, P2, CO_SUB); + goto __END; + +__OBJECT: + + operator_object(P1, P2, CO_SUB); + goto __END; + +__VARIANT: + + MANAGE_VARIANT_POINTER_OBJECT(_SUBR_sub); + goto __ERROR; + +__ERROR: + + THROW(E_TYPE, "Number", TYPE_get_name(type)); + +__END: + + SP--; +} + +static void _SUBR_mul(ushort code) +{ + static void *jump[] = { + &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__ERROR, + &&__OBJECT_FLOAT, &&__FLOAT_OBJECT, &&__OBJECT_CONV, &&__CONV_OBJECT, &&__OBJECT + }; + + TYPE type; + VALUE *P1, *P2; + + P1 = SP - 2; + P2 = P1 + 1; + + type = code & 0x0F; + goto *jump[type]; + +__BOOLEAN: + + P1->type = T_BOOLEAN; + P1->_integer.value = P1->_integer.value & P2->_integer.value; goto __END; + +__BYTE: + + P1->type = T_BYTE; + P1->_integer.value = (unsigned char)(P1->_integer.value * P2->_integer.value); goto __END; + +__SHORT: + + P1->type = T_SHORT; + P1->_integer.value = (short)(P1->_integer.value * P2->_integer.value); goto __END; + +__INTEGER: + + P1->type = T_INTEGER; + P1->_integer.value *= P2->_integer.value; goto __END; + +__LONG: + + VALUE_conv(P1, T_LONG); + VALUE_conv(P2, T_LONG); + + P1->_long.value *= P2->_long.value; goto __END; + +__SINGLE: + + VALUE_conv(P1, T_SINGLE); + VALUE_conv(P2, T_SINGLE); + + P1->_single.value *= P2->_single.value; goto __END; + +__FLOAT: + + VALUE_conv_float(P1); + VALUE_conv_float(P2); + + P1->_float.value *= P2->_float.value; + //fprintf(stderr, "*: %.24g\n", P1->_float.value); + goto __END; + +__OBJECT_FLOAT: + + operator_object_float(P1, P2, CO_MULF); + goto __END; + +__FLOAT_OBJECT: + + operator_float_object(P1, P2, CO_MULF); + goto __END; + +__OBJECT_CONV: + + operator_object_conv(P1, P2, CO_MUL); + goto __END; + +__CONV_OBJECT: + + operator_conv_object(P1, P2, CO_MUL); + goto __END; + +__OBJECT: + + operator_object(P1, P2, CO_MUL); + goto __END; + +__VARIANT: + + MANAGE_VARIANT_OBJECT(_SUBR_mul); + goto __ERROR; + +__ERROR: + + THROW(E_TYPE, "Number", TYPE_get_name(type)); + +__END: + + SP--; +} + +static void _SUBR_div(ushort code) +{ + static void *jump[] = { + &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__ERROR, + &&__OBJECT_FLOAT, &&__FLOAT_OBJECT, &&__OBJECT_CONV, &&__CONV_OBJECT, &&__OBJECT + }; + + TYPE type; + VALUE *P1, *P2; + + P1 = SP - 2; + P2 = P1 + 1; + + type = code & 0x0F; + goto *jump[type]; + +__BOOLEAN: +__BYTE: +__SHORT: +__INTEGER: +__LONG: +__SINGLE: +__FLOAT: + + VALUE_conv_float(P1); + VALUE_conv_float(P2); + + P1->_float.value /= P2->_float.value; + if (isfinite(P1->_float.value)) + goto __END; + + THROW(E_ZERO); + +__OBJECT_FLOAT: + + operator_object_float(P1, P2, CO_DIVF); + goto __CHECK_OBJECT; + +__FLOAT_OBJECT: + + operator_float_object(P1, P2, CO_IDIVF); + goto __CHECK_OBJECT; + +__OBJECT_CONV: + + operator_object_conv(P1, P2, CO_DIV); + goto __CHECK_OBJECT; + +__CONV_OBJECT: + + operator_conv_object(P1, P2, CO_DIV); + goto __CHECK_OBJECT; + +__OBJECT: + + operator_object(P1, P2, CO_DIV); + goto __CHECK_OBJECT; + +__VARIANT: + + MANAGE_VARIANT_OBJECT(_SUBR_div); + goto __ERROR; + +__ERROR: + + THROW(E_TYPE, "Number", TYPE_get_name(type)); + +__CHECK_OBJECT: + + if (P1->_object.object == NULL) + THROW(E_ZERO); + +__END: + + SP--; +} + +static void _SUBR_compi(ushort code) +{ + static void *jump[17] = { + &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__DATE, + &&__STRING, &&__STRING, &&__POINTER, &&__ERROR, &&__ERROR, &&__ERROR, &&__NULL, &&__OBJECT + }; + + static void *test[] = { &&__GT, &&__LE, &&__LT, &&__GE }; + + char NO_WARNING(result); + VALUE *P1; + VALUE *P2; + TYPE type; + + P1 = SP - 2; + P2 = P1 + 1; + + type = code & 0x1F; + goto *jump[type]; + +__BOOLEAN: +__BYTE: +__SHORT: +__INTEGER: + + result = P1->_integer.value > P2->_integer.value ? 1 : P1->_integer.value < P2->_integer.value ? -1 : 0; + goto __END; + +__LONG: + + VALUE_conv(P1, T_LONG); + VALUE_conv(P2, T_LONG); + + result = P1->_long.value > P2->_long.value ? 1 : P1->_long.value < P2->_long.value ? -1 : 0; + goto __END; + +__DATE: + + VALUE_conv(P1, T_DATE); + VALUE_conv(P2, T_DATE); + + result = DATE_comp_value(P1, P2); + goto __END; + +__NULL: +__STRING: + + VALUE_conv_string(P1); + VALUE_conv_string(P2); + + result = STRING_compare(P1->_string.addr + P1->_string.start, P1->_string.len, P2->_string.addr + P2->_string.start, P2->_string.len); + + RELEASE_STRING(P1); + RELEASE_STRING(P2); + goto __END; + +__SINGLE: + + VALUE_conv(P1, T_SINGLE); + VALUE_conv(P2, T_SINGLE); + + result = P1->_single.value > P2->_single.value ? 1 : P1->_single.value < P2->_single.value ? -1 : 0; + goto __END; + +__FLOAT: + + VALUE_conv_float(P1); + VALUE_conv_float(P2); + + result = P1->_float.value > P2->_float.value ? 1 : P1->_float.value < P2->_float.value ? -1 : 0; + goto __END; + +__POINTER: + + VALUE_conv(P1, T_POINTER); + VALUE_conv(P2, T_POINTER); + + result = P1->_pointer.value > P2->_pointer.value ? 1 : P1->_pointer.value < P2->_pointer.value ? -1 : 0; + goto __END; + +__OBJECT: + + result = OBJECT_comp_value(P1, P2); + //RELEASE_OBJECT(P1); + //RELEASE_OBJECT(P2); + goto __END_RELEASE; + +__VARIANT: + + { + bool variant = FALSE; + + if (TYPE_is_variant(P1->type)) + { + VARIANT_undo(P1); + variant = TRUE; + } + + if (TYPE_is_variant(P2->type)) + { + VARIANT_undo(P2); + variant = TRUE; + } + + type = Max(P1->type, P2->type); + + if (type == T_NULL || TYPE_is_string(type)) + { + TYPE typem = Min(P1->type, P2->type); + if (!TYPE_is_string(typem)) + THROW(E_TYPE, TYPE_get_name(typem), TYPE_get_name(type)); + } + else if (TYPE_is_object(type)) + goto __ERROR; + else if (TYPE_is_void(type)) + THROW(E_NRETURN); + + if (!variant) + *PC |= type; + + goto *jump[type]; + } + +__ERROR: + + THROW(E_TYPE, "Number, Date or String", TYPE_get_name(type)); + +__END_RELEASE: + + RELEASE(P1); + RELEASE(P2); + +__END: + + P1->type = T_BOOLEAN; + SP--; + + goto *test[(code >> 8) - (C_GT >> 8)]; + +__GT: + P1->_boolean.value = result > 0 ? -1 : 0; + return; + +__GE: + P1->_boolean.value = result >= 0 ? -1 : 0; + return; + +__LT: + P1->_boolean.value = result < 0 ? -1 : 0; + return; + +__LE: + P1->_boolean.value = result <= 0 ? -1 : 0; + return; +} diff --git a/main/gbx/gbx_object.h b/main/gbx/gbx_object.h index 3cf1e33c2..e6676cb81 100644 --- a/main/gbx/gbx_object.h +++ b/main/gbx/gbx_object.h @@ -53,7 +53,7 @@ typedef #define OBJECT_is(_object, _class) (OBJECT_class(_object) == _class) #define OBJECT_is_class(_object) OBJECT_is(_object, CLASS_Class) #define OBJECT_class(_object) ((_object) ? ((OBJECT *)_object)->class : NULL) -#define OBJECT_count(_object) ((_object) ? ((OBJECT *)_object)->ref : 0) +#define OBJECT_count(_object) (((OBJECT *)_object)->ref) void *OBJECT_new(CLASS *class, const char *name, OBJECT *parent); void OBJECT_attach(OBJECT *ob, OBJECT *parent, const char *name); diff --git a/main/gbx/gbx_subr_math.c b/main/gbx/gbx_subr_math.c index ae3a258ae..60706d896 100644 --- a/main/gbx/gbx_subr_math.c +++ b/main/gbx/gbx_subr_math.c @@ -52,6 +52,30 @@ #include "gbx_subr_math_temp.h" +static bool check_operators(VALUE *P1) +{ + return (TYPE_is_object(P1->type) && OBJECT_class(P1->_object.object)->has_operators); +} + +static void operator_object_abs(VALUE *P1) +{ + double (*func)(void *) = (double (*)(void *))((void **)(OBJECT_class(P1->_object.object)->operators))[CO_ABS]; + double result = (*func)(P1->_object.object); + OBJECT_UNREF(P1->_object.object, "operator_object_abs"); + P1->type = T_FLOAT; + P1->_float.value = result; +} + +static void operator_object(VALUE *P1, uchar op) +{ + void *(*func)(void *) = (void *(*)(void *))((void **)(OBJECT_class(P1->_object.object)->operators))[op]; + void *result = (*func)(P1->_object.object); + OBJECT_REF(result, "operator_object"); + OBJECT_UNREF(P1->_object.object, "operator_object"); + P1->_object.object = result; +} + + void SUBR_pi(ushort code) { SUBR_ENTER(); @@ -135,7 +159,6 @@ void SUBR_round(ushort code) void SUBR_math(ushort code) { - static void *jump[] = { NULL, &&__FRAC, &&__LOG, &&__EXP, &&__SQRT, &&__SIN, &&__COS, &&__TAN, &&__ATAN, &&__ASIN, &&__ACOS, &&__DEG, &&__RAD, &&__LOG10, &&__SINH, &&__COSH, &&__TANH, &&__ASINH, &&__ACOSH, &&__ATANH, @@ -493,6 +516,41 @@ __END: } \ }) +#define MANAGE_VARIANT_OBJECT(_func) \ +({ \ + type = P1->type; \ + \ + if (TYPE_is_number_date(type)) \ + { \ + *PC |= type; \ + goto *jump[type]; \ + } \ + \ + if (check_operators(P1)) \ + { \ + *PC |= T_DATE + 1; \ + goto *jump[T_DATE + 1]; \ + } \ + \ + if (TYPE_is_variant(type)) \ + { \ + VARIANT_undo(P1); \ + type = P1->type; \ + if (TYPE_is_number_date(type)) \ + { \ + (_func)(code | type); \ + VALUE_conv_variant(P1); \ + return; \ + } \ + if (check_operators(P1)) \ + { \ + (_func)(T_DATE + 1); \ + VALUE_conv_variant(P1); \ + return; \ + } \ + } \ +}) + void SUBR_sgn(ushort code) { @@ -550,7 +608,7 @@ __END: void SUBR_neg(ushort code) { static void *jump[] = { - &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__ERROR + &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__ERROR, &&__OBJECT }; VALUE *P1; @@ -590,9 +648,14 @@ __FLOAT: P1->_float.value = (-P1->_float.value); return; +__OBJECT: + + operator_object(P1, CO_NEG); + return; + __VARIANT: - MANAGE_VARIANT(SUBR_neg); + MANAGE_VARIANT_OBJECT(SUBR_neg); __ERROR: @@ -603,7 +666,7 @@ __ERROR: void SUBR_abs(ushort code) { static void *jump[] = { - &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__ERROR + &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__ERROR, &&__OBJECT }; VALUE *P1; @@ -643,9 +706,14 @@ __FLOAT: P1->_float.value = fabs(P1->_float.value); return; +__OBJECT: + + operator_object_abs(P1); + return; + __VARIANT: - MANAGE_VARIANT(SUBR_abs); + MANAGE_VARIANT_OBJECT(SUBR_abs); __ERROR: diff --git a/main/gbx/gbx_value.c b/main/gbx/gbx_value.c index 62ba64e35..ea74dc9d2 100644 --- a/main/gbx/gbx_value.c +++ b/main/gbx/gbx_value.c @@ -728,7 +728,13 @@ __OBJECT: if (type == T_VARIANT) goto __2v; - goto __N; + if (value->type == T_OBJECT) + class = OBJECT_class(value->_object.object); + else + class = value->_object.class; + + goto __CONVERT; + //goto __N; } if (!TYPE_is_object(value->type)) @@ -771,13 +777,7 @@ __OBJECT: goto __TYPE; if (value->type == T_OBJECT) - { - /*if (value->_object.object == NULL) - goto __TYPE;*/ - class = OBJECT_class(value->_object.object); - /* on continue */ - } else class = value->_object.class; @@ -799,14 +799,14 @@ __RETRY: goto __RETRY; } - if (class->special[SPEC_CONVERT] != NO_SYMBOL) +__CONVERT: + + if (class->has_convert) { - void *conv = ((void *(*)())(CLASS_get_desc(class, class->special[SPEC_CONVERT])->constant.value._pointer))(value->_object.object, type); - if (conv) + void *unref = value->_object.object; + if (!((bool (*)())(CLASS_get_desc(class, class->special[SPEC_CONVERT])->constant.value._pointer))(value->_object.object, type, value)) { - OBJECT_REF(conv, "VALUE_conv"); - OBJECT_UNREF(value->_object.object, "VALUE_conv"); - value->_object.object = conv; + OBJECT_UNREF(unref, "VALUE_conv"); goto __TYPE; } } @@ -1175,12 +1175,29 @@ __STRING: __OBJECT: - if (VALUE_is_null(value)) - goto __NULL; + { + CLASS *class; + + if (VALUE_is_null(value)) + goto __NULL; - *len = sprintf(COMMON_buffer, "(%s %p)", OBJECT_class(value->_object.object)->name, value->_object.object); - *addr = COMMON_buffer; - return; + class = OBJECT_class(value->_object.object); + if (class->has_convert) + { + VALUE temp; + if (!((bool (*)())(CLASS_get_desc(class, class->special[SPEC_CONVERT])->constant.value._pointer))(value->_object.object, T_CSTRING, &temp)) + { + *addr = temp._string.addr + temp._string.start; + *len = temp._string.len; + STRING_free_later(*addr); + return; + } + } + + *len = sprintf(COMMON_buffer, "(%s %p)", class->name, value->_object.object); + *addr = COMMON_buffer; + return; + } __POINTER: diff --git a/main/share/gambas.h b/main/share/gambas.h index 4963af61f..66a3298f8 100644 --- a/main/share/gambas.h +++ b/main/share/gambas.h @@ -297,6 +297,7 @@ typedef GB_BOOLEAN _boolean; GB_INTEGER _integer; GB_LONG _long; + GB_SINGLE _single; GB_FLOAT _float; GB_DATE _date; GB_STRING _string; @@ -314,6 +315,7 @@ typedef #define GB_ERR_NPROPERTY ((char *)17) #define GB_ERR_ARG ((char *)20) #define GB_ERR_BOUND ((char *)21) +#define GB_ERR_ZERO ((char *)26) /* Gambas description start macro */ @@ -813,6 +815,34 @@ typedef #define POINTER(_pointer) (void **)(void *)_pointer +/* For classes that implements arithmetic operators (e.g. complex numbers...) */ + +typedef + struct { + int (*equal)(void *, void *); + int (*equalf)(void *, double); + int (*comp)(void *, void *); + int (*compf)(void *, double); + void *(*add)(void *, void *); + void *(*addf)(void *, double); + void *(*sub)(void *, void *); + void *(*subf)(void *, double); + void *(*mul)(void *, void *); + void *(*mulf)(void *, double); + void *(*div)(void *, void *); + void *(*divf)(void *, double); + void *(*idivf)(void *, double); + void *(*neg)(void *); + void *(*pow)(void *, void *); + void *(*powf)(void *, double); + void *(*abs)(void *); + void *(*max)(void *, void *); + void *(*min)(void *, void *); + } + PACKED + GB_OPERATOR_DESC; + + /* Gambas Application Programming Interface */ typedef diff --git a/main/share/gbx_subr_common.h b/main/share/gbx_subr_common.h index b74602e55..bf546fc59 100644 --- a/main/share/gbx_subr_common.h +++ b/main/share/gbx_subr_common.h @@ -26,6 +26,87 @@ #define STATIC_SUBR static #endif +#define OP_OBJECT_FLOAT (T_POINTER + 1) +#define OP_FLOAT_OBJECT (T_POINTER + 2) +#define OP_OBJECT_CONV (T_POINTER + 3) +#define OP_CONV_OBJECT (T_POINTER + 4) +#define OP_OBJECT (T_POINTER + 5) + +static int check_operators(VALUE *P1, VALUE *P2) +{ + if (TYPE_is_number(P1->type)) + { + if (OBJECT_class(P2->_object.object)->operators) + return OP_FLOAT_OBJECT; + } + else if (TYPE_is_number(P2->type)) + { + if (OBJECT_class(P1->_object.object)->operators) + return OP_OBJECT_FLOAT; + } + else + { + CLASS *class1 = OBJECT_class(P1->_object.object); + CLASS *class2 = OBJECT_class(P2->_object.object); + + if (class1->operators) + { + if (class1 == class2) + return OP_OBJECT; + + if (class2->operators) + { + if (class1->operators->strength > class2->operators->strength) + return OP_OBJECT_CONV; + else + return OP_CONV_OBJECT; + } + } + } + + return 0; +} + +static void operator_object_float(VALUE *P1, VALUE *P2, uchar op) +{ + void *(*func)(void *, double) = (void *(*)(void *, double))((void **)(OBJECT_class(P1->_object.object)->operators))[op]; + VALUE_conv_float(P2); + void *result = (*func)(P1->_object.object, P2->_float.value); + OBJECT_unref(P1->_object.object); + P1->_object.object = result; +} + +static void operator_float_object(VALUE *P1, VALUE *P2, uchar op) +{ + void *(*func)(void *, double) = (void *(*)(void *, double))((void **)(OBJECT_class(P2->_object.object)->operators))[op]; + VALUE_conv_float(P1); + void *result = (*func)(P2->_object.object, P1->_float.value); + P1->_object.class = P2->_object.class; + OBJECT_unref(P2->_object.object); + P1->_object.object = result; +} + +static void operator_object(VALUE *P1, VALUE *P2, uchar op) +{ + void *(*func)(void *, void *) = (void *(*)(void *, void *))((void **)(OBJECT_class(P2->_object.object)->operators))[op]; + void *result = (*func)(P1->_object.object, P2->_object.object); + OBJECT_unref(P1->_object.object); + OBJECT_unref(P2->_object.object); + P1->_object.object = result; +} + +static void operator_object_conv(VALUE *P1, VALUE *P2, char op) +{ + VALUE_conv(P2, (TYPE)P1->_object.class); + operator_object(P1, P2, op); +} + +static void operator_conv_object(VALUE *P1, VALUE *P2, char op) +{ + VALUE_conv(P1, (TYPE)P2->_object.class); + operator_object(P1, P2, op); +} + #define MANAGE_VARIANT(_func) \ ({ \ type = Max(P1->type, P2->type); \ @@ -95,10 +176,57 @@ }) +#define MANAGE_VARIANT_POINTER_OBJECT(_func) \ +({ \ + type = Max(P1->type, P2->type); \ + if (TYPE_is_void(P1->type) || TYPE_is_void(P2->type)) \ + THROW(E_NRETURN); \ + \ + if (TYPE_is_number_date(type) || TYPE_is_pointer(type)) \ + { \ + *PC |= type; \ + goto *jump[type]; \ + } \ + \ + VARIANT_undo(P1); \ + VARIANT_undo(P2); \ + \ + if (TYPE_is_string(P1->type)) \ + VALUE_conv_float(P1); \ + \ + if (TYPE_is_string(P2->type)) \ + VALUE_conv_float(P2); \ + \ + if (TYPE_is_null(P1->type) || TYPE_is_null(P2->type)) \ + type = T_NULL; \ + else \ + type = Max(P1->type, P2->type); \ + \ + if (TYPE_is_number_date(type) || TYPE_is_pointer(type)) \ + { \ + (_func)(code | type); \ + VALUE_conv_variant(P1); \ + return; \ + } \ + \ + if (TYPE_is_object(type)) \ + { \ + type = check_operators(P1, P2); \ + if (type) \ + { \ + *PC |= type; \ + goto *jump[type]; \ + } \ + } \ +}) + + STATIC_SUBR void _SUBR_add(ushort code) { static void *jump[] = { - &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__DATE, NULL, NULL, &&__POINTER + &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, + &&__DATE, NULL, NULL, &&__POINTER, + &&__OBJECT_FLOAT, &&__FLOAT_OBJECT, &&__OBJECT_CONV, &&__CONV_OBJECT, &&__OBJECT }; TYPE type; @@ -161,11 +289,36 @@ __POINTER: P1->_pointer.value += (intptr_t)P2->_pointer.value; goto __END; +__OBJECT_FLOAT: + + operator_object_float(P1, P2, CO_ADDF); + goto __END; + +__FLOAT_OBJECT: + + operator_float_object(P1, P2, CO_ADDF); + goto __END; + +__OBJECT_CONV: + + operator_object_conv(P1, P2, CO_ADDF); + goto __END; + +__CONV_OBJECT: + + operator_conv_object(P1, P2, CO_ADDF); + goto __END; + +__OBJECT: + + operator_object(P1, P2, CO_ADDF); + goto __END; + __VARIANT: - MANAGE_VARIANT_POINTER(_SUBR_add); + MANAGE_VARIANT_POINTER_OBJECT(_SUBR_add); goto __ERROR; - + __ERROR: THROW(E_TYPE, "Number", TYPE_get_name(type));