X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-psi;a=blobdiff_plain;f=src%2Ftypes%2Fimpl_def_val.c;h=e8d7b4697a0d1b38bde3f3402fccda9f1ea58d4e;hp=311b39d27cde78b07b0f78a0f480ee59d9ef9880;hb=d9f1274417f65d980e143700726d1527462123d3;hpb=2fa436074ca9a5e87f39b696de832fa2188fcfc6 diff --git a/src/types/impl_def_val.c b/src/types/impl_def_val.c index 311b39d..e8d7b46 100644 --- a/src/types/impl_def_val.c +++ b/src/types/impl_def_val.c @@ -26,16 +26,24 @@ #include "php_psi_stdinc.h" #include "data.h" +#include "zend_smart_str.h" + #include #include +#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 = calloc(1, sizeof(*def)); + 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: @@ -83,120 +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) { + /* 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; + ZVAL_BOOL(zv, tmp.zend.bval); 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->defs); - - switch (typ) { - case PSI_T_FLOAT: - val->ival.dval = val->ival.fval; + 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: - val->type = PSI_T_FLOAT; - type->type = PSI_T_FLOAT; - zend_string_release(type->name); - type->name = zend_string_init(ZEND_STRL("float"), 1); + goto is_double; break; - default: - val->type = PSI_T_INT; - type->type = PSI_T_INT; - zend_string_release(type->name); - type->name = zend_string_init(ZEND_STRL("int"), 1); +#if HAVE_LONG_DOUBLE + case PSI_T_LONG_DOUBLE: + ZVAL_DOUBLE(zv, tmp.ldval); break; +#endif + default: + assert(0); } - psi_num_exp_free(&val->data.num); - return true; + break; + default: + assert(0); + break; } break; + default: + assert(0); + 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->defs); - psi_num_exp_free(&val->data.num); - } - if (val->type == PSI_T_INT) { +} + +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: + 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_NUMBER) { - val->type = PSI_T_DOUBLE; - val->ival.dval = psi_num_exp_get_double(val->data.num, NULL, scope->defs); - psi_num_exp_free(&val->data.num); - } - if (val->type == 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; } - 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.", + "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, "%ld", 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(dump, val->data.num); break; default: assert(0); } +#if 0 + PSI_DUMP(dump, "\t/* impl_def_val.type=%d */ ", val->type); +#endif }