X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-psi;a=blobdiff_plain;f=src%2Fmarshal.c;h=cb0aa10fcbf1cd28b1c2501892e139fa1dac7fb1;hp=66b6ae617a274e3d1e5e152308c294604e39a9e2;hb=09529efcde471127419e141807b83b37077003a0;hpb=898c6dac30d12d7fe56662d66a8e73c340926d64 diff --git a/src/marshal.c b/src/marshal.c index 66b6ae6..cb0aa10 100644 --- a/src/marshal.c +++ b/src/marshal.c @@ -1,36 +1,187 @@ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * 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. + + 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. +*******************************************************************************/ + +#include "php_psi_stdinc.h" +#include "data.h" +#include "calc.h" #include "php.h" #include "php_psi.h" -#include "parser.h" -#include "marshal.h" -#include "calc.h" -void psi_to_void(zval *return_value, set_value *set, impl_val *ret_val) +#include "Zend/zend_interfaces.h" +#include "ext/spl/spl_iterators.h" + +zend_long psi_zval_count(zval *zvalue) +{ + /* mimic PHP count() */ + zend_long count; + zval retval; + + switch (Z_TYPE_P(zvalue)) { + default: + count = 1; + break; + case IS_NULL: + count = 0; + break; + case IS_ARRAY: + count = zend_array_count(Z_ARRVAL_P(zvalue)); + break; + case IS_OBJECT: + count = 1; + if (Z_OBJ_HT_P(zvalue)->count_elements) { + if (SUCCESS == Z_OBJ_HT_P(zvalue)->count_elements(zvalue, &count)) { + break; + } + } + + if (instanceof_function(Z_OBJCE_P(zvalue), spl_ce_Countable)) { + zend_call_method_with_0_params(zvalue, NULL, NULL, "count", &retval); + if (Z_TYPE(retval) != IS_UNDEF) { + count = zval_get_long(&retval); + zval_ptr_dtor(&retval); + } + } + break; + } + + return count; +} + +int psi_internal_type(struct psi_impl_type *type) +{ + switch (type->type) { + case PSI_T_BOOL: + return _IS_BOOL; + case PSI_T_INT: + return IS_LONG; + case PSI_T_FLOAT: + case PSI_T_DOUBLE: + return IS_DOUBLE; + case PSI_T_STRING: + return IS_STRING; + case PSI_T_ARRAY: + return IS_ARRAY; + default: + return 0; + } +} + +zend_internal_arg_info *psi_internal_arginfo(struct psi_impl *impl) +{ + size_t i = 0, argc = psi_plist_count(impl->func->args); + zend_internal_arg_info *aip; + zend_internal_function_info *fi; + struct psi_impl_arg *iarg; + + 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; + + if (impl->func->vararg) { + struct psi_impl_arg *vararg = impl->func->vararg; + zend_internal_arg_info *ai = &aip[argc]; + + ai->name = vararg->var->name->val; +#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; + } + ai->is_variadic = 1; + } + + while (psi_plist_get(impl->func->args, i++, &iarg)) { + zend_internal_arg_info *ai = &aip[i]; + + ai->name = iarg->var->name->val; +#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; + } + } + + return aip; +} + +/* + * return void(dvar) + */ +void psi_set_void(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame) { RETVAL_NULL(); } -impl_val *psi_let_void(impl_val *tmp, decl_type *type, impl_arg *iarg, 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; } -void psi_to_zval(zval *return_value, set_value *set, impl_val *ret_val) { +/* + * set $ivar = zval(dvar) + */ +void psi_set_zval(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame) { RETVAL_ZVAL(ret_val->ptr, 1, 0); } -impl_val *psi_let_zval(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free) +/* + * let dvar = zval($ivar) + */ +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, iarg->_zv); + ZVAL_COPY_VALUE(tmp->ptr, zvalue); return tmp; } -void psi_to_bool(zval *return_value, set_value *set, impl_val *ret_val) +/* + * return to_bool(dvar) + */ +void psi_set_to_bool(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame) { - psi_to_int(return_value, set, ret_val); + psi_set_to_int(return_value, set, ret_val, frame); convert_to_boolean(return_value); } @@ -44,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 @@ -54,32 +209,76 @@ static inline impl_val *psi_val_boolval(impl_val *tmp, token_t real_type, zend_b return tmp; } -impl_val *psi_let_boolval(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free) +/* + * let dvar = boolval($ivar) + */ +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 = type ? real_decl_type(type)->type : PSI_T_UINT8; + token_t real_type = spec ? psi_decl_type_get_real(spec->type)->type : PSI_T_UINT8; - if (iarg->type->type == PSI_T_BOOL) { - boolval = iarg->val.zend.bval; + if (ival && impl_type == PSI_T_BOOL) { + boolval = ival->zend.bval; } else { - boolval = zend_is_true(iarg->_zv); + boolval = zend_is_true(zvalue); } 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)); \ +#if HAVE_INT128 +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); +} + +# 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); \ - } - -void psi_to_int(zval *return_value, set_value *set, impl_val *ret_val) + } 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) + */ +void psi_set_to_int(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame) { - decl_var *var = set->vars->vars[0]; - token_t t = real_decl_type(var->arg->type)->type; + struct psi_decl_var *var = psi_set_exp_get_decl_var(set); + token_t t = psi_decl_type_get_real(var->arg->type)->type; impl_val *v = deref_impl_val(ret_val, var); switch (t) { @@ -87,19 +286,31 @@ void psi_to_int(zval *return_value, set_value *set, impl_val *ret_val) 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) { @@ -108,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 @@ -125,24 +339,118 @@ static inline impl_val *psi_val_intval(impl_val *tmp, token_t real_type, zend_lo return tmp; } -impl_val *psi_let_intval(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free) -{ - zend_long intval; - token_t real_type = type ? real_decl_type(type)->type : PSI_T_LONG; +#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; + } - if (iarg->type->type == PSI_T_INT) { - intval = iarg->val.zend.lval; +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_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) +{ + 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(iarg->_zv); + intval = zval_get_long(zvalue); } return psi_val_intval(tmp, real_type, intval); } -void psi_to_double(zval *return_value, set_value *set, impl_val *ret_val) +/* + * set $ivar = to_float(dvar) + */ +void psi_set_to_float(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame) { - decl_var *var = set->vars->vars[0]; - token_t t = real_decl_type(var->arg->type)->type; + struct psi_decl_var *var = psi_set_exp_get_decl_var(set); + token_t t = psi_decl_type_get_real(var->arg->type)->type; impl_val *v = deref_impl_val(ret_val, var); switch (t) { @@ -159,6 +467,10 @@ void psi_to_double(zval *return_value, set_value *set, impl_val *ret_val) 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(); } } @@ -173,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 @@ -184,70 +500,76 @@ static inline impl_val *psi_val_floatval(impl_val *tmp, token_t real_type, doubl return tmp; } -impl_val *psi_let_floatval(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free) +/* + * let dvar = floatval($ivar) + */ +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 = type ? real_decl_type(type)->type : PSI_T_DOUBLE; + token_t real_type = spec ? psi_decl_type_get_real(spec->type)->type : PSI_T_DOUBLE; - if (iarg->type->type == PSI_T_FLOAT || iarg->type->type == PSI_T_DOUBLE) { - floatval = iarg->val.dval; + if (ival && (impl_type == PSI_T_FLOAT || impl_type == PSI_T_DOUBLE)) { + floatval = ival->dval; } else { - floatval = zval_get_double(iarg->_zv); + floatval = zval_get_double(zvalue); } return psi_val_floatval(tmp, real_type, floatval); } -void psi_to_string(zval *return_value, set_value *set, impl_val *ret_val) +/* + * set $ivar = to_string(dvar) + */ +void psi_set_to_string(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame) { + struct psi_decl_var *var = psi_set_exp_get_decl_var(set); + impl_val *ptr = deref_impl_val(ret_val, var); char *str; - decl_var *var = set->vars->vars[0]; - token_t t = real_decl_type(var->arg->type)->type; - switch (t) { - case PSI_T_FLOAT: RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->fval); break; - case PSI_T_DOUBLE: RETVAL_DOUBLE(deref_impl_val(ret_val, var)->dval); break; -#ifdef HAVE_LONG_DOUBLE - case PSI_T_LONG_DOUBLE: RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->ldval); break; -#endif - default: - if (!var->arg->var->pointer_level) { - RETVAL_STRINGL(&ret_val->cval, 1); - } else { - ret_val = deref_impl_val(ret_val, var); - if (var->arg->var->array_size) { - str = (char *) ret_val; - } else { - str = ret_val->ptr; - } - if (str) { - if (set->num) { - zend_long n = psi_long_num_exp(set->num, set->outer.val); - RETVAL_STRINGL(str, n); - } else { - RETVAL_STRING(str); - } - } else { - RETVAL_EMPTY_STRING(); - } - } - return; + if (var->arg->var->array_size && var->arg->var->pointer_level == 1) { + str = (char *) ptr; + } else { + str = ptr->ptr; + } + + if (str) { + RETVAL_STRING(str); + } else { + RETVAL_EMPTY_STRING(); } +} - convert_to_string(return_value); +/* + * set $ivar = to_string(dvar, num_exp) + */ +void psi_set_to_stringl(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame) +{ + struct psi_decl_var *var = psi_set_exp_get_decl_var(set); + char *str = deref_impl_val(ret_val, var)->ptr; + + if (str) { + struct psi_set_exp *sub_exp; + + psi_plist_get(set->inner, 0, &sub_exp); + RETVAL_STRINGL(str, psi_num_exp_get_long(sub_exp->data.num, frame, NULL)); + } else { + RETVAL_EMPTY_STRING(); + } } -impl_val *psi_let_strval(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free) +/* + * let dvar = strval($ivar) + */ +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 (iarg->type->type == PSI_T_STRING) { - if (iarg->val.zend.str) { - tmp->ptr = estrndup(iarg->val.zend.str->val, iarg->val.zend.str->len); - *to_free = tmp->ptr; + if (ival && impl_type == PSI_T_STRING) { + if (ival->zend.str) { + tmp->ptr = ival->zend.str->val; } else { tmp->ptr = ""; } } else { - zend_string *zs = zval_get_string(iarg->_zv); + zend_string *zs = zval_get_string(zvalue); tmp->ptr = estrdup(zs->val); *to_free = tmp->ptr; zend_string_release(zs); @@ -256,286 +578,178 @@ impl_val *psi_let_strval(impl_val *tmp, decl_type *type, impl_arg *iarg, void ** return tmp; } -impl_val *psi_let_pathval(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free) +/* + * let dvar = pathval($ivar) + */ +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, type, iarg, to_free); + tmp = psi_let_strval(tmp, spec, impl_type, ival, zvalue, to_free); if (SUCCESS != php_check_open_basedir(tmp->ptr)) { efree(tmp->ptr); + tmp->ptr = NULL; return *to_free = NULL; } return tmp; } -impl_val *psi_let_strlen(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free) +/* + * let dvar = strlen($ivar) + */ +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 (iarg->type->type == PSI_T_STRING) { - if (iarg->val.zend.str) { - tmp->lval = iarg->val.zend.str->len; + if (ival && impl_type == PSI_T_STRING) { + if (ival->zend.str) { + tmp->u64 = ival->zend.str->len; } else { - tmp->lval = 0; + tmp->u64 = 0; } } else { - zend_string *zs = zval_get_string(iarg->_zv); - tmp->lval = zs->len; + zend_string *zs = zval_get_string(zvalue); + 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, ((void*) val) + size * i, size); + memcpy(tmp, ((char *) val) + size * i, size); return tmp; } - -void psi_from_zval_ex(impl_val **ptr, decl_arg *spec, token_t cast, zval *zv, void **tmp) -{ - decl_type *real = real_decl_type(spec->type); - impl_val *val = *ptr; - - switch (real->type) { - default: - ZEND_ASSERT(0); - val->i64 = zval_get_long(zv); - break; - case PSI_T_INT8: - val->i8 = zval_get_long(zv); - break; - case PSI_T_UINT8: - val->u8 = zval_get_long(zv); - break; - case PSI_T_INT16: - val->i16 = zval_get_long(zv); - break; - case PSI_T_UINT16: - val->u16 = zval_get_long(zv); - break; - case PSI_T_INT32: - val->i32 = zval_get_long(zv); - break; - case PSI_T_UINT32: - val->u32 = zval_get_long(zv); - break; - case PSI_T_INT64: - val->i64 = zval_get_long(zv); - break; - case PSI_T_UINT64: - val->u64 = zval_get_long(zv); - break; - case PSI_T_FLOAT: - val->fval = zval_get_double(zv); - break; - case PSI_T_DOUBLE: - val->dval = zval_get_double(zv); - break; -#ifdef HAVE_LONG_DOUBLE - case PSI_T_LONG_DOUBLE: - val->ldval = zval_get_double(zv); - break; #endif - case PSI_T_ENUM: - val->ival = zval_get_long(zv); - break; - case PSI_T_STRUCT: - *tmp = *ptr = psi_array_to_struct(real->real.strct, HASH_OF(zv)); - break; - case PSI_T_UNION: - *tmp = *ptr = psi_array_to_union(real->real.unn, HASH_OF(zv)); - break; - case PSI_T_FUNCTION: - /*FIXME*/ - val->ptr = NULL; - break; - case PSI_T_VOID: - val->ptr = NULL; - if (Z_TYPE_P(zv) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zv), psi_object_get_class_entry())) { - *ptr = PSI_OBJ(zv, NULL)->data; - } else { - zend_string *zs = zval_get_string(zv); - *tmp = val->ptr = estrndup(zs->val, zs->len); - zend_string_release(zs); - } - break; - } + +/* + * set $ivar = to_array(dvar, + * $foo = to_int(d_foo), + * $bar = to_string(d_bar), + * $baz = to_array(*d_next, ...) + */ +void psi_set_to_recursive(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame) { + set->outer->data.func->handler(return_value, set, r_val, frame); } -void *psi_array_to_struct(decl_struct *s, HashTable *arr) +/* + * set $ivar = to_array(dvar, to_string(*dvar)); + */ +void psi_set_to_array_simple(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame) { - size_t i, j = 0; - char *mem = ecalloc(1, s->size + s->args->count * sizeof(void *)); - - if (arr) for (i = 0; i < s->args->count; ++i) { - decl_arg *darg = s->args->args[i]; - zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name)); - - if (entry) { - impl_val val, *ptr = &val; - void *tmp = NULL; - - memset(&val, 0, sizeof(val)); - psi_from_zval_ex(&ptr, darg, /*FIXME*/0, entry, &tmp); - memcpy(mem + darg->layout->pos, ptr, darg->layout->len); - if (tmp) { - ((void **)(mem + s->size))[j++] = tmp; - } - } - } - return mem; -} + struct psi_set_exp *sub_exp; + struct psi_decl_var *var; + impl_val *ret_val; + char *ptr; + size_t size; -void *psi_array_to_union(decl_union *u, HashTable *arr) { - size_t i; - char *mem = ecalloc(1, u->size + sizeof(void *)); + array_init(return_value); - if (arr) for (i = 0; i < u->args->count; ++i) { - decl_arg *darg = u->args->args[i]; - zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name)); + var = psi_set_exp_get_decl_var(set); + ret_val = deref_impl_val(r_val, var); + if ((intptr_t) ret_val <= (intptr_t) 0) { + return; + } - if (entry) { - impl_val val, *ptr = &val; - void *tmp = NULL; + psi_plist_get(set->inner, 0, &sub_exp); - memset(&val, 0, sizeof(val)); - psi_from_zval_ex(&ptr, darg, /*FIXME*/0, entry, &tmp); - memcpy(mem, &val, darg->layout->len); - if (tmp) { - ((void **)(mem + u->size))[0] = tmp; - } - /* first found entry wins */ - break; - } - } + size = psi_decl_arg_get_size(var->arg); + for (ptr = ret_val->ptr; *(void **) ptr; ptr += size) { + zval ele; - return mem; + ZVAL_NULL(&ele); + sub_exp->data.func->handler(&ele, sub_exp, (void *) ptr, frame); + add_next_index_zval(return_value, &ele); + } } -void psi_to_recursive(zval *return_value, set_value *set, impl_val *r_val) +/* + * set $ivar = to_array(dvar, num_exp, to_string(*dvar)); + */ +void psi_set_to_array_counted(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame) { - set->outer.set->func->handler(return_value, set, r_val); -} + struct psi_set_exp *sub_exp; + struct psi_decl_var *var; + impl_val *ret_val; + char *ptr; + size_t size; + zend_long count; -void psi_to_array(zval *return_value, set_value *set, impl_val *r_val) -{ - size_t i; - decl_var *var = set->vars->vars[0]; - token_t t = real_decl_type(var->arg->type)->type; - impl_val tmp, *ret_val = deref_impl_val(r_val, var); + array_init(return_value); + var = psi_set_exp_get_decl_var(set); + ret_val = deref_impl_val(r_val, var); if ((intptr_t) ret_val <= (intptr_t) 0) { - RETURN_NULL(); + return; } - array_init(return_value); + psi_plist_get(set->inner, 0, &sub_exp); + count = psi_num_exp_get_long(sub_exp->data.num, frame, NULL); + psi_plist_get(set->inner, 1, &sub_exp); - if (t == PSI_T_STRUCT || t == PSI_T_UNION) { - // decl_struct *s = real_decl_type(var->arg->type)->strct; + size = psi_decl_var_get_size(psi_set_exp_get_decl_var(sub_exp)); + for (ptr = (char *) ret_val; 0 < count--; ptr += size) { + zval ele; - if (set->inner && set->inner->count) { - /* explicit member casts */ - for (i = 0; i < set->inner->count; ++i) { - set_value *sub_set = set->inner->vals[i]; - decl_var *sub_var = sub_set->vars->vars[0]; + ZVAL_NULL(&ele); + sub_exp->data.func->handler(&ele, sub_exp, (void *) &ptr, frame); + add_next_index_zval(return_value, &ele); + } +} - sub_set->outer.val = ret_val; +#include "call.h" - if (sub_var->arg) { - impl_val *tmp = NULL, *val; - zval ztmp; +/* + * set $ivar = to_array(dvar, + * $foo = to_int(d_foo), + * $bar = to_string(d_bar)); + */ +void psi_set_to_array(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame) +{ + struct psi_set_exp *sub_exp; + struct psi_decl_var *var; + impl_val *ret_val; + size_t i = 0; - val = struct_member_ref(sub_var->arg, ret_val, &tmp); - sub_set->func->handler(&ztmp, sub_set, val); - add_assoc_zval(return_value, sub_var->name, &ztmp); + array_init(return_value); - if (tmp) { - free(tmp); - } - } - } - return; - } + var = psi_set_exp_get_decl_var(set); + ret_val = deref_impl_val(r_val, var); + if ((intptr_t) ret_val <= (intptr_t) 0) { + return; } - if (var->arg->var->array_size) { - /* to_array(foo[NUMBER]) */ - for (i = 0; i < var->arg->var->array_size; ++i) { - size_t size = psi_t_size(var->arg->var->pointer_level > 1 ? PSI_T_POINTER : t); - impl_val *ptr = iterate(ret_val, size, i, &tmp); - zval ele; + while (psi_plist_get(set->inner, i++, &sub_exp)) { + zval ele; + struct psi_decl_var *dvar = psi_set_exp_get_decl_var(sub_exp); + struct psi_impl_var *ivar = psi_set_exp_get_impl_var(sub_exp); + struct psi_call_frame_symbol *sym; - switch (t) { - case PSI_T_FLOAT: - ZVAL_DOUBLE(&ele, (double) ptr->fval); - break; - case PSI_T_DOUBLE: - ZVAL_DOUBLE(&ele, ptr->dval); - break; - default: - ZVAL_LONG(&ele, ptr->lval); - break; - } + sym = psi_call_frame_fetch_symbol(frame, dvar); + sym->ptr = ((char *) ret_val) + dvar->arg->layout->pos; - add_next_index_zval(return_value, &ele); - } - return; - } else if (set->num) { - /* to_array(arr_var, num_expr, to_int(*arr_var)) */ - zval ele; - char *ptr; - zend_long i, n = psi_long_num_exp(set->num, set->outer.val); - size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t); - set_value *sub_set = set->inner->vals[0]; - - sub_set->outer.val = set->outer.val; - for (i = 0; i < n; ++i) { - ptr = (char *) ret_val->ptr + i * size; - sub_set->func->handler(&ele, sub_set, (void *) ptr); - add_next_index_zval(return_value, &ele); - } - } else { - /* to_array(arr_var, to_int(*arr_var)) */ - zval ele; - char *ptr = ret_val->ptr; - size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t); - set_value *sub_set = set->inner->vals[0]; - - sub_set->outer.val = set->outer.val; - while (*(void **) ptr) { - sub_set->func->handler(&ele, sub_set, (void *) ptr); - add_next_index_zval(return_value, &ele); - ptr += size; - } + ZVAL_NULL(&ele); + psi_set_exp_exec_ex(sub_exp, &ele, sym->ptr, frame); + add_assoc_zval_ex(return_value, ivar->name->val + 1, ivar->name->len - 1, &ele); } } -impl_val *psi_let_arrval(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free) +/* + * let dvar = count($ivar) + */ +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) { - decl_type *real = real_decl_type(type); - HashTable *arr; - - if (iarg->type->type != PSI_T_ARRAY) { - SEPARATE_ARG_IF_REF(iarg->_zv); - convert_to_array(iarg->_zv); - } - arr = HASH_OF(iarg->_zv); - - 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; - EMPTY_SWITCH_DEFAULT_CASE(); - } - - return tmp; + return psi_val_intval(tmp, psi_decl_type_get_real(spec->type)->type, psi_zval_count(zvalue)); } -void psi_to_object(zval *return_value, set_value *set, impl_val *r_val) +/* + * set $ivar = to_object(dvar) + */ +void psi_set_to_object(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame) { - decl_var *var = set->vars->vars[0]; + struct psi_decl_var *var = psi_set_exp_get_decl_var(set); impl_val *ret_val = deref_impl_val(r_val, var); if ((intptr_t) ret_val->ptr > (intptr_t) 0) { @@ -546,16 +760,19 @@ void psi_to_object(zval *return_value, set_value *set, impl_val *r_val) } } -impl_val *psi_let_objval(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free) +/* + * let dvar = objval($ivar) + */ +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; - if (Z_TYPE_P(iarg->_zv) != IS_OBJECT - || !instanceof_function(Z_OBJCE_P(iarg->_zv), psi_object_get_class_entry())) { + if (Z_TYPE_P(zvalue) != IS_OBJECT + || !instanceof_function(Z_OBJCE_P(zvalue), psi_object_get_class_entry())) { return NULL; } - obj = PSI_OBJ(iarg->_zv, NULL); + obj = PSI_OBJ(zvalue, NULL); tmp->ptr = obj->data; return tmp;