X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-psi;a=blobdiff_plain;f=src%2Ftypes%2Fimpl_def_val.c;h=e8d7b4697a0d1b38bde3f3402fccda9f1ea58d4e;hp=e24b4c28fd38ea19c3ddf75078088374bb288c40;hb=d9f1274417f65d980e143700726d1527462123d3;hpb=91f2f40eee4e1d1dd62ad5de06517f9b27b4aaee diff --git a/src/types/impl_def_val.c b/src/types/impl_def_val.c index e24b4c2..e8d7b46 100644 --- a/src/types/impl_def_val.c +++ b/src/types/impl_def_val.c @@ -26,14 +26,43 @@ #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, const char *text) +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: + /* 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; - def->type = t; - def->text = text ? strdup(text) : NULL; + default: + assert(0); + } return def; } @@ -44,77 +73,280 @@ void psi_impl_def_val_free(struct psi_impl_def_val **def_ptr) struct psi_impl_def_val *def = *def_ptr; *def_ptr = NULL; - if (def->token) { - free(def->token); - } + psi_token_free(&def->token); switch (def->type) { + case PSI_T_NUMBER: + psi_num_exp_free(&def->data.num); + break; + case PSI_T_STRING: - case PSI_T_QUOTED_STRING: if (def->ival.zend.str) { zend_string_release(def->ival.zend.str); } break; - } - if (def->text) { - free(def->text); + default: + break; } free(def); } } -bool psi_impl_def_val_validate(struct psi_data *data, - struct psi_impl_def_val *def, token_t type_t, const char *type_name) +void psi_impl_def_val_get_zval(struct psi_impl_def_val *val, token_t typ, zval *zv) { - if (def->type != PSI_T_NULL && def->text) { - switch (type_t) { - case PSI_T_BOOL: - def->ival.zend.bval = def->type == PSI_T_TRUE ? 1 : 0; + 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_INT: - def->ival.zend.lval = zend_atol(def->text, strlen(def->text)); + case PSI_T_TRUE: + ZVAL_TRUE(zv); break; - case PSI_T_FLOAT: - case PSI_T_DOUBLE: - def->ival.dval = zend_strtod(def->text, NULL); + case PSI_T_FALSE: + ZVAL_FALSE(zv); break; case PSI_T_STRING: - /* used for consts */ - def->ival.zend.str = zend_string_init(def->text, strlen(def->text), 1); + goto is_string; break; - case PSI_T_QUOTED_STRING: - def->ival.zend.str = zend_string_init(&def->text[1], strlen(def->text) - 2, 1); + 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: - data->error(data, def->token, PSI_WARNING, - "Invalid default value type '%s', expected one of bool, int, double, string.", - type_name); + assert(0); + break; + } + break; + default: + assert(0); + break; + } + +} + +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_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}; + 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/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); } - return true; + + 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: + 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: - 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: - dprintf(fd, "%f", val->ival.dval); + 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: - dprintf(fd, "\"%s\"", val->ival.zend.str->val); + PSI_DUMP(dump, "\"%s\"", val->ival.zend.str->val); break; - case PSI_T_QUOTED_STRING: - dprintf(fd, "\"%s\"", val->text); + case PSI_T_NUMBER: + psi_num_exp_dump(dump, val->data.num); break; default: - if (val->text) { - dprintf(fd, "%s", val->text); - } else { - assert(0); - } - break; + assert(0); } +#if 0 + PSI_DUMP(dump, "\t/* impl_def_val.type=%d */ ", val->type); +#endif }