flush
authorMichael Wallner <mike@php.net>
Thu, 19 Nov 2015 12:36:53 +0000 (13:36 +0100)
committerMichael Wallner <mike@php.net>
Thu, 19 Nov 2015 12:37:15 +0000 (13:37 +0100)
19 files changed:
config.m4
php_psi.h
src/context.c
src/context.h
src/libffi.c
src/libjit.c
src/module.c
src/parser.h
src/parser.re
src/parser_proc.h
src/parser_proc.y
tests/time/asc_gmtime001.phpt [new file with mode: 0644]
tests/time/gettimeofday001.phpt [new file with mode: 0644]
tests/time/nanosleep001.phpt [new file with mode: 0644]
tests/time/time001.phpt [deleted file]
tests/time/time002.phpt [deleted file]
tests/time/time003.phpt [deleted file]
tests/time/time004.phpt [deleted file]
tests/time/times001.phpt [new file with mode: 0644]

index 77373a8..0b11787 100644 (file)
--- a/config.m4
+++ b/config.m4
@@ -238,7 +238,7 @@ if test "$PHP_PSI" != "no"; then
                                fi
                        ], [], PSI_INCLUDES_DEFAULT($4))
                ])
-               if test "$1" != "$psi_struct_name"
+               if test "$1" = "$psi_struct_name"
                then
                        PSI_TYPES="{PSI_T_STRUCT, \"$psi_struct_name\", \"$psi_struct_name\"}, $PSI_TYPES"
                fi
index b4b96e8..066d9d6 100644 (file)
--- a/php_psi.h
+++ b/php_psi.h
@@ -32,11 +32,11 @@ int psi_internal_type(impl_type *type);
 zend_internal_arg_info *psi_internal_arginfo(impl *impl);
 size_t psi_num_min_args(impl *impl);
 
-void psi_to_bool(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var);
-void psi_to_int(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var);
-void psi_to_double(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var);
-void psi_to_string(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var);
-void psi_to_array(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var);
+void psi_to_bool(zval *return_value, set_value *set, impl_val *ret_val);
+void psi_to_int(zval *return_value, set_value *set, impl_val *ret_val);
+void psi_to_double(zval *return_value, set_value *set, impl_val *ret_val);
+void psi_to_string(zval *return_value, set_value *set, impl_val *ret_val);
+void psi_to_array(zval *return_value, set_value *set, impl_val *ret_val);
 
 void psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl);
 
index 987fb9a..d7eabb5 100644 (file)
@@ -14,6 +14,9 @@
 #include "context.h"
 #include "parser.h"
 
+#include "libjit.h"
+#include "libffi.h"
+
 #define psi_predef_count(of) ((sizeof(psi_predef ##of## s)/sizeof(psi_predef ##of))-1)
 typedef struct psi_predef_type {
        token_t type_tag;
@@ -275,14 +278,15 @@ static inline int validate_decl(PSI_Data *data, void *dl, decl *decl) {
 }
 
 static inline decl_arg *locate_struct_member(decl_struct *s, decl_var *var) {
-       size_t i;
+       if (s->args) {
+               size_t i;
 
-       ZEND_ASSERT(s);
-       for (i = 0; i < s->args->count; ++i) {
-               decl_arg *darg = s->args->args[i];
+               for (i = 0; i < s->args->count; ++i) {
+                       decl_arg *darg = s->args->args[i];
 
-               if (!strcmp(var->name, darg->var->name)) {
-                       return var->arg = darg;
+                       if (!strcmp(var->name, darg->var->name)) {
+                               return var->arg = darg;
+                       }
                }
        }
 
@@ -315,33 +319,53 @@ static inline int validate_set_value(PSI_Data *data, set_value *set, decl_arg *r
        if (strcmp(set_var->name, ref->var->name)) {
                return 0;
        }
+       ZEND_ASSERT(!set_var->arg || set_var->arg == ref);
+       set_var->arg = ref;
 
-       if (set->count && (set->func->type != PSI_T_TO_ARRAY || ref_type->type != PSI_T_STRUCT)) {
-               data->error(E_WARNING, "Inner `set` statement casts only work with to_array() casts on structs");
+       if (set->count && (set->func->type != PSI_T_TO_ARRAY || (ref_type->type != PSI_T_STRUCT && !ref->var->arg->var->pointer_level))) {
+               data->error(E_WARNING, "Inner `set` statement casts only work with to_array() casts on structs or pointers");
                return 0;
        }
-       for (i = 0; i < set->count; ++i) {
-               decl_var *sub_var = set->inner[i]->vars->vars[0];
-               decl_arg *sub_ref = locate_struct_member(ref_type->strct, sub_var);
+
+       if (ref_type->type == PSI_T_STRUCT) {
+               for (i = 0; i < set->count; ++i) {
+                       decl_var *sub_var = set->inner[i]->vars->vars[0];
+                       decl_arg *sub_ref = locate_struct_member(ref_type->strct, sub_var);
+
+                       if (sub_ref) {
+                               if (!validate_set_value(data, set->inner[i], sub_ref)) {
+                                       return 0;
+                               }
+                       }
+               }
+       } else if (set->count == 1) {
+               decl_var *sub_var = set->inner[0]->vars->vars[0];
+               decl_arg *sub_ref = sub_var->arg;
 
                if (sub_ref) {
-                       if (!validate_set_value(data, set->inner[i], sub_ref)) {
+                       if (!validate_set_value(data, set->inner[0], sub_ref)) {
                                return 0;
                        }
                }
+       } else if (set->count > 1) {
+               data->error(E_WARNING, "Inner `set` statement casts on pointers may only occur once");
+               return 0;
        }
 
        return 1;
 }
 static inline decl *locate_impl_decl(decls *decls, return_stmt *ret) {
-       size_t i;
+       if (decls) {
+               size_t i;
 
-       for (i = 0; i < decls->count; ++i) {
-               if (!strcmp(decls->list[i]->func->var->name, ret->set->vars->vars[0]->name)) {
-                       ret->decl = decls->list[i]->func;
-                       return decls->list[i];
+               for (i = 0; i < decls->count; ++i) {
+                       if (!strcmp(decls->list[i]->func->var->name, ret->set->vars->vars[0]->name)) {
+                               ret->decl = decls->list[i]->func;
+                               return decls->list[i];
+                       }
                }
        }
+
        return NULL;
 }
 static inline int validate_impl_ret_stmt(PSI_Data *data, impl *impl) {
@@ -486,14 +510,17 @@ static inline int validate_impl_set_stmts(PSI_Data *data, impl *impl) {
        return 1;
 }
 static inline decl *locate_free_decl(decls *decls, free_call *f) {
-       size_t i;
+       if (decls)  {
+               size_t i;
 
-       for (i = 0; i < decls->count; ++i) {
-               if (!strcmp(decls->list[i]->func->var->name, f->func)) {
-                       f->decl = decls->list[i];
-                       return decls->list[i];
+               for (i = 0; i < decls->count; ++i) {
+                       if (!strcmp(decls->list[i]->func->var->name, f->func)) {
+                               f->decl = decls->list[i];
+                               return decls->list[i];
+                       }
                }
        }
+
        return NULL;
 }
 static inline int validate_impl_free_stmts(PSI_Data *data, impl *impl) {
@@ -739,7 +766,7 @@ static int psi_select_dirent(const struct dirent *entry)
 
 void PSI_ContextBuild(PSI_Context *C, const char *paths)
 {
-       int i, n;
+       int i, n, flags = getenv("PSI_DEBUG") ? PSI_PARSER_DEBUG : 0;
        char *sep = NULL, *cpy = strdup(paths), *ptr = cpy;
        struct dirent **entries = NULL;
 
@@ -762,7 +789,7 @@ void PSI_ContextBuild(PSI_Context *C, const char *paths)
                                        C->error(PSI_WARNING, "Path to PSI file too long: %s/%s",
                                                ptr, entries[i]->d_name);
                                }
-                               if (!PSI_ParserInit(&P, psi, C->error, 0)) {
+                               if (!PSI_ParserInit(&P, psi, C->error, flags)) {
                                        C->error(PSI_WARNING, "Failed to init PSI parser (%s): %s",
                                                psi, strerror(errno));
                                        continue;
@@ -836,6 +863,68 @@ void PSI_ContextCall(PSI_Context *C, impl_val *ret_val, decl *decl)
        C->ops->call(C, ret_val, decl);
 }
 
+static inline void dump_decl_type(int fd, decl_type *t) {
+       const char *pre;
+
+       switch (t->type) {
+       case PSI_T_STRUCT:
+               pre = "struct ";
+               break;
+       default:
+               pre = "";
+       }
+       dprintf(fd, "%s%s", pre, t->name);
+}
+static inline void dump_decl_var(int fd, decl_var *v) {
+       dprintf(fd, "%.*s%s", v->pointer_level-!!v->array_size, "**********", v->name);
+       if (v->array_size) {
+               dprintf(fd, "[%u]", v->array_size);
+       }
+}
+static inline void dump_decl_arg(int fd, decl_arg *a) {
+       dump_decl_type(fd, a->type);
+       dprintf(fd, " ");
+       dump_decl_var(fd, a->var);
+}
+void PSI_ContextDump(PSI_Context *C, int fd)
+{
+       size_t i, j;
+
+#ifdef HAVE_LIBJIT
+       if (C->ops == PSI_Libjit()) {
+               dprintf(fd, "#PSI(libjit)\n");
+       }
+#endif
+#ifdef HAVE_LIBFFI
+       if (C->ops == PSI_Libffi()) {
+               dprintf(fd, "#PSI(libffi)\n");
+       }
+#endif
+
+       if (C->defs) for (i = 0; i < C->defs->count; ++i) {
+               decl_typedef *tdef = C->defs->list[i];
+
+               dprintf(fd, "typedef ");
+               dump_decl_type(fd, tdef->type);
+               dprintf(fd, " %s;\n", tdef->alias);
+       }
+       if (C->structs) for (i = 0; i < C->structs->count; ++i) {
+               decl_struct *strct = C->structs->list[i];
+               decl_arg *sarg = NULL;
+
+               dprintf(fd, "struct %s::(%zu) {\n", strct->name, strct->size);
+               for (j = 0; j < strct->args->count; ++j) {
+                       sarg = strct->args->args[j];
+                       dprintf(fd, "\t");
+                       dump_decl_arg(fd, sarg);
+                       dprintf(fd, "::(%zu, %zu);\n", sarg->layout->pos, sarg->layout->len);
+               }
+               dprintf(fd, "}\n");
+       }
+
+       dprintf(fd, "\n");
+}
+
 void PSI_ContextDtor(PSI_Context *C)
 {
        size_t i;
@@ -847,15 +936,19 @@ void PSI_ContextDtor(PSI_Context *C)
 
        free_decl_libs(&C->psi.libs);
 
-       for (i = 0; i < C->count; ++i) {
-               PSI_DataDtor(&C->data[i]);
+       if (C->data) {
+               for (i = 0; i < C->count; ++i) {
+                       PSI_DataDtor(&C->data[i]);
+               }
+               free(C->data);
        }
-       free(C->data);
 
-       for (zfe = C->closures; zfe->fname; ++zfe) {
-               free((void *) zfe->arg_info);
+       if (C->closures) {
+               for (zfe = C->closures; zfe->fname; ++zfe) {
+                       free((void *) zfe->arg_info);
+               }
+               free(C->closures);
        }
-       free(C->closures);
 
        if (C->consts) {
                if (C->consts->list) {
index 4f86444..e68eddf 100644 (file)
@@ -31,6 +31,7 @@ void PSI_ContextBuild(PSI_Context *C, const char *path);
 int PSI_ContextValidate(PSI_Context *C, PSI_Parser *P);
 zend_function_entry *PSI_ContextCompile(PSI_Context *C);
 void PSI_ContextCall(PSI_Context *C, impl_val *ret_val, decl *decl);
+void PSI_ContextDump(PSI_Context *C, int fd);
 void PSI_ContextDtor(PSI_Context *C);
 void PSI_ContextFree(PSI_Context **C);
 
index bb1f34f..d515827 100644 (file)
@@ -192,14 +192,17 @@ static void psi_ffi_init(PSI_Context *C)
        C->context = PSI_LibffiContextInit(NULL);
 }
 
-static void psi_ffi_dtor(PSI_Context *C) {
-       size_t i;
+static void psi_ffi_dtor(PSI_Context *C)
+{
+       if (C->decls) {
+               size_t i;
 
-       for (i = 0; i < C->decls->count; ++i) {
-               decl *decl = C->decls->list[i];
+               for (i = 0; i < C->decls->count; ++i) {
+                       decl *decl = C->decls->list[i];
 
-               if (decl->call.info) {
-                       PSI_LibffiCallFree(decl->call.info);
+                       if (decl->call.info) {
+                               PSI_LibffiCallFree(decl->call.info);
+                       }
                }
        }
        free(C->context);
index 6e2760d..45ee8e7 100644 (file)
@@ -149,12 +149,14 @@ static void psi_jit_init(PSI_Context *C)
 
 static void psi_jit_dtor(PSI_Context *C)
 {
-       size_t i;
+       if (C->decls) {
+               size_t i;
 
-       for (i = 0; i < C->decls->count; ++i) {
-               decl *decl = C->decls->list[i];
+               for (i = 0; i < C->decls->count; ++i) {
+                       decl *decl = C->decls->list[i];
 
-               PSI_LibjitCallFree(decl->call.info);
+                       PSI_LibjitCallFree(decl->call.info);
+               }
        }
        PSI_LibjitContextFree((void *) &C->context);
 }
index 20b25ea..8637bab 100644 (file)
@@ -204,8 +204,10 @@ size_t psi_num_min_args(impl *impl)
        return n;
 }
 
-void psi_to_bool(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var)
+void psi_to_bool(zval *return_value, set_value *set, impl_val *ret_val)
 {
+       decl_var *var = set->vars->vars[0];
+       token_t t = real_decl_type(var->arg->type)->type;
        impl_val *v = deref_impl_val(ret_val, var);
 
        switch (t) {
@@ -222,8 +224,10 @@ void psi_to_bool(zval *return_value, token_t t, impl_val *ret_val, set_value *se
        convert_to_boolean(return_value);
 }
 
-void psi_to_int(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var)
+void psi_to_int(zval *return_value, set_value *set, impl_val *ret_val)
 {
+       decl_var *var = set->vars->vars[0];
+       token_t t = real_decl_type(var->arg->type)->type;
        impl_val *v = deref_impl_val(ret_val, var);
 
        switch (t) {
@@ -240,8 +244,10 @@ void psi_to_int(zval *return_value, token_t t, impl_val *ret_val, set_value *set
        convert_to_long(return_value);
 }
 
-void psi_to_double(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var)
+void psi_to_double(zval *return_value, set_value *set, impl_val *ret_val)
 {
+       decl_var *var = set->vars->vars[0];
+       token_t t = real_decl_type(var->arg->type)->type;
        impl_val *v = deref_impl_val(ret_val, var);
 
        switch (t) {
@@ -257,8 +263,11 @@ void psi_to_double(zval *return_value, token_t t, impl_val *ret_val, set_value *
        }
 }
 
-void psi_to_string(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var)
+void psi_to_string(zval *return_value, set_value *set, impl_val *ret_val)
 {
+       decl_var *var = set->vars->vars[0];
+       token_t t = real_decl_type(var->arg->type)->type;
+
        switch (t) {
        case PSI_T_INT8:
        case PSI_T_UINT8:
@@ -346,17 +355,18 @@ void *psi_array_to_struct(decl_struct *s, HashTable *arr)
        return mem;
 }
 
-void psi_to_array(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var)
+void psi_to_array(zval *return_value, set_value *set, impl_val *r_val)
 {
        zval ele;
        unsigned i;
-       impl_val tmp;
+       decl_var *var = set->vars->vars[0];
+       token_t t = real_decl_type(var->arg->type)->type;
+       impl_val tmp, *ret_val = deref_impl_val(r_val, var);
 
        array_init(return_value);
 
        if (t == PSI_T_STRUCT) {
                decl_struct *s = real_decl_type(var->arg->type)->strct;
-               ret_val = deref_impl_val(ret_val, var);
 
                ZEND_ASSERT(s);
 
@@ -370,13 +380,12 @@ void psi_to_array(zval *return_value, token_t t, impl_val *ret_val, set_value *s
                                decl_arg *sub_arg = sub_var->arg;
 
                                if (sub_arg) {
-                                       token_t t = real_decl_type(sub_arg->type)->type;
                                        void *ptr = malloc(sub_arg->layout->len);
 
                                        memcpy(ptr, (char *) ret_val->ptr + sub_arg->layout->pos,
                                                        sub_arg->layout->len);
                                        tmp_ptr = enref_impl_val(ptr, sub_arg->var);
-                                       sub_set->func->handler(&ztmp, t, tmp_ptr, sub_set, sub_var);
+                                       sub_set->func->handler(&ztmp, sub_set, tmp_ptr);
                                        add_assoc_zval(return_value, sub_var->name, &ztmp);
                                        free(tmp_ptr);
                                        if (tmp_ptr != ptr) {
@@ -386,7 +395,6 @@ void psi_to_array(zval *return_value, token_t t, impl_val *ret_val, set_value *s
                        }
                }
                return;
-
 //             for (i = 0; i < s->args->count; ++i) {
 //                     decl_arg *darg = s->args->args[i];
 //                     impl_val tmp, tmp_ptr;
@@ -425,25 +433,36 @@ void psi_to_array(zval *return_value, token_t t, impl_val *ret_val, set_value *s
 //                     }
 //                     add_assoc_zval(return_value, darg->var->name, &ztmp);
 //             }
-               return;
        }
-       ret_val = deref_impl_val(ret_val, var);
-       for (i = 0; i < var->arg->var->array_size; ++i) {
-               impl_val *ptr = iterate(ret_val, t, i, &tmp);
+       if (var->arg->var->array_size) {
+               /* to_array(foo[NUMBER]) */
+               for (i = 0; i < var->arg->var->array_size; ++i) {
+                       impl_val *ptr = iterate(ret_val, t, i, &tmp);
+
+                       switch (t) {
+                       case PSI_T_FLOAT:
+                               ZVAL_DOUBLE(&ele, (double) ptr->fval);
+                               break;
+                       case PSI_T_DOUBLE:
+                               ZVAL_DOUBLE(&ele, ptr->dval);
+                               break;
+                       default:
+                               ZVAL_LONG(&ele, ptr->lval);
+                               break;
+                       }
 
-               switch (t) {
-               case PSI_T_FLOAT:
-                       ZVAL_DOUBLE(&ele, (double) ptr->fval);
-                       break;
-               case PSI_T_DOUBLE:
-                       ZVAL_DOUBLE(&ele, ptr->dval);
-                       break;
-               default:
-                       ZVAL_LONG(&ele, ptr->lval);
-                       break;
+                       add_next_index_zval(return_value, &ele);
                }
+               return;
+       } else {
+               /* pointer to something */
+               impl_val *ptr;
 
-               add_next_index_zval(return_value, &ele);
+               for (i = 0; (ptr = iterate(ret_val, t, i, &tmp)); ++i) {
+                       if (!ptr->ptr) {
+                               break;
+                       }
+               }
        }
 }
 
@@ -606,20 +625,15 @@ static inline void *psi_do_let(decl_arg *darg)
 
 static inline void psi_do_set(zval *return_value, set_value *set)
 {
-       impl_val *val = (impl_val *) &set->vars->vars[0]->arg->let->ptr;
-       token_t t = real_decl_type(set->vars->vars[0]->arg->type)->type;
-
        ZVAL_DEREF(return_value);
        zval_dtor(return_value);
 
-       set->func->handler(return_value, t, val, set, set->vars->vars[0]);
+       set->func->handler(return_value, set, set->vars->vars[0]->arg->let->ptr);
 }
 
 static inline void psi_do_return(zval *return_value, return_stmt *ret, impl_val *ret_val)
 {
-       token_t t = real_decl_type(ret->decl->type)->type;
-
-       ret->set->func->handler(return_value, t, ret_val, ret->set, ret->decl->var);
+       ret->set->func->handler(return_value, ret->set, ret_val);
 }
 
 static inline void psi_do_free(free_stmt *fre)
@@ -739,6 +753,10 @@ PHP_MINIT_FUNCTION(psi)
        PSI_ContextInit(&PSI_G(context), ops, psi_error);
        PSI_ContextBuild(&PSI_G(context), PSI_G(directory));
 
+       if (getenv("PSI_DUMP")) {
+               PSI_ContextDump(&PSI_G(context), STDOUT_FILENO);
+       }
+
        return SUCCESS;
 }
 PHP_MSHUTDOWN_FUNCTION(psi)
index d8955e5..683192b 100644 (file)
@@ -351,7 +351,7 @@ typedef union impl_val {
 static inline impl_val *deref_impl_val(impl_val *ret_val, decl_var *var) {
        unsigned i;
 
-       if (var->arg->var != var) for (i = 0; i < var->pointer_level; ++i) {
+       if (var->arg->var != var) for (i = 1; i < var->pointer_level; ++i) {
                ret_val = *(void **) ret_val;
        }
        return ret_val;
@@ -595,7 +595,7 @@ struct set_value;
 typedef struct set_func {
        token_t type;
        char *name;
-       void (*handler)(zval *, token_t, impl_val *, struct set_value *set, decl_var *);
+       void (*handler)(zval *, struct set_value *set, impl_val *ret_val);
 } set_func;
 
 static inline set_func *init_set_func(token_t type, const char *name) {
index 0eae943..81005f2 100644 (file)
@@ -144,21 +144,6 @@ void PSI_ParserFree(PSI_Parser **P)
        return t; \
 } while(1)
 
-/*             DIGIT = [0-9]
-               DIGITS = DIGIT+
-               DECIMALS = (+|-)? DIGIT* "."
-               digits ::= digits DIGIT.
-               decimals ::= digits DOT digits.
-               decimals ::= DOT digits.
-               decimals ::= digits DOT.
-               number ::= digits.
-               number ::= PLUS digits.
-               number ::= MINUS digits.
-               number ::= decimals.
-               number ::= MINUS decimals.
-               number ::= PLUS decimals.
-
-*/
 token_t PSI_ParserScan(PSI_Parser *P)
 {
        for (;;) {
@@ -179,7 +164,7 @@ token_t PSI_ParserScan(PSI_Parser *P)
                QUOTED_STRING = "\"" ([^\"])+ "\"";
                NUMBER = [+-]? [0-9]* "."? [0-9]+ ([eE] [+-]? [0-9]+)?;
 
-               "#" .* "\n" { ++P->line; RETURN(PSI_T_COMMENT);}
+               ("#"|"//") .* "\n" { ++P->line; continue;}
                "(" {RETURN(PSI_T_LPAREN);}
                ")" {RETURN(PSI_T_RPAREN);}
                ";" {RETURN(PSI_T_EOS);}
index 7f3e440..3c07664 100644 (file)
@@ -4,25 +4,25 @@
 #define PSI_T_LET                              4
 #define PSI_T_RETURN                           5
 #define PSI_T_LIB                              6
-#define PSI_T_COMMENT                          7
+#define PSI_T_INT                              7
 #define PSI_T_QUOTED_STRING                    8
 #define PSI_T_EOS                              9
 #define PSI_T_STRUCT                          10
 #define PSI_T_LBRACE                          11
 #define PSI_T_RBRACE                          12
-#define PSI_T_BOOL                            13
-#define PSI_T_INT                             14
-#define PSI_T_FLOAT                           15
-#define PSI_T_STRING                          16
-#define PSI_T_CONST                           17
-#define PSI_T_NSNAME                          18
-#define PSI_T_EQUALS                          19
-#define PSI_T_TYPEDEF                         20
-#define PSI_T_LPAREN                          21
-#define PSI_T_RPAREN                          22
-#define PSI_T_VOID                            23
-#define PSI_T_LBRACKET                        24
-#define PSI_T_NUMBER                          25
+#define PSI_T_COLON                           13
+#define PSI_T_LPAREN                          14
+#define PSI_T_NUMBER                          15
+#define PSI_T_RPAREN                          16
+#define PSI_T_BOOL                            17
+#define PSI_T_FLOAT                           18
+#define PSI_T_STRING                          19
+#define PSI_T_CONST                           20
+#define PSI_T_NSNAME                          21
+#define PSI_T_EQUALS                          22
+#define PSI_T_TYPEDEF                         23
+#define PSI_T_VOID                            24
+#define PSI_T_LBRACKET                        25
 #define PSI_T_RBRACKET                        26
 #define PSI_T_COMMA                           27
 #define PSI_T_DOUBLE                          28
 #define PSI_T_INT64                           35
 #define PSI_T_UINT64                          36
 #define PSI_T_FUNCTION                        37
-#define PSI_T_COLON                           38
-#define PSI_T_REFERENCE                       39
-#define PSI_T_NULL                            40
-#define PSI_T_TRUE                            41
-#define PSI_T_FALSE                           42
-#define PSI_T_DOLLAR                          43
-#define PSI_T_CALLOC                          44
-#define PSI_T_ARRVAL                          45
-#define PSI_T_STRLEN                          46
-#define PSI_T_STRVAL                          47
-#define PSI_T_FLOATVAL                        48
-#define PSI_T_INTVAL                          49
-#define PSI_T_BOOLVAL                         50
-#define PSI_T_TO_ARRAY                        51
-#define PSI_T_TO_STRING                       52
-#define PSI_T_TO_INT                          53
-#define PSI_T_TO_FLOAT                        54
-#define PSI_T_TO_BOOL                         55
-#define PSI_T_MIXED                           56
-#define PSI_T_ARRAY                           57
-#define PSI_T_POINTER                         58
+#define PSI_T_REFERENCE                       38
+#define PSI_T_NULL                            39
+#define PSI_T_TRUE                            40
+#define PSI_T_FALSE                           41
+#define PSI_T_DOLLAR                          42
+#define PSI_T_CALLOC                          43
+#define PSI_T_ARRVAL                          44
+#define PSI_T_STRLEN                          45
+#define PSI_T_STRVAL                          46
+#define PSI_T_FLOATVAL                        47
+#define PSI_T_INTVAL                          48
+#define PSI_T_BOOLVAL                         49
+#define PSI_T_TO_ARRAY                        50
+#define PSI_T_TO_STRING                       51
+#define PSI_T_TO_INT                          52
+#define PSI_T_TO_FLOAT                        53
+#define PSI_T_TO_BOOL                         54
+#define PSI_T_MIXED                           55
+#define PSI_T_ARRAY                           56
+#define PSI_T_POINTER                         57
index 69d6955..f3a51f4 100644 (file)
 }
 
 %nonassoc NAME.
-%fallback NAME FREE SET LET RETURN LIB.
+%fallback NAME FREE SET LET RETURN LIB INT.
 
 file ::= blocks.
 
 blocks ::= block.
 blocks ::= blocks block.
 
-block ::= COMMENT.
-
 block ::= LIB(T) QUOTED_STRING(libname) EOS. {
        if (P->psi.file.ln) {
                PSI_ParserSyntaxError(P, P->psi.file.ln, T->line, "Extra 'lib %s' statement has no effect", libname->text);
@@ -59,11 +57,21 @@ block ::= decl_struct(strct). {
 
 %type decl_struct {decl_struct*}
 %destructor decl_struct {free_decl_struct($$);}
-decl_struct(strct) ::= STRUCT NAME(N) LBRACE struct_args(args) RBRACE. {
+decl_struct(strct) ::= STRUCT NAME(N) struct_size(size_) LBRACE struct_args(args) RBRACE. {
        strct = init_decl_struct(N->text, args);
+       strct->size = size_;
        free(N);
 }
 
+%type struct_size {size_t}
+struct_size(size) ::= . {
+       size = 0;
+}
+struct_size(size) ::= COLON COLON LPAREN NUMBER(SIZ) RPAREN. {
+       size = atol(SIZ->text);
+       free(SIZ);
+}
+
 %token_class const_type_token BOOL INT FLOAT STRING.
 %type const_type {const_type*}
 %destructor const_type {free_const_type($$);}
@@ -173,12 +181,29 @@ decl_args(args) ::= decl_args(args_) COMMA decl_arg(arg). {
 }
 %type struct_args {decl_args*}
 %destructor struct_args {free_decl_args($$);}
-struct_args(args) ::= decl_arg(arg) EOS. {
+struct_args(args) ::= struct_arg(arg). {
        args = init_decl_args(arg);
 }
-struct_args(args) ::= struct_args(args_) decl_arg(arg) EOS. {
+struct_args(args) ::= struct_args(args_) struct_arg(arg). {
        args = add_decl_arg(args_, arg);
 }
+%type struct_arg {decl_arg*}
+%destructor struct_arg {free_decl_arg($$);}
+struct_arg(arg) ::= decl_arg(arg_) struct_layout(layout_) EOS. {
+       arg_->layout = layout_;
+       arg = arg_;
+}
+
+%type struct_layout {decl_struct_layout*}
+%destructor struct_layout {free_decl_struct_layout($$);}
+struct_layout(layout) ::= . {
+       layout = NULL;
+}
+struct_layout(layout) ::= COLON COLON LPAREN NUMBER(POS) COMMA NUMBER(SIZ) RPAREN. {
+       layout = init_decl_struct_layout(atol(POS->text), atol(SIZ->text));
+       free(POS);
+       free(SIZ);
+}
 
 %token_class decl_type_token FLOAT DOUBLE INT8 UINT8 INT16 UINT16 INT32 UINT32 INT64 UINT64 NAME.
 %type decl_type {decl_type*}
diff --git a/tests/time/asc_gmtime001.phpt b/tests/time/asc_gmtime001.phpt
new file mode 100644 (file)
index 0000000..3ae7850
--- /dev/null
@@ -0,0 +1,30 @@
+--TEST--
+asctime/gmtime
+--SKIPIF--
+<?php
+extension_loaded("psi") or die("skip - need ext/psi");
+?>
+--ENV--
+TZ=UTC
+--INI--
+psi.directory = {PWD}/../../psi.d:{PWD}
+--FILE--
+===TEST===
+<?php
+var_dump(psi\asctime(NULL));
+var_dump(psi\asctime_r(NULL));
+var_dump(psi\asctime(psi\gmtime(1234567890)));
+var_dump(psi\asctime_r(psi\gmtime_r(1234567890)));
+?>
+===DONE===
+--EXPECT--
+===TEST===
+string(25) "Sun Jan  0 00:00:00 1900
+"
+string(25) "Sun Jan  0 00:00:00 1900
+"
+string(25) "Fri Feb 13 23:31:30 2009
+"
+string(25) "Fri Feb 13 23:31:30 2009
+"
+===DONE===
diff --git a/tests/time/gettimeofday001.phpt b/tests/time/gettimeofday001.phpt
new file mode 100644 (file)
index 0000000..746dcd9
--- /dev/null
@@ -0,0 +1,58 @@
+--TEST--
+gettimeofday
+--INI--
+psi.directory = {PWD}/../../psi.d:{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/nanosleep001.phpt b/tests/time/nanosleep001.phpt
new file mode 100644 (file)
index 0000000..f9e0451
--- /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}/../../psi.d:{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(%r\d\d\d\d\d%r)
+===DONE===
diff --git a/tests/time/time001.phpt b/tests/time/time001.phpt
deleted file mode 100644 (file)
index 746dcd9..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
---TEST--
-gettimeofday
---INI--
-psi.directory = {PWD}/../../psi.d:{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
deleted file mode 100644 (file)
index 3ae7850..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
---TEST--
-asctime/gmtime
---SKIPIF--
-<?php
-extension_loaded("psi") or die("skip - need ext/psi");
-?>
---ENV--
-TZ=UTC
---INI--
-psi.directory = {PWD}/../../psi.d:{PWD}
---FILE--
-===TEST===
-<?php
-var_dump(psi\asctime(NULL));
-var_dump(psi\asctime_r(NULL));
-var_dump(psi\asctime(psi\gmtime(1234567890)));
-var_dump(psi\asctime_r(psi\gmtime_r(1234567890)));
-?>
-===DONE===
---EXPECT--
-===TEST===
-string(25) "Sun Jan  0 00:00:00 1900
-"
-string(25) "Sun Jan  0 00:00:00 1900
-"
-string(25) "Fri Feb 13 23:31:30 2009
-"
-string(25) "Fri Feb 13 23:31:30 2009
-"
-===DONE===
diff --git a/tests/time/time003.phpt b/tests/time/time003.phpt
deleted file mode 100644 (file)
index f9e0451..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
---TEST--
-nanosleep
---SKIPIF--
-<?php
-extension_loaded("psi") or die("skip - need ext/psi");
-?>
---ENV--
-TZ=UTC
---INI--
-psi.directory = {PWD}/../../psi.d:{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(%r\d\d\d\d\d%r)
-===DONE===
diff --git a/tests/time/time004.phpt b/tests/time/time004.phpt
deleted file mode 100644 (file)
index 816b0b5..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
---TEST--
-times
---INI--
-psi.directory={PWD}/../../psi.d:{PWD}
---SKIPIF--
-<?php
-extension_loaded("psi") or die("skip - need ext/psi");
-?>
---FILE--
-===TEST===
-<?php 
-var_dump(psi\times($times), $times);
-?>
-===DONE===
---EXPECTF--
-===TEST===
-int(%d)
-array(4) {
-  ["tms_utime"]=>
-  int(%d)
-  ["tms_stime"]=>
-  int(%d)
-  ["tms_cutime"]=>
-  int(%d)
-  ["tms_cstime"]=>
-  int(%d)
-}
-===DONE===
diff --git a/tests/time/times001.phpt b/tests/time/times001.phpt
new file mode 100644 (file)
index 0000000..816b0b5
--- /dev/null
@@ -0,0 +1,28 @@
+--TEST--
+times
+--INI--
+psi.directory={PWD}/../../psi.d:{PWD}
+--SKIPIF--
+<?php
+extension_loaded("psi") or die("skip - need ext/psi");
+?>
+--FILE--
+===TEST===
+<?php 
+var_dump(psi\times($times), $times);
+?>
+===DONE===
+--EXPECTF--
+===TEST===
+int(%d)
+array(4) {
+  ["tms_utime"]=>
+  int(%d)
+  ["tms_stime"]=>
+  int(%d)
+  ["tms_cutime"]=>
+  int(%d)
+  ["tms_cstime"]=>
+  int(%d)
+}
+===DONE===