flush
authorMichael Wallner <mike@php.net>
Fri, 6 Nov 2015 09:41:47 +0000 (10:41 +0100)
committerMichael Wallner <mike@php.net>
Fri, 6 Nov 2015 09:41:47 +0000 (10:41 +0100)
12 files changed:
php_psi.h
src/libffi.c
src/libjit.c
src/module.c
src/parser.h
src/parser_proc.h
src/parser_proc.y
src/validator.c
tests/time/time.psi [new file with mode: 0644]
tests/time/time001.phpt [new file with mode: 0644]
tests/time/time002.phpt [new file with mode: 0644]
tests/time/time003.phpt [new file with mode: 0644]

index 298240269d506f4e93110933128639d865b8d64e..f9e89b798c1bd5b7357c781b2303cc7d9e1df29f 100644 (file)
--- a/php_psi.h
+++ b/php_psi.h
@@ -37,7 +37,7 @@ void psi_to_double(zval *return_value, token_t t, impl_val *ret_val, decl_var *v
 void psi_to_string(zval *return_value, token_t t, impl_val *ret_val, decl_var *var);
 
 ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, impl *impl);
-impl_val *psi_do_let(decl_arg *darg);
+void *psi_do_let(decl_arg *darg);
 void psi_do_set(zval *return_value, set_func *func, decl_vars *vars);
 void psi_do_return(impl *impl, impl_val *ret_val, zval *return_value);
 void psi_do_free(free_stmt *fre);
index 897affbd56d28dded713f8029159b7ec0fa70884..b0100f61d96b47763700d1cbf0d06609119899b4 100644 (file)
@@ -48,7 +48,7 @@ static void psi_ffi_closure_free(void *c)
 #endif
 }
 
-static void handler(ffi_cif *signature, void *_result, void **_args, void *_data);
+static void psi_ffi_handler(ffi_cif *signature, void *_result, void **_args, void *_data);
 
 static inline ffi_abi psi_ffi_abi(const char *convention) {
        return FFI_DEFAULT_ABI;
@@ -149,12 +149,12 @@ static inline PSI_LibffiData *PSI_LibffiDataAlloc(PSI_LibffiContext *context, im
        rc = ffi_prep_closure_loc(
                        data->closure,
                        &context->signature,
-                       handler,
+                       psi_ffi_handler,
                        data,
                        data->code);
        ZEND_ASSERT(FFI_OK == rc);
 #elif PSI_HAVE_FFI_PREP_CLOSURE
-       rc = ffi_prep_closure(data->code, &context->signature, handler, data);
+       rc = ffi_prep_closure(data->code, &context->signature, psi_ffi_handler, data);
        ZEND_ASSERT(FFI_OK == rc);
 #else
 # error "Neither ffi_prep_closure() nor ffi_prep_closure_loc() available"
@@ -207,11 +207,11 @@ static inline void PSI_LibffiContextFree(PSI_LibffiContext **L) {
        }
 }
 
-static void handler(ffi_cif *_sig, void *_result, void **_args, void *_data)
+static void psi_ffi_handler(ffi_cif *_sig, void *_result, void **_args, void *_data)
 {
        PSI_LibffiData *data = _data;
        size_t i;
-       void **arg_ptr = NULL, **arg_prm = NULL;
+       void **arg_prm = NULL;
        impl_val ret_val;
 
        if (SUCCESS != psi_parse_args(*(zend_execute_data **)_args[0], data->impl)) {
@@ -219,17 +219,12 @@ static void handler(ffi_cif *_sig, void *_result, void **_args, void *_data)
        }
 
        if (data->impl->decl->args) {
-               arg_ptr = malloc(data->impl->decl->args->count * sizeof(*arg_ptr));
                arg_prm = malloc(data->impl->decl->args->count * sizeof(*arg_prm));
 
                for (i = 0; i < data->impl->decl->args->count; ++i) {
                        decl_arg *darg = data->impl->decl->args->args[i];
 
-                       arg_ptr[i] = psi_do_let(darg);
-                       arg_prm[i] = (darg->let->val && darg->let->val->is_reference)
-                                       ? &arg_ptr[i] : arg_ptr[i];
-
-                       darg->let->ptr = arg_ptr[i];
+                       arg_prm[i] = psi_do_let(darg);
                }
        }
 
@@ -253,25 +248,22 @@ static void handler(ffi_cif *_sig, void *_result, void **_args, void *_data)
 
        psi_do_clean(data->impl);
 
-       if (arg_ptr) {
-               free(arg_ptr);
-       }
        if (arg_prm) {
                free(arg_prm);
        }
 }
 
-static void init(PSI_Context *C)
+static void psi_ffi_init(PSI_Context *C)
 {
        C->context = PSI_LibffiContextInit(NULL);
 }
 
-static void dtor(PSI_Context *C)
+static void psi_ffi_dtor(PSI_Context *C)
 {
        PSI_LibffiContextFree((void *) &C->context);
 }
 
-static zend_function_entry *compile(PSI_Context *C, PSI_Data *D)
+static zend_function_entry *psi_ffi_compile(PSI_Context *C, PSI_Data *D)
 {
        size_t i, j = 0;
        zend_function_entry *zfe = calloc(D->impls->count + 1, sizeof(*zfe));
@@ -297,9 +289,9 @@ static zend_function_entry *compile(PSI_Context *C, PSI_Data *D)
 }
 
 static PSI_ContextOps ops = {
-       init,
-       dtor,
-       compile,
+       psi_ffi_init,
+       psi_ffi_dtor,
+       psi_ffi_compile,
 };
 
 PSI_ContextOps *PSI_Libffi(void)
index 9e43fd2999b5a091c7d1cd56d08b6cafe38f724b..fd68c5089af636202d537c2cf76b858a69939b1c 100644 (file)
@@ -4,7 +4,7 @@
 
 #include <jit/jit.h>
 
-static void handler(jit_type_t _sig, void *result, void **_args, void *_data);
+static void psi_jit_handler(jit_type_t _sig, void *result, void **_args, void *_data);
 
 static inline jit_abi_t psi_jit_abi(const char *convention) {
        return jit_abi_cdecl;
@@ -94,7 +94,7 @@ static inline PSI_LibjitData *PSI_LibjitDataAlloc(PSI_LibjitContext *context, im
                data->params,
                data->impl->decl->args->count,
                1);
-       data->closure = jit_closure_create(context->jit, context->signature, &handler, data);
+       data->closure = jit_closure_create(context->jit, context->signature, &psi_jit_handler, data);
 
        context->data.list = realloc(context->data.list, ++context->data.count * sizeof(*context->data.list));
        context->data.list[context->data.count-1] = data;
@@ -146,11 +146,11 @@ static inline void PSI_LibjitContextFree(PSI_LibjitContext **L) {
        }
 }
 
-static void handler(jit_type_t _sig, void *result, void **_args, void *_data)
+static void psi_jit_handler(jit_type_t _sig, void *result, void **_args, void *_data)
 {
        PSI_LibjitData *data = _data;
        size_t i;
-       void **arg_ptr = NULL, **arg_prm = NULL;
+       void **arg_prm = NULL;
        impl_val ret_val;
 
        if (SUCCESS != psi_parse_args(*(zend_execute_data **)_args[0], data->impl)) {
@@ -158,16 +158,12 @@ static void handler(jit_type_t _sig, void *result, void **_args, void *_data)
        }
 
        if (data->impl->decl->args->count) {
-               arg_ptr = malloc(data->impl->decl->args->count * sizeof(*arg_ptr));
                arg_prm = malloc(data->impl->decl->args->count * sizeof(*arg_prm));
 
                for (i = 0; i < data->impl->decl->args->count; ++i) {
                        decl_arg *darg = data->impl->decl->args->args[i];
 
-                       arg_ptr[i] = psi_do_let(darg);
-                       arg_prm[i] = darg->let->val->is_reference ? &arg_ptr[i] : arg_ptr[i];
-
-                       darg->let->ptr = arg_ptr[i];
+                       arg_prm[i] = psi_do_let(darg);
                }
        }
 
@@ -191,25 +187,22 @@ static void handler(jit_type_t _sig, void *result, void **_args, void *_data)
 
        psi_do_clean(data->impl);
 
-       if (arg_ptr) {
-               free(arg_ptr);
-       }
        if (arg_prm) {
                free(arg_prm);
        }
 }
 
-static void init(PSI_Context *C)
+static void psi_jit_init(PSI_Context *C)
 {
        C->context = PSI_LibjitContextInit(NULL);
 }
 
-static void dtor(PSI_Context *C)
+static void psi_jit_dtor(PSI_Context *C)
 {
        PSI_LibjitContextFree((void *) &C->context);
 }
 
-static zend_function_entry *compile(PSI_Context *C, PSI_Data *D)
+static zend_function_entry *psi_jit_compile(PSI_Context *C, PSI_Data *D)
 {
        size_t i, j = 0;
        zend_function_entry *zfe = calloc(D->impls->count + 1, sizeof(*zfe));
@@ -239,9 +232,9 @@ static zend_function_entry *compile(PSI_Context *C, PSI_Data *D)
 }
 
 static PSI_ContextOps ops = {
-       init,
-       dtor,
-       compile,
+       psi_jit_init,
+       psi_jit_dtor,
+       psi_jit_compile,
 };
 
 PSI_ContextOps *PSI_Libjit(void)
index 2705df1e5616a91f5e8ac5e4fa7f9fc75ba7c99b..03d9d8350f3c0b0412cfd6833b403d6e90b5d3a6 100644 (file)
@@ -316,6 +316,7 @@ void psi_from_zval(impl_val *mem, decl_arg *spec, zval *zv, void **tmp)
                        zend_string_release(zs);
                        break;
                }
+               /* no break */
        default:
                mem->zend.lval = zval_get_long(zv);
                break;
@@ -327,7 +328,7 @@ void *psi_array_to_struct(decl_struct *s, HashTable *arr)
        size_t i, j = 0, size = decl_struct_size(s);
        char *mem = ecalloc(1, size + s->args->count * sizeof(void *));
 
-       for (i = 0; i < s->args->count; ++i) {
+       if (arr) for (i = 0; i < s->args->count; ++i) {
                decl_struct_layout *layout = &s->layout[i];
                decl_arg *darg = s->args->args[i];
                zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name));
@@ -365,7 +366,7 @@ void psi_to_array(zval *return_value, token_t t, impl_val *ret_val, decl_var *va
                        decl_struct_layout layout = s->layout[i];
                        impl_val tmp;
                        zval ztmp;
-                       char *ptr = (char *) ret_val + layout.pos;
+                       char *ptr = (char *) ret_val->ptr + layout.pos;
 
                        memset(&tmp, 0, sizeof(tmp));
                        memcpy(&tmp, ptr, layout.len);
@@ -375,7 +376,7 @@ void psi_to_array(zval *return_value, token_t t, impl_val *ret_val, decl_var *va
                                        psi_to_string(&ztmp, real_decl_type(darg->type)->type, &tmp, darg->var);
                                        break;
                                }
-                               /* nobreak */
+                               /* no break */
                        case PSI_T_INT:
                        case PSI_T_LONG:
                                psi_to_int(&ztmp, real_decl_type(darg->type)->type, &tmp, darg->var);
@@ -481,10 +482,13 @@ void *psi_do_calloc(let_calloc *alloc)
        return ecalloc(alloc->n, size);
 }
 
-impl_val *psi_do_let(decl_arg *darg)
+void *psi_do_let(decl_arg *darg)
 {
-       impl_val *arg_val = &darg->let->out;
        impl_arg *iarg = darg->let->arg;
+       impl_val *arg_val;
+
+       darg->let->ptr = &darg->let->out;
+       arg_val = darg->let->ptr;
 
        if (!iarg) {
                /* let foo = calloc(1, long);
@@ -500,62 +504,66 @@ impl_val *psi_do_let(decl_arg *darg)
                } else {
                        memset(arg_val, 0, sizeof(*arg_val));
                }
-               return arg_val;
-       }
-
-       switch (darg->let->val->func->type) {
-       case PSI_T_BOOLVAL:
-               if (iarg->type->type == PSI_T_BOOL) {
-                       arg_val->cval = iarg->val.zend.bval;
-               } else {
-                       arg_val->cval = zend_is_true(iarg->_zv);
-               }
-               break;
-       case PSI_T_INTVAL:
-               if (iarg->type->type == PSI_T_INT || iarg->type->type == PSI_T_LONG) {
-                       arg_val->lval = iarg->val.zend.lval;
-               } else {
-                       arg_val->lval = zval_get_long(iarg->_zv);
-               }
-               break;
-       case PSI_T_STRVAL:
-               if (iarg->type->type == PSI_T_STRING) {
-                       arg_val->ptr = estrdup(iarg->val.zend.str->val);
-                       darg->let->mem = arg_val->ptr;
-                       zend_string_release(iarg->val.zend.str);
-               } else {
-                       zend_string *zs = zval_get_string(iarg->_zv);
-                       arg_val->ptr = estrdup(zs->val);
-                       darg->let->mem = arg_val->ptr;
-                       zend_string_release(zs);
-               }
-               break;
-       case PSI_T_STRLEN:
-               if (iarg->type->type == PSI_T_STRING) {
-                       arg_val->lval = iarg->val.zend.str->len;
-                       zend_string_release(iarg->val.zend.str);
-               } else {
-                       zend_string *zs = zval_get_string(iarg->_zv);
-                       arg_val->lval = zs->len;
-                       zend_string_release(zs);
-               }
-               break;
-       case PSI_T_ARRVAL:
-               if (iarg->type->type == PSI_T_ARRAY) {
-                       decl_type *type = real_decl_type(darg->type);
+       } else {
 
-                       switch (type->type) {
-                       case PSI_T_STRUCT:
-                               arg_val->ptr = psi_array_to_struct(type->strct, HASH_OF(iarg->_zv));
+               switch (darg->let->val->func->type) {
+               case PSI_T_BOOLVAL:
+                       if (iarg->type->type == PSI_T_BOOL) {
+                               arg_val->cval = iarg->val.zend.bval;
+                       } else {
+                               arg_val->cval = zend_is_true(iarg->_zv);
+                       }
+                       break;
+               case PSI_T_INTVAL:
+                       if (iarg->type->type == PSI_T_INT || iarg->type->type == PSI_T_LONG) {
+                               arg_val->lval = iarg->val.zend.lval;
+                       } else {
+                               arg_val->lval = zval_get_long(iarg->_zv);
+                       }
+                       break;
+               case PSI_T_STRVAL:
+                       if (iarg->type->type == PSI_T_STRING) {
+                               arg_val->ptr = estrdup(iarg->val.zend.str->val);
                                darg->let->mem = arg_val->ptr;
-                               break;
+                               zend_string_release(iarg->val.zend.str);
+                       } else {
+                               zend_string *zs = zval_get_string(iarg->_zv);
+                               arg_val->ptr = estrdup(zs->val);
+                               darg->let->mem = arg_val->ptr;
+                               zend_string_release(zs);
+                       }
+                       break;
+               case PSI_T_STRLEN:
+                       if (iarg->type->type == PSI_T_STRING) {
+                               arg_val->lval = iarg->val.zend.str->len;
+                               zend_string_release(iarg->val.zend.str);
+                       } else {
+                               zend_string *zs = zval_get_string(iarg->_zv);
+                               arg_val->lval = zs->len;
+                               zend_string_release(zs);
+                       }
+                       break;
+               case PSI_T_ARRVAL:
+                       if (iarg->type->type == PSI_T_ARRAY) {
+                               decl_type *type = real_decl_type(darg->type);
+
+                               switch (type->type) {
+                               case PSI_T_STRUCT:
+                                       arg_val->ptr = psi_array_to_struct(type->strct, HASH_OF(iarg->_zv));
+                                       darg->let->mem = arg_val->ptr;
+                                       break;
+                               }
                        }
+                       break;
+               EMPTY_SWITCH_DEFAULT_CASE();
                }
-               break;
-       EMPTY_SWITCH_DEFAULT_CASE();
        }
 
-       return arg_val;
+       if (darg->let->val && darg->let->val->is_reference) {
+               return &darg->let->ptr;
+       } else {
+               return darg->let->ptr;
+       }
 }
 
 void psi_do_set(zval *return_value, set_func *func, decl_vars *vars)
index 7424414f9cdcf9a30925d399cbd39ca9e9945969..cd1e0d4b253fa489fd368eb6a83eb01123aa4305 100644 (file)
@@ -950,3 +950,4 @@ void PSI_ParserDtor(PSI_Parser *P);
 void PSI_ParserFree(PSI_Parser **P);
 
 #endif
+
index 3d86e2b37284a88c78fc6359638ac0479b1e42ba..5940f9257fd512a77daf9708c447e7c42999ce16 100644 (file)
@@ -1,9 +1,9 @@
-#define PSI_T_COMMENT                          1
-#define PSI_T_LIB                              2
-#define PSI_T_QUOTED_STRING                    3
-#define PSI_T_EOS                              4
-#define PSI_T_STRUCT                           5
-#define PSI_T_NAME                             6
+#define PSI_T_NAME                             1
+#define PSI_T_COMMENT                          2
+#define PSI_T_LIB                              3
+#define PSI_T_QUOTED_STRING                    4
+#define PSI_T_EOS                              5
+#define PSI_T_STRUCT                           6
 #define PSI_T_LBRACE                           7
 #define PSI_T_RBRACE                           8
 #define PSI_T_BOOL                             9
index efffcf79fdc0061da00aa89c609190d9d8cb0cc1..62e8011992d36fa3d6acb530a0b1e0f3002f7fa2 100644 (file)
@@ -17,6 +17,9 @@
 %syntax_error {
        PSI_ParserSyntaxError(P, P->fn, P->line, "Unexpected token '%s'", TOKEN->text);
 }
+
+%nonassoc NAME.
+
 file ::= blocks.
 
 blocks ::= block.
@@ -240,6 +243,11 @@ decl_type(type_) ::= NAME(T). {
        type_ = init_decl_type(T->type, T->text);
        free(T);
 }
+decl_type(type_) ::= STRUCT(S) NAME(T). {
+       type_ = init_decl_type(S->type, T->text);
+       free(S);
+       free(T);
+}
 
 %type impl {impl*}
 %destructor impl {free_impl($$);}
index 510bba1ad7280ceb0b262177f77f57c1b289ab5f..128b2acb07e513639f29d0e62fac05a4a3c7973a 100644 (file)
@@ -215,8 +215,15 @@ static inline int validate_struct(PSI_Validator *V, decl_struct *s) {
        s->layout = calloc(s->args->count, sizeof(*s->layout));
        for (i = 0; i < s->args->count; ++i) {
                decl_arg *darg = s->args->args[i];
-               decl_type *type = real_decl_type(darg->type);
-               token_t t = darg->var->pointer_level ? PSI_T_POINTER : type->type;
+               token_t t;
+
+               if (!validate_decl_arg(V, darg)) {
+                       return 0;
+               }
+
+               t = darg->var->pointer_level
+                               ? PSI_T_POINTER
+                               : real_decl_type(darg->type)->type;
 
                if (i) {
                        decl_struct_layout *l = &s->layout[i-1];
@@ -278,50 +285,38 @@ static inline decl *locate_impl_decl(decls *decls, return_stmt *ret) {
        }
        return NULL;
 }
-
-static inline int validate_impl_stmts(PSI_Validator *V, impl *impl, impl_stmts *stmts) {
-       /* okay,
-        * - we must have exactly one ret stmt delcaring the native func to call and which type cast to apply
-        * - we can have multiple let stmts; every arg of the ret stmts var (the function to call) must have one
-        * - we can have any count of set stmts; processing out vars
-        * - we can have any count of free stmts; freeing any out vars
-        */
-       size_t i, j, k;
-       return_stmt *ret;
-       decl *decl;
-
-        if (!stmts) {
-               V->error(PSI_WARNING, "Missing body for implementation %s!",
-                               impl->func->name);
-               return 0;
-       }
-       if (stmts->ret.count != 1) {
-               if (stmts->ret.count > 1) {
-                       V->error(PSI_WARNING, "Too many `ret` statements for implmentation %s;"
+static inline int validate_impl_ret_stmt(PSI_Validator *V, impl *impl) {
+       /* we must have exactly one ret stmt delcaring the native func to call */
+       /* and which type cast to apply */
+       if (impl->stmts->ret.count != 1) {
+               if (impl->stmts->ret.count > 1) {
+                       V->error(PSI_WARNING, "Too many `return` statements for implmentation %s;"
                                        " found %zu, exactly one is needed",
-                                       impl->func->name, stmts->ret.count);
+                                       impl->func->name, impl->stmts->ret.count);
                } else {
-                       V->error(PSI_WARNING, "Missing `ret` statement for implementation %s",
+                       V->error(PSI_WARNING, "Missing `return` statement for implementation %s",
                                        impl->func->name);
                }
                return 0;
        }
-
-       ret = stmts->ret.list[0];
-       decl = locate_impl_decl(V->decls, ret);
-       if (!decl) {
+       if (!(impl->decl = locate_impl_decl(V->decls, impl->stmts->ret.list[0]))) {
                V->error(PSI_WARNING, "Missing declaration for implementation %s",
                                impl->func->name);
                return 0;
        }
 
+       return 1;
+}
+static inline int validate_impl_let_stmts(PSI_Validator *V, impl *impl) {
+       size_t i, j;
+       /* we can have multiple let stmts */
        /* check that we have a let stmt for every decl arg */
-       if (decl->args) for (i = 0; i < decl->args->count; ++i) {
-               decl_arg *darg = decl->args->args[i];
+       if (impl->decl->args) for (i = 0; i < impl->decl->args->count; ++i) {
+               decl_arg *darg = impl->decl->args->args[i];
                int check = 0;
 
-               for (j = 0; j < stmts->let.count; ++j) {
-                       let_stmt *let = stmts->let.list[j];
+               for (j = 0; j < impl->stmts->let.count; ++j) {
+                       let_stmt *let = impl->stmts->let.list[j];
 
                        if (!strcmp(let->var->name, darg->var->name)) {
                                darg->let = let;
@@ -333,13 +328,13 @@ static inline int validate_impl_stmts(PSI_Validator *V, impl *impl, impl_stmts *
                        V->error(PSI_WARNING, "Missing `let` statement for arg '%s %.*s%s'"
                                        " of declaration '%s' for implementation '%s'",
                                        darg->type->name, (int) darg->var->pointer_level, "*****",
-                                       darg->var->name, decl->func->var->name, impl->func->name);
+                                       darg->var->name, impl->decl->func->var->name, impl->func->name);
                        return 0;
                }
        }
        /* check that the let_value references a known variable or NULL */
-       for (i = 0; i < stmts->let.count; ++i) {
-               let_stmt *let = stmts->let.list[i];
+       for (i = 0; i < impl->stmts->let.count; ++i) {
+               let_stmt *let = impl->stmts->let.list[i];
                int check = 0;
 
                if (let->val && let->val->func && let->val->func->alloc) {
@@ -367,9 +362,14 @@ static inline int validate_impl_stmts(PSI_Validator *V, impl *impl, impl_stmts *
                        }
                }
        }
+       return 1;
+}
+static inline int validate_impl_set_stmts(PSI_Validator *V, impl *impl) {
+       size_t i, j, k;
+       /* we can have any count of set stmts; processing out vars */
        /* check that set stmts reference known variables */
-       for (i = 0; i < stmts->set.count; ++i) {
-               set_stmt *set = stmts->set.list[i];
+       for (i = 0; i < impl->stmts->set.count; ++i) {
+               set_stmt *set = impl->stmts->set.list[i];
                int check = 0;
 
                if (impl->func->args) for (j = 0; j < impl->func->args->count; ++j) {
@@ -392,8 +392,8 @@ static inline int validate_impl_stmts(PSI_Validator *V, impl *impl, impl_stmts *
                        decl_var *set_var = set->val->vars->vars[j];
 
                        check = 0;
-                       if (decl->args) for (k = 0; k < decl->args->count; ++k) {
-                               decl_arg *set_arg = decl->args->args[k];
+                       if (impl->decl->args) for (k = 0; k < impl->decl->args->count; ++k) {
+                               decl_arg *set_arg = impl->decl->args->args[k];
 
                                if (!strcmp(set_var->name, set_arg->var->name)) {
                                        check = 1;
@@ -410,19 +410,23 @@ static inline int validate_impl_stmts(PSI_Validator *V, impl *impl, impl_stmts *
                        }
                }
        }
-       /* check free stmts */
-       for (i = 0; i < stmts->fre.count; ++i) {
-               free_stmt *fre = stmts->fre.list[i];
+       return 1;
+}
+static inline int validate_impl_free_stmts(PSI_Validator *V, impl *impl) {
+       size_t i, j, k;
+       /* we can have any count of free stmts; freeing any out vars */
+       for (i = 0; i < impl->stmts->fre.count; ++i) {
+               free_stmt *fre = impl->stmts->fre.list[i];
 
                for (j = 0; j < fre->vars->count; ++j) {
                        decl_var *free_var = fre->vars->vars[j];
                        int check = 0;
 
-                       if (!strcmp(free_var->name, decl->func->var->name)) {
+                       if (!strcmp(free_var->name, impl->decl->func->var->name)) {
                                continue;
                        }
-                       if (decl->args) for (k = 0; k < decl->args->count; ++k) {
-                               decl_arg *free_arg = decl->args->args[k];
+                       if (impl->decl->args) for (k = 0; k < impl->decl->args->count; ++k) {
+                               decl_arg *free_arg = impl->decl->args->args[k];
 
                                if (!strcmp(free_var->name, free_arg->var->name)) {
                                        check = 1;
@@ -439,8 +443,28 @@ static inline int validate_impl_stmts(PSI_Validator *V, impl *impl, impl_stmts *
                        }
                }
        }
+       return 1;
+}
+static inline int validate_impl_stmts(PSI_Validator *V, impl *impl) {
+       if (!impl->stmts) {
+               V->error(PSI_WARNING, "Missing body for implementation %s!",
+                               impl->func->name);
+               return 0;
+       }
 
-       impl->decl = decl;
+       if (!validate_impl_ret_stmt(V, impl)) {
+               return 0;
+       }
+
+       if (!validate_impl_let_stmts(V, impl)) {
+               return 0;
+       }
+       if (!validate_impl_set_stmts(V, impl)) {
+               return 0;
+       }
+       if (!validate_impl_free_stmts(V, impl)) {
+               return 0;
+       }
 
        return 1;
 }
@@ -449,7 +473,7 @@ static inline int validate_impl(PSI_Validator *V, impl *impl) {
        if (!validate_impl_func(V, impl, impl->func)) {
                return 0;
        }
-       if (!validate_impl_stmts(V, impl, impl->stmts)) {
+       if (!validate_impl_stmts(V, impl)) {
                return 0;
        }
        return 1;
diff --git a/tests/time/time.psi b/tests/time/time.psi
new file mode 100644 (file)
index 0000000..5a9b2b0
--- /dev/null
@@ -0,0 +1,61 @@
+typedef long time_t;
+typedef int suseconds_t;
+
+struct timespec {
+       time_t tv_sec;
+       long tv_nsec;
+}
+
+struct timeval {
+       time_t tv_sec;
+       suseconds_t tv_usec;
+}
+
+struct timezone {
+       int tz_minuteswest;
+       int tz_dsttime;
+}
+
+struct tm {
+       int tm_sec;
+       int tm_min;
+       int tm_hour;
+       int tm_mday;
+       int tm_mon;
+       int tm_year;
+       int tm_wday;
+       int tm_yday;
+       int tm_isdst;
+       long tm_gmtoff;
+       char *tm_zone;
+}
+
+extern int gettimeofday(struct timeval *tv, struct timezone *tz);
+function psi\gettimeofday(array &$tv = NULL, array &$tz = NULL) : int {
+       let tv = calloc(1, struct timeval);
+       let tz = calloc(1, struct timezone);
+       return to_int(gettimeofday);
+       set $tv = to_array(*tv);
+       set $tz = to_array(*tz);
+}
+
+extern char *asctime(struct tm *tm);
+function psi\asctime(array $tm = NULL) : string {
+       let tm = arrval($tm);
+       return to_string(asctime);
+}
+
+
+extern struct tm *gmtime(time_t tp);
+function psi\gmtime(int $ts) : array {
+       let tp = &intval($ts);
+       return to_array(gmtime);
+}
+
+extern int nanosleep(struct timespec *rqtp, struct timespec *rmtp);
+function psi\nanosleep(array $rq = NULL, array &$rm = NULL) : int {
+       let rqtp = arrval($rq);
+       let rmtp = calloc(1, struct timespec);
+       return to_int(nanosleep);
+       set $rm = to_array(*rmtp);
+}
diff --git a/tests/time/time001.phpt b/tests/time/time001.phpt
new file mode 100644 (file)
index 0000000..8c35eb9
--- /dev/null
@@ -0,0 +1,57 @@
+--TEST--
+gettimeofday
+--INI--
+psi.directory = {PWD}
+--SKIPIF--
+<?php
+extension_loaded("psi") or die("skip - need ext/psi");
+?>
+--FILE--
+===TEST===
+<?php
+
+var_dump($ar = gettimeofday());
+
+var_dump(psi\gettimeofday());
+var_dump(psi\gettimeofday($tv), $tv);
+var_dump(psi\gettimeofday($tv, $tz), $tv, $tz);
+
+var_dump(abs($ar["sec"] - $tv["tv_sec"]) <= 1);
+?>
+===DONE===
+--EXPECTF--
+===TEST===
+array(4) {
+  ["sec"]=>
+  int(1%d)
+  ["usec"]=>
+  int(%d)
+  ["minuteswest"]=>
+  int(%d)
+  ["dsttime"]=>
+  int(%d)
+}
+int(0)
+int(0)
+array(2) {
+  ["tv_sec"]=>
+  int(1%d)
+  ["tv_usec"]=>
+  int(%d)
+}
+int(0)
+array(2) {
+  ["tv_sec"]=>
+  int(1%d)
+  ["tv_usec"]=>
+  int(%d)
+}
+array(2) {
+  ["tz_minuteswest"]=>
+  int(%d)
+  ["tz_dsttime"]=>
+  int(%d)
+}
+bool(true)
+===DONE===
+                         
\ No newline at end of file
diff --git a/tests/time/time002.phpt b/tests/time/time002.phpt
new file mode 100644 (file)
index 0000000..6e091e0
--- /dev/null
@@ -0,0 +1,24 @@
+--TEST--
+asctime/gmtime
+--SKIPIF--
+<?php
+extension_loaded("psi") or die("skip - need ext/psi");
+?>
+--ENV--
+TZ=UTC
+--INI--
+psi.directory = {PWD}
+--FILE--
+===TEST===
+<?php
+var_dump(psi\asctime(NULL));
+var_dump(psi\asctime(psi\gmtime(1234567890)));
+?>
+===DONE===
+--EXPECT--
+===TEST===
+string(25) "Sun Jan  0 00:00:00 1900
+"
+string(25) "Fri Feb 13 23:31:30 2009
+"
+===DONE===
diff --git a/tests/time/time003.phpt b/tests/time/time003.phpt
new file mode 100644 (file)
index 0000000..1fe5073
--- /dev/null
@@ -0,0 +1,44 @@
+--TEST--
+nanosleep
+--SKIPIF--
+<?php
+extension_loaded("psi") or die("skip - need ext/psi");
+?>
+--ENV--
+TZ=UTC
+--INI--
+psi.directory = {PWD}
+--FILE--
+===TEST===
+<?php
+var_dump(psi\gettimeofday($tv1), $tv1);
+var_dump(psi\nanosleep(["tv_nsec" => 10000000], $rm), $rm);
+var_dump(psi\gettimeofday($tv2), $tv2);
+var_dump($tv2["tv_usec"]-$tv1["tv_usec"]);
+?>
+===DONE===
+--EXPECTF--
+===TEST===
+int(0)
+array(2) {
+  ["tv_sec"]=>
+  int(1%d)
+  ["tv_usec"]=>
+  int(%d)
+}
+int(0)
+array(2) {
+  ["tv_sec"]=>
+  int(0)
+  ["tv_nsec"]=>
+  int(0)
+}
+int(0)
+array(2) {
+  ["tv_sec"]=>
+  int(%d)
+  ["tv_usec"]=>
+  int(%d)
+}
+int(10%r\d\d\d%r)
+===DONE===