X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-psi;a=blobdiff_plain;f=src%2Ftypes%2Fimpl_def_val.c;h=e8d7b4697a0d1b38bde3f3402fccda9f1ea58d4e;hp=eec90e6783ea123dac39de26f5eb058a25b92909;hb=d9f1274417f65d980e143700726d1527462123d3;hpb=a7ac1c0a3c855321f21682c127a4b707de33a303 diff --git a/src/types/impl_def_val.c b/src/types/impl_def_val.c index eec90e6..e8d7b46 100644 --- a/src/types/impl_def_val.c +++ b/src/types/impl_def_val.c @@ -26,6 +26,8 @@ #include "php_psi_stdinc.h" #include "data.h" +#include "zend_smart_str.h" + #include #include @@ -37,7 +39,11 @@ struct psi_impl_def_val *psi_impl_def_val_init(token_t t, void *data) 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: @@ -85,192 +91,262 @@ void psi_impl_def_val_free(struct psi_impl_def_val **def_ptr) } } -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) +void psi_impl_def_val_get_zval(struct psi_impl_def_val *val, token_t typ, zval *zv) { - if (val->type == PSI_T_NULL) { - return true; - } else if (val->type == PSI_T_NUMBER) { - if (!psi_num_exp_validate(data, val->data.num, scope)) { - return false; - } - } + impl_val tmp = val->ival; - switch (type ? type->type : PSI_T_MIXED) { + /* c->val has already been forced to the type of the containing constant or impl_arg */ + switch (typ) { 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; - } + ZVAL_BOOL(zv, tmp.zend.bval); 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; - } + ZVAL_LONG(zv, tmp.zend.lval); 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; - } + is_double: ; + ZVAL_DOUBLE(zv, tmp.dval); break; - case PSI_T_STRING: - if (val->type == PSI_T_STRING) { - return true; + 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: - case PSI_T_NULL: + ZVAL_FALSE(zv); + break; case PSI_T_STRING: - case PSI_T_FLOAT: - case PSI_T_DOUBLE: - case PSI_T_INT: - return true; - default: + goto is_string; break; - } - 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_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 - promote_double: ; - psi_calc_cast(typ, &val->ival, PSI_T_DOUBLE, &val->ival); - /* no break */ - case PSI_T_DOUBLE: - val->type = PSI_T_DOUBLE; - return true; - case PSI_T_UINT64: - if (val->ival.u64 > (uint64_t) ZEND_LONG_MAX) { - if (val->ival.u64 > (1LU<<53)) { - char buf[0x20]; + default: + assert(0); + } + break; + default: + assert(0); + break; + } + break; + default: + assert(0); + break; + } - /* convert to string */ - char *res = zend_print_ulong_to_buf(buf + sizeof(buf) - 1, val->ival.u64); - val->type = PSI_T_STRING; - val->ival.zend.str = zend_string_init(res, buf + sizeof(buf) - 1 - res, 1); +} - return true; - } - goto promote_double; - } +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) { + zend_string *tmp = val->ival.zend.str; + + val->ival.zend.bval = (*tmp->val && *tmp->val != '0'); + zend_string_release(tmp); + } + val->ityp = PSI_T_UINT8; + val->type = PSI_T_BOOL; + 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: - psi_calc_cast(typ, &val->ival, PSI_T_INT64, &val->ival); + 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 = PSI_T_INT; + 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 PSI_T_INT64: - val->type = PSI_T_INT; - return true; + case IS_DOUBLE: + break; + default: + val->ival.dval = 0; } + zend_string_release(str); + val->type = val->ityp = PSI_T_DOUBLE; + return true; } - /* no break */ + 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}; + struct psi_dump dump = {{.hn = &str}, + .fun = (psi_dump_cb) smart_str_append_printf}; + + switch (val->ityp) { + CASE_IMPLVAL_NUM_DUMP(&dump, 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, string.", - type ? type->name->val : "mixed"); + "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; } -void psi_impl_def_val_dump(int fd, struct psi_impl_def_val *val) { +void psi_impl_def_val_dump(struct psi_dump *dump, struct psi_impl_def_val *val) { switch (val->type) { case PSI_T_NULL: - dprintf(fd, "NULL"); + PSI_DUMP(dump, "NULL"); break; case PSI_T_TRUE: - dprintf(fd, "true"); + PSI_DUMP(dump, "true"); break; case PSI_T_FALSE: - dprintf(fd, "false"); + PSI_DUMP(dump, "false"); break; case PSI_T_BOOL: - dprintf(fd, "%s", val->ival.zend.bval ? "true" : "false"); + PSI_DUMP(dump, "%s", val->ival.zend.bval ? "true" : "false"); break; case PSI_T_INT: - dprintf(fd, ZEND_LONG_FMT, val->ival.zend.lval); + PSI_DUMP(dump, ZEND_LONG_FMT, val->ival.zend.lval); break; case PSI_T_FLOAT: case PSI_T_DOUBLE: if (isinf(val->ival.dval)) { - dprintf(fd, "\\INF"); + PSI_DUMP(dump, "\\INF"); } else if (isnan(val->ival.dval)) { - dprintf(fd, "\\NAN"); + PSI_DUMP(dump, "\\NAN"); } else { - dprintf(fd, "%" PRIdval, val->ival.dval); + PSI_DUMP(dump, "%" PRIdval, val->ival.dval); } break; case PSI_T_STRING: - dprintf(fd, "\"%s\"", val->ival.zend.str->val); + PSI_DUMP(dump, "\"%s\"", val->ival.zend.str->val); break; case PSI_T_NUMBER: - psi_num_exp_dump(fd, val->data.num); + psi_num_exp_dump(dump, val->data.num); break; default: assert(0); } +#if 0 + PSI_DUMP(dump, "\t/* impl_def_val.type=%d */ ", val->type); +#endif }