flush
authorMichael Wallner <mike@php.net>
Fri, 11 Dec 2015 17:14:19 +0000 (18:14 +0100)
committerMichael Wallner <mike@php.net>
Fri, 11 Dec 2015 17:14:19 +0000 (18:14 +0100)
php_psi.h
psi.d/stat.psi
psi.d/time.psi
psi.d/uname.psi
src/context.c
src/module.c
src/parser.h
src/parser_proc.y

index 54d78b0a5b3445feb128eb772a5033b1f09bad86..dd422b7a848a47b328ad336c82e2f112a7636c87 100644 (file)
--- a/php_psi.h
+++ b/php_psi.h
@@ -60,6 +60,90 @@ void psi_to_object(zval *return_value, set_value *set, impl_val *ret_val);
 
 void psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl);
 
+static inline int psi_calc_num_exp_value(num_exp *exp, impl_val *val) {
+       switch (exp->t) {
+       case PSI_T_NUMBER:
+               switch (is_numeric_string(exp->u.numb, strlen(exp->u.numb), (zend_long *) val, (double *) val, 0)) {
+               case IS_LONG:
+                       return PSI_T_INT64;
+               case IS_DOUBLE:
+                       return PSI_T_DOUBLE;
+               }
+               break;
+
+       case PSI_T_NSNAME:
+               switch (exp->u.cnst->type->type) {
+               case PSI_T_INT:
+                       val->i64 = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.lval;
+                       return PSI_T_INT64;
+               case PSI_T_FLOAT:
+                       val->dval = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.dval;
+                       return PSI_T_DOUBLE;
+               default:
+                       return 0;
+               }
+               break;
+
+       case PSI_T_NAME:
+               switch (real_decl_type(exp->u.dvar->arg->type)->type) {
+               case PSI_T_INT8:
+               case PSI_T_UINT8:
+               case PSI_T_INT16:
+               case PSI_T_UINT16:
+               case PSI_T_INT32:
+               case PSI_T_UINT32:
+               case PSI_T_INT64:
+               case PSI_T_UINT64:
+                       memcpy(val, deref_impl_val(exp->u.dvar->arg->let->ptr, exp->u.dvar), sizeof(*val));
+                       return real_decl_type(exp->u.dvar->arg->type)->type;
+
+               case PSI_T_FLOAT:
+               case PSI_T_DOUBLE:
+                       memcpy(val, deref_impl_val(exp->u.dvar->arg->let->ptr, exp->u.dvar), sizeof(*val));
+                       return real_decl_type(exp->u.dvar->arg->type)->type;
+
+               EMPTY_SWITCH_DEFAULT_CASE();
+               }
+               break;
+
+       EMPTY_SWITCH_DEFAULT_CASE();
+       }
+       return  0;
+}
+
+static inline int psi_calc_num_exp(num_exp *exp, impl_val *val) {
+       impl_val num = {0};
+       int num_type = psi_calc_num_exp_value(exp, &num);
+
+       if (exp->operand) {
+               impl_val tmp = {0};
+               int tmp_type = psi_calc_num_exp(exp->operand, &tmp);
+
+               return exp->calculator(num_type, &num, tmp_type, &tmp, val);
+       }
+
+       memcpy(val, &num, sizeof(*val));
+       return num_type;
+}
+
+static inline zend_long psi_long_num_exp(num_exp *exp) {
+       impl_val val = {0};
+
+       switch (psi_calc_num_exp(exp, &val)) {
+       case PSI_T_UINT8:       val.u16 = val.u8;
+       case PSI_T_UINT16:      val.u32 = val.u16;
+       case PSI_T_UINT32:      val.u64 = val.u32;
+       case PSI_T_UINT64:      return val.u64;
+       case PSI_T_INT8:        val.i16 = val.i8;
+       case PSI_T_INT16:       val.i32 = val.i16;
+       case PSI_T_INT32:       val.i64 = val.i32;
+       case PSI_T_INT64:       return val.i64;
+       case PSI_T_FLOAT:       val.dval = val.fval;
+       case PSI_T_DOUBLE:      return val.dval;
+       EMPTY_SWITCH_DEFAULT_CASE();
+       }
+}
+
 ZEND_BEGIN_MODULE_GLOBALS(psi)
        char *engine;
        char *directory;
index 17dc18851597e53c0cd5c39e9e3fd2d78f55795f..dc89119624d37cc474ee60b3549d440ee74f1472 100644 (file)
@@ -1,7 +1,7 @@
 // extern int stat(char *path, struct stat *buf);
 function psi\stat(string $path, array &$buf = NULL) : int {
        let path = strval($path);
-       let buf = calloc(1, struct stat);
+       let buf = calloc(1, psi\SIZEOF_STRUCT_STAT);
        return to_int(stat);
        set $buf = to_array(*buf,
                to_int(st_dev),
index a8082c6456c679e76d9c02a4c3fa39399b6821e0..ae16b0a71d0d7544daed3de3818b25dadbfe3431 100644 (file)
@@ -5,8 +5,8 @@ function psi\time() : int {
 
 // extern int gettimeofday(struct timeval *tp, struct timezone *tz);
 function psi\gettimeofday(array &$tv = NULL, array &$tz = NULL) : int {
-       let tp = calloc(1, struct timeval);
-       let tz = calloc(1, struct timezone);
+       let tp = calloc(1, psi\SIZEOF_STRUCT_TIMEVAL);
+       let tz = calloc(1, psi\SIZEOF_STRUCT_TIMEZONE);
        return to_int(gettimeofday);
        set $tv = to_array(*tp,
                to_int(tv_sec),
@@ -25,7 +25,7 @@ function psi\asctime(array $tm = NULL) : string {
 // extern char *asctime_r(struct tm *tm, char *buf);
 function psi\asctime_r(array $tm = NULL) : string {
        let tm = arrval($tm);
-       let buf = calloc(32, char);
+       let buf = calloc(32, psi\SIZEOF_CHAR);
        return to_string(asctime_r);
 }
 
@@ -48,7 +48,7 @@ function psi\gmtime(int $ts) : array {
 // extern struct tm *gmtime_r(time_t *t, struct tm *buf);
 function psi\gmtime_r(int $ts) : array {
        let t = &intval($ts);
-       let buf = calloc(1, struct tm);
+       let buf = calloc(1, psi\SIZEOF_STRUCT_TM);
        return to_array(*gmtime_r,
                to_int(tm_sec),
                to_int(tm_min),
@@ -65,7 +65,7 @@ function psi\gmtime_r(int $ts) : array {
 // extern int nanosleep(struct timespec *rqts, struct timespec *rmts);
 function psi\nanosleep(array $rq = NULL, array &$rm = NULL) : int {
        let rqts = arrval($rq);
-       let rmts = calloc(1, struct timespec);
+       let rmts = calloc(1, psi\SIZEOF_STRUCT_TIMESPEC);
        return to_int(nanosleep);
        set $rm = to_array(*rmts,
                to_int(tv_sec),
@@ -75,7 +75,7 @@ function psi\nanosleep(array $rq = NULL, array &$rm = NULL) : int {
 
 // extern clock_t times(struct tms *buf);
 function psi\times(array &$tms = NULL) : int {
-       let buf = calloc(1, struct tms);
+       let buf = calloc(1, psi\SIZEOF_STRUCT_TMS);
        return to_int(times);
        set $tms = to_array(*buf,
                to_int(tms_utime),
index c79cc8e8cb0aab1b4bf705f20f7f143d12624042..6c6a6b0f914ec142dd6acd7f7e7bc66de0fbd2d3 100644 (file)
@@ -1,5 +1,5 @@
 function psi\uname(array &$u = NULL) : int {
-       let name = calloc(1, struct utsname);
+       let name = calloc(1, psi\SIZEOF_STRUCT_UTSNAME);
        return to_int(uname);
        set $u = to_array(*name,
                to_string(sysname),
index 134acdd40dd69d8fb454a23535e6db0892f7b7e5..1e8204ac9e7d4d500229d060a4580dbb24531858 100644 (file)
@@ -548,6 +548,42 @@ static inline int validate_impl_ret_stmt(PSI_Data *data, impl *impl) {
 
        return 1;
 }
+static inline constant *locate_num_exp_constant(num_exp *exp, constants *consts) {
+       size_t i;
+
+       for (i = 0; i < consts->count; ++i) {
+               constant *cnst = consts->list[i];
+
+               if (!strcmp(cnst->name, exp->u.numb)) {
+                       free(exp->u.numb);
+                       return exp->u.cnst = cnst;
+               }
+       }
+
+       return NULL;
+}
+static inline int validate_num_exp(PSI_Data *data, impl *impl, num_exp *exp) {
+       switch (exp->t) {
+       case PSI_T_NAME:
+               if (!locate_decl_var_arg(exp->u.dvar, impl->decl->args)) {
+                       data->error(PSI_WARNING, "Unknown variable '%s' in numeric expression"
+                                       " of implementation '%s'", exp->u.dvar->name, impl->func->name);
+                       return 0;
+               }
+               return 1;
+       case PSI_T_NSNAME:
+               if (!locate_num_exp_constant(exp, data->consts)) {
+                       data->error(PSI_WARNING, "Unknown constant '%s' in numeric expression"
+                                       " of implementation '%s'", exp->u.numb, impl->func->name);
+                       return 0;
+               }
+               return 1;
+       case PSI_T_NUMBER:
+               return 1;
+       default:
+               return 0;
+       }
+}
 static inline int validate_impl_let_stmts(PSI_Data *data, impl *impl) {
        size_t i, j;
        /* we can have multiple let stmts */
@@ -579,9 +615,10 @@ static inline int validate_impl_let_stmts(PSI_Data *data, impl *impl) {
                int check = 0;
 
                if (let->val && let->val->func && let->val->func->alloc) {
-                       if (!validate_decl_type(data, let->val->func->alloc->type)) {
-                               data->error(PSI_WARNING, "Cannot use '%s' as type for calloc in `let` statement",
-                                       let->val->func->alloc->type->name);
+                       if (!validate_num_exp(data, impl, let->val->func->alloc->nmemb)) {
+                               return 0;
+                       }
+                       if (!validate_num_exp(data, impl, let->val->func->alloc->size)) {
                                return 0;
                        }
                }
@@ -1095,6 +1132,20 @@ static inline void dump_impl_set_value(int fd, set_value *set, unsigned level) {
                dprintf(fd, ");\n");
        }
 }
+static inline void dump_num_exp(int fd, num_exp *exp) {
+       switch (exp->t) {
+       case PSI_T_NUMBER:
+               dprintf(fd, "%s", exp->u.numb);
+               break;
+       case PSI_T_NAME:
+               dump_decl_var(fd, exp->u.dvar);
+               break;
+       case PSI_T_NSNAME:
+               dprintf(fd, "%s", exp->u.cnst->name);
+               break;
+       EMPTY_SWITCH_DEFAULT_CASE();
+       }
+}
 void PSI_ContextDump(PSI_Context *C, int fd)
 {
        size_t i, j, k, l;
@@ -1198,8 +1249,9 @@ void PSI_ContextDump(PSI_Context *C, int fd)
                                                if (let->val->func) {
                                                        dprintf(fd, "%s(", let->val->func->name);
                                                        if (let->val->func->alloc) {
-                                                               dprintf(fd, "%zu, ", let->val->func->alloc->n);
-                                                               dump_decl_type(fd, let->val->func->alloc->type);
+                                                               dump_num_exp(fd, let->val->func->alloc->nmemb);
+                                                               dprintf(fd, ", ");
+                                                               dump_num_exp(fd, let->val->func->alloc->size);
                                                        } else {
                                                                dprintf(fd, "$%s", let->val->var->name);
                                                        }
index da623b2c16ee78b772c1dfd85daceb22651ddf95..873d56bc10192521c211dd55cde3de1e0e6f42f2 100644 (file)
@@ -7,6 +7,8 @@
 #include "php_ini.h"
 #include "ext/standard/info.h"
 #include "zend_exceptions.h"
+#include "zend_constants.h"
+#include "zend_operators.h"
 
 #include "php_psi.h"
 #include "parser.h"
@@ -550,17 +552,10 @@ static inline ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, i
 
 static inline void *psi_do_calloc(let_calloc *alloc)
 {
-       decl_type *type = real_decl_type(alloc->type);
-       size_t size;
-
-       if (type->type == PSI_T_STRUCT) {
-               /* psi_do_clean expects at least one NULL pointer after the struct */
-               size = type->strct->size + sizeof(void *);
-       } else {
-               size = psi_t_size(type->type);
-       }
-
-       return ecalloc(alloc->n, size);
+       zend_long n = psi_long_num_exp(alloc->nmemb), s = psi_long_num_exp(alloc->size);
+       void *mem = safe_emalloc(n, s, sizeof(void *));
+       memset(mem, 0, n * s + sizeof(void *));
+       return mem;
 }
 
 static inline void *psi_do_let(decl_arg *darg)
@@ -734,6 +729,134 @@ static inline void psi_do_clean(impl *impl)
        }
 }
 
+
+#define PSI_CALC_OP(var) res->var = PSI_CALC(v1->var, v2->var)
+#define PSI_CALC_OP2(vres, var1, var2) res->vres = PSI_CALC(v1->var1, v2->var2)
+
+int psi_calc_plus(unsigned char t1, impl_val *v1, unsigned char t2, impl_val *v2, impl_val *res)
+{
+#undef PSI_CALC
+#define PSI_CALC(var1, var2) (var1) + (var2)
+       if (t1 == t2) {
+               switch (t1) {
+               case PSI_T_FLOAT:       PSI_CALC_OP(fval);      break;
+               case PSI_T_DOUBLE:      PSI_CALC_OP(dval);      break;
+               case PSI_T_INT8:        PSI_CALC_OP(i8);        break;
+               case PSI_T_UINT8:       PSI_CALC_OP(u8);        break;
+               case PSI_T_INT16:       PSI_CALC_OP(i16);       break;
+               case PSI_T_UINT16:      PSI_CALC_OP(u16);       break;
+               case PSI_T_INT32:       PSI_CALC_OP(i32);       break;
+               case PSI_T_UINT32:      PSI_CALC_OP(u32);       break;
+               case PSI_T_INT64:       PSI_CALC_OP(i64);       break;
+               case PSI_T_UINT64:      PSI_CALC_OP(u64);       break;
+               EMPTY_SWITCH_DEFAULT_CASE();
+               }
+               return t1;
+       } else if (t1 == PSI_T_DOUBLE) {
+               switch (t2) {
+               case PSI_T_FLOAT:       PSI_CALC_OP2(dval, dval, fval); break;
+               case PSI_T_INT8:        PSI_CALC_OP2(dval, dval, i8);   break;
+               case PSI_T_UINT8:       PSI_CALC_OP2(dval, dval, u8);   break;
+               case PSI_T_INT16:       PSI_CALC_OP2(dval, dval, i16);  break;
+               case PSI_T_UINT16:      PSI_CALC_OP2(dval, dval, u16);  break;
+               case PSI_T_INT32:       PSI_CALC_OP2(dval, dval, i32);  break;
+               case PSI_T_UINT32:      PSI_CALC_OP2(dval, dval, u32);  break;
+               case PSI_T_INT64:       PSI_CALC_OP2(dval, dval, i64);  break;
+               case PSI_T_UINT64:      PSI_CALC_OP2(dval, dval, u64);  break;
+               EMPTY_SWITCH_DEFAULT_CASE();
+               }
+               return t1;
+       } else if (t2 == PSI_T_DOUBLE) {
+               switch (t1) {
+               case PSI_T_FLOAT:       PSI_CALC_OP2(dval, fval, dval); break;
+               case PSI_T_INT8:        PSI_CALC_OP2(dval, i8, dval);   break;
+               case PSI_T_UINT8:       PSI_CALC_OP2(dval, u8, dval);   break;
+               case PSI_T_INT16:       PSI_CALC_OP2(dval, i16, dval);  break;
+               case PSI_T_UINT16:      PSI_CALC_OP2(dval, u16, dval);  break;
+               case PSI_T_INT32:       PSI_CALC_OP2(dval, i32, dval);  break;
+               case PSI_T_UINT32:      PSI_CALC_OP2(dval, u32, dval);  break;
+               case PSI_T_INT64:       PSI_CALC_OP2(dval, i64, dval);  break;
+               case PSI_T_UINT64:      PSI_CALC_OP2(dval, u64, dval);  break;
+               EMPTY_SWITCH_DEFAULT_CASE();
+               }
+               return t2;
+       } else if (t1 == PSI_T_FLOAT) {
+               switch (t2) {
+               case PSI_T_DOUBLE:      PSI_CALC_OP2(dval, fval, dval); return t2;
+               case PSI_T_INT8:        PSI_CALC_OP2(fval, fval, i8);   break;
+               case PSI_T_UINT8:       PSI_CALC_OP2(fval, fval, u8);   break;
+               case PSI_T_INT16:       PSI_CALC_OP2(fval, fval, i16);  break;
+               case PSI_T_UINT16:      PSI_CALC_OP2(fval, fval, u16);  break;
+               case PSI_T_INT32:       PSI_CALC_OP2(fval, fval, i32);  break;
+               case PSI_T_UINT32:      PSI_CALC_OP2(fval, fval, u32);  break;
+               case PSI_T_INT64:       PSI_CALC_OP2(fval, fval, i64);  break;
+               case PSI_T_UINT64:      PSI_CALC_OP2(fval, fval, u64);  break;
+               EMPTY_SWITCH_DEFAULT_CASE();
+               }
+               return t1;
+       } else if (t2 == PSI_T_FLOAT) {
+               switch (t1) {
+               case PSI_T_DOUBLE:      PSI_CALC_OP2(dval, dval, fval); return t1;
+               case PSI_T_INT8:        PSI_CALC_OP2(fval, i8, fval);   break;
+               case PSI_T_UINT8:       PSI_CALC_OP2(fval, u8, fval);   break;
+               case PSI_T_INT16:       PSI_CALC_OP2(fval, i16, fval);  break;
+               case PSI_T_UINT16:      PSI_CALC_OP2(fval, u16, fval);  break;
+               case PSI_T_INT32:       PSI_CALC_OP2(fval, i32, fval);  break;
+               case PSI_T_UINT32:      PSI_CALC_OP2(fval, u32, fval);  break;
+               case PSI_T_INT64:       PSI_CALC_OP2(fval, i64, fval);  break;
+               case PSI_T_UINT64:      PSI_CALC_OP2(fval, u64, fval);  break;
+               EMPTY_SWITCH_DEFAULT_CASE();
+               }
+               return t2;
+       } else {
+               int64_t sval1 = v1->i64, sval2 = v2->i64;
+               uint64_t uval1 = v1->u64, uval2 = v2->u64;
+
+               switch (t1) {
+               case PSI_T_INT8:        sval1 >>= 8;
+               case PSI_T_INT16:       sval1 >>= 8;
+               case PSI_T_INT32:       sval1 >>= 8;
+               case PSI_T_INT64:
+                       switch (t2) {
+                       case PSI_T_INT8:        sval2 >>= 8;
+                       case PSI_T_INT16:       sval2 >>= 8;
+                       case PSI_T_INT32:       sval2 >>= 8;
+                       case PSI_T_INT64:
+                               res->i64 = PSI_CALC(sval1 , sval2);
+                               return PSI_T_INT64;
+                       case PSI_T_UINT8:       uval2 >>= 8;
+                       case PSI_T_UINT16:      uval2 >>= 8;
+                       case PSI_T_UINT32:      uval2 >>= 8;
+                       case PSI_T_UINT64:
+                               res->i64 = PSI_CALC(sval1, uval2);
+                               return PSI_T_INT64;
+                       }
+                       break;
+               case PSI_T_UINT8:       uval1 >>= 8;
+               case PSI_T_UINT16:      uval1 >>= 8;
+               case PSI_T_UINT32:      uval1 >>= 8;
+               case PSI_T_UINT64:
+                       switch (t2) {
+                       case PSI_T_INT8:        sval2 >>= 8;
+                       case PSI_T_INT16:       sval2 >>= 8;
+                       case PSI_T_INT32:       sval2 >>= 8;
+                       case PSI_T_INT64:
+                               res->i64 = PSI_CALC(uval1, sval2);
+                               return PSI_T_INT64;
+                       case PSI_T_UINT8:       uval2 >>= 8;
+                       case PSI_T_UINT16:      uval2 >>= 8;
+                       case PSI_T_UINT32:      uval2 >>= 8;
+                       case PSI_T_UINT64:
+                               res->u64 = PSI_CALC(uval1, uval2);
+                               return PSI_T_UINT64;
+                       }
+                       break;
+               }
+       }
+       ZEND_ASSERT(0);
+       return 0;
+}
+
 void psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl)
 {
        impl_val ret_val;
index faa95e4931d9811788bf76e5decaa87a87fc08d6..28f436f592e98dc11609f6e0ade3d5d3f0dd2ba1 100644 (file)
@@ -576,10 +576,11 @@ typedef struct num_exp {
        token_t t;
        union {
                char *numb;
-               char *cnst;
+               constant *cnst;
                decl_var *dvar;
        } u;
        token_t operator;
+       int (*calculator)(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res);
        struct num_exp *operand;
 } num_exp;
 
@@ -587,10 +588,8 @@ static inline num_exp *init_num_exp(token_t t, void *num) {
        num_exp *exp = calloc(1, sizeof(*exp));
        switch (exp->t = t) {
        case PSI_T_NUMBER:
-               exp->u.numb = strdup(num);
-               break;
        case PSI_T_NSNAME:
-               exp->u.cnst = strdup(num);
+               exp->u.numb = strdup(num);
                break;
        case PSI_T_NAME:
                exp->u.dvar = num;
@@ -606,7 +605,6 @@ static inline void free_num_exp(num_exp *exp) {
                free(exp->u.numb);
                break;
        case PSI_T_NSNAME:
-               free(exp->u.cnst);
                break;
        case PSI_T_NAME:
                free_decl_var(exp->u.dvar);
index 0a7259ed8f3b082332bfc78328820bc5095fb92a..0dc928f86d9d84106d0db790693a73fa6a3abc5c 100644 (file)
@@ -23,7 +23,8 @@
 }
 
 %nonassoc NAME.
-%left PLUS MINUS SLASH ASTERISK.
+%left PLUS MINUS.
+%left SLASH ASTERISK.
 %fallback NAME FREE SET LET RETURN LIB INT UNSIGNED.
 
 file ::= blocks.