impl_def_val: handle INF/NAN
[m6w6/ext-psi] / src / types / impl_def_val.c
index cadefe23db5b848404043ee83429312b31207bbe..fe11b269f6e3a02d6883f07fb7db3e5c5ce9f590 100644 (file)
 #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)
+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));
 
-       def->type = t;
-       def->text = text ? strdup(text) : NULL;
+       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_init(data, strlen(data), 1);
+               }
+               break;
+
+       case PSI_T_NUMBER:
+               def->data.num = data;
+               break;
+
+       default:
+               assert(0);
+       }
 
        return def;
 }
@@ -48,54 +69,114 @@ void psi_impl_def_val_free(struct psi_impl_def_val **def_ptr)
                        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)
+               struct psi_impl_def_val *val, struct psi_impl_type *type,
+               struct psi_validate_scope *scope)
 {
-       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;
-                       break;
-               case PSI_T_INT:
-                       def->ival.zend.lval = zend_atol(def->text, strlen(def->text));
-                       break;
-               case PSI_T_FLOAT:
-               case PSI_T_DOUBLE:
-                       def->ival.dval = zend_strtod(def->text, NULL);
-                       break;
-               case PSI_T_STRING:
-                       /* used for consts */
-                       def->ival.zend.str = zend_string_init(def->text, strlen(def->text), 1);
-                       break;
-               case PSI_T_QUOTED_STRING:
-                       def->ival.zend.str = zend_string_init(&def->text[1], strlen(def->text) - 2, 1);
-                       break;
-               default:
-                       data->error(data, def->token, PSI_WARNING,
-                                       "Invalid default value type '%s', expected one of bool, int, double, string.",
-                                       type_name);
+       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;
                }
        }
-       return true;
+
+       switch (type->type) {
+       case PSI_T_BOOL:
+               val->ival.zend.bval = val->type == PSI_T_TRUE ? 1 : 0;
+               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;
+                               /* no break */
+                       case PSI_T_DOUBLE:
+                               val->type = PSI_T_FLOAT;
+                               type->type = PSI_T_FLOAT;
+                               strcpy(type->name, "float");
+                               break;
+                       default:
+                               val->type = PSI_T_INT;
+                               type->type = PSI_T_INT;
+                               strcpy(type->name, "int");
+                               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->defs);
+                       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->defs);
+                       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;
+
+       default:
+               data->error(data, val->token, PSI_WARNING,
+                               "Invalid default value type '%s', "
+                               "expected one of bool, int, float, string.",
+                               type->name);
+       }
+
+       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;
@@ -104,20 +185,18 @@ void psi_impl_def_val_dump(int fd, struct psi_impl_def_val *val) {
                break;
        case PSI_T_FLOAT:
        case PSI_T_DOUBLE:
-               dprintf(fd, "%f", val->ival.dval);
+               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:
                dprintf(fd, "\"%s\"", val->ival.zend.str->val);
                break;
-       case PSI_T_QUOTED_STRING:
-               dprintf(fd, "\"%s\"", val->text);
-               break;
        default:
-               if (val->text) {
-                       dprintf(fd, "%s", val->text);
-               } else {
-                       assert(0);
-               }
-               break;
+               assert(0);
        }
 }