Merge branch 'slimconfigure'
[m6w6/ext-psi] / src / marshal.c
index 87abf98444948801ab8e25cb405ba12927afe38c..6473eca10a23b2e11021783d0e4d442ebd8811bb 100644 (file)
@@ -99,18 +99,26 @@ zend_internal_arg_info *psi_internal_arginfo(struct psi_impl *impl)
        aip = calloc(argc + 1 + !!impl->func->vararg, sizeof(*aip));
 
        fi = (zend_internal_function_info *) &aip[0];
+#ifdef ZEND_TYPE_ENCODE
+       fi->type = ZEND_TYPE_ENCODE(psi_internal_type(impl->func->return_type), 1);
+#else
        fi->allow_null = 1;
+       fi->type_hint = psi_internal_type(impl->func->return_type);
+#endif
        fi->required_num_args = psi_impl_num_min_args(impl);
        fi->return_reference = impl->func->return_reference;
-       fi->type_hint = psi_internal_type(impl->func->return_type);
 
        if (impl->func->vararg) {
                struct psi_impl_arg *vararg = impl->func->vararg;
                zend_internal_arg_info *ai = &aip[argc];
 
                ai->name = vararg->var->name;
+#ifdef ZEND_TYPE_ENCODE
+               ai->type = ZEND_TYPE_ENCODE(psi_internal_type(vararg->type), 1);
+#else
                ai->allow_null = 1;
                ai->type_hint = psi_internal_type(vararg->type);
+#endif
                if (vararg->var->reference) {
                        ai->pass_by_reference = 1;
                }
@@ -121,12 +129,15 @@ zend_internal_arg_info *psi_internal_arginfo(struct psi_impl *impl)
                zend_internal_arg_info *ai = &aip[i];
 
                ai->name = iarg->var->name;
+#ifdef ZEND_TYPE_ENCODE
+               ai->type = ZEND_TYPE_ENCODE(psi_internal_type(iarg->type), 1);
+#else
+               ai->allow_null = 1;
                ai->type_hint = psi_internal_type(iarg->type);
+#endif
                if (iarg->var->reference) {
                        ai->pass_by_reference = 1;
                }
-               /* FIXME: if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) */
-               ai->allow_null = 1;
        }
 
        return aip;
@@ -143,7 +154,7 @@ void psi_set_void(zval *return_value, struct psi_set_exp *set, impl_val *ret_val
 /*
  * ?
  */
-impl_val *psi_let_void(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+impl_val *psi_let_void(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        return tmp;
 }
@@ -158,7 +169,7 @@ void psi_set_zval(zval *return_value, struct psi_set_exp *set, impl_val *ret_val
 /*
  * let dvar = zval($ivar)
  */
-impl_val *psi_let_zval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+impl_val *psi_let_zval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        *to_free = tmp->ptr = emalloc(sizeof(zval));
        ZVAL_COPY_VALUE(tmp->ptr, zvalue);
@@ -184,6 +195,10 @@ static inline impl_val *psi_val_boolval(impl_val *tmp, token_t real_type, zend_b
        case PSI_T_UINT32:              tmp->u32 = boolval;             break;
        case PSI_T_INT64:               tmp->i64 = boolval;             break;
        case PSI_T_UINT64:              tmp->u64 = boolval;             break;
+#ifdef HAVE_INT128
+       case PSI_T_INT128:              tmp->i128 = boolval;    break;
+       case PSI_T_UINT128:             tmp->u128 = boolval;    break;
+#endif
        case PSI_T_FLOAT:               tmp->fval = boolval;    break;
        case PSI_T_DOUBLE:              tmp->dval = boolval;    break;
 #ifdef HAVE_LONG_DOUBLE
@@ -197,10 +212,10 @@ static inline impl_val *psi_val_boolval(impl_val *tmp, token_t real_type, zend_b
 /*
  * let dvar = boolval($ivar)
  */
-impl_val *psi_let_boolval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+impl_val *psi_let_boolval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        zend_bool boolval;
-       token_t real_type = spec ? psi_decl_type_get_real(spec)->type : PSI_T_UINT8;
+       token_t real_type = spec ? psi_decl_type_get_real(spec->type)->type : PSI_T_UINT8;
 
        if (ival && impl_type == PSI_T_BOOL) {
                boolval = ival->zend.bval;
@@ -211,14 +226,52 @@ impl_val *psi_let_boolval(impl_val *tmp, struct psi_decl_type *spec, token_t imp
        return psi_val_boolval(tmp, real_type, boolval);
 }
 
-# define RETVAL_LONG_U64(V) \
-               if (V > ZEND_LONG_MAX) { \
-                       char d[24] = {0}; \
-                       RETVAL_STRING(zend_print_ulong_to_buf(&d[22], V)); \
+static inline char *psi_u128_to_buf(char *buf, unsigned __int128 u128)
+{
+       for (*buf = 0; u128 > 0; u128 /= 10) {
+               *--buf = ((u128 % 10) + '0') & 0xff;
+       }
+       return buf;
+}
+
+static inline char *psi_i128_to_buf(char *buf, __int128 i128)
+{
+       if (i128 < 0) {
+               char *res = psi_u128_to_buf(buf, ~((unsigned __int128) i128) + 1);
+
+               *--res = '-';
+               return res;
+       }
+       return psi_u128_to_buf(buf, i128);
+}
+
+#if HAVE_INT128
+# define RETVAL_LONG_STR(V, s) do {\
+               char buf[0x30] = {0}; \
+               if (s && V >= ZEND_LONG_MIN && V <= ZEND_LONG_MAX) { \
+                       RETVAL_LONG(V); \
+               } else if (!s && V <= ZEND_LONG_MAX) { \
+                       RETVAL_LONG(V); \
+               } else if (!s && V <= ZEND_ULONG_MAX) { \
+                       RETVAL_STRING(zend_print_ulong_to_buf(&buf[sizeof(buf) - 1], V)); \
+               } else if (s && V >= INT128_MIN && V <= INT128_MAX) { \
+                       RETVAL_STRING(psi_i128_to_buf(&buf[sizeof(buf) - 1], V)); \
                } else { \
+                       RETVAL_STRING(psi_u128_to_buf(&buf[sizeof(buf) - 1], V)); \
+               } \
+       } while (0)
+#else
+# define RETVAL_LONG_STR(V, s) do {\
+               char buf[0x20] = {0}; \
+               if (s && V >= ZEND_LONG_MIN && V <= ZEND_LONG_MAX) { \
                        RETVAL_LONG(V); \
-               }
-
+               } else if (!s && V <= ZEND_LONG_MAX) { \
+                       RETVAL_LONG(V); \
+               } else { \
+                       RETVAL_STRING(zend_print_ulong_to_buf(&buf[sizeof(buf) - 1], V)); \
+               } \
+       } while (0)
+#endif
 /*
  * set $ivar = to_int(*dvar)
  */
@@ -233,19 +286,31 @@ void psi_set_to_int(zval *return_value, struct psi_set_exp *set, impl_val *ret_v
        case PSI_T_UINT8:               RETVAL_LONG(v->u8);                                     break;
        case PSI_T_INT16:               RETVAL_LONG(v->i16);                            break;
        case PSI_T_UINT16:              RETVAL_LONG(v->u16);                            break;
+       case PSI_T_ENUM:
        case PSI_T_INT32:               RETVAL_LONG(v->i32);                            break;
        case PSI_T_UINT32:              RETVAL_LONG(v->u32);                            break;
        case PSI_T_INT64:               RETVAL_LONG(v->i64);                            break;
-       case PSI_T_UINT64:              RETVAL_LONG_U64(v->u64);                        break;
-       case PSI_T_FLOAT:               RETVAL_DOUBLE((double) v->fval);        break;
-       case PSI_T_DOUBLE:              RETVAL_DOUBLE(v->dval);                         break;
+       case PSI_T_UINT64:              RETVAL_LONG_STR(v->u64, 0);                     break;
+#ifdef HAVE_INT128
+       case PSI_T_INT128:              RETVAL_LONG_STR(v->i128, 1);            break;
+       case PSI_T_UINT128:             RETVAL_LONG_STR(v->u128, 0);            break;
+#endif
+       case PSI_T_FLOAT:
+               RETVAL_DOUBLE((double) v->fval);
+               convert_to_long(return_value);
+               break;
+       case PSI_T_DOUBLE:
+               RETVAL_DOUBLE(v->dval);
+               convert_to_long(return_value);
+               break;
 #ifdef HAVE_LONG_DOUBLE
-       case PSI_T_LONG_DOUBLE: RETVAL_DOUBLE((double) v->ldval);       break;
+       case PSI_T_LONG_DOUBLE:
+               RETVAL_DOUBLE((double) v->ldval);
+               convert_to_long(return_value);
+               break;
 #endif
        EMPTY_SWITCH_DEFAULT_CASE();
        }
-
-       convert_to_long(return_value);
 }
 
 static inline impl_val *psi_val_intval(impl_val *tmp, token_t real_type, zend_long intval) {
@@ -254,12 +319,15 @@ static inline impl_val *psi_val_intval(impl_val *tmp, token_t real_type, zend_lo
        case PSI_T_UINT8:               tmp->u8 = intval;               break;
        case PSI_T_INT16:               tmp->i16 = intval;              break;
        case PSI_T_UINT16:              tmp->u16 = intval;              break;
+       case PSI_T_ENUM:
        case PSI_T_INT32:               tmp->i32 = intval;              break;
        case PSI_T_UINT32:              tmp->u32 = intval;              break;
        case PSI_T_INT64:               tmp->i64 = intval;              break;
        case PSI_T_UINT64:              tmp->u64 = intval;              break;
-       case PSI_T_INT:                 tmp->ival = intval;             break;
-       case PSI_T_LONG:                tmp->lval = intval;             break;
+#if HAVE_INT128
+       case PSI_T_INT128:              tmp->i128 = intval;             break;
+       case PSI_T_UINT128:             tmp->u128 = intval;             break;
+#endif
        case PSI_T_FLOAT:               tmp->fval = intval;             break;
        case PSI_T_DOUBLE:              tmp->dval = intval;             break;
 #ifdef HAVE_LONG_DOUBLE
@@ -271,16 +339,104 @@ static inline impl_val *psi_val_intval(impl_val *tmp, token_t real_type, zend_lo
        return tmp;
 }
 
+#if HAVE_INT128
+void psi_strto_i128(char *ptr, char *end, token_t real_type, impl_val *val) {
+       unsigned __int128 i = 0;
+       bool oct = false, hex = false, sign = false;
+
+       if (*ptr == '+') {
+               ++ptr;
+       } else if (*ptr == '-') {
+               sign = true;
+               ++ptr;
+       } else if (*ptr == '\\') {
+               switch (*++ptr) {
+               case 'x':
+                       hex = true;
+                       ++ptr;
+                       break;
+               case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':
+                       oct = true;
+                       break;
+               default:
+                       goto fail;
+               }
+       }
+       while (ptr < end) {
+               switch (*ptr) {
+               case '8':case '9':
+                       if (oct) {
+                               goto fail;
+                       }
+                       /* no break */
+               case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':
+                       if (oct) {
+                               i <<= 3;
+                       } else if (hex) {
+                               i <<= 4;
+                       } else {
+                               i *= 10;
+                       }
+                       i += *ptr - '0';
+                       break;
+               case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':
+                       if (!hex) {
+                               goto fail;
+                       }
+                       i <<= 4;
+                       i += 10 + (*ptr - 'a');
+                       break;
+               case 'A':case 'B':case 'C':case 'D':case 'E':case 'F':
+                       if (!hex) {
+                               goto fail;
+                       }
+                       i <<= 4;
+                       i += 10 + (*ptr - 'A');
+                       break;
+               default:
+               fail:
+                       zend_error(E_WARNING, "A non well formed numeric value encountered");
+                       goto stop;
+               }
+               ++ptr;
+       }
+
+stop:
+       if (real_type == PSI_T_UINT128) {
+               if (sign) {
+                       val->u128 = -i;
+               } else {
+                       val->u128 = i;
+               }
+       } else {
+               if (sign) {
+                       val->i128 = -i;
+               } else {
+                       val->i128 = i;
+               }
+       }
+}
+#endif
+
 /*
  * let dvar = intval($ivar)
  */
-impl_val *psi_let_intval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+impl_val *psi_let_intval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
-       zend_long intval;
-       token_t real_type = spec ? psi_decl_type_get_real(spec)->type : PSI_T_LONG;
+       int64_t intval;
+       token_t real_type = spec ? psi_decl_type_get_real(spec->type)->type : PSI_T_INT64;
+
 
        if (ival && impl_type == PSI_T_INT) {
                intval = ival->zend.lval;
+#if HAVE_INT128
+       } else if ((real_type == PSI_T_UINT128 || real_type == PSI_T_INT128) &&
+                       !((Z_TYPE_P(zvalue) == IS_TRUE || Z_TYPE_P(zvalue) == IS_FALSE || Z_TYPE_P(zvalue) == IS_LONG || Z_TYPE_P(zvalue) == IS_DOUBLE || Z_TYPE_P(zvalue) == IS_NULL))) {
+               zend_string *str = zval_get_string(zvalue);
+               psi_strto_i128(str->val, str->val + str->len, real_type, tmp);
+               zend_string_release(str);
+               return tmp;
+#endif
        } else {
                intval = zval_get_long(zvalue);
        }
@@ -311,6 +467,10 @@ void psi_set_to_float(zval *return_value, struct psi_set_exp *set, impl_val *ret
        case PSI_T_UINT32:              RETVAL_DOUBLE((double) v->u32);         break;
        case PSI_T_INT64:               RETVAL_DOUBLE((double) v->i64);         break;
        case PSI_T_UINT64:              RETVAL_DOUBLE((double) v->u64);         break;
+#if HAVE_INT128
+       case PSI_T_INT128:              RETVAL_DOUBLE((double) v->i128);        break;
+       case PSI_T_UINT128:             RETVAL_DOUBLE((double) v->u128);        break;
+#endif
        EMPTY_SWITCH_DEFAULT_CASE();
        }
 }
@@ -325,6 +485,10 @@ static inline impl_val *psi_val_floatval(impl_val *tmp, token_t real_type, doubl
        case PSI_T_UINT32:              tmp->u32 = floatval;    break;
        case PSI_T_INT64:               tmp->i64 = floatval;    break;
        case PSI_T_UINT64:              tmp->u64 = floatval;    break;
+#if HAVE_INT128
+       case PSI_T_INT128:              tmp->i128 = floatval;   break;
+       case PSI_T_UINT128:             tmp->u128 = floatval;   break;
+#endif
        case PSI_T_FLOAT:               tmp->fval = floatval;   break;
        case PSI_T_DOUBLE:              tmp->dval = floatval;   break;
 #ifdef HAVE_LONG_DOUBLE
@@ -339,10 +503,10 @@ static inline impl_val *psi_val_floatval(impl_val *tmp, token_t real_type, doubl
 /*
  * let dvar = floatval($ivar)
  */
-impl_val *psi_let_floatval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+impl_val *psi_let_floatval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        double floatval;
-       token_t real_type = spec ? psi_decl_type_get_real(spec)->type : PSI_T_DOUBLE;
+       token_t real_type = spec ? psi_decl_type_get_real(spec->type)->type : PSI_T_DOUBLE;
 
        if (ival && (impl_type == PSI_T_FLOAT || impl_type == PSI_T_DOUBLE)) {
                floatval = ival->dval;
@@ -387,7 +551,7 @@ void psi_set_to_stringl(zval *return_value, struct psi_set_exp *set, impl_val *r
                struct psi_set_exp *sub_exp;
 
                psi_plist_get(set->inner, 0, &sub_exp);
-               RETVAL_STRINGL(str, psi_long_num_exp(sub_exp->data.num, frame));
+               RETVAL_STRINGL(str, psi_num_exp_get_long(sub_exp->data.num, frame, NULL));
        } else {
                RETVAL_EMPTY_STRING();
        }
@@ -396,7 +560,7 @@ void psi_set_to_stringl(zval *return_value, struct psi_set_exp *set, impl_val *r
 /*
  * let dvar = strval($ivar)
  */
-impl_val *psi_let_strval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+impl_val *psi_let_strval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        if (ival && impl_type == PSI_T_STRING) {
                if (ival->zend.str) {
@@ -404,8 +568,6 @@ impl_val *psi_let_strval(impl_val *tmp, struct psi_decl_type *spec, token_t impl
                } else {
                        tmp->ptr = "";
                }
-       } else if (0 && Z_TYPE_P(zvalue) == IS_STRING) {
-               tmp->ptr = Z_STRVAL_P(zvalue);
        } else {
                zend_string *zs = zval_get_string(zvalue);
                tmp->ptr = estrdup(zs->val);
@@ -419,7 +581,7 @@ impl_val *psi_let_strval(impl_val *tmp, struct psi_decl_type *spec, token_t impl
 /*
  * let dvar = pathval($ivar)
  */
-impl_val *psi_let_pathval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+impl_val *psi_let_pathval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        tmp = psi_let_strval(tmp, spec, impl_type, ival, zvalue, to_free);
        if (SUCCESS != php_check_open_basedir(tmp->ptr)) {
@@ -433,29 +595,34 @@ impl_val *psi_let_pathval(impl_val *tmp, struct psi_decl_type *spec, token_t imp
 /*
  * let dvar = strlen($ivar)
  */
-impl_val *psi_let_strlen(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+impl_val *psi_let_strlen(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        if (ival && impl_type == PSI_T_STRING) {
                if (ival->zend.str) {
-                       tmp->lval = ival->zend.str->len;
+                       tmp->u64 = ival->zend.str->len;
                } else {
-                       tmp->lval = 0;
+                       tmp->u64 = 0;
                }
        } else {
                zend_string *zs = zval_get_string(zvalue);
-               tmp->lval = zs->len;
+               tmp->u64 = zs->len;
                zend_string_release(zs);
        }
 
+       if (spec) {
+               psi_calc_cast(PSI_T_UINT64, tmp, psi_decl_type_get_real(spec->type)->type, tmp);
+       }
        return tmp;
 }
 
+#if 0
 static impl_val *iterate(impl_val *val, size_t size, unsigned i, impl_val *tmp)
 {
        memset(tmp, 0, sizeof(*tmp));
        memcpy(tmp, ((char *) val) + size * i, size);
        return tmp;
 }
+#endif
 
 /*
  * set $ivar = to_array(dvar,
@@ -519,7 +686,7 @@ void psi_set_to_array_counted(zval *return_value, struct psi_set_exp *set, impl_
        }
 
        psi_plist_get(set->inner, 0, &sub_exp);
-       count = psi_long_num_exp(sub_exp->data.num, frame);
+       count = psi_num_exp_get_long(sub_exp->data.num, frame, NULL);
        psi_plist_get(set->inner, 1, &sub_exp);
 
        for (ptr = (char *) ret_val; 0 < count--; ptr += size) {
@@ -569,49 +736,12 @@ void psi_set_to_array(zval *return_value, struct psi_set_exp *set, impl_val *r_v
        }
 }
 
-//impl_val *psi_let_arrval(impl_val *tmp, decl_type *spec, decl_var *spec_var, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
-//{
-//     decl_type *real = real_decl_type(spec);
-//     HashTable *arr;
-//     zval *zv;
-//     size_t i, sz;
-//     decl_arg tmp_arg = {0};
-//
-//     if (impl_type != PSI_T_ARRAY) {
-//             SEPARATE_ARG_IF_REF(zvalue);
-//             convert_to_array(zvalue);
-//     }
-//     arr = HASH_OF(zvalue);
-//
-//     switch (real->type) {
-//     case PSI_T_STRUCT:
-//             *to_free = tmp = psi_array_to_struct(real->real.strct, arr);
-//             break;
-//     case PSI_T_UNION:
-//             *to_free = tmp = psi_array_to_union(real->real.unn, arr);
-//             break;
-//     default:
-//             sz = psi_t_size(real->type);
-//             tmp = *to_free = ecalloc(zend_hash_num_elements(arr), sz);
-//             tmp_arg.type = spec;
-//             tmp_arg.var = spec_var;
-//             ZEND_HASH_FOREACH_VAL_IND(arr, zv)
-//             {
-//                     void *ptr = ((char *) tmp) + (i++ * sz);
-//                     psi_from_zval_ex(NULL, (impl_val **) &ptr, &tmp_arg, 0, zv, NULL);
-//             }
-//             ZEND_HASH_FOREACH_END();
-//     }
-//
-//     return tmp;
-//}
-
 /*
  * let dvar = count($ivar)
  */
-impl_val *psi_let_count(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+impl_val *psi_let_count(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
-       return psi_val_intval(tmp, psi_decl_type_get_real(spec)->type, psi_zval_count(zvalue));
+       return psi_val_intval(tmp, psi_decl_type_get_real(spec->type)->type, psi_zval_count(zvalue));
 }
 
 /*
@@ -633,7 +763,7 @@ void psi_set_to_object(zval *return_value, struct psi_set_exp *set, impl_val *r_
 /*
  * let dvar = objval($ivar)
  */
-impl_val *psi_let_objval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+impl_val *psi_let_objval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        psi_object *obj;