X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-psi;a=blobdiff_plain;f=src%2Ftypes%2Fimpl_def_val.c;h=8b2d37b6029cf39f2aea10949179b0e8b9af7694;hp=0d176f309eea9845d6ff2222243ef761c6d4f98a;hb=b1c7c64ca1d1d9dc79a59c0f612bd07e7a997a60;hpb=2f5af21b263403997e154658635d6b6e6eaab453 diff --git a/src/types/impl_def_val.c b/src/types/impl_def_val.c index 0d176f3..8b2d37b 100644 --- a/src/types/impl_def_val.c +++ b/src/types/impl_def_val.c @@ -23,34 +23,459 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif +#include "php_psi_stdinc.h" +#include "data.h" -#include -#include +#include "zend_smart_str.h" -#include "impl_def_val.h" +#include +#include -void free_impl_def_val(impl_def_val *def) { - free(def->text); - free(def); -} +#define PSI_IMPL_DEF_VAL_DEBUG 0 + +struct psi_impl_def_val *psi_impl_def_val_init(token_t t, void *data) +{ + struct psi_impl_def_val *def = pecalloc(1, sizeof(*def), 1); + + switch ((def->type = t)) { + case PSI_T_TRUE: + def->ival.zend.bval = 1; + /* no break */ + case PSI_T_FALSE: + def->ityp = PSI_T_UINT8; + /* no break */ + case PSI_T_NULL: + break; + case PSI_T_QUOTED_STRING: + /* immediate upgrade */ + def->type = PSI_T_STRING; + /* no break */ + case PSI_T_STRING: + if (data) { + def->ival.zend.str = zend_string_copy(data); + } + break; + + case PSI_T_NUMBER: + def->data.num = data; + break; + + default: + assert(0); + } -impl_def_val *init_impl_def_val(token_t t, const char *text) { - impl_def_val *def = calloc(1, sizeof(*def)); - def->type = t; - def->text = strdup(text); return def; } -void dump_impl_def_val(int fd, impl_def_val *val) { - if (val->type == PSI_T_QUOTED_STRING) { - dprintf(fd, "\"%s\"", val->text); - } else { - dprintf(fd, "%s", val->text); +void psi_impl_def_val_free(struct psi_impl_def_val **def_ptr) +{ + if (*def_ptr) { + struct psi_impl_def_val *def = *def_ptr; + + *def_ptr = NULL; + psi_token_free(&def->token); + switch (def->type) { + case PSI_T_NUMBER: + psi_num_exp_free(&def->data.num); + break; + + case PSI_T_STRING: + if (def->ival.zend.str) { + zend_string_release(def->ival.zend.str); + } + break; + default: + break; + } + free(def); + } +} + +void psi_impl_def_val_get_zval(struct psi_impl_def_val *val, token_t typ, zval *zv) +{ + impl_val tmp = val->ival; + + /* c->val has already been forced to the type of the containing constant or impl_arg */ + switch (typ) { + case PSI_T_BOOL: + ZVAL_BOOL(zv, tmp.zend.bval); + break; + case PSI_T_INT: + ZVAL_LONG(zv, tmp.zend.lval); + break; + case PSI_T_FLOAT: + case PSI_T_DOUBLE: + is_double: ; + ZVAL_DOUBLE(zv, tmp.dval); + break; + case PSI_T_STRING: + is_string: ; + ZVAL_NEW_STR(zv, zend_string_copy(tmp.zend.str)); + if (ZSTR_IS_INTERNED(Z_STR_P(zv))) { + Z_TYPE_FLAGS_P(zv) = 0; + } + break; + case PSI_T_MIXED: + switch (val->type) { + case PSI_T_NULL: + ZVAL_NULL(zv); + break; + case PSI_T_TRUE: + ZVAL_TRUE(zv); + break; + case PSI_T_FALSE: + ZVAL_FALSE(zv); + break; + case PSI_T_STRING: + goto is_string; + break; + case PSI_T_NUMBER: + switch (val->ityp) { + case PSI_T_INT8: + case PSI_T_UINT8: + case PSI_T_INT16: + case PSI_T_UINT16: + case PSI_T_INT32: + case PSI_T_UINT32: + psi_calc_cast(val->ityp, &tmp, PSI_T_INT64, &tmp); + /* no break */ + case PSI_T_INT64: + ZVAL_LONG(zv, tmp.i64); + break; + case PSI_T_UINT64: + ZVAL_LONG_DOUBLE_STR(zv, tmp.u64, is_signed=false;persistent=true); + break; +#if HAVE_INT128 + case PSI_T_INT128: + ZVAL_LONG_DOUBLE_STR(zv, tmp.i128, is_signed=true;persistent=true); + break; + case PSI_T_UINT128: + ZVAL_LONG_DOUBLE_STR(zv, tmp.u128, is_signed=false;persistent=true); +#endif + break; + case PSI_T_FLOAT: + ZVAL_DOUBLE(zv, tmp.fval); + break; + case PSI_T_DOUBLE: + goto is_double; + break; +#if HAVE_LONG_DOUBLE + case PSI_T_LONG_DOUBLE: + ZVAL_DOUBLE(zv, tmp.ldval); + break; +#endif + default: + assert(0); + } + break; + default: + assert(0); + break; + } + break; + default: + assert(0); + break; + } + +} +/* +token_t psi_impl_def_val_get_zend(struct psi_impl_def_val *val, impl_val *res) +{ + switch (val->type) { + case PSI_T_NULL: + return PSI_T_NULL; + case PSI_T_TRUE: + case PSI_T_FALSE: + res->zend.bval = val->ival.zend.bval; + return PSI_T_BOOL; + case PSI_T_STRING: + res->zend.str = val->ival.zend.str + ? zend_string_copy(val->ival.zend.str) + : zend_empty_string; + return PSI_T_STRING; + case PSI_T_NUMBER: + switch (val->ityp) { + case PSI_T_FLOAT: + res->dval = val->ival.fval; + return PSI_T_DOUBLE; + case PSI_T_DOUBLE: + res->dval = val->ival.dval; + return PSI_T_DOUBLE; +#if HAVE_LONG_DOUBLE + case PSI_T_LONG_DOUBLE: + res->dval = val->ival.ldval; + return PSI_T_DOUBLE; +#endif + default: + psi_calc_cast(val->ityp, &val->ival, PSI_T_INT64, res); + return PSI_T_INT; + } + break; + default: + assert(0); + return 0; } +} +*/ + +static inline bool psi_impl_def_val_validate_impl_type(struct psi_data *data, + struct psi_impl_def_val *val, struct psi_impl_type *type, + struct psi_validate_scope *scope) +{ + switch (type->type) { + case PSI_T_BOOL: + switch (val->type) { + case PSI_T_TRUE: + case PSI_T_FALSE: + return true; + case PSI_T_STRING: + if (val->ival.zend.str + && *val->ival.zend.str->val + && *val->ival.zend.str->val != '0') { + zend_string_release(val->ival.zend.str); + val->ival.zend.bval = 1; + } else { + if (val->ival.zend.str) { + zend_string_release(val->ival.zend.str); + } + val->ival.zend.bval = 0; + } + val->ityp = PSI_T_UINT8; + return true; + default: + assert(0); + break; + } + break; + case PSI_T_INT: + if (val->type == PSI_T_STRING) { + zend_string *str = val->ival.zend.str; + switch (is_numeric_str_function(str, &val->ival.zend.lval, &val->ival.dval)) { + case IS_DOUBLE: + val->ival.zend.lval = zend_dval_to_lval_cap(val->ival.dval); + /* no break */ + case IS_LONG: + break; + default: + val->ival.zend.lval = 0; + } + zend_string_release(str); + val->ityp = PSI_T_INT64; + return true; + } + psi_calc_cast(val->ityp, &val->ival, PSI_T_INT64, &val->ival); + val->type = val->ityp = PSI_T_INT64; + return true; + case PSI_T_FLOAT: + case PSI_T_DOUBLE: + if (val->type == PSI_T_STRING) { + zend_string *str = val->ival.zend.str; + switch (is_numeric_str_function(str, &val->ival.zend.lval, &val->ival.dval)) { + case IS_LONG: + val->ival.dval = val->ival.zend.lval; + /* no break */ + case IS_DOUBLE: + break; + default: + val->ival.dval = 0; + } + zend_string_release(str); + val->type = val->ityp = PSI_T_DOUBLE; + return true; + } + psi_calc_cast(val->ityp, &val->ival, PSI_T_DOUBLE, &val->ival); + val->ityp = PSI_T_DOUBLE; + return true; + case PSI_T_STRING: + if (val->type == PSI_T_STRING) { + return true; + } else { + smart_str str = {0}; + switch (val->ityp) { + CASE_IMPLVAL_NUM_PRINTF(smart_str_append_printf, &str, val->ival, false); + default: + assert(0); + } + val->ival.zend.str = smart_str_extract(&str); + val->type = PSI_T_STRING; + return true; + } + break; + default: + data->error(data, val->token, PSI_WARNING, + "Invalid default value type '%s', " + "expected one of bool, int, float/double or string.", + type->name->val); + + } + return false; +} + +bool psi_impl_def_val_validate(struct psi_data *data, + struct psi_impl_def_val *val, struct psi_impl_type *type, + struct psi_validate_scope *scope) +{ + /* NULL can be anything */ + if (val->type == PSI_T_NULL) { + return true; + } + + /* a number can be anything */ + if (val->type == PSI_T_NUMBER) { + if (!psi_num_exp_validate(data, val->data.num, scope)) { + return false; + } + val->ityp = psi_num_exp_exec(val->data.num, &val->ival, NULL, scope->cpp); + } + + /* forced type, like `const foo`, or function param ` $xyz` */ + if (type) { + return psi_impl_def_val_validate_impl_type(data, val, type, scope); + } + + switch (val->type) { + case PSI_T_NUMBER: + case PSI_T_NULL: + case PSI_T_TRUE: + case PSI_T_FALSE: + case PSI_T_STRING: + return true; + default: + assert(0); + break; + } + + return false; +/* + switch (type ? type->type : PSI_T_MIXED) { + case PSI_T_BOOL: + val->ival.zend.bval = val->type == PSI_T_TRUE ? 1 : 0; + return true; + break; + + // macros + case PSI_T_NUMBER: + if (val->type == PSI_T_NUMBER) { + token_t typ = psi_num_exp_exec(val->data.num, &val->ival, NULL, scope->cpp); + + switch (typ) { + case PSI_T_FLOAT: + val->ival.dval = val->ival.fval; + // no break + case PSI_T_DOUBLE: + val->type = PSI_T_FLOAT; + type->type = PSI_T_FLOAT; + zend_string_release(type->name); + type->name = zend_string_init_interned(ZEND_STRL("float"), 1); + break; + case PSI_T_UINT64: + if (val->ival.u64 > ZEND_LONG_MAX) { + data->error(data, val->token, PSI_WARNING, + "Integer too big for signed representation: '%" PRIu64 "'", + val->ival.u64); + } + default: + // FIXME big integers + val->type = PSI_T_INT; + type->type = PSI_T_INT; + zend_string_release(type->name); + type->name = zend_string_init_interned(ZEND_STRL("int"), 1); + break; + } + psi_num_exp_free(&val->data.num); + return true; + } + break; + + case PSI_T_INT: + if (val->type == PSI_T_NUMBER) { + val->type = PSI_T_INT; + val->ival.zend.lval = psi_num_exp_get_long(val->data.num, NULL, scope->cpp); +#if PSI_IMPL_DEF_VAL_DEBUG + PSI_DEBUG_PRINT(data, "PSI: NUMBER (long) %" PRIi64 " from ", val->ival.zend.lval); + PSI_DEBUG_DUMP(data, psi_num_exp_dump, val->data.num); + PSI_DEBUG_PRINT(data, "\n"); +#endif + psi_num_exp_free(&val->data.num); + } + if (val->type == PSI_T_INT) { + return true; + } + break; + + case PSI_T_FLOAT: + case PSI_T_DOUBLE: + if (val->type == PSI_T_NUMBER) { + val->type = PSI_T_DOUBLE; + val->ival.dval = psi_num_exp_get_double(val->data.num, NULL, scope->cpp); +#if PSI_IMPL_DEF_VAL_DEBUG + PSI_DEBUG_PRINT(data, "PSI: NUMBER (double) %" PRIdval " from ", val->ival.dval); + PSI_DEBUG_DUMP(data, psi_num_exp_dump, val->data.num); + PSI_DEBUG_PRINT(data, "\n"); +#endif + psi_num_exp_free(&val->data.num); + } + if (val->type == PSI_T_DOUBLE) { + return true; + } + break; + + case PSI_T_STRING: + if (val->type == PSI_T_STRING) { + return true; data->error(data, val->token, PSI_WARNING, + "Invalid default value type '%s', " + "expected one of bool, int, float, string.", + type ? type->name->val : "mixed"); + + } + break; + + case PSI_T_MIXED: + + } + // no break + default: + } +*/ +} + +void psi_impl_def_val_dump(struct psi_dump *dump, struct psi_impl_def_val *val) { + switch (val->type) { + case PSI_T_NULL: + PSI_DUMP(dump, "NULL"); + break; + case PSI_T_TRUE: + PSI_DUMP(dump, "true"); + break; + case PSI_T_FALSE: + PSI_DUMP(dump, "false"); + break; + case PSI_T_BOOL: + PSI_DUMP(dump, "%s", val->ival.zend.bval ? "true" : "false"); + break; + case PSI_T_INT: + PSI_DUMP(dump, ZEND_LONG_FMT, val->ival.zend.lval); + break; + case PSI_T_FLOAT: + case PSI_T_DOUBLE: + if (isinf(val->ival.dval)) { + PSI_DUMP(dump, "\\INF"); + } else if (isnan(val->ival.dval)) { + PSI_DUMP(dump, "\\NAN"); + } else { + PSI_DUMP(dump, "%" PRIdval, val->ival.dval); + } + break; + case PSI_T_STRING: + PSI_DUMP(dump, "\"%s\"", val->ival.zend.str->val); + break; + case PSI_T_NUMBER: + psi_num_exp_dump(dump, val->data.num); + break; + default: + assert(0); + } + PSI_DUMP(dump, "\t/* t=%d */ ", val->type); }