flush
authorMichael Wallner <mike@php.net>
Mon, 24 Oct 2016 17:56:18 +0000 (19:56 +0200)
committerMichael Wallner <mike@php.net>
Mon, 24 Oct 2016 17:56:18 +0000 (19:56 +0200)
27 files changed:
psi.d/getopt.psi [new file with mode: 0644]
psi.d/time.psi
src/engine.c
src/engine.h
src/marshal.c
src/marshal.h
src/parser.re
src/parser_def.h
src/parser_proc.h
src/parser_proc.y
src/types.h
src/types/decl.c
src/types/decl_type.c
src/types/decl_type.h
src/types/let_callback.c
src/types/let_func.c
src/types/let_func.h
src/types/let_stmt.c
src/types/let_stmt.h
src/types/let_val.c
src/types/let_val.h
src/types/let_vals.h
src/types/set_stmt.c
tests/getopt/getopt001.phpt [new file with mode: 0644]
tests/ndbm/ndbm.psi
tests/ndbm/ndbm001.phpt
tests/parser/validate001.phpt

diff --git a/psi.d/getopt.psi b/psi.d/getopt.psi
new file mode 100644 (file)
index 0000000..5f5bae6
--- /dev/null
@@ -0,0 +1,24 @@
+function psi\opterr() : int {
+       return to_int(opterr);
+}
+function psi\optind() : int {
+       return to_int(optind);
+}
+function psi\optopt() : int {
+       return to_int(optopt);
+}
+function psi\optarg() : string {
+       return to_string(optarg);
+}
+
+function psi\getopt(array &$argv, string $options) : int {
+       let argc = count($argv);
+       let argv = &arrval($argv,
+               *argv = strval($argv)
+       );
+       let optstring = strval($options);
+       return to_int(getopt); 
+       set $argv = to_array(argv,
+               to_string(argv)
+       );
+}
index 30f713b..9302b13 100644 (file)
@@ -1,3 +1,4 @@
+// extern time_t time(time_t *t);
 function psi\time() : int {
        let t = NULL;
        return to_int(time);
index 09dc429..6fba400 100644 (file)
@@ -8,6 +8,8 @@
 #include "php_psi.h"
 
 #include "zend_exceptions.h"
+#include "zend_interfaces.h"
+#include "ext/spl/spl_iterators.h"
 
 #include "parser.h"
 #include "engine.h"
@@ -41,6 +43,43 @@ int psi_internal_type(impl_type *type)
        }
 }
 
+zend_long psi_zval_count(zval *zvalue)
+{
+       /* mimic PHP count() */
+       zend_long count;
+       zval retval;
+
+       switch (Z_TYPE_P(zvalue)) {
+       default:
+               count = 1;
+               break;
+       case IS_NULL:
+               count = 0;
+               break;
+       case IS_ARRAY:
+               count = zend_array_count(Z_ARRVAL_P(zvalue));
+               break;
+       case IS_OBJECT:
+               count = 1;
+               if (Z_OBJ_HT_P(zvalue)->count_elements) {
+                       if (SUCCESS == Z_OBJ_HT_P(zvalue)->count_elements(zvalue, &count)) {
+                               break;
+                       }
+               }
+
+               if (instanceof_function(Z_OBJCE_P(zvalue), spl_ce_Countable)) {
+                       zend_call_method_with_0_params(zvalue, NULL, NULL, "count", &retval);
+                       if (Z_TYPE(retval) != IS_UNDEF) {
+                               count = zval_get_long(&retval);
+                               zval_ptr_dtor(&retval);
+                       }
+               }
+               break;
+       }
+
+       return count;
+}
+
 zend_internal_arg_info *psi_internal_arginfo(impl *impl)
 {
        size_t i;
@@ -251,29 +290,14 @@ static inline void *psi_let_val(let_val *val, decl_arg *darg)
                break;
        }
 
-       if (val && val->flags.one.is_reference) {
+       if (val && val->is_reference) {
                return darg->let = &darg->ptr;
        } else {
                return darg->let = darg->ptr;
        }
 }
 
-static void marshal_func(void *cb_ctx, impl_val **ptr, decl_arg *spec, token_t cast, zval *zv, void **tmp) {
-       let_vals *vals = cb_ctx;
-       size_t i;
-
-       for (i = 0; i < vals->count; ++i) {
-               impl_var *var = locate_let_val_impl_var(vals->vals[i]);
-
-               if (!strcmp(&var->name[1], spec->var->name)) {
-                       *ptr = psi_let_val(vals->vals[i], spec);
-                       *tmp = spec->mem;
-                       break;
-               }
-       }
-}
-
-static inline impl_val *psi_let_func_ex(let_func *func, void *dptr, decl_type *dtype, token_t itype, impl_val *ival, zval *zvalue, void **to_free) {
+static inline impl_val *psi_let_func_ex(let_func *func, void *dptr, decl_type *dtype, decl_var *dvar, token_t itype, impl_val *ival, zval *zvalue, void **to_free) {
        switch (func->type) {
        case PSI_T_BOOLVAL:
                return psi_let_boolval(dptr, dtype, itype, ival, zvalue, to_free);
@@ -293,19 +317,78 @@ static inline impl_val *psi_let_func_ex(let_func *func, void *dptr, decl_type *d
                return psi_let_zval(dptr, dtype, itype, ival, zvalue, to_free);
        case PSI_T_VOID:
                return psi_let_void(dptr, dtype, itype, ival, zvalue, to_free);
-               break;
+       case PSI_T_COUNT:
+               return psi_let_count(dptr, dtype, itype, ival, zvalue, to_free);
        case PSI_T_ARRVAL:
                if (func->inner) {
-                       decl_type *real = real_decl_type(dtype);
+                       char *mem = NULL;
+                       size_t i, j = 0;
+                       decl_type *real;
+                       decl_args *args = extract_decl_type_args(dtype, &real);
 
                        if (itype != PSI_T_ARRAY) {
                                SEPARATE_ARG_IF_REF(zvalue);
                                convert_to_array(zvalue);
                        }
 
-                       return *to_free = psi_array_to_struct_ex(real->real.strct, Z_ARRVAL_P(zvalue), marshal_func, func->inner);
+                       if (args) {
+                               size_t size = extract_decl_type_size(real, NULL);
+
+                               mem = ecalloc(1, size + args->count * sizeof(void *));
+
+                               for (i = 0; i < args->count; ++i) {
+                                       decl_arg *darg = args->args[i];
+                                       let_val *lval = locate_let_vals_val(func->inner, darg->var->name);
+                                       impl_val *ptr = NULL;
+
+                                       if (lval) {
+                                               if ((ptr = psi_let_val(lval, darg))) {
+                                                       memcpy(mem + darg->layout->pos, ptr, darg->layout->len);
+                                                       if (darg->mem) {
+                                                               ((void **)(mem + size))[j++] = darg->mem;
+                                                       }
+                                               }
+                                               if (real->type == PSI_T_UNION) {
+                                                       break;
+                                               }
+                                       }
+                               }
+                       } else {
+                               zval *zv;
+                               let_val *inner = func->inner->vals[0];
+                               decl_var *sub_var;
+                               size_t size;
+
+                               if (inner->var) {
+                                       sub_var = inner->var;
+                               } else {
+                                       sub_var = copy_decl_var(dvar);
+                                       assert(sub_var->pointer_level);
+                                       --sub_var->pointer_level;
+                               }
+
+                               size = sub_var->pointer_level ? SIZEOF_VOID_P : extract_decl_type_size(real, NULL);
+                               mem = ecalloc(1, size * (1 + zend_array_count(Z_ARRVAL_P(zvalue))));
+
+                               ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(zvalue), zv)
+                               {
+                                       void *tmp = NULL;
+                                       impl_val val = {0}, *ptr, *sub;
+
+                                       ptr = psi_let_func_ex(inner->data.func, &val, real, dvar, 0, NULL, zv, &tmp);
+                                       sub = deref_impl_val(ptr, sub_var);
+
+                                       memcpy(&mem[size * j++], &sub, size);
+                               }
+                               ZEND_HASH_FOREACH_END();
+
+                               if (sub_var != inner->var) {
+                                       free_decl_var(sub_var);
+                               }
+                       }
+                       return *to_free = mem;
                } else {
-                       return psi_let_arrval(dptr, dtype, itype, ival, zvalue, to_free);
+                       return psi_let_arrval(dptr, dtype, dvar, itype, ival, zvalue, to_free);
                }
                break;
        default:
@@ -315,25 +398,41 @@ static inline impl_val *psi_let_func_ex(let_func *func, void *dptr, decl_type *d
 }
 
 static inline impl_val *psi_let_func(let_func *func, decl_arg *darg) {
-       impl_arg *iarg = func->var->arg;
 
-       if (func->outer && !iarg) {
-               impl_arg *outer_arg = locate_let_val_impl_var(func->outer)->arg;
-               iarg = init_impl_arg(
+       if (func->var->arg) {
+               return darg->ptr = psi_let_func_ex(func,
+                               darg->ptr, darg->type, darg->var,
+                               func->var->arg->type->type,
+                               &func->var->arg->val,
+                               func->var->arg->_zv,
+                               &darg->mem);
+       } else {
+               impl_var *ivar = locate_let_val_impl_var(func->outer);
+               zval *entry = zend_symtable_str_find(Z_ARRVAL_P(ivar->arg->_zv), func->var->name+1, strlen(func->var->name)-1);
+               impl_arg *iarg = init_impl_arg(
                                init_impl_type(PSI_T_MIXED, "mixed"),
                                copy_impl_var(func->var), NULL);
 
+               func->var->arg = iarg;
+               if (entry) {
+                       iarg->_zv = entry;
+               } else {
+                       zval ztmp;
 
-               if (!(iarg->_zv = zend_hash_str_find(Z_ARRVAL_P(outer_arg->_zv), &iarg->var->name[1], strlen(iarg->var->name)-1))) {
-                       iarg->_zv = zend_hash_str_add_empty_element(Z_ARRVAL_P(outer_arg->_zv), &iarg->var->name[1], strlen(iarg->var->name)-1);
+                       ZVAL_NULL(&ztmp);
+                       iarg->_zv = zend_symtable_str_update_ind(Z_ARRVAL_P(ivar->arg->_zv), func->var->name+1, strlen(func->var->name)-1, &ztmp);
                }
+
+               psi_let_func(func, darg);
+               free_impl_arg(iarg);
+               return darg->ptr;
        }
-       return darg->ptr = psi_let_func_ex(func, darg->ptr, darg->type, iarg->type->type, &iarg->val, iarg->_zv, &darg->mem);
+
 }
 
 static inline void *psi_do_let(let_stmt *let)
 {
-       return psi_let_val(let->val, let->var->arg);
+       return psi_let_val(let->val, let->val->var->arg);
 }
 
 static inline void psi_do_return(zval *return_value, return_stmt *ret)
@@ -365,7 +464,6 @@ static inline void psi_clean_array_struct(let_val *val, decl_arg *darg) {
        if (val->kind == PSI_LET_FUNC
        &&      val->data.func->type == PSI_T_ARRVAL) {
                decl_type *type = real_decl_type(darg->type);
-               decl_args *args = NULL;
 
                if (type->type == PSI_T_STRUCT) {
                        void **ptr = (void **) ((char *) darg->mem + type->real.strct->size);
@@ -373,15 +471,16 @@ static inline void psi_clean_array_struct(let_val *val, decl_arg *darg) {
                        while (*ptr) {
                                efree(*ptr++);
                        }
-                       args = type->real.strct->args;
+                       // args = type->real.strct->args;
                } else if (type->type == PSI_T_UNION) {
                        void **ptr = (void **) ((char *) darg->mem + type->real.unn->size);
 
                        if (*ptr) {
                                efree(*ptr);
                        }
-                       args = type->real.unn->args;
+                       // args = type->real.unn->args;
                }
+#if 0
                if (args && val->data.func->inner) {
                        size_t i;
 
@@ -392,13 +491,40 @@ static inline void psi_clean_array_struct(let_val *val, decl_arg *darg) {
 
                                if (subarg) {
                                        psi_clean_array_struct(val->data.func->inner->vals[i], subarg);
-                                       if (subarg && subarg->mem) {
+                                       if (subarg->mem) {
                                                efree(subarg->mem);
                                                subarg->mem = NULL;
                                        }
                                }
                        }
                }
+#endif
+       }
+}
+
+static inline void psi_clean_let_val(let_val *val) {
+
+       let_func *func = locate_let_val_func(val);
+
+       if (func && func->inner) {
+               size_t i;
+
+               for (i = 0; i < func->inner->count; ++i) {
+                       let_val *inner = func->inner->vals[i];
+                       psi_clean_let_val(inner);
+               }
+       }
+       if (val->var) {
+               decl_arg *darg = val->var->arg;
+               if (darg) {
+                       if (darg->mem) {
+                               psi_clean_array_struct(val, darg);
+                               efree(darg->mem);
+                               darg->mem = NULL;
+                       }
+                       darg->ptr = &darg->val;
+                       darg->let = darg->ptr;
+               }
        }
 }
 
@@ -433,15 +559,7 @@ static inline void psi_do_clean(impl *impl)
 
        for (i = 0; i < impl->stmts->let.count; ++i) {
                let_stmt *let = impl->stmts->let.list[i];
-               decl_arg *darg = let->var->arg;
-
-               if (darg->mem) {
-                       psi_clean_array_struct(let->val, darg);
-                       efree(darg->mem);
-                       darg->mem = NULL;
-               }
-               darg->ptr = &darg->val;
-               darg->let = darg->ptr;
+               psi_clean_let_val(let->val);
        }
 
        if (impl->func->args->vararg.args) {
@@ -477,14 +595,16 @@ static inline void psi_do_args(impl *impl) {
        }
 
        if (!impl->decl->func->var->pointer_level) {
-               decl_type *real = real_decl_type(impl->decl->func->type);
+               decl_type *real;
+               decl_args *args = extract_decl_type_args(impl->decl->func->type, &real);
 
                switch (real->type) {
                case PSI_T_STRUCT:
-                       impl->decl->func->ptr = psi_array_to_struct(real->real.strct, NULL);
-                       break;
                case PSI_T_UNION:
-                       impl->decl->func->ptr = psi_array_to_union(real->real.unn, NULL);
+                       impl->decl->func->ptr = ecalloc(1,
+                                       extract_decl_type_size(real, NULL) + args->count * sizeof(void*));
+                       break;
+               default:
                        break;
                }
        }
@@ -631,7 +751,7 @@ ZEND_RESULT_CODE psi_callback(let_callback *cb, void *retval, unsigned argc, voi
        case PSI_T_STRING:      zend_parse_arg_str(iarg->_zv, &iarg->val.zend.str, 0);                          break;
        }
        */
-       result = psi_let_func_ex(cb->func, retval, decl_cb->func->type, 0, &iarg->val, iarg->_zv, &to_free);
+       result = psi_let_func_ex(cb->func, retval, decl_cb->func->type, decl_cb->func->var, 0, &iarg->val, iarg->_zv, &to_free);
        // result = cb->func->handler(retval, decl_cb->func->type, iarg, &to_free);
 
        if (result != retval) {
index d7891a2..624ddfb 100644 (file)
@@ -4,6 +4,7 @@
 int psi_internal_type(impl_type *type);
 zend_internal_arg_info *psi_internal_arginfo(impl *impl);
 size_t psi_num_min_args(impl *impl);
+zend_long psi_zval_count(zval *zvalue);
 
 ZEND_RESULT_CODE psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl);
 ZEND_RESULT_CODE psi_callback(let_callback *cb, void *retval, unsigned argc, void **argv);
index 00c1a81..1e71a64 100644 (file)
@@ -8,6 +8,7 @@
 #include "php_psi.h"
 #include "parser.h"
 #include "marshal.h"
+#include "engine.h"
 #include "calc.h"
 
 void psi_to_void(zval *return_value, set_value *set, impl_val *ret_val)
@@ -244,11 +245,14 @@ impl_val *psi_let_strval(impl_val *tmp, decl_type *spec, token_t impl_type, impl
 {
        if (ival && impl_type == PSI_T_STRING) {
                if (ival->zend.str) {
-                       tmp->ptr = estrndup(ival->zend.str->val, ival->zend.str->len);
-                       *to_free = tmp->ptr;
+                       /*tmp->ptr = estrndup(ival->zend.str->val, ival->zend.str->len);
+                       *to_free = tmp->ptr;*/
+                       tmp->ptr = ival->zend.str->val;
                } else {
                        tmp->ptr = "";
                }
+       } else if (0 && Z_TYPE_P(zvalue) == IS_STRING) {
+               tmp->ptr = Z_STRVAL_P(zvalue);
        } else {
                zend_string *zs = zval_get_string(zvalue);
                tmp->ptr = estrdup(zs->val);
@@ -290,7 +294,7 @@ impl_val *psi_let_strlen(impl_val *tmp, decl_type *spec, token_t impl_type, impl
 static impl_val *iterate(impl_val *val, size_t size, unsigned i, impl_val *tmp)
 {
        memset(tmp, 0, sizeof(*tmp));
-       memcpy(tmp, ((void*) val) + size * i, size);
+       memcpy(tmp, ((char *) val) + size * i, size);
        return tmp;
 }
 
@@ -472,7 +476,7 @@ void psi_to_array(zval *return_value, set_value *set, impl_val *r_val)
                /* to_array(foo[NUMBER]) */
                for (i = 0; i < var->arg->var->array_size; ++i) {
                        size_t size = psi_t_size(var->arg->var->pointer_level > 1 ? PSI_T_POINTER : t);
-                       impl_val *ptr = iterate(ret_val, size, i, &tmp);
+                       impl_val *ptr = iterate(ret_val->ptr, size, i, &tmp);
                        zval ele;
 
                        switch (t) {
@@ -520,10 +524,13 @@ void psi_to_array(zval *return_value, set_value *set, impl_val *r_val)
        }
 }
 
-impl_val *psi_let_arrval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+impl_val *psi_let_arrval(impl_val *tmp, decl_type *spec, decl_var *spec_var, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        decl_type *real = real_decl_type(spec);
        HashTable *arr;
+       zval *zv;
+       size_t i, sz;
+       decl_arg tmp_arg = {0};
 
        if (impl_type != PSI_T_ARRAY) {
                SEPARATE_ARG_IF_REF(zvalue);
@@ -538,12 +545,28 @@ impl_val *psi_let_arrval(impl_val *tmp, decl_type *spec, token_t impl_type, impl
        case PSI_T_UNION:
                *to_free = tmp = psi_array_to_union(real->real.unn, arr);
                break;
-       EMPTY_SWITCH_DEFAULT_CASE();
+       default:
+               sz = psi_t_size(real->type);
+               tmp = *to_free = ecalloc(zend_hash_num_elements(arr), sz);
+               tmp_arg.type = spec;
+               tmp_arg.var = spec_var;
+               ZEND_HASH_FOREACH_VAL_IND(arr, zv)
+               {
+                       void *ptr = ((char *) tmp) + (i++ * sz);
+                       psi_from_zval_ex(NULL, (impl_val **) &ptr, &tmp_arg, 0, zv, NULL);
+               }
+               ZEND_HASH_FOREACH_END();
        }
 
        return tmp;
 }
 
+impl_val *psi_let_count(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+{
+       return psi_val_intval(tmp, real_decl_type(spec)->type, psi_zval_count(zvalue));
+}
+
+
 void psi_to_object(zval *return_value, set_value *set, impl_val *r_val)
 {
        decl_var *var = set->vars->vars[0];
index c1d3de8..bf9267d 100644 (file)
@@ -24,15 +24,15 @@ void psi_from_zval_ex(void *cb_ctx, impl_val **ptr, decl_arg *spec, token_t cast
 void *psi_array_to_struct_ex(decl_struct *s, HashTable *arr, psi_marshal_zval cb, void *cb_ctx);
 void *psi_array_to_union_ex(decl_union *u, HashTable *arr, psi_marshal_zval cb, void *cb_ctx);
 
-impl_val *psi_let_void(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_boolval(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_intval(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_floatval(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_strval(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_pathval(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_strlen(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_arrval(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_objval(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_zval(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-
+impl_val *psi_let_void(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_boolval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_intval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_floatval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_strval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_pathval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_strlen(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_arrval(impl_val *tmp, decl_type *spec, decl_var *spec_var, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_objval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_zval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_count(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free);
 #endif
index dcc76e3..48e90ed 100644 (file)
@@ -91,7 +91,7 @@ ssize_t psi_parser_fill(struct psi_parser *P, size_t n)
                }
        }
        if (P->flags & PSI_PARSER_DEBUG) {
-               fprintf(stderr, "PSI> Fill: avail=%zd\n", P->lim - P->cur);
+               fprintf(stderr, "PSI> Fill: avail=%td\n", P->lim - P->cur);
        }
        return P->lim - P->cur;
 }
@@ -171,7 +171,7 @@ token_t psi_parser_scan(struct psi_parser *P)
                W = [a-zA-Z0-9_];
                NAME = [a-zA-Z_]W*;
                NSNAME = (NAME)? ("\\" NAME)+;
-               DOLLAR_NAME = '$' NAME;
+               DOLLAR_NAME = '$' W+;
                QUOTED_STRING = "\"" ([^\"])+ "\"";
                NUMBER = [+-]? [0-9]* "."? [0-9]+ ([eE] [+-]? [0-9]+)?;
 
@@ -243,6 +243,7 @@ token_t psi_parser_scan(struct psi_parser *P)
                'ARRVAL' {RETURN(PSI_T_ARRVAL);}
                'OBJVAL' {RETURN(PSI_T_OBJVAL);}
                'ZVAL' {RETURN(PSI_T_ZVAL);}
+               'COUNT' {RETURN(PSI_T_COUNT);}
                'CALLOC' {RETURN(PSI_T_CALLOC);}
                'TO_OBJECT' {RETURN(PSI_T_TO_OBJECT);}
                'TO_ARRAY' {RETURN(PSI_T_TO_ARRAY);}
index af3ea8a..42106b2 100644 (file)
@@ -4,7 +4,7 @@
 
 #ifdef GENERATE
 #define DEF(dn, dv) dn dv
-#define LET(nt, rule) nt ::= rule.
+#define PASS(nt, rule) nt ::= rule.
 #define PARSE(nt, rule) nt ::= rule.
 #define PARSE_NAMED(nt, nt_name, rule) NAMED(nt, nt_name) ::= rule.
 #define PARSE_TYPED(nt, nt_name, rule) TYPED(nt, nt_name) ::= rule.
 #include "parser.h"
 #endif
 #define DEF(dn, dv)
-#define LET(nt, rule)
+#define PASS(nt, rule) \
+       static void COUNTED(nt) (struct psi_parser *P) { \
+               (void) #rule; \
+       }
 #define PARSE(nt, rule) \
        static void COUNTED(nt) (struct psi_parser *P rule)
 #define PARSE_NAMED(nt, nt_name, rule) \
@@ -28,7 +31,7 @@
 #define TOKEN(t)
 #define NAMED(t, name) , struct psi_token *name
 #define TYPED(t, name) , TOKEN_TYPE_NAME(t) name
-#define TOKEN_TYPE_NAME(token) _##token##_type
+#define TOKEN_TYPE_NAME(token) ##token##_parse_t
 #define TOKEN_TYPE(token, type) typedef type TOKEN_TYPE_NAME(token);
 #define TOKEN_DTOR(token, dtor)
 #endif
@@ -52,15 +55,16 @@ DEF(%syntax_error, {
 
 DEF(%nonassoc, NAME.)
 DEF(%left, PLUS MINUS.)
-DEF(%left, SLASH ASTERISK.)
-DEF(%fallback, NAME TEMP FREE SET LET RETURN CALLOC CALLBACK ZVAL LIB STRING.)
+DEF(%left, ASTERISK SLASH.)
+DEF(%nonassoc, AMPERSAND.)
+DEF(%fallback, NAME TEMP FREE SET LET RETURN CALLOC CALLBACK ZVAL LIB STRING COUNT.)
 
 DEF(%token_class, const_type_token BOOL INT FLOAT STRING.)
 DEF(%token_class, decl_type_token FLOAT DOUBLE INT8 UINT8 INT16 UINT16 INT32 UINT32 INT64 UINT64 NAME.)
 DEF(%token_class, impl_def_val_token NULL NUMBER TRUE FALSE QUOTED_STRING.)
 DEF(%token_class, num_exp_token NUMBER NSNAME.)
 DEF(%token_class, num_exp_op_token PLUS MINUS ASTERISK SLASH.)
-DEF(%token_class, let_func_token ZVAL OBJVAL ARRVAL PATHVAL STRLEN STRVAL FLOATVAL INTVAL BOOLVAL.)
+DEF(%token_class, let_func_token ZVAL OBJVAL ARRVAL PATHVAL STRLEN STRVAL FLOATVAL INTVAL BOOLVAL COUNT.)
 DEF(%token_class, set_func_token TO_OBJECT TO_ARRAY TO_STRING TO_INT TO_FLOAT TO_BOOL ZVAL VOID.)
 DEF(%token_class, impl_type_token VOID MIXED BOOL INT FLOAT STRING ARRAY OBJECT CALLABLE.)
 
@@ -173,12 +177,12 @@ TOKEN_TYPE(reference, char)
 TOKEN_TYPE(indirection, unsigned)
 TOKEN_TYPE(pointers, unsigned)
 
-LET(file, blocks)
-LET(blocks, block)
-LET(blocks, blocks block)
+PASS(file, blocks)
+PASS(blocks, block)
+PASS(blocks, blocks block)
 
-LET(block, EOF)
-LET(block, EOS)
+PASS(block, EOF)
+PASS(block, EOS)
 
 PARSE(block, NAMED(LIB, token) NAMED(QUOTED_STRING, libname) TOKEN(EOS)) {
        if (P->psi.file.ln) {
@@ -537,20 +541,32 @@ PARSE_TYPED(decl_abi, abi,
 }
 
 PARSE_TYPED(decl_var, var,
-               TYPED(indirection, p)
-               NAMED(NAME, T)) {
-       var = init_decl_var(T->text, p, 0);
+               NAMED(NAME, T)
+               NAMED(decl_var_array_size, as)) {
+       var = init_decl_var(T->text, 0, as?atol(as->text):0);
        var->token = T;
+       if (as) {
+               free(as);
+       }
 }
 PARSE_TYPED(decl_var, var,
-               TYPED(indirection, p)
+               TYPED(pointers, p)
                NAMED(NAME, T)
+               NAMED(decl_var_array_size, as)) {
+       var = init_decl_var(T->text, p+!!as, as?atol(as->text):0);
+       var->token = T;
+       if (as) {
+               free(as);
+       }
+}
+PARSE_NAMED(decl_var_array_size, as, ) {
+       as = NULL;
+}
+PARSE_NAMED(decl_var_array_size, as,
                TOKEN(LBRACKET)
                NAMED(NUMBER, D)
                TOKEN(RBRACKET)) {
-       var = init_decl_var(T->text, p+1, atol(D->text));
-       var->token = T;
-       free(D);
+       as = D;
 }
 
 PARSE_TYPED(decl_vars, vars,
@@ -620,8 +636,8 @@ PARSE_TYPED(decl_arg, arg_,
        arg_->token = N;
 }
 
-LET(decl_args, )
-LET(decl_args, VOID)
+PASS(decl_args, )
+PASS(decl_args, VOID)
 PARSE_TYPED(decl_args, args,
                TYPED(decl_arg, arg)) {
        args = init_decl_args(arg);
@@ -965,38 +981,153 @@ PARSE_TYPED(num_exp, exp,
        free(operator_);
 }
 
+TOKEN_TYPE(let_exp, let_val*)
+TOKEN_DTOR(let_exp, free_let_val($$);)
+
+TOKEN_TYPE(let_callback, let_callback*)
+TOKEN_DTOR(let_callback, free_let_callback($$);)
+
+/*
+ * let_val: NULL
+ */
+PARSE_TYPED(let_val, val,
+               TOKEN(NULL)) {
+       val = init_let_val(PSI_LET_NULL, NULL);
+}
+/*
+ * let_val: &NULL
+ */
+PARSE_TYPED(let_val, val,
+               TOKEN(AMPERSAND)
+               TOKEN(NULL)) {
+       val = init_let_val(PSI_LET_NULL, NULL);
+       val->is_reference = 1;
+}
+/*
+ * let_val: callback
+ */
+PARSE_TYPED(let_val, val,
+               TYPED(let_callback, cb)) {
+       val = init_let_val(PSI_LET_CALLBACK, cb);
+}
+/*
+ * let_val: calloc
+ */
+PARSE_TYPED(let_val, val,
+               TYPED(let_calloc, ca)) {
+       val = init_let_val(PSI_LET_CALLOC, ca);
+}
+/*
+ * let_val: &calloc
+ */
+PARSE_TYPED(let_val, val,
+               TOKEN(AMPERSAND)
+               TYPED(let_calloc, ca)) {
+       val = init_let_val(PSI_LET_CALLOC, ca);
+       val->is_reference = 1;
+}
+/*
+ * let_val: func
+ */
+PARSE_TYPED(let_val, val,
+               TYPED(let_func, fn)) {
+       val = init_let_val_ex(NULL, PSI_LET_FUNC, fn);
+}
+/*
+ * let_val: &func
+ */
+PARSE_TYPED(let_val, val,
+               TOKEN(AMPERSAND)
+               TYPED(let_func, fn)) {
+       val = init_let_val_ex(NULL, PSI_LET_FUNC, fn);
+       val->is_reference = 1;
+}
+/*
+ * let_val: 1234
+ */
+PARSE_TYPED(let_val, val,
+               TYPED(num_exp, exp)) {
+       val = init_let_val_ex(NULL, PSI_LET_NUMEXP, exp);
+}
+/*
+ * let_val: &1234
+ */
+PARSE_TYPED(let_val, val,
+               TOKEN(AMPERSAND)
+               TYPED(num_exp, exp)) {
+       val = init_let_val_ex(NULL, PSI_LET_NUMEXP, exp);
+       val->is_reference = 1;
+}
+
+/*
+ * let_exp: var = val
+ */
+PARSE_TYPED(let_exp, exp,
+               TYPED(decl_var, var_)
+               TOKEN(EQUALS)
+               TYPED(let_val, val)) {
+       exp = val;
+       exp->var = var_;
+}
+
+/*
+ * let_stmt: LET exp ;
+ */
 PARSE_TYPED(let_stmt, let,
-               TOKEN(LET)
-               TYPED(decl_var, var)
+               NAMED(LET, T)
+               TYPED(let_exp, val)
                TOKEN(EOS)) {
-       let = init_let_stmt(var, init_let_val(PSI_LET_NULL, NULL));
+       let = init_let_stmt(val);
+       let->token = T;
 }
+
+/*
+ * let_stmt: TEMP foo = bar ;
+ */
 PARSE_TYPED(let_stmt, let,
-               TOKEN(LET)
+               NAMED(TEMP, T)
                TYPED(decl_var, var)
                TOKEN(EQUALS)
                TYPED(reference, r)
-               TYPED(let_val, val)
+               TYPED(decl_var, val_)
                TOKEN(EOS)) {
-       val->flags.one.is_reference = r ? 1 : 0;
-       let = init_let_stmt(var, val);
+       let = init_let_stmt(init_let_val_ex(var, PSI_LET_TMP, val_));
+       let->token = T;
+       let->val->is_reference = r ? 1 : 0;
 }
-PARSE_TYPED(let_stmt, let,
-               TOKEN(TEMP)
-               TYPED(decl_var, var)
-               TOKEN(EQUALS)
-               TYPED(decl_var, val)
-               TOKEN(EOS)) {
-       let = init_let_stmt(var, init_let_val(PSI_LET_TMP, val));
+
+/*
+ * let_callback: CALLBACK cast($var($args))
+ */
+PARSE_TYPED(let_callback, cb,
+               TOKEN(CALLBACK)
+               NAMED(callback_rval, F)
+               TOKEN(LPAREN)
+               TYPED(impl_var, var)
+               TOKEN(LPAREN)
+               TYPED(callback_arg_list, args_)
+               TOKEN(RPAREN)
+               TOKEN(RPAREN)) {
+       cb = init_let_callback(init_let_func(F->type, F->text, var), args_);
+       free(F);
 }
 
+/*
+ * let_calloc: CALLOC ( num_exp nmemb , num_exp size )
+ */
 PARSE_TYPED(let_calloc, alloc,
+               TOKEN(CALLOC)
+               TOKEN(LPAREN)
                TYPED(num_exp, nmemb)
                TOKEN(COMMA)
-               TYPED(num_exp, size)) {
+               TYPED(num_exp, size)
+               TOKEN(RPAREN)) {
        alloc = init_let_calloc(nmemb, size);
 }
 
+/*
+ * let_func: FUNC ( $var )
+ */
 PARSE_TYPED(let_func, func,
                NAMED(let_func_token, T)
                TOKEN(LPAREN)
@@ -1005,18 +1136,9 @@ PARSE_TYPED(let_func, func,
        func = init_let_func(T->type, T->text, var);
        free(T);
 }
-
-PARSE_TYPED(let_vals, vals,
-               TYPED(let_val, val)) {
-       vals = init_let_vals(val);
-}
-PARSE_TYPED(let_vals, vals,
-               TYPED(let_vals, vals_)
-               TOKEN(COMMA)
-               TYPED(let_val, val)) {
-       vals = add_let_val(vals_, val);
-}
-
+/*
+ * let_func: FUNC ( $var (,exps)? )
+ */
 PARSE_TYPED(let_func, func,
                NAMED(let_func_token, T)
                TOKEN(LPAREN)
@@ -1028,8 +1150,34 @@ PARSE_TYPED(let_func, func,
        func->inner = vals;
        free(T);
 }
+/*
+ * let_vals: exps = exp
+ */
+PARSE_TYPED(let_vals, vals,
+               TYPED(let_exp, val)) {
+       vals = init_let_vals(val);
+}
+PARSE_TYPED(let_vals, vals,
+               TYPED(let_val, val)) {
+       vals = init_let_vals(val);
+}
+/*
+ * let_vals: exps = exps, exp
+ */
+PARSE_TYPED(let_vals, vals,
+               TYPED(let_vals, vals_)
+               TOKEN(COMMA)
+               TYPED(let_exp, val)) {
+       vals = add_let_val(vals_, val);
+}
+PARSE_TYPED(let_vals, vals,
+               TYPED(let_vals, vals_)
+               TOKEN(COMMA)
+               TYPED(let_val, val)) {
+       vals = add_let_val(vals_, val);
+}
 
-LET(callback_arg_list, )
+PASS(callback_arg_list, )
 PARSE_TYPED(callback_arg_list, args,
                TYPED(callback_args, args_)) {
        args = args_;
@@ -1054,39 +1202,6 @@ PARSE_NAMED(callback_rval, rval,
        rval = V;
 }
 
-PARSE_TYPED(let_val, val,
-               TOKEN(NULL)) {
-       val = init_let_val(PSI_LET_NULL, NULL);
-}
-PARSE_TYPED(let_val, val,
-               TYPED(num_exp, exp)) {
-       val = init_let_val(PSI_LET_NUMEXP, exp);
-}
-PARSE_TYPED(let_val, val,
-               TOKEN(CALLOC)
-               TOKEN(LPAREN)
-               TYPED(let_calloc, alloc)
-               TOKEN(RPAREN)) {
-       val = init_let_val(PSI_LET_CALLOC, alloc);
-}
-PARSE_TYPED(let_val, val,
-               TYPED(let_func, func_)) {
-       val = init_let_val(PSI_LET_FUNC, func_);
-}
-PARSE_TYPED(let_val, val,
-               TOKEN(CALLBACK)
-               NAMED(callback_rval, F)
-               TOKEN(LPAREN)
-               TYPED(impl_var, var)
-               TOKEN(LPAREN)
-               TYPED(callback_arg_list, args_)
-               TOKEN(RPAREN)
-               TOKEN(RPAREN)) {
-       val = init_let_val(PSI_LET_CALLBACK, init_let_callback(
-               init_let_func(F->type, F->text, var), args_));
-       free(F);
-}
-
 PARSE_TYPED(set_stmt, set,
                TOKEN(SET)
                TYPED(impl_var, var)
index 2acef5a..ff30cc1 100644 (file)
@@ -1,77 +1,78 @@
 #define PSI_T_NAME                             1
 #define PSI_T_PLUS                             2
 #define PSI_T_MINUS                            3
-#define PSI_T_SLASH                            4
-#define PSI_T_ASTERISK                         5
-#define PSI_T_TEMP                             6
-#define PSI_T_FREE                             7
-#define PSI_T_SET                              8
-#define PSI_T_LET                              9
-#define PSI_T_RETURN                          10
-#define PSI_T_CALLOC                          11
-#define PSI_T_CALLBACK                        12
-#define PSI_T_ZVAL                            13
-#define PSI_T_LIB                             14
-#define PSI_T_STRING                          15
-#define PSI_T_BOOL                            16
-#define PSI_T_INT                             17
-#define PSI_T_FLOAT                           18
-#define PSI_T_DOUBLE                          19
-#define PSI_T_INT8                            20
-#define PSI_T_UINT8                           21
-#define PSI_T_INT16                           22
-#define PSI_T_UINT16                          23
-#define PSI_T_INT32                           24
-#define PSI_T_UINT32                          25
-#define PSI_T_INT64                           26
-#define PSI_T_UINT64                          27
-#define PSI_T_NULL                            28
-#define PSI_T_NUMBER                          29
-#define PSI_T_TRUE                            30
-#define PSI_T_FALSE                           31
-#define PSI_T_QUOTED_STRING                   32
-#define PSI_T_NSNAME                          33
-#define PSI_T_OBJVAL                          34
-#define PSI_T_ARRVAL                          35
-#define PSI_T_PATHVAL                         36
-#define PSI_T_STRLEN                          37
-#define PSI_T_STRVAL                          38
-#define PSI_T_FLOATVAL                        39
-#define PSI_T_INTVAL                          40
-#define PSI_T_BOOLVAL                         41
-#define PSI_T_TO_OBJECT                       42
-#define PSI_T_TO_ARRAY                        43
-#define PSI_T_TO_STRING                       44
-#define PSI_T_TO_INT                          45
-#define PSI_T_TO_FLOAT                        46
-#define PSI_T_TO_BOOL                         47
-#define PSI_T_VOID                            48
-#define PSI_T_MIXED                           49
-#define PSI_T_ARRAY                           50
-#define PSI_T_OBJECT                          51
-#define PSI_T_CALLABLE                        52
-#define PSI_T_EOF                             53
-#define PSI_T_EOS                             54
-#define PSI_T_ENUM                            55
-#define PSI_T_LBRACE                          56
-#define PSI_T_RBRACE                          57
-#define PSI_T_COMMA                           58
-#define PSI_T_EQUALS                          59
-#define PSI_T_UNION                           60
-#define PSI_T_STRUCT                          61
-#define PSI_T_COLON                           62
-#define PSI_T_LPAREN                          63
-#define PSI_T_RPAREN                          64
-#define PSI_T_CONST                           65
-#define PSI_T_TYPEDEF                         66
-#define PSI_T_LBRACKET                        67
-#define PSI_T_RBRACKET                        68
-#define PSI_T_ELLIPSIS                        69
-#define PSI_T_CHAR                            70
-#define PSI_T_SHORT                           71
-#define PSI_T_LONG                            72
-#define PSI_T_UNSIGNED                        73
-#define PSI_T_SIGNED                          74
-#define PSI_T_FUNCTION                        75
-#define PSI_T_DOLLAR_NAME                     76
-#define PSI_T_AMPERSAND                       77
+#define PSI_T_ASTERISK                         4
+#define PSI_T_SLASH                            5
+#define PSI_T_AMPERSAND                        6
+#define PSI_T_TEMP                             7
+#define PSI_T_FREE                             8
+#define PSI_T_SET                              9
+#define PSI_T_LET                             10
+#define PSI_T_RETURN                          11
+#define PSI_T_CALLOC                          12
+#define PSI_T_CALLBACK                        13
+#define PSI_T_ZVAL                            14
+#define PSI_T_LIB                             15
+#define PSI_T_STRING                          16
+#define PSI_T_COUNT                           17
+#define PSI_T_BOOL                            18
+#define PSI_T_INT                             19
+#define PSI_T_FLOAT                           20
+#define PSI_T_DOUBLE                          21
+#define PSI_T_INT8                            22
+#define PSI_T_UINT8                           23
+#define PSI_T_INT16                           24
+#define PSI_T_UINT16                          25
+#define PSI_T_INT32                           26
+#define PSI_T_UINT32                          27
+#define PSI_T_INT64                           28
+#define PSI_T_UINT64                          29
+#define PSI_T_NULL                            30
+#define PSI_T_NUMBER                          31
+#define PSI_T_TRUE                            32
+#define PSI_T_FALSE                           33
+#define PSI_T_QUOTED_STRING                   34
+#define PSI_T_NSNAME                          35
+#define PSI_T_OBJVAL                          36
+#define PSI_T_ARRVAL                          37
+#define PSI_T_PATHVAL                         38
+#define PSI_T_STRLEN                          39
+#define PSI_T_STRVAL                          40
+#define PSI_T_FLOATVAL                        41
+#define PSI_T_INTVAL                          42
+#define PSI_T_BOOLVAL                         43
+#define PSI_T_TO_OBJECT                       44
+#define PSI_T_TO_ARRAY                        45
+#define PSI_T_TO_STRING                       46
+#define PSI_T_TO_INT                          47
+#define PSI_T_TO_FLOAT                        48
+#define PSI_T_TO_BOOL                         49
+#define PSI_T_VOID                            50
+#define PSI_T_MIXED                           51
+#define PSI_T_ARRAY                           52
+#define PSI_T_OBJECT                          53
+#define PSI_T_CALLABLE                        54
+#define PSI_T_EOF                             55
+#define PSI_T_EOS                             56
+#define PSI_T_ENUM                            57
+#define PSI_T_LBRACE                          58
+#define PSI_T_RBRACE                          59
+#define PSI_T_COMMA                           60
+#define PSI_T_EQUALS                          61
+#define PSI_T_UNION                           62
+#define PSI_T_STRUCT                          63
+#define PSI_T_COLON                           64
+#define PSI_T_LPAREN                          65
+#define PSI_T_RPAREN                          66
+#define PSI_T_CONST                           67
+#define PSI_T_TYPEDEF                         68
+#define PSI_T_LBRACKET                        69
+#define PSI_T_RBRACKET                        70
+#define PSI_T_ELLIPSIS                        71
+#define PSI_T_CHAR                            72
+#define PSI_T_SHORT                           73
+#define PSI_T_LONG                            74
+#define PSI_T_UNSIGNED                        75
+#define PSI_T_SIGNED                          76
+#define PSI_T_FUNCTION                        77
+#define PSI_T_DOLLAR_NAME                     78
index 5813b42..a5696b5 100644 (file)
 %syntax_error { ++P->errors; if (TOKEN && TOKEN->type != PSI_T_EOF) { psi_error(PSI_WARNING, TOKEN->file, TOKEN->line, "PSI syntax error: Unexpected token '%s' at pos %u", TOKEN->text, TOKEN->col); } else { psi_error(PSI_WARNING, P->psi.file.fn, P->line, "PSI syntax error: Unexpected end of input"); } }
 %nonassoc NAME.
 %left PLUS MINUS.
-%left SLASH ASTERISK.
-%fallback NAME TEMP FREE SET LET RETURN CALLOC CALLBACK ZVAL LIB STRING.
+%left ASTERISK SLASH.
+%nonassoc AMPERSAND.
+%fallback NAME TEMP FREE SET LET RETURN CALLOC CALLBACK ZVAL LIB STRING COUNT.
 %token_class const_type_token BOOL INT FLOAT STRING.
 %token_class decl_type_token FLOAT DOUBLE INT8 UINT8 INT16 UINT16 INT32 UINT32 INT64 UINT64 NAME.
 %token_class impl_def_val_token NULL NUMBER TRUE FALSE QUOTED_STRING.
 %token_class num_exp_token NUMBER NSNAME.
 %token_class num_exp_op_token PLUS MINUS ASTERISK SLASH.
-%token_class let_func_token ZVAL OBJVAL ARRVAL PATHVAL STRLEN STRVAL FLOATVAL INTVAL BOOLVAL.
+%token_class let_func_token ZVAL OBJVAL ARRVAL PATHVAL STRLEN STRVAL FLOATVAL INTVAL BOOLVAL COUNT.
 %token_class set_func_token TO_OBJECT TO_ARRAY TO_STRING TO_INT TO_FLOAT TO_BOOL ZVAL VOID.
 %token_class impl_type_token VOID MIXED BOOL INT FLOAT STRING ARRAY OBJECT CALLABLE.
 %type decl_enum {decl_enum *}
@@ -376,14 +377,25 @@ decl_abi(abi) ::= NAME(T). {
  abi = init_decl_abi(T->text);
  abi->token = T;
 }
-decl_var(var) ::= indirection(p) NAME(T). {
- var = init_decl_var(T->text, p, 0);
+decl_var(var) ::= NAME(T) decl_var_array_size(as). {
+ var = init_decl_var(T->text, 0, as?atol(as->text):0);
  var->token = T;
+ if (as) {
+  free(as);
+ }
 }
-decl_var(var) ::= indirection(p) NAME(T) LBRACKET NUMBER(D) RBRACKET. {
- var = init_decl_var(T->text, p+1, atol(D->text));
+decl_var(var) ::= pointers(p) NAME(T) decl_var_array_size(as). {
+ var = init_decl_var(T->text, p+!!as, as?atol(as->text):0);
  var->token = T;
- free(D);
+ if (as) {
+  free(as);
+ }
+}
+decl_var_array_size(as) ::= . {
+ as = NULL;
+}
+decl_var_array_size(as) ::= LBRACKET NUMBER(D) RBRACKET. {
+ as = D;
 }
 decl_vars(vars) ::= decl_var(var). {
  vars = init_decl_vars(var);
@@ -652,33 +664,81 @@ num_exp(exp) ::= num_exp(exp_) num_exp_op_token(operator_) num_exp(operand_). {
  exp = exp_;
  free(operator_);
 }
-let_stmt(let) ::= LET decl_var(var) EOS. {
- let = init_let_stmt(var, init_let_val(PSI_LET_NULL, NULL));
+%type let_exp {let_val*}
+%destructor let_exp {free_let_val($$);}
+%type let_callback {let_callback*}
+%destructor let_callback {free_let_callback($$);}
+let_val(val) ::= NULL. {
+ val = init_let_val(PSI_LET_NULL, NULL);
+}
+let_val(val) ::= AMPERSAND NULL. {
+ val = init_let_val(PSI_LET_NULL, NULL);
+ val->is_reference = 1;
+}
+let_val(val) ::= let_callback(cb). {
+ val = init_let_val(PSI_LET_CALLBACK, cb);
+}
+let_val(val) ::= let_calloc(ca). {
+ val = init_let_val(PSI_LET_CALLOC, ca);
+}
+let_val(val) ::= AMPERSAND let_calloc(ca). {
+ val = init_let_val(PSI_LET_CALLOC, ca);
+ val->is_reference = 1;
 }
-let_stmt(let) ::= LET decl_var(var) EQUALS reference(r) let_val(val) EOS. {
- val->flags.one.is_reference = r ? 1 : 0;
- let = init_let_stmt(var, val);
+let_val(val) ::= let_func(fn). {
+ val = init_let_val_ex(NULL, PSI_LET_FUNC, fn);
 }
-let_stmt(let) ::= TEMP decl_var(var) EQUALS decl_var(val) EOS. {
- let = init_let_stmt(var, init_let_val(PSI_LET_TMP, val));
+let_val(val) ::= AMPERSAND let_func(fn). {
+ val = init_let_val_ex(NULL, PSI_LET_FUNC, fn);
+ val->is_reference = 1;
 }
-let_calloc(alloc) ::= num_exp(nmemb) COMMA num_exp(size). {
+let_val(val) ::= num_exp(exp). {
+ val = init_let_val_ex(NULL, PSI_LET_NUMEXP, exp);
+}
+let_val(val) ::= AMPERSAND num_exp(exp). {
+ val = init_let_val_ex(NULL, PSI_LET_NUMEXP, exp);
+ val->is_reference = 1;
+}
+let_exp(exp) ::= decl_var(var_) EQUALS let_val(val). {
+ exp = val;
+ exp->var = var_;
+}
+let_stmt(let) ::= LET(T) let_exp(val) EOS. {
+ let = init_let_stmt(val);
+ let->token = T;
+}
+let_stmt(let) ::= TEMP(T) decl_var(var) EQUALS reference(r) decl_var(val_) EOS. {
+ let = init_let_stmt(init_let_val_ex(var, PSI_LET_TMP, val_));
+ let->token = T;
+ let->val->is_reference = r ? 1 : 0;
+}
+let_callback(cb) ::= CALLBACK callback_rval(F) LPAREN impl_var(var) LPAREN callback_arg_list(args_) RPAREN RPAREN. {
+ cb = init_let_callback(init_let_func(F->type, F->text, var), args_);
+ free(F);
+}
+let_calloc(alloc) ::= CALLOC LPAREN num_exp(nmemb) COMMA num_exp(size) RPAREN. {
  alloc = init_let_calloc(nmemb, size);
 }
 let_func(func) ::= let_func_token(T) LPAREN impl_var(var) RPAREN. {
  func = init_let_func(T->type, T->text, var);
  free(T);
 }
+let_func(func) ::= let_func_token(T) LPAREN impl_var(var) COMMA let_vals(vals) RPAREN. {
+ func = init_let_func(T->type, T->text, var);
+ func->inner = vals;
+ free(T);
+}
+let_vals(vals) ::= let_exp(val). {
+ vals = init_let_vals(val);
+}
 let_vals(vals) ::= let_val(val). {
  vals = init_let_vals(val);
 }
-let_vals(vals) ::= let_vals(vals_) COMMA let_val(val). {
+let_vals(vals) ::= let_vals(vals_) COMMA let_exp(val). {
  vals = add_let_val(vals_, val);
 }
-let_func(func) ::= let_func_token(T) LPAREN impl_var(var) COMMA let_vals(vals) RPAREN. {
- func = init_let_func(T->type, T->text, var);
- func->inner = vals;
- free(T);
+let_vals(vals) ::= let_vals(vals_) COMMA let_val(val). {
+ vals = add_let_val(vals_, val);
 }
 callback_arg_list ::= .
 callback_arg_list(args) ::= callback_args(args_). {
@@ -696,23 +756,6 @@ callback_rval(rval) ::= let_func_token(F). {
 callback_rval(rval) ::= VOID(V). {
  rval = V;
 }
-let_val(val) ::= NULL. {
- val = init_let_val(PSI_LET_NULL, NULL);
-}
-let_val(val) ::= num_exp(exp). {
- val = init_let_val(PSI_LET_NUMEXP, exp);
-}
-let_val(val) ::= CALLOC LPAREN let_calloc(alloc) RPAREN. {
- val = init_let_val(PSI_LET_CALLOC, alloc);
-}
-let_val(val) ::= let_func(func_). {
- val = init_let_val(PSI_LET_FUNC, func_);
-}
-let_val(val) ::= CALLBACK callback_rval(F) LPAREN impl_var(var) LPAREN callback_arg_list(args_) RPAREN RPAREN. {
- val = init_let_val(PSI_LET_CALLBACK, init_let_callback(
-  init_let_func(F->type, F->text, var), args_));
- free(F);
-}
 set_stmt(set) ::= SET impl_var(var) EQUALS set_value(val) EOS. {
  set = init_set_stmt(var, val);
 }
index 7c4c896..97f00d4 100644 (file)
@@ -57,7 +57,7 @@
 static inline impl_val *deref_impl_val(impl_val *ret_val, decl_var *var) {
        unsigned i;
 
-       ZEND_ASSERT(var->arg->var != var);
+       ZEND_ASSERT(!var->arg || var->arg->var != var);
 #if 0
        fprintf(stderr, "deref: %s pl=%u:%u as=%u:%u %p\n",
                        var->name, var->pointer_level, var->arg->var->pointer_level,
index eda2303..ef6bd6d 100644 (file)
 # include "php_config.h"
 #endif
 
+#if __GNUC__ >= 5
+# pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
+#endif
 #include "php_psi_macros.h"
 #include "php_psi_redirs.h"
+#if __GNUC__ >= 5
+# pragma GCC diagnostic pop
+#endif
 
 #include <stdlib.h>
 #include <stdio.h>
index 8e5f9e6..c7b19b6 100644 (file)
@@ -71,6 +71,23 @@ decl_args *extract_decl_type_args(decl_type *dtyp, decl_type **real_typ_ptr) {
        }
 }
 
+size_t extract_decl_type_size(decl_type *dtyp, decl_type **real_typ_ptr) {
+       decl_type *var_typ;
+       var_typ = real_decl_type(dtyp);
+       if (real_typ_ptr) {
+               *real_typ_ptr = var_typ;
+       }
+       switch (var_typ->type) {
+       case PSI_T_STRUCT:
+               return var_typ->real.strct->size;
+       case PSI_T_UNION:
+               return var_typ->real.unn->size;
+       default:
+               return psi_t_size(var_typ->type);
+       }
+}
+
+
 
 int locate_decl_type_alias(decl_typedefs *defs, decl_type *type) {
        size_t i;
@@ -244,7 +261,7 @@ int weak_decl_type(decl_type *type) {
 }
 
 decl_type *real_decl_type(decl_type *type) {
-       while (weak_decl_type(type)) {
+       while (weak_decl_type(type) && type->real.def) {
                type = type->real.def->type;
        }
        return type;
index d7c01fb..4f88ef9 100644 (file)
@@ -49,6 +49,8 @@ void free_decl_type(decl_type *type);
 void dump_decl_type(int fd, decl_type *t, unsigned level);
 
 struct decl_args *extract_decl_type_args(decl_type *dtyp, decl_type** real_typ_ptr);
+size_t extract_decl_type_size(decl_type *dtyp, decl_type **real_typ_ptr);
+
 int weak_decl_type(decl_type *type);
 decl_type *real_decl_type(decl_type *type);
 
index 4c5809c..e1a6ac9 100644 (file)
@@ -52,10 +52,6 @@ int validate_let_callback(struct psi_data *data, decl_var *cb_var, let_callback
        decl *cb_func;
        decl_type *cb_type = real_decl_type(cb_var->arg->type);
 
-       if (!validate_let_func(data, cb->func, cb_var, impl)) {
-               return 0;
-       }
-
        if (cb_type->type != PSI_T_FUNCTION) {
                data->error(data, cb_var->token, PSI_WARNING, "Not a function: %s", cb_var->name);
                return 0;
index d32b00b..42180ec 100644 (file)
@@ -83,6 +83,7 @@ static inline int validate_let_func_type(struct psi_data *data, let_func *func,
        case PSI_T_OBJVAL:
        case PSI_T_ZVAL:
        case PSI_T_VOID:
+       case PSI_T_COUNT:
                return 1;
        default:
                data->error(data, func->var->token, PSI_WARNING,
@@ -92,44 +93,66 @@ static inline int validate_let_func_type(struct psi_data *data, let_func *func,
        }
 }
 
-static inline int validate_let_func_inner(struct psi_data *data, let_func *func, decl_var *let_var, impl *impl) {
+static inline int validate_let_func_inner(struct psi_data *data, let_val *val, let_func *func, decl_var *let_var, impl *impl) {
+
        if (func->inner) {
                size_t i;
                decl_type *var_typ;
                decl_args *sub_args = extract_decl_type_args(let_var->arg->type, &var_typ);
 
-               if (!sub_args) {
-                       data->error(data, let_var->token, PSI_WARNING,
-                                       "Inner let statement's values must refer to a structure type,"
-                                       " got '%s' for '%s'",
-                                       var_typ->name, let_var->name);
-                       return 0;
-               }
-
-               for (i = 0; i < func->inner->count; ++i) {
-                       let_val *inner = func->inner->vals[i];
-                       let_val *outer = func->outer;
-                       const char *name = locate_let_val_varname(inner);
-                       decl_arg *sub_arg;
-
-                       if (name) {
-                               sub_arg = locate_decl_arg(sub_args, name);
+               if (func->type == PSI_T_ARRVAL && sub_args) {
+                       /* struct = arrval($array,
+                        *      member = strval($member) ...)
+                        */
+                       size_t i;
+
+                       for (i = 0; i < func->inner->count; ++i) {
+                               let_val *inner = func->inner->vals[i];
+                               const char *name = locate_let_val_varname(inner);
+                               let_func *fn = locate_let_val_func(inner);
+                               decl_arg *sub_arg;
+
+                               if (name) {
+                                       sub_arg = locate_decl_arg(sub_args, name);
+                               }
+                               if (!name || !sub_arg) {
+                                       data->error(data, let_var->token, PSI_WARNING,
+                                                       "Unknown variable '%s'", name);
+                                       return 0;
+                               }
+
+                               fn->outer = val;
+                               fn->ref = sub_arg;
+
+                               if (!validate_let_val(data, inner, sub_arg->var, impl)) {
+                                       return 0;
+                               }
                        }
-                       if (!name || !sub_arg) {
-                               data->error(data, let_var->token, PSI_WARNING,
-                                               "Unknown variable '%s' of '%s'",
-                                               name, var_typ->real.strct->name);
+               } else if (func->type == PSI_T_ARRVAL && func->inner->count == 1 && let_var->arg->var->pointer_level) {
+                       /* array = arrval($array,
+                        *      strval($array)) // cast foreach entry
+                        */
+                       impl_var *sub_var = locate_let_val_impl_var(val);
+                       impl_var *sub_ref = locate_let_val_impl_var(func->inner->vals[0]);
+
+                       if (strcmp(sub_var->name, sub_ref->name)) {
+                               data->error(data, sub_var->token, E_WARNING, "Inner `set` statement casts on pointers must reference the same variable");
                                return 0;
                        }
-                       if (!validate_let_val(data, inner, sub_arg->var, impl)) {
+                       if (!validate_let_val(data, func->inner->vals[0], let_var, impl)) {
                                return 0;
                        }
+               } else {
+                       data->error(data, let_var->token, PSI_WARNING,
+                                       "Inner let statement's values must refer to a structure or array type, got '%s%s' for '%s'",
+                                       var_typ->name, psi_t_indirection(let_var->arg->var->pointer_level), let_var->name);
+                       return 0;
                }
        }
        return 1;
 }
 
-int validate_let_func(struct psi_data *data, let_func *func, decl_var *let_var, impl *impl) {
+int validate_let_func(struct psi_data *data, let_val *val, let_func *func, decl_var *let_var, impl *impl) {
        if (func->outer) {
 
        }
@@ -147,7 +170,7 @@ int validate_let_func(struct psi_data *data, let_func *func, decl_var *let_var,
        if (!validate_let_func_type(data, func, impl)) {
                return 0;
        }
-       if (!validate_let_func_inner(data, func, let_var, impl)) {
+       if (!validate_let_func_inner(data, val, func, let_var, impl)) {
                return 0;
        }
        return 1;
index b02d20c..936c38d 100644 (file)
@@ -46,7 +46,8 @@ void dump_let_func(int fd, let_func *func, unsigned level);
 
 struct psi_data;
 struct impl;
+struct let_val;
 
-int validate_let_func(struct psi_data *data, let_func *func, decl_var *let_var, struct impl *impl);
+int validate_let_func(struct psi_data *data, struct let_val *val, let_func *func, decl_var *let_var, struct impl *impl);
 
 #endif
index db24d10..5474ae2 100644 (file)
 
 #include "data.h"
 
-let_stmt *init_let_stmt(decl_var *var, let_val *val) {
+let_stmt *init_let_stmt(let_val *val) {
        let_stmt *let = calloc(1, sizeof(*let));
-       let->var = var;
        let->val = val;
+
        return let;
 }
 
 void free_let_stmt(let_stmt *stmt) {
        if (stmt->val) {
-               if (stmt->val->kind == PSI_LET_TMP && stmt->var->arg) {
-                       free_decl_arg(stmt->var->arg);
-               }
                free_let_val(stmt->val);
        }
-       free_decl_var(stmt->var);
+       if (stmt->token) {
+               free(stmt->token);
+       }
        free(stmt);
 }
 
 void dump_let_stmt(int fd, let_stmt *let) {
-       dprintf(fd, "\tlet %s", let->var->name);
-       if (let->val) {
-               dprintf(fd, " = ");
-               dump_let_val(fd, let->val, 1, 1);
-       }
+       dprintf(fd, "\t%s ", let->val->kind == PSI_LET_TMP ? "temp" : "let");
+       dump_let_val(fd, let->val, 1, 1);
 }
 
 int validate_let_stmts(struct psi_data *data, impl *impl) {
@@ -73,7 +69,7 @@ int validate_let_stmts(struct psi_data *data, impl *impl) {
                if (let->val && let->val->kind == PSI_LET_TMP) {
                        let_var = let->val->data.var;
                } else {
-                       let_var = let->var;
+                       let_var = let->val->var;
                }
 
                if (!locate_decl_var_arg(let_var, impl->decl->args, impl->decl->func)) {
@@ -97,7 +93,7 @@ int validate_let_stmts(struct psi_data *data, impl *impl) {
                        return 0;
                }
 
-               if (!validate_let_val(data, let->val, let->var, impl)) {
+               if (!validate_let_val(data, let->val, let->val->var, impl)) {
                        return 0;
                }
        }
@@ -109,7 +105,7 @@ int validate_let_stmts(struct psi_data *data, impl *impl) {
                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)) {
+                       if (!strcmp(let->val->var->name, darg->var->name)) {
                                check = 1;
                                break;
                        }
index 1ffd56e..3b6ab3c 100644 (file)
 #include "let_val.h"
 
 typedef struct let_stmt {
-       decl_var *var;
+       struct psi_token *token;
        let_val *val;
 } let_stmt;
 
-let_stmt *init_let_stmt(decl_var *var, let_val *val);
+let_stmt *init_let_stmt(let_val *val);
 void free_let_stmt(let_stmt *stmt);
 void dump_let_stmt(int fd, let_stmt *let);
 
index 3be8e88..23b3afc 100644 (file)
 
 #include "data.h"
 
+let_val *init_let_val_ex(decl_var *var, enum let_val_kind kind, void *data) {
+       let_val *val = init_let_val(kind, data);
+       val->var = var;
+       return val;
+}
+
 let_val *init_let_val(enum let_val_kind kind, void *data) {
        let_val *let = calloc(1, sizeof(*let));
        switch (let->kind = kind) {
        case PSI_LET_NULL:
+               assert(!data);
                break;
        case PSI_LET_NUMEXP:
                let->data.num = data;
@@ -78,11 +85,17 @@ void free_let_val(let_val *let) {
                free_let_func(let->data.func);
                break;
        case PSI_LET_TMP:
+               if (let->var->arg) {
+                       free_decl_arg(let->var->arg);
+               }
                free_decl_var(let->data.var);
                break;
        default:
                assert(0);
        }
+       if (let->var) {
+               free_decl_var(let->var);
+       }
        free(let);
 }
 
@@ -92,7 +105,13 @@ void dump_let_val(int fd, let_val *val, unsigned level, int last) {
                dprintf(fd, "%s", psi_t_indent(level));
        }
 
-       dprintf(fd, "%s", val->flags.one.is_reference ? "&" : "");
+       if (val->var) {
+               dump_decl_var(fd, val->var);
+               dprintf(fd, " = ");
+       }
+       if (val->is_reference) {
+               dprintf(fd, "&");
+       }
 
        switch (val->kind) {
        case PSI_LET_NULL:
@@ -152,7 +171,7 @@ int validate_let_val(struct psi_data *data, let_val *val, decl_var *let_var, imp
        case PSI_LET_TMP:
                if (!let_var) {
                        data->error(data, NULL, PSI_WARNING,
-                                       "Ivalid let statement value of implementation '%s'",
+                                       "Ivalid temp statement value of implementation '%s'",
                                        impl->func->name);
                        return 0;
                }
@@ -188,85 +207,15 @@ int validate_let_val(struct psi_data *data, let_val *val, decl_var *let_var, imp
                                        impl->func->name);
                        return 0;
                }
-               if (val->data.callback->func->inner) {
-                       size_t i;
-                       decl_type *var_typ = real_decl_type(let_var->arg->type);
-                       decl_args *sub_args;
-
-                       switch (var_typ->type) {
-                       case PSI_T_STRUCT:
-                               sub_args = var_typ->real.strct->args;
-                               break;
-                       case PSI_T_UNION:
-                               sub_args = var_typ->real.unn->args;
-                               break;
-                       default:
-                               data->error(data, let_var->token, PSI_WARNING,
-                                               "Inner let statement's values must refer to a structure type, got '%s' for '%s'",
-                                               real_decl_type(let_var->arg->type)->name, let_var->name);
-                               return 0;
-                       }
-                       for (i = 0; i < val->data.callback->func->inner->count; ++i) {
-                               let_val *inner = val->data.callback->func->inner->vals[i];
-                               switch (inner->kind) {
-                               case PSI_LET_FUNC:
-                                       inner->data.func->outer = val;
-                                       inner->data.func->ref = locate_decl_arg(sub_args,
-                                                       &inner->data.func->var->name[1]);
-                                       break;
-
-                                       break;
-                               case PSI_LET_CALLBACK:
-                                       inner->data.callback->func->outer = val;
-                                       inner->data.callback->func->ref = locate_decl_arg(sub_args,
-                                                       &inner->data.callback->func->var->name[1]);
-                                       break;
-                               }
-                       }
+               if (!validate_let_func(data, val, val->data.callback->func, let_var, impl)) {
+                       return 0;
                }
                if (!validate_let_callback(data, let_var, val->data.callback, impl)) {
                        return 0;
                }
                break;
        case PSI_LET_FUNC:
-               if (val->data.func->inner) {
-                       size_t i;
-                       decl_type *var_typ = real_decl_type(let_var->arg->type);
-                       decl_args *sub_args;
-
-                       switch (var_typ->type) {
-                       case PSI_T_STRUCT:
-                               sub_args = var_typ->real.strct->args;
-                               break;
-                       case PSI_T_UNION:
-                               sub_args = var_typ->real.unn->args;
-                               break;
-                       default:
-                               data->error(data, let_var->token, PSI_WARNING,
-                                               "Inner let statement's values must refer to a structure type, got '%s' for '%s'",
-                                               real_decl_type(let_var->arg->type)->name, let_var->name);
-                               return 0;
-                       }
-                       for (i = 0; i < val->data.func->inner->count; ++i) {
-                               let_val *inner = val->data.func->inner->vals[i];
-                               switch (inner->kind) {
-                               case PSI_LET_FUNC:
-                                       inner->data.func->outer = val;
-                                       inner->data.func->ref = locate_decl_arg(sub_args,
-                                                       &inner->data.func->var->name[1]);
-                                       break;
-                               case PSI_LET_CALLBACK:
-                                       inner->data.callback->func->outer = val;
-                                       inner->data.callback->func->ref = locate_decl_arg(sub_args,
-                                                       &inner->data.callback->func->var->name[1]);
-                                       break;
-                               }
-                       }
-               }
-
-               val->data.func->var;
-
-               if (!validate_let_func(data, val->data.func, let_var, impl)) {
+               if (!validate_let_func(data, val, val->data.func, let_var, impl)) {
                        return 0;
                }
                break;
index c3b5f38..c741633 100644 (file)
@@ -53,15 +53,12 @@ typedef struct let_val {
                let_func *func;
                decl_var *var;
        } data;
-       union {
-               struct {
-                       unsigned is_reference:1;
-               } one;
-               unsigned all;
-       } flags;
+       unsigned is_reference:1;
 } let_val;
 
+
 let_val* init_let_val(enum let_val_kind kind, void* data);
+let_val* init_let_val_ex(decl_var *var, enum let_val_kind kind, void* data);
 void free_let_val(let_val* let);
 void dump_let_val(int fd, let_val *val, unsigned level, int last);
 
@@ -70,42 +67,43 @@ struct impl;
 
 int validate_let_val(struct psi_data *data, let_val *val, decl_var *let_var, struct impl *impl);
 
-static inline decl_arg *locate_let_val_inner_ref(let_val *val) {
-       decl_arg *ref = NULL;
-
-       switch (val->kind) {
-       case PSI_LET_CALLBACK:
-               ref = val->data.callback->func->ref;
-               break;
-       case PSI_LET_FUNC:
-               ref = val->data.func->ref;
-               break;
-       default:
-               break;
-       }
-       return ref;
-}
-static inline impl_var *locate_let_val_impl_var(let_val *val) {
+static inline let_func *locate_let_val_func(let_val *val) {
        if (val) {
                switch (val->kind) {
                case PSI_LET_CALLBACK:
-                       return val->data.callback->func->var;
+                       return val->data.callback->func;
                case PSI_LET_FUNC:
-                       return val->data.func->var;
+                       return val->data.func;
                default:
                        break;
                }
        }
+
        return NULL;
 }
 
+static inline decl_arg *locate_let_val_inner_ref(let_val *val) {
+       let_func *fn = locate_let_val_func(val);
+       return fn ? fn->ref: NULL;
+}
+
+static inline impl_var *locate_let_val_impl_var(let_val *val) {
+       let_func *fn = locate_let_val_func(val);
+       return fn ? fn->var : NULL;
+}
+
 static inline const char *locate_let_val_varname(let_val *val) {
-       impl_var *var = locate_let_val_impl_var(val);
+       impl_var *var;
+
+       if (val->var) {
+               return val->var->name;
+       }
+
+       var = locate_let_val_impl_var(val);
 
        if (var) {
                return &var->name[1];
        }
        return NULL;
 }
-
 #endif
index 442ba59..01b1d84 100644 (file)
@@ -37,4 +37,18 @@ let_vals *init_let_vals(struct let_val *val);
 let_vals *add_let_val(let_vals *vals, struct let_val *val);
 void free_let_vals(let_vals *vals);
 
+static inline let_val *locate_let_vals_val(let_vals *vals, const char *name) {
+       size_t i;
+
+       for (i = 0; i < vals->count; ++i) {
+               let_val *val = vals->vals[i];
+               const char *var = locate_let_val_varname(val);
+
+               if (!strcmp(var, name)) {
+                       return val;
+               }
+       }
+
+       return NULL;
+}
 #endif
index ad67340..8827063 100644 (file)
@@ -100,9 +100,9 @@ int validate_set_stmts(struct psi_data *data, impl *impl) {
 
                                        /* check temp vars */
                                        if (let->val && let->val->kind == PSI_LET_TMP) {
-                                               if (!strcmp(set_var->name, let->var->name)) {
+                                               if (!strcmp(set_var->name, let->val->var->name)) {
                                                        check = 1;
-                                                       set_var->arg = let->var->arg;
+                                                       set_var->arg = let->val->var->arg;
                                                        if (!validate_set_value(data, set->val, 1, &set_var->arg, 1, &impl->decl->func, impl->decl->args->count, impl->decl->args->args, 0)) {
                                                                return 0;
                                                        }
diff --git a/tests/getopt/getopt001.phpt b/tests/getopt/getopt001.phpt
new file mode 100644 (file)
index 0000000..462b470
--- /dev/null
@@ -0,0 +1,80 @@
+--TEST--
+getopt
+--INI--
+psi.directory={PWD}:{PWD}/../../psi.d
+--SKIPIF--
+<?php 
+extension_loaded("psi") or die("skip - need ext/psi");
+function_exists("psi\\div") or die("skip - need psi\\div()");
+?>
+--ENV--
+POSIXLY_CORRECT=
+--FILE--
+===TEST===
+<?php
+
+$args = [
+       "progname", "huh", "-v", "-x", 1, "-s", "foo", "--", "-gotcha", "--bar", "baz"
+];
+
+$opts = "v::x:s:";
+
+while (($opt = chr(psi\getopt($args, $opts)))) {
+       switch ($opt) {
+       case "v":
+               printf("got v\n");
+               break;
+       case "x":
+       case "s":
+               printf("got %s: %s\n", $opt, psi\optarg());
+               break;
+       default: 
+               printf("error '%s'\n", $opt);
+       case chr(-1):
+               break 2;
+       }
+}
+
+$pos = psi\optind();
+while ($pos < count($args)) {
+       printf("arg: %s\n", $args[$pos++]);
+}
+
+var_dump($args);
+
+?>
+===DONE===
+--EXPECT--
+===TEST===
+got v
+got x: 1
+got s: foo
+arg: huh
+arg: -gotcha
+arg: --bar
+arg: baz
+array(11) {
+  [0]=>
+  string(8) "progname"
+  [1]=>
+  string(2) "-v"
+  [2]=>
+  string(2) "-x"
+  [3]=>
+  string(1) "1"
+  [4]=>
+  string(2) "-s"
+  [5]=>
+  string(3) "foo"
+  [6]=>
+  string(2) "--"
+  [7]=>
+  string(3) "huh"
+  [8]=>
+  string(7) "-gotcha"
+  [9]=>
+  string(5) "--bar"
+  [10]=>
+  string(3) "baz"
+}
+===DONE===
index 139f446..fd132a9 100644 (file)
@@ -5,15 +5,15 @@ function psi\dbm_open(string $file, int $open_flags, int $file_mode) : object {
        return to_object(dbm_open);
 }
 
-function psi\dbm_store(object $db, array $key, array $data, int $mode) : int {
+function psi\dbm_store(object $db, string $key, string $data, int $mode) : int {
        let db = objval($db);
        let key = arrval($key,
-               strval($dptr),
-               intval($dsize)
+               dptr = strval($0),
+               dsize = strlen($0)
        );
        let content = arrval($data,
-               strval($dptr),
-               intval($dsize)
+               dptr = strval($0),
+               dsize = strlen($0)
        );
        let store_mode = intval($mode);
        return to_int(dbm_store);
@@ -22,8 +22,8 @@ function psi\dbm_store(object $db, array $key, array $data, int $mode) : int {
 function psi\dbm_fetch(object $db, array $key) : array {
        let db = objval($db);
        let key = arrval($key,
-               strval($dptr),
-               intval($dsize)
+               dptr = strval($dptr),
+               dsize = intval($dsize)
        );
        return to_array(dbm_fetch,
                to_string(dptr, dsize),
index 2914bac..403bdc3 100644 (file)
@@ -24,13 +24,7 @@ class db {
        }
 
        function __set($k, $v) {
-               return psi\dbm_store($this->db, [
-                               "dptr" => $k,
-                               "dsize" => strlen($k)
-                       ], [
-                               "dptr" => $v,
-                               "dsize" => strlen($v)
-                       ], psi\DBM_REPLACE);
+               return psi\dbm_store($this->db, $k, $v, psi\DBM_REPLACE);
        }
 
        function __get($k) {
index 378db8d..4cb8b2d 100644 (file)
@@ -7,6 +7,7 @@ extension_loaded("psi") or die("skip - need ext/psi");
 --FILE--
 ===TEST===
 <?php 
+
 function validate($check, $psi) {
        $file = __DIR__."/001.psi";
        file_put_contents($file, $psi);
@@ -96,4 +97,6 @@ Warning: Cannot compute size of empty struct 'a' in %s001.psi on line 1
 Warning: Unknown variable 'X' in numeric expression in %s001.psi on line 4
 
 Warning: PSI syntax error: Unexpected token '(' at pos 26 in %s001.psi on line 1
+
+Warning: PSI syntax error: Unexpected token '(' at pos 32 in %s001.psi on line 1
 ===DONE===