types: missing 'long double' in psi_t_size() and psi_t_alignment()
[m6w6/ext-psi] / src / calc.c
index f701b5a3fca9388227de8943c42f222861263b8f..f88ab30ad7f708801019ae6fa8ecc05d38cd04b3 100644 (file)
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "php.h"
-#include "php_psi.h"
-#include "parser.h"
-#include "calc.h"
-
-static inline int psi_calc_num_exp_value(num_exp *exp, impl_val *strct, impl_val *res) {
-       impl_val *ref, *tmp = NULL;
-
-       switch (exp->t) {
-       case PSI_T_NUMBER:
-               switch (is_numeric_string(exp->u.numb, strlen(exp->u.numb), (zend_long *) res, (double *) res, 0)) {
-               case IS_LONG:
-                       return PSI_T_INT64;
-               case IS_DOUBLE:
-                       return PSI_T_DOUBLE;
-               }
-               break;
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
 
-       case PSI_T_NSNAME:
-               switch (exp->u.cnst->type->type) {
-               case PSI_T_INT:
-                       res->i64 = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.lval;
-                       return PSI_T_INT64;
-               case PSI_T_FLOAT:
-                       res->dval = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.dval;
-                       return PSI_T_DOUBLE;
-               default:
-                       return 0;
-               }
-               break;
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
 
-       case PSI_T_ENUM:
-               return psi_calc_num_exp(exp->u.enm->num ?: &exp->u.enm->inc, NULL, res);
-               break;
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
 
-       case PSI_T_NAME:
-               if (strct) {
-                       ref = struct_member_ref(exp->u.dvar->arg, strct, &tmp);
-               } else {
-                       ref = exp->u.dvar->arg->let;
-               }
-               switch (real_decl_type(exp->u.dvar->arg->type)->type) {
-               case PSI_T_INT8:
-               case PSI_T_UINT8:
-               case PSI_T_INT16:
-               case PSI_T_UINT16:
-               case PSI_T_INT32:
-               case PSI_T_UINT32:
-               case PSI_T_INT64:
-               case PSI_T_UINT64:
-                       memcpy(res, deref_impl_val(ref, exp->u.dvar), sizeof(*res));
-                       if (tmp) {
-                               free(tmp);
-                       }
-                       return real_decl_type(exp->u.dvar->arg->type)->type;
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
 
-               case PSI_T_FLOAT:
-               case PSI_T_DOUBLE:
-                       memcpy(res, deref_impl_val(ref, exp->u.dvar), sizeof(*res));
-                       if (tmp) {
-                               free(tmp);
-                       }
-                       return real_decl_type(exp->u.dvar->arg->type)->type;
+#include "php_psi_stdinc.h"
+#include <assert.h>
 
-               EMPTY_SWITCH_DEFAULT_CASE();
-               }
-               break;
+#include "token.h"
+#include "calc.h"
 
-       EMPTY_SWITCH_DEFAULT_CASE();
-       }
-       return  0;
+#define PSI_CALC_CAST_SET(in_type, in_val, op, out_val, out_var) \
+switch (in_type) { \
+case PSI_T_INT8:               (out_val)->out_var op (in_val)->i8;             break; \
+case PSI_T_UINT8:              (out_val)->out_var op (in_val)->u8;             break; \
+case PSI_T_INT16:              (out_val)->out_var op (in_val)->i16;    break; \
+case PSI_T_UINT16:             (out_val)->out_var op (in_val)->u16;    break; \
+case PSI_T_INT32:              (out_val)->out_var op (in_val)->i32;    break; \
+case PSI_T_UINT32:             (out_val)->out_var op (in_val)->u32;    break; \
+case PSI_T_INT64:              (out_val)->out_var op (in_val)->i64;    break; \
+case PSI_T_UINT64:             (out_val)->out_var op (in_val)->u64;    break; \
+case PSI_T_FLOAT:              (out_val)->out_var op (in_val)->fval;   break; \
+case PSI_T_DOUBLE:             (out_val)->out_var op (in_val)->dval;   break; \
+case PSI_T_LONG_DOUBLE:        (out_val)->out_var op (in_val)->ldval;  break; \
+default: \
+       assert(0); \
 }
 
-int psi_calc_num_exp(num_exp *exp, impl_val *strct, impl_val *res) {
-       impl_val num = {0};
-       int num_type = psi_calc_num_exp_value(exp, strct, &num);
-
-       if (exp->operand) {
-               impl_val tmp = {0};
-               int tmp_type = psi_calc_num_exp(exp->operand, strct, &tmp);
-
-               return exp->calculator(num_type, &num, tmp_type, &tmp, res);
-       }
+#define PSI_CALC_CAST(in_type, in_val, op, out_type, out_val) \
+switch (out_type) { \
+case PSI_T_INT8:               PSI_CALC_CAST_SET(in_type, in_val, op, out_val, i8)             break; \
+case PSI_T_UINT8:              PSI_CALC_CAST_SET(in_type, in_val, op, out_val, u8)             break; \
+case PSI_T_INT16:              PSI_CALC_CAST_SET(in_type, in_val, op, out_val, i16)    break; \
+case PSI_T_UINT16:             PSI_CALC_CAST_SET(in_type, in_val, op, out_val, u16)    break; \
+case PSI_T_INT32:              PSI_CALC_CAST_SET(in_type, in_val, op, out_val, i32)    break; \
+case PSI_T_UINT32:             PSI_CALC_CAST_SET(in_type, in_val, op, out_val, u32)    break; \
+case PSI_T_INT64:              PSI_CALC_CAST_SET(in_type, in_val, op, out_val, i64)    break; \
+case PSI_T_UINT64:             PSI_CALC_CAST_SET(in_type, in_val, op, out_val, u64)    break; \
+case PSI_T_FLOAT:              PSI_CALC_CAST_SET(in_type, in_val, op, out_val, fval)   break; \
+case PSI_T_DOUBLE:             PSI_CALC_CAST_SET(in_type, in_val, op, out_val, dval)   break; \
+case PSI_T_LONG_DOUBLE:        PSI_CALC_CAST_SET(in_type, in_val, op, out_val, ldval)  break; \
+default: \
+       assert(0); \
+}
 
-       memcpy(res, &num, sizeof(*res));
-       return num_type;
+#define PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, out_var) \
+switch (in_type) { \
+case PSI_T_INT8:               (out_val)->out_var op (in_val)->i8;             break; \
+case PSI_T_UINT8:              (out_val)->out_var op (in_val)->u8;             break; \
+case PSI_T_INT16:              (out_val)->out_var op (in_val)->i16;    break; \
+case PSI_T_UINT16:             (out_val)->out_var op (in_val)->u16;    break; \
+case PSI_T_INT32:              (out_val)->out_var op (in_val)->i32;    break; \
+case PSI_T_UINT32:             (out_val)->out_var op (in_val)->u32;    break; \
+case PSI_T_INT64:              (out_val)->out_var op (in_val)->i64;    break; \
+case PSI_T_UINT64:             (out_val)->out_var op (in_val)->u64;    break; \
+default: \
+       assert(0); \
+}
+#define PSI_CALC_CAST_INT(in_type, in_val, op, out_type, out_val) \
+switch (out_type) { \
+case PSI_T_INT8:               PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, i8)         break; \
+case PSI_T_UINT8:              PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, u8)         break; \
+case PSI_T_INT16:              PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, i16)        break; \
+case PSI_T_UINT16:             PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, u16)        break; \
+case PSI_T_INT32:              PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, i32)        break; \
+case PSI_T_UINT32:             PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, u32)        break; \
+case PSI_T_INT64:              PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, i64)        break; \
+case PSI_T_UINT64:             PSI_CALC_CAST_SET_INT(in_type, in_val, op, out_val, u64)        break; \
+default: \
+       assert(0); \
 }
 
-#define PRIfval "f"
-#define PRIdval "lf"
-#define PRIldval "Lf"
+void psi_calc_cast(token_t in_type, impl_val *in_val, token_t out_type, impl_val *out_val)
+{
+       PSI_CALC_CAST(in_type, in_val, =, out_type, out_val)
+}
 
+#if 0
 #define PSI_CALC_OP(var) do { \
        const char *fmt = "calc %" PRI##var ", %" PRI##var ": %" PRI##var "\n"; \
        res->var = PSI_CALC(v1->var, v2->var); \
-       if (!res->var) fprintf(stderr, fmt, v1->var, v2->var, res->var); \
+       if (!res->var && (v1->var || v2->var)) fprintf(stderr, fmt, v1->var, v2->var, res->var); \
 } while (0)
 #define PSI_CALC_OP2(vres, var1, var2) do { \
        const char *fmt = "calc %" PRI##var1 ", %" PRI##var2 ": %" PRI##vres "\n"; \
        res->vres = PSI_CALC(v1->var1, v2->var2); \
-       if (!res->vres) fprintf(stderr, fmt, v1->var1, v2->var2, res->vres); \
+       if (!res->vres && (v1->var1 || v2->var2)) fprintf(stderr, fmt, v1->var1, v2->var2, res->vres); \
 } while(0)
+#else
+#define PSI_CALC_OP(var) res->var = PSI_CALC(v1->var, v2->var)
+#define PSI_CALC_OP2(vres, var1, var2) res->vres = PSI_CALC(v1->var1, v2->var2)
+#endif
 
 #ifdef HAVE_LONG_DOUBLE
-#define PSI_CALC_NO_LD
-#define PSI_CALC_OP_LD PSI_CALC_OP(ldval)
-#define PSI_CALC_OP2_LD2(var1) PSI_CALC_OP2(ldval, var1, ldval)
-#define PSI_CALC_OP2_LD1(var2) PSI_CALC_OP2(ldval, ldval, var2)
+# define PSI_CALC_NO_LD
+# define PSI_CALC_OP_LD PSI_CALC_OP(ldval)
+# define PSI_CALC_OP2_LD2(var1) PSI_CALC_OP2(ldval, var1, ldval)
+# define PSI_CALC_OP2_LD1(var2) PSI_CALC_OP2(ldval, ldval, var2)
 #else
-#define PSI_CALC_NO_LD abort()
-#define PSI_CALC_OP_LD PSI_CALC_NO_LD
-#define PSI_CALC_OP2_LD2(var) PSI_CALC_NO_LD
-#define PSI_CALC_OP2_LD1(var) PSI_CALC_NO_LD
+# define PSI_CALC_NO_LD abort()
+# define PSI_CALC_OP_LD PSI_CALC_NO_LD
+# define PSI_CALC_OP2_LD2(var) PSI_CALC_NO_LD
+# define PSI_CALC_OP2_LD1(var) PSI_CALC_NO_LD
 #endif
 
-#define PSI_CALC_FN(op) int psi_calc_##op(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res) \
+#define PSI_CALC_FN(op) token_t psi_calc_##op(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res) \
 { \
        if (t1 == t2) { \
                switch (t1) { \
@@ -271,7 +277,7 @@ int psi_calc_num_exp(num_exp *exp, impl_val *strct, impl_val *res) {
                        break; \
                } \
        } \
-       ZEND_ASSERT(0); \
+       assert(0); \
        return 0; \
 }
 
@@ -287,3 +293,62 @@ PSI_CALC_FN(sub)
 #undef PSI_CALC
 #define PSI_CALC(var1, var2) (var1) / (var2)
 PSI_CALC_FN(div)
+#undef PSI_CALC
+
+token_t psi_calc_mod(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       impl_val i1, i2;
+
+       PSI_CALC_CAST(t1, v1, =, PSI_T_INT64, &i1);
+       PSI_CALC_CAST(t2, v2, =, PSI_T_INT64, &i2);
+
+       res->i64 = i1.i64 % i2.i64;
+
+       return PSI_T_INT64;
+}
+
+#define PSI_CALC_BIT_FN(op) token_t psi_calc_##op(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res) \
+{ \
+       impl_val i1, i2; \
+       PSI_CALC_CAST(t1, v1, =, PSI_T_UINT64, &i1); \
+       PSI_CALC_CAST(t2, v2, =, PSI_T_UINT64, &i2); \
+       res->u64 = PSI_CALC(i1.u64, i2.u64); \
+       return PSI_T_UINT64; \
+}
+
+#define PSI_CALC(var1, var2) (var1) << (var2)
+PSI_CALC_BIT_FN(bin_lshift)
+#undef PSI_CALC
+#define PSI_CALC(var1, var2) (var1) >> (var2)
+PSI_CALC_BIT_FN(bin_rshift)
+#undef PSI_CALC
+#define PSI_CALC(var1, var2) (var1) & (var2)
+PSI_CALC_BIT_FN(bin_and)
+#undef PSI_CALC
+#define PSI_CALC(var1, var2) (var1) ^ (var2)
+PSI_CALC_BIT_FN(bin_xor)
+#undef PSI_CALC
+#define PSI_CALC(var1, var2) (var1) | (var2)
+PSI_CALC_BIT_FN(bin_or)
+#undef PSI_CALC
+
+token_t psi_calc_not(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       (void) t2;
+       (void) v2;
+
+       PSI_CALC_CAST(t1, v1, =!, t1, res);
+       return t1;
+}
+
+token_t psi_calc_bin_not(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res)
+{
+       impl_val i1;
+
+       (void) t2;
+       (void) v2;
+
+       PSI_CALC_CAST(t1, v1, =, PSI_T_UINT64, &i1);
+       PSI_CALC_CAST_INT(t1, &i1, =~, t1, res);
+       return t1;
+}