#include "data.h"
#include <assert.h>
+#include <math.h>
-struct psi_impl_def_val *psi_impl_def_val_init(token_t t, const char *text)
+#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:
+ case PSI_T_FALSE:
+ 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 = strdup(text);
+ default:
+ assert(0);
+ }
return def;
}
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:
- assert(0);
- /* no break */
- case PSI_T_QUOTED_STRING:
if (def->ival.zend.str) {
zend_string_release(def->ival.zend.str);
}
break;
+ default:
+ break;
}
- free(def->text);
free(def);
}
}
bool psi_impl_def_val_validate(struct psi_data *data,
- struct psi_impl_def_val *def, struct psi_impl_type *type)
+ struct psi_impl_def_val *val, struct psi_impl_type *type,
+ struct psi_validate_scope *scope)
{
- if (def->type != PSI_T_NULL) {
- switch (type->type) {
- case PSI_T_BOOL:
- def->ival.zend.bval = def->type == PSI_T_TRUE ? 1 : 0;
- break;
- case PSI_T_INT:
- def->ival.zend.lval = zend_atol(def->text, strlen(def->text));
- break;
+ 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;
+ }
+ }
+
+ 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;
+ }
+ break;
+
+ case PSI_T_MIXED:
+ switch (val->type) {
+ case PSI_T_TRUE:
+ case PSI_T_FALSE:
+ case PSI_T_NULL:
+ case PSI_T_STRING:
case PSI_T_FLOAT:
case PSI_T_DOUBLE:
- def->ival.dval = zend_strtod(def->text, NULL);
- break;
- case PSI_T_STRING:
- assert(0);
- /* no break */
- case PSI_T_QUOTED_STRING:
- def->ival.zend.str = zend_string_init(&def->text[1], strlen(def->text) - 2, 1);
- break;
+ case PSI_T_INT:
+ return true;
default:
- data->error(data, def->token, PSI_WARNING,
- "Invalid default value type '%s', expected one of bool, int, double, string.",
- type->name);
- return false;
+ 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_FLOAT:
+#if HAVE_LONG_DOUBLE
+ case PSI_T_LONG_DOUBLE:
+#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];
+
+ /* 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;
+ }
+ /* no break */
+ default:
+ psi_calc_cast(typ, &val->ival, PSI_T_INT64, &val->ival);
+ /* no break */
+ case PSI_T_INT64:
+ val->type = PSI_T_INT;
+ return true;
+ }
+ }
+ /* no 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");
}
- return true;
+
+ return false;
}
void psi_impl_def_val_dump(int fd, struct psi_impl_def_val *val) {
switch (val->type) {
+ case PSI_T_NULL:
+ dprintf(fd, "NULL");
+ break;
+ case PSI_T_TRUE:
+ dprintf(fd, "true");
+ break;
+ case PSI_T_FALSE:
+ dprintf(fd, "false");
+ break;
+ case PSI_T_BOOL:
+ dprintf(fd, "%s", val->ival.zend.bval ? "true" : "false");
+ break;
+ case PSI_T_INT:
+ dprintf(fd, ZEND_LONG_FMT, val->ival.zend.lval);
+ break;
+ case PSI_T_FLOAT:
+ case PSI_T_DOUBLE:
+ if (isinf(val->ival.dval)) {
+ dprintf(fd, "\\INF");
+ } else if (isnan(val->ival.dval)) {
+ dprintf(fd, "\\NAN");
+ } else {
+ dprintf(fd, "%" PRIdval, val->ival.dval);
+ }
+ break;
case PSI_T_STRING:
- assert(0);
- /* no break */
- case PSI_T_QUOTED_STRING:
- dprintf(fd, "\"%s\"", val->text);
+ dprintf(fd, "\"%s\"", val->ival.zend.str->val);
+ break;
+ case PSI_T_NUMBER:
+ psi_num_exp_dump(fd, val->data.num);
break;
default:
- dprintf(fd, "%s", val->text);
+ assert(0);
}
}