flush
authorMichael Wallner <mike@php.net>
Tue, 22 Dec 2015 14:43:29 +0000 (15:43 +0100)
committerMichael Wallner <mike@php.net>
Tue, 22 Dec 2015 14:43:29 +0000 (15:43 +0100)
src/context.c
src/module.c
src/parser.h
src/parser.re
src/parser_proc.h
src/parser_proc.y
tests/iconv/iconv.psi [new file with mode: 0644]
tests/iconv/iconv001.phpt [new file with mode: 0644]
tests/iconv/iconv002.phpt [new file with mode: 0644]

index 709c6b4..ef9cc40 100644 (file)
@@ -543,8 +543,9 @@ static inline int validate_set_value_ex(PSI_Data *data, set_value *set, decl_arg
        }
 
        for (i = 0; i < set->vars->count; ++i) {
-               if (!locate_decl_var_arg(set->vars->vars[i], ref_list, NULL)) {
-                       data->error(PSI_WARNING, "Unknown variable '%s'", set->vars->vars[i]->name);
+               decl_var *svar = set->vars->vars[i];
+               if (!svar->arg && !locate_decl_var_arg(svar, ref_list, NULL)) {
+                       data->error(PSI_WARNING, "Unknown variable '%s'", svar->name);
                        return 0;
                }
        }
@@ -671,15 +672,70 @@ static inline int validate_impl_ret_stmt(PSI_Data *data, impl *impl) {
 static inline int validate_impl_let_stmts(PSI_Data *data, impl *impl) {
        size_t i, j;
        /* we can have multiple let stmts */
+
        /* check that we have a decl arg for every let stmt */
        for (i = 0; i < impl->stmts->let.count; ++i) {
                let_stmt *let = impl->stmts->let.list[i];
+               decl_var *let_var;
+               int check = 0;
 
-               if (!locate_decl_var_arg(let->var, impl->decl->args, impl->decl->func)) {
+               if (let->val && let->val->kind == PSI_LET_TMP) {
+                       let_var = let->val->data.var;
+               } else {
+                       let_var = let->var;
+               }
+
+               if (!locate_decl_var_arg(let_var, impl->decl->args, impl->decl->func)) {
                        data->error(PSI_WARNING, "Unknown variable '%s' in `let` statement"
-                                       " of implementation '%s'", let->var->name, impl->func->name);
+                                       " of implementation '%s'", let_var->name, impl->func->name);
                        return 0;
                }
+
+               switch (let->val->kind) {
+               case PSI_LET_NULL:
+                       break;
+               case PSI_LET_TMP:
+                       /* e.g. let bar = &strval($bar); // decl_arg(char **bar) */
+                       /* e.g. let foo = *bar;  */
+                       let->var->pointer_level = let->val->data.var->pointer_level;
+                       let->var->arg = init_decl_arg(
+                                       init_decl_type(real_decl_type(let->val->data.var->arg->type)->type,
+                                                       real_decl_type(let->val->data.var->arg->type)->name),
+                                                       init_decl_var(let->var->name, let->var->pointer_level, let->var->array_size));
+                       break;
+               case PSI_LET_NUMEXP:
+                       if (!validate_num_exp(data, impl->decl->args, impl->decl->func, let->val->data.num)) {
+                               return 0;
+                       }
+                       break;
+               case PSI_LET_CALLOC:
+                       if (!validate_num_exp(data, impl->decl->args, impl->decl->func, let->val->data.alloc->nmemb)) {
+                               return 0;
+                       }
+                       if (!validate_num_exp(data, impl->decl->args, impl->decl->func, let->val->data.alloc->size)) {
+                               return 0;
+                       }
+                       break;
+               case PSI_LET_FUNC:
+                       if (impl->func->args) {
+                               for (j = 0; j < impl->func->args->count; ++j) {
+                                       impl_arg *iarg = impl->func->args->args[j];
+
+                                       if (!strcmp(let->val->data.func->var->name, iarg->var->name)) {
+                                               let->val->data.func->arg = iarg;
+                                               check = 1;
+                                               break;
+                                       }
+                               }
+                       }
+                       if (!check) {
+                               data->error(PSI_WARNING, "Unknown value '$%s' of `let` statement"
+                                               " for variable '%s' of implementation '%s'",
+                                               let->val->data.func->var->name, let->var->name, impl->func->name);
+                               return 0;
+                       }
+                       break;
+               }
        }
 
        /* check that we have a let stmt for every decl arg */
@@ -704,42 +760,7 @@ static inline int validate_impl_let_stmts(PSI_Data *data, impl *impl) {
                        return 0;
                }
        }
-       /* check that the let_value references a known variable or NULL */
-       for (i = 0; i < impl->stmts->let.count; ++i) {
-               let_stmt *let = impl->stmts->let.list[i];
-               int check = 0;
 
-               if (let->val && let->val->func && let->val->func->alloc) {
-                       if (!validate_num_exp(data, impl->decl->args, impl->decl->func, let->val->func->alloc->nmemb)) {
-                               return 0;
-                       }
-                       if (!validate_num_exp(data, impl->decl->args, impl->decl->func, let->val->func->alloc->size)) {
-                               return 0;
-                       }
-               }
-               if (let->val && let->val->var) {
-                       if (impl->func->args) for (j = 0; j < impl->func->args->count; ++j) {
-                               impl_arg *iarg = impl->func->args->args[j];
-
-                               if (!strcmp(let->val->var->name, iarg->var->name)) {
-                                       let->arg = iarg;
-                                       check = 1;
-                                       break;
-                               }
-                       }
-                       if (!check) {
-                               data->error(PSI_WARNING, "Unknown value '$%s' of `let` statement"
-                                               " for variable '%s' of implementation '%s'",
-                                               let->val->var->name, let->var->name, impl->func->name);
-                               return 0;
-                       }
-               }
-               if (let->val && let->val->num) {
-                       if (!validate_num_exp(data, impl->decl->args, impl->decl->func, let->val->num)) {
-                               return 0;
-                       }
-               }
-       }
        return 1;
 }
 static inline int validate_impl_set_stmts(PSI_Data *data, impl *impl) {
@@ -770,16 +791,35 @@ static inline int validate_impl_set_stmts(PSI_Data *data, impl *impl) {
                        decl_var *set_var = set->val->vars->vars[j];
 
                        check = 0;
-                       if (impl->decl->args) for (k = 0; k < impl->decl->args->count; ++k) {
-                               decl_arg *set_arg = impl->decl->args->args[k];
-
-                               if (!strcmp(set_var->name, set_arg->var->name)) {
-                                       check = 1;
-                                       set_var->arg = set_arg;
-                                       if (!validate_set_value(data, set->val, 1, &set_arg, 1, &impl->decl->func, impl->decl->args->count, impl->decl->args->args, 0)) {
-                                               return 0;
+                       if (impl->decl->args) {
+                               for (k = 0; k < impl->decl->args->count; ++k) {
+                                       decl_arg *set_arg = impl->decl->args->args[k];
+
+                                       if (!strcmp(set_var->name, set_arg->var->name)) {
+                                               check = 1;
+                                               set_var->arg = set_arg;
+                                               if (!validate_set_value(data, set->val, 1, &set_arg, 1, &impl->decl->func, impl->decl->args->count, impl->decl->args->args, 0)) {
+                                                       return 0;
+                                               }
+                                               break;
+                                       }
+                               }
+                       }
+                       if (!check) {
+                               for (k = 0; k < impl->stmts->let.count; ++k) {
+                                       let_stmt *let = impl->stmts->let.list[k];
+
+                                       /* check temp vars */
+                                       if (let->val && let->val->kind == PSI_LET_TMP) {
+                                               if (!strcmp(set_var->name, let->var->name)) {
+                                                       check = 1;
+                                                       set_var->arg = let->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;
+                                                       }
+                                                       break;
+                                               }
                                        }
-                                       break;
                                }
                        }
 
@@ -1363,20 +1403,29 @@ void PSI_ContextDump(PSI_Context *C, int fd)
 
                                        dprintf(fd, "\tlet %s", let->var->name);
                                        if (let->val) {
-                                               dprintf(fd, " = %s", let->val->is_reference ? "&" : "");
-                                               if (let->val->func) {
-                                                       dprintf(fd, "%s(", let->val->func->name);
-                                                       if (let->val->func->alloc) {
-                                                               dump_num_exp(fd, let->val->func->alloc->nmemb);
-                                                               dprintf(fd, ", ");
-                                                               dump_num_exp(fd, let->val->func->alloc->size);
-                                                       } else {
-                                                               dprintf(fd, "$%s", let->val->var->name);
-                                                       }
-                                                       dprintf(fd, ");\n");
-                                               } else {
-                                                       dprintf(fd, "NULL;\n");
+                                               dprintf(fd, " = %s", let->val->flags.one.is_reference ? "&" : "");
+                                               switch (let->val->kind) {
+                                               case PSI_LET_NULL:
+                                                       dprintf(fd, "NULL");
+                                                       break;
+                                               case PSI_LET_TMP:
+                                                       dump_decl_var(fd, let->val->data.var);
+                                                       break;
+                                               case PSI_LET_CALLOC:
+                                                       dprintf(fd, "calloc(");
+                                                       dump_num_exp(fd, let->val->data.alloc->nmemb);
+                                                       dprintf(fd, ", ");
+                                                       dump_num_exp(fd, let->val->data.alloc->size);
+                                                       dprintf(fd, ")");
+                                                       break;
+                                               case PSI_LET_FUNC:
+                                                       dprintf(fd, "%s($%s)", let->val->data.func->name,
+                                                                       let->val->data.func->var->name);
+                                                       break;
+
+                                               EMPTY_SWITCH_DEFAULT_CASE();
                                                }
+                                               dprintf(fd, ";\n");
                                        }
                                }
                                for (j = 0; j < impl->stmts->ret.count; ++j) {
index 9d97a3e..bde40a4 100644 (file)
@@ -373,6 +373,10 @@ void psi_to_array(zval *return_value, set_value *set, impl_val *r_val)
        token_t t = real_decl_type(var->arg->type)->type;
        impl_val tmp, *ret_val = deref_impl_val(r_val, var);
 
+       if ((intptr_t) ret_val->ptr <= (intptr_t) 0) {
+               RETURN_NULL();
+       }
+
        array_init(return_value);
 
        if (t == PSI_T_STRUCT) {
@@ -425,38 +429,6 @@ void psi_to_array(zval *return_value, set_value *set, impl_val *r_val)
                        add_next_index_zval(return_value, &ele);
                }
                return;
-       } else if (set->vars->count > 1) {
-               /* to_array(arr_var, cnt_var[, cnt_var...], to_int(*arr_var))
-                * check for length in second var
-                * /
-               size_t count = 0;
-               zval ele;
-
-               if (set->outer.set) {
-                       / * struct *//*
-                       for (i = 1; i < set->vars->count; ++i) {
-                               impl_val *tmp = NULL, *cnt_val;
-                               decl_var *cnt_var = set->vars->vars[i];
-
-                               cnt_val = struct_member_ref(cnt_var->arg, set->outer.val, &tmp);
-                               count += deref_impl_val(cnt_val, cnt_var)->lval;
-
-                               if (tmp) {
-                                       free(tmp);
-                               }
-                       }
-               } else {
-                       ZEND_ASSERT(0);
-               }
-
-               for (i = 0; i < count; ++i) {
-                       size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t);
-                       impl_val *ptr = iterate(ret_val, size, i, &tmp);
-
-                       set->inner[0]->func->handler(&ele, set->inner[0], ptr);
-                       add_next_index_zval(return_value, &ele);
-               }
-               */
        } else if (set->num) {
                /* to_array(arr_var, num_expr, to_int(*arr_var))
                 */
@@ -481,7 +453,7 @@ void psi_to_object(zval *return_value, set_value *set, impl_val *r_val)
        impl_val *ret_val = deref_impl_val(r_val, var);
        psi_object *obj;
 
-       if (ret_val->ptr) {
+       if ((intptr_t) ret_val->ptr > (intptr_t) 0) {
                object_init_ex(return_value, psi_class_entry);
                obj = PSI_OBJ(return_value, NULL);
                obj->data = ret_val->ptr;
@@ -507,39 +479,6 @@ static inline ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, i
                return rv;
        }
 
-       /* set up defaults */
-       for (i = 0; i < impl->func->args->count; ++i) {
-               iarg = impl->func->args->args[i];
-
-               if (i < EX_NUM_ARGS()) {
-                       iarg->_zv = ++zarg;
-                       ZVAL_DEREF(iarg->_zv);
-//                     if (iarg->var->reference) {
-//                             zval_dtor(iarg->_zv);
-//                             ZVAL_NULL(iarg->_zv);
-//                     }
-               }
-
-               if (iarg->def) {
-                       switch (iarg->type->type) {
-                       case PSI_T_BOOL:
-                               iarg->val.zend.bval = iarg->def->type == PSI_T_TRUE ? 1 : 0;
-                               break;
-                       case PSI_T_INT:
-                               iarg->val.zend.lval = zend_atol(iarg->def->text, strlen(iarg->def->text));
-                               break;
-                       case PSI_T_FLOAT:
-                       case PSI_T_DOUBLE:
-                               iarg->val.dval = zend_strtod(iarg->def->text, NULL);
-                               break;
-                       case PSI_T_STRING:
-                               /* FIXME */
-                               iarg->val.zend.str = zend_string_init(&iarg->def->text[1], strlen(iarg->def->text) - 2, 0);
-                               break;
-                       }
-               }
-       }
-
        ZEND_PARSE_PARAMETERS_START(psi_num_min_args(impl), impl->func->args->count)
        nextarg:
                iarg = impl->func->args->args[_i];
@@ -547,25 +486,15 @@ static inline ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, i
                        Z_PARAM_OPTIONAL;
                }
                if (PSI_T_BOOL == iarg->type->type) {
-                       if (iarg->def) {
-                               iarg->val.zend.bval = iarg->def->type == PSI_T_TRUE ? 1 : 0;
-                       }
                        Z_PARAM_BOOL(iarg->val.zend.bval);
                } else if (PSI_T_INT == iarg->type->type) {
-                       if (iarg->def) {
-                               iarg->val.zend.lval = zend_atol(iarg->def->text, strlen(iarg->def->text));
-                       }
                        Z_PARAM_LONG(iarg->val.zend.lval);
                } else if (PSI_T_FLOAT == iarg->type->type || PSI_T_DOUBLE == iarg->type->type) {
-                       if (iarg->def) {
-                               iarg->val.dval = zend_strtod(iarg->def->text, NULL);
-                       }
                        Z_PARAM_DOUBLE(iarg->val.dval);
                } else if (PSI_T_STRING == iarg->type->type) {
-                       zend_string *str = iarg->val.zend.str;
                        Z_PARAM_STR_EX(iarg->val.zend.str, 1, iarg->var->reference);
-                       if (str && str != iarg->val.zend.str) {
-                               zend_string_release(str);
+                       if (iarg->val.zend.str) {
+                               zend_string_addref(iarg->val.zend.str);
                        }
                } else if (PSI_T_ARRAY == iarg->type->type) {
                        Z_PARAM_PROLOGUE(0);
@@ -583,6 +512,33 @@ static inline ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, i
                return FAILURE
        );
 
+       /* set up defaults */
+       for (i = 0; i < impl->func->args->count; ++i) {
+               iarg = impl->func->args->args[i];
+
+               if (i < EX_NUM_ARGS()) {
+                       iarg->_zv = ++zarg;
+                       ZVAL_DEREF(iarg->_zv);
+               } else if (iarg->def) {
+                       switch (iarg->type->type) {
+                       case PSI_T_BOOL:
+                               iarg->val.zend.bval = iarg->def->type == PSI_T_TRUE ? 1 : 0;
+                               break;
+                       case PSI_T_INT:
+                               iarg->val.zend.lval = zend_atol(iarg->def->text, strlen(iarg->def->text));
+                               break;
+                       case PSI_T_FLOAT:
+                       case PSI_T_DOUBLE:
+                               iarg->val.dval = zend_strtod(iarg->def->text, NULL);
+                               break;
+                       case PSI_T_STRING:
+                               /* FIXME */
+                               iarg->val.zend.str = zend_string_init(&iarg->def->text[1], strlen(iarg->def->text) - 2, 0);
+                               break;
+                       }
+               }
+       }
+
        zend_restore_error_handling(&zeh);
        return SUCCESS;
 }
@@ -599,24 +555,31 @@ static inline void *psi_do_let(let_stmt *let)
 {
        decl_arg *darg = let->var->arg;
        impl_val *arg_val = darg->ptr;
+       impl_arg *iarg;
 
-       if (!let->val) {
+       switch (let->val ? let->val->kind : PSI_LET_NULL) {
+       case PSI_LET_TMP:
+               arg_val->ptr = deref_impl_val(let->val->data.var->arg->val.ptr, let->var);
+               break;
+       case PSI_LET_NULL:
                if (darg->var->array_size) {
                        arg_val->ptr = ecalloc(darg->var->array_size, sizeof(*arg_val));
                        darg->mem = arg_val->ptr;
                } else {
                        memset(arg_val, 0, sizeof(*arg_val));
                }
-       } else if (let->val->num) {
-               arg_val->zend.lval = psi_long_num_exp(darg->let->val->num, NULL);
-       } else {
-               impl_arg *iarg = darg->let->arg;
+               break;
+       case PSI_LET_CALLOC:
+               arg_val->ptr = psi_do_calloc(let->val->data.alloc);
+               darg->mem = arg_val->ptr;
+               break;
+       case PSI_LET_NUMEXP:
+               arg_val->zend.lval = psi_long_num_exp(let->val->data.num, NULL);
+               break;
+       case PSI_LET_FUNC:
+               iarg = let->val->data.func->arg;
 
-               switch (let->val->func->type) {
-               case PSI_T_CALLOC:
-                       arg_val->ptr = psi_do_calloc(let->val->func->alloc);
-                       darg->mem = arg_val->ptr;
-                       break;
+               switch (let->val->data.func->type) {
                case PSI_T_BOOLVAL:
                        if (iarg->type->type == PSI_T_BOOL) {
                                arg_val->cval = iarg->val.zend.bval;
@@ -634,16 +597,19 @@ static inline void *psi_do_let(let_stmt *let)
                case PSI_T_PATHVAL:
                case PSI_T_STRVAL:
                        if (iarg->type->type == PSI_T_STRING) {
-                               arg_val->ptr = estrdup(iarg->val.zend.str->val);
-                               darg->mem = arg_val->ptr;
-                               zend_string_release(iarg->val.zend.str);
+                               if (iarg->val.zend.str) {
+                                       arg_val->ptr = estrdup(iarg->val.zend.str->val);
+                                       darg->mem = arg_val->ptr;
+                               } else {
+                                       arg_val->ptr = "";
+                               }
                        } else {
                                zend_string *zs = zval_get_string(iarg->_zv);
                                arg_val->ptr = estrdup(zs->val);
                                darg->mem = arg_val->ptr;
                                zend_string_release(zs);
                        }
-                       if (PSI_T_PATHVAL == darg->let->val->func->type) {
+                       if (PSI_T_PATHVAL == darg->let->val->data.func->type) {
                                if (SUCCESS != php_check_open_basedir(arg_val->ptr)) {
                                        efree(arg_val->ptr);
                                        return NULL;
@@ -652,8 +618,11 @@ static inline void *psi_do_let(let_stmt *let)
                        break;
                case PSI_T_STRLEN:
                        if (iarg->type->type == PSI_T_STRING) {
-                               arg_val->lval = iarg->val.zend.str->len;
-                               zend_string_release(iarg->val.zend.str);
+                               if (iarg->val.zend.str) {
+                                       arg_val->lval = iarg->val.zend.str->len;
+                               } else {
+                                       arg_val->lval = 0;
+                               }
                        } else {
                                zend_string *zs = zval_get_string(iarg->_zv);
                                arg_val->lval = zs->len;
@@ -688,10 +657,10 @@ static inline void *psi_do_let(let_stmt *let)
                }
        }
 
-       if (darg->let->val && darg->let->val->is_reference) {
-               return darg->let->ptr = &darg->ptr;
+       if (let->val && let->val->flags.one.is_reference) {
+               return let->ptr = &darg->ptr;
        } else {
-               return darg->let->ptr = darg->ptr;
+               return let->ptr = darg->ptr;
        }
 }
 
index 0bac3ef..796705d 100644 (file)
@@ -617,58 +617,98 @@ static inline void free_let_calloc(let_calloc *alloc) {
 typedef struct let_func {
        token_t type;
        char *name;
-       let_calloc *alloc;
+       impl_var *var;
+       impl_arg *arg;
 } let_func;
 
-static inline let_func *init_let_func(token_t type, const char *name, let_calloc *alloc) {
+static inline let_func *init_let_func(token_t type, const char *name, impl_var *var) {
        let_func *func = calloc(1, sizeof(*func));
        func->type = type;
        func->name = strdup(name);
-       func->alloc = alloc;
+       func->var = var;
        return func;
 }
 
 static inline void free_let_func(let_func *func) {
-       if (func->alloc) {
-               free_let_calloc(func->alloc);
-       }
+       free_impl_var(func->var);
        free(func->name);
        free(func);
 }
 
-typedef struct let_value {
-       let_func *func;
-       impl_var *var;
-       num_exp *num;
-       unsigned is_reference:1;
-} let_value;
-
-static inline let_value *init_let_value(let_func *func, impl_var *var, int is_reference) {
-       let_value *val = calloc(1, sizeof(*val));
-       val->is_reference = is_reference;
-       val->func = func;
-       val->var = var;
-       return val;
+#define PSI_LET_REFERENCE 0x1;
+typedef struct let_val {
+       enum let_val_kind {
+               PSI_LET_NULL,
+               PSI_LET_NUMEXP,
+               PSI_LET_CALLOC,
+               PSI_LET_FUNC,
+               PSI_LET_TMP,
+       } kind;
+       union {
+               num_exp *num;
+               let_calloc *alloc;
+               let_func *func;
+               decl_var *var;
+       } data;
+       union {
+               struct {
+                       unsigned is_reference:1;
+               } one;
+               unsigned all;
+       } flags;
+} let_val;
+
+static inline 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:
+               break;
+       case PSI_LET_NUMEXP:
+               let->data.num = data;
+               break;
+       case PSI_LET_CALLOC:
+               let->data.alloc = data;
+               break;
+       case PSI_LET_FUNC:
+               let->data.func = data;
+               break;
+       case PSI_LET_TMP:
+               let->data.var = data;
+               break;
+       EMPTY_SWITCH_DEFAULT_CASE();
+       }
+       return let;
 }
 
-static inline void free_let_value(let_value *val) {
-       if (val->func) {
-               free_let_func(val->func);
-       }
-       if (val->var) {
-               free_impl_var(val->var);
+static inline void free_let_val(let_val *let) {
+       switch (let->kind) {
+       case PSI_LET_NULL:
+               break;
+       case PSI_LET_NUMEXP:
+               free_num_exp(let->data.num);
+               break;
+       case PSI_LET_CALLOC:
+               free_let_calloc(let->data.alloc);
+               break;
+       case PSI_LET_FUNC:
+               free_let_func(let->data.func);
+               break;
+       case PSI_LET_TMP:
+               free_decl_var(let->data.var);
+               break;
+       EMPTY_SWITCH_DEFAULT_CASE();
        }
-       free(val);
+       free(let);
 }
 
 typedef struct let_stmt {
        decl_var *var;
-       let_value *val;
-       impl_arg *arg;
+       let_val *val;
+
        void *ptr;
 } let_stmt;
 
-static inline let_stmt *init_let_stmt(decl_var *var, let_value *val) {
+static inline let_stmt *init_let_stmt(decl_var *var, let_val *val) {
        let_stmt *let = calloc(1, sizeof(*let));
        let->var = var;
        let->val = val;
@@ -678,7 +718,7 @@ static inline let_stmt *init_let_stmt(decl_var *var, let_value *val) {
 static inline void free_let_stmt(let_stmt *stmt) {
        free_decl_var(stmt->var);
        if (stmt->val) {
-               free_let_value(stmt->val);
+               free_let_val(stmt->val);
        }
        free(stmt);
 }
index d5a0f8e..affe901 100644 (file)
@@ -216,6 +216,7 @@ token_t PSI_ParserScan(PSI_Parser *P)
                'SET' {RETURN(PSI_T_SET);}
                'RETURN' {RETURN(PSI_T_RETURN);}
                'FREE' {RETURN(PSI_T_FREE);}
+               'TEMP' {RETURN(PSI_T_TEMP);}
                'STRLEN' {RETURN(PSI_T_STRLEN);}
                'STRVAL' {RETURN(PSI_T_STRVAL);}
                'PATHVAL' {RETURN(PSI_T_PATHVAL);}
index 615581d..64cfe82 100644 (file)
@@ -3,64 +3,65 @@
 #define PSI_T_MINUS                            3
 #define PSI_T_SLASH                            4
 #define PSI_T_ASTERISK                         5
-#define PSI_T_FREE                             6
-#define PSI_T_SET                              7
-#define PSI_T_LET                              8
-#define PSI_T_RETURN                           9
-#define PSI_T_LIB                             10
-#define PSI_T_INT                             11
-#define PSI_T_UNSIGNED                        12
-#define PSI_T_EOF                             13
-#define PSI_T_QUOTED_STRING                   14
-#define PSI_T_EOS                             15
-#define PSI_T_STRUCT                          16
-#define PSI_T_LBRACE                          17
-#define PSI_T_RBRACE                          18
-#define PSI_T_COLON                           19
-#define PSI_T_LPAREN                          20
-#define PSI_T_NUMBER                          21
-#define PSI_T_RPAREN                          22
-#define PSI_T_BOOL                            23
-#define PSI_T_FLOAT                           24
-#define PSI_T_STRING                          25
-#define PSI_T_CONST                           26
-#define PSI_T_NSNAME                          27
-#define PSI_T_EQUALS                          28
-#define PSI_T_TYPEDEF                         29
-#define PSI_T_VOID                            30
-#define PSI_T_LBRACKET                        31
-#define PSI_T_RBRACKET                        32
-#define PSI_T_COMMA                           33
-#define PSI_T_DOUBLE                          34
-#define PSI_T_INT8                            35
-#define PSI_T_UINT8                           36
-#define PSI_T_INT16                           37
-#define PSI_T_UINT16                          38
-#define PSI_T_INT32                           39
-#define PSI_T_UINT32                          40
-#define PSI_T_INT64                           41
-#define PSI_T_UINT64                          42
-#define PSI_T_FUNCTION                        43
-#define PSI_T_AMPERSAND                       44
-#define PSI_T_NULL                            45
-#define PSI_T_TRUE                            46
-#define PSI_T_FALSE                           47
-#define PSI_T_DOLLAR                          48
-#define PSI_T_CALLOC                          49
-#define PSI_T_OBJVAL                          50
-#define PSI_T_ARRVAL                          51
-#define PSI_T_PATHVAL                         52
-#define PSI_T_STRLEN                          53
-#define PSI_T_STRVAL                          54
-#define PSI_T_FLOATVAL                        55
-#define PSI_T_INTVAL                          56
-#define PSI_T_BOOLVAL                         57
-#define PSI_T_TO_OBJECT                       58
-#define PSI_T_TO_ARRAY                        59
-#define PSI_T_TO_STRING                       60
-#define PSI_T_TO_INT                          61
-#define PSI_T_TO_FLOAT                        62
-#define PSI_T_TO_BOOL                         63
-#define PSI_T_MIXED                           64
-#define PSI_T_ARRAY                           65
-#define PSI_T_OBJECT                          66
+#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_LIB                             11
+#define PSI_T_INT                             12
+#define PSI_T_UNSIGNED                        13
+#define PSI_T_EOF                             14
+#define PSI_T_QUOTED_STRING                   15
+#define PSI_T_EOS                             16
+#define PSI_T_STRUCT                          17
+#define PSI_T_LBRACE                          18
+#define PSI_T_RBRACE                          19
+#define PSI_T_COLON                           20
+#define PSI_T_LPAREN                          21
+#define PSI_T_NUMBER                          22
+#define PSI_T_RPAREN                          23
+#define PSI_T_BOOL                            24
+#define PSI_T_FLOAT                           25
+#define PSI_T_STRING                          26
+#define PSI_T_CONST                           27
+#define PSI_T_NSNAME                          28
+#define PSI_T_EQUALS                          29
+#define PSI_T_TYPEDEF                         30
+#define PSI_T_VOID                            31
+#define PSI_T_LBRACKET                        32
+#define PSI_T_RBRACKET                        33
+#define PSI_T_COMMA                           34
+#define PSI_T_DOUBLE                          35
+#define PSI_T_INT8                            36
+#define PSI_T_UINT8                           37
+#define PSI_T_INT16                           38
+#define PSI_T_UINT16                          39
+#define PSI_T_INT32                           40
+#define PSI_T_UINT32                          41
+#define PSI_T_INT64                           42
+#define PSI_T_UINT64                          43
+#define PSI_T_FUNCTION                        44
+#define PSI_T_AMPERSAND                       45
+#define PSI_T_NULL                            46
+#define PSI_T_TRUE                            47
+#define PSI_T_FALSE                           48
+#define PSI_T_DOLLAR                          49
+#define PSI_T_CALLOC                          50
+#define PSI_T_OBJVAL                          51
+#define PSI_T_ARRVAL                          52
+#define PSI_T_PATHVAL                         53
+#define PSI_T_STRLEN                          54
+#define PSI_T_STRVAL                          55
+#define PSI_T_FLOATVAL                        56
+#define PSI_T_INTVAL                          57
+#define PSI_T_BOOLVAL                         58
+#define PSI_T_TO_OBJECT                       59
+#define PSI_T_TO_ARRAY                        60
+#define PSI_T_TO_STRING                       61
+#define PSI_T_TO_INT                          62
+#define PSI_T_TO_FLOAT                        63
+#define PSI_T_TO_BOOL                         64
+#define PSI_T_MIXED                           65
+#define PSI_T_ARRAY                           66
+#define PSI_T_OBJECT                          67
index 06e4be5..c5eecba 100644 (file)
@@ -25,7 +25,7 @@
 %nonassoc NAME.
 %left PLUS MINUS.
 %left SLASH ASTERISK.
-%fallback NAME FREE SET LET RETURN LIB INT UNSIGNED.
+%fallback NAME TEMP FREE SET LET RETURN LIB INT UNSIGNED.
 
 file ::= blocks.
 
@@ -370,46 +370,64 @@ num_exp(exp) ::= num_exp(exp_) num_exp_op_token(operator_) num_exp(operand_). {
 %type let_stmt {let_stmt*}
 %destructor let_stmt {free_let_stmt($$);}
 let_stmt(let) ::= LET decl_var(var) EOS. {
-       let = init_let_stmt(var, NULL);
-}
-let_stmt(let) ::= LET decl_var(var) EQUALS let_value(val) EOS. {
+       let = init_let_stmt(var, init_let_val(PSI_LET_NULL, NULL));
+}/*
+let_stmt(let) ::= LET decl_var(var) EQUALS let_val(val) EOS. {
+       let = init_let_stmt(var, val);
+}*/
+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_stmt(let) ::= decl_arg(arg) EQUALS decl_var(var_) EOS. {
-       let = init_let_stmt(arg->var, NULL);
+let_stmt(let) ::= TEMP decl_var(var) EQUALS decl_var(val) EOS. {
+       let = init_let_stmt(var, init_let_val(PSI_LET_TMP, val));
 }
 
-%type let_value {let_value*}
-%destructor let_value {free_let_value($$);}
-let_value(val) ::= reference(r) CALLOC(F) LPAREN let_calloc(alloc) RPAREN. {
-       val = init_let_value(init_let_func(F->type, F->text, alloc), NULL, r);
-       free(F);
+%type let_val {let_val*}
+%destructor let_val {free_let_val($$);}
+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_stmt(let) ::= LET decl_var(var) EQUALS reference(r) NULL EOS. {
+       let = init_let_stmt(var, init_let_val(PSI_LET_NULL, NULL, r?PSI_LET_REFERENCE:0));
+}
+let_stmt(let) ::= LET decl_var(var) EQUALS reference(r) num_exp(exp) EOS. {
+       let = init_let_stmt(var, init_let_val(PSI_LET_NUMEXP, exp, r?PSI_LET_REFERENCE:0));
+}
+let_stmt(let) ::= LET decl_var(var) EQUALS reference(r) CALLOC LPAREN let_calloc(alloc) RPAREN EOS. {
+       let = init_let_stmt(var, init_let_val(PSI_LET_CALLOC, alloc, r?PSI_LET_REFERENCE:0));
 }
+let_stmt(let) ::= LET decl_var(var) EQUALS reference(r) let_func(func) EOS. {
+       let = init_let_stmt(var, init_let_val(PSI_LET_FUNC, func, r?PSI_LET_REFERENCE:0));
+}
+let_stmt(let) ::= LET decl_var(var) EQUALS decl_var(val) EOS. {
+       let = init_let_stmt(var, init_let_val(PSI_LET_VAR, val, 0));
+}
+*/
 %type let_calloc {let_calloc*}
 %destructor let_calloc {free_let_calloc($$);}
 let_calloc(alloc) ::= num_exp(nmemb) COMMA num_exp(size). {
        alloc = init_let_calloc(nmemb, size);
 }
-
-let_value(val) ::= reference(r) num_exp(exp). {
-       val = init_let_value(NULL, NULL, r);
-       val->num = exp;
-}
-let_value(val) ::= reference(r) let_func(func) LPAREN impl_var(var) RPAREN. {
-       val = init_let_value(func, var, r);
-}
-let_value(val) ::= reference(r) NULL. {
-       val = init_let_value(NULL, NULL, r);
-}
-
 %token_class let_func_token OBJVAL ARRVAL PATHVAL STRLEN STRVAL FLOATVAL INTVAL BOOLVAL.
 %type let_func {let_func*}
 %destructor let_func {free_let_func($$);}
-let_func(func) ::= let_func_token(T). {
-       func = init_let_func(T->type, T->text, NULL);
+let_func(func) ::= let_func_token(T) LPAREN impl_var(var) RPAREN. {
+       func = init_let_func(T->type, T->text, var);
        free(T);
 }
 
+
 %type set_stmt {set_stmt*}
 %destructor set_stmt {free_set_stmt($$);}
 set_stmt(set) ::= SET impl_var(var) EQUALS set_value(val) EOS. {
diff --git a/tests/iconv/iconv.psi b/tests/iconv/iconv.psi
new file mode 100644 (file)
index 0000000..e414dc0
--- /dev/null
@@ -0,0 +1,25 @@
+extern void *iconv_open(char *tocode, char *fromcode);
+function psi\iconv_open(string $to, string $from) : object {
+       let tocode = strval($to);
+       let fromcode = strval($from);
+       return to_object(iconv_open);
+}
+
+extern size_t iconv (void *cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
+function psi\iconv(object $iconv, string &$inbuf, string &$outbuf) : int {
+       let cd = objval($iconv);
+       let inbuf = &strval($inbuf);
+       let inbytesleft = &strlen($inbuf);
+       let outbytesleft = &8192;
+       let outbuf = &calloc(1, 8192);
+       temp result = *outbuf;
+       return to_int(iconv);
+       set $inbuf = to_string(*inbuf, *inbytesleft);
+       set $outbuf = to_string(result, 8192 - *outbytesleft);
+}
+
+extern int iconv_close(void *cd);
+function psi\iconv_close(object $iconv) : int {
+       let cd = objval($iconv);
+       return to_int(iconv_close);
+}
diff --git a/tests/iconv/iconv001.phpt b/tests/iconv/iconv001.phpt
new file mode 100644 (file)
index 0000000..6227c2a
--- /dev/null
@@ -0,0 +1,28 @@
+--TEST--
+iconv
+--SKIPIF--
+<?php 
+extension_loaded("psi") or die("skip - need ext/psi");
+function_exists("psi\\iconv_open") or die("skip - need iconv");
+?>
+--INI--
+psi.directory={PWD}/../../psi.d:{PWD}
+--FILE--
+===TEST===
+<?php 
+
+$cd = psi\iconv_open("latin1", "utf8");
+$in = "ß";
+$rc = psi\iconv($cd, $in, $tr);
+var_dump($tr === "\xdf");
+var_dump($in === "");
+var_dump(psi\iconv_close($cd));
+
+?>
+===DONE===
+--EXPECT--
+===TEST===
+bool(true)
+bool(true)
+int(0)
+===DONE===
diff --git a/tests/iconv/iconv002.phpt b/tests/iconv/iconv002.phpt
new file mode 100644 (file)
index 0000000..16095b5
--- /dev/null
@@ -0,0 +1,79 @@
+--TEST--
+iconv abstraction
+--INI--
+psi.directory={PWD}/../../psi.d:{PWD}
+--SKIPIF--
+<?php 
+extension_loaded("psi") or die("skip - need ext/psi");
+function_exists("psi\\iconv_open") or die("skip - need iconv");
+?>
+--FILE--
+===TEST===
+<?php 
+
+class iconv_stream {
+       private $cd;
+       
+       function __construct($from, $to) {
+               if (!$this->cd = psi\iconv_open($to, $from)) {
+                       throw new Exception(psi\strerror(psi\errno()));
+               }
+       }
+       
+       function __destruct() {
+               psi\iconv_close($this->cd);
+       }
+       
+       function update(string $data) : string {
+               if (0 > psi\iconv($this->cd, $data, $result)) {
+                       throw new Exception(psi\strerror(psi\errno()));
+               }
+               return $result;
+       }
+}
+
+$ic = new iconv_stream("utf8", "latin1");
+
+foreach (["föö", "bää", "baßß"] as $str) {
+       var_dump(array_map("ord", str_split($ic->update($str))));
+}
+
+$bc = new iconv_stream("latin1", "utf8");
+foreach (["föö", "bää", "baßß"] as $str) {
+       var_dump($bc->update($ic->update($str)));
+}
+
+?>
+===DONE===
+--EXPECT--
+===TEST===
+array(3) {
+  [0]=>
+  int(102)
+  [1]=>
+  int(246)
+  [2]=>
+  int(246)
+}
+array(3) {
+  [0]=>
+  int(98)
+  [1]=>
+  int(228)
+  [2]=>
+  int(228)
+}
+array(4) {
+  [0]=>
+  int(98)
+  [1]=>
+  int(97)
+  [2]=>
+  int(223)
+  [3]=>
+  int(223)
+}
+string(5) "föö"
+string(5) "bää"
+string(6) "baßß"
+===DONE===