flush
authorMichael Wallner <mike@php.net>
Thu, 22 Oct 2015 18:15:52 +0000 (20:15 +0200)
committerMichael Wallner <mike@php.net>
Thu, 22 Oct 2015 18:15:52 +0000 (20:15 +0200)
php_psi.h
src/libffi.c
src/module.c
src/parser.h
src/parser.re
src/parser_proc.h
src/parser_proc.y
src/validator.c
tests/pipe/pipe.psi [new file with mode: 0644]
tests/pipe/pipe001.phpt [new file with mode: 0644]

index 3e582d0..0889801 100644 (file)
--- a/php_psi.h
+++ b/php_psi.h
@@ -23,6 +23,7 @@ extern zend_module_entry psi_module_entry;
 #include "parser.h"
 
 void psi_error(int type, const char *msg, ...);
+size_t psi_t_size(token_t t);
 int psi_internal_type(impl_type *type);
 zend_internal_arg_info *psi_internal_arginfo(impl *impl);
 size_t psi_num_min_args(impl *impl);
index eb5b2b5..4963fc5 100644 (file)
@@ -216,7 +216,8 @@ static void handler(ffi_cif *_sig, void *_result, void **_args, void *_data)
                        decl_arg *darg = data->impl->decl->args->args[i];
 
                        arg_ptr[i] = psi_do_let(darg);
-                       arg_prm[i] = darg->let->val->is_reference ? &arg_ptr[i] : arg_ptr[i];
+                       arg_prm[i] = (darg->let->val && darg->let->val->is_reference)
+                                       ? &arg_ptr[i] : arg_ptr[i];
 
                        darg->let->ptr = arg_ptr[i];
                }
index 57fe9d6..4d6e5c9 100644 (file)
@@ -142,6 +142,85 @@ void psi_to_string(impl_val *ret_val, decl_arg *func, zval *return_value)
        }
 }
 
+size_t psi_t_size(token_t t)
+{
+       size_t size;
+
+       switch (t) {
+       case PSI_T_CHAR:
+               size = sizeof(char);
+               break;
+       case PSI_T_SINT8:
+       case PSI_T_UINT8:
+               size = 1;
+               break;
+       case PSI_T_SHORT:
+               size = sizeof(short);
+               break;
+       case PSI_T_SINT16:
+       case PSI_T_UINT16:
+               size = 2;
+               break;
+       case PSI_T_INT:
+               size = sizeof(int);
+               break;
+       case PSI_T_SINT32:
+       case PSI_T_UINT32:
+               size = 4;
+               break;
+       case PSI_T_LONG:
+               size = sizeof(long);
+               break;
+       case PSI_T_SINT64:
+       case PSI_T_UINT64:
+               size = 8;
+               break;
+       case PSI_T_FLOAT:
+               size = sizeof(float);
+               break;
+       case PSI_T_DOUBLE:
+               size = sizeof(double);
+               break;
+       EMPTY_SWITCH_DEFAULT_CASE();
+       }
+       return size;
+}
+
+static impl_val *iterate(impl_val *val, token_t t, unsigned i, impl_val *tmp)
+{
+       size_t size = psi_t_size(t);
+
+       memset(tmp, 0, sizeof(*tmp));
+       memcpy(tmp, val->ptr + size * i, size);
+       return tmp;
+}
+
+void psi_to_array(impl_val *ret_val, decl_arg *func, zval *return_value)
+{
+       zval ele;
+       unsigned i;
+       impl_val tmp;
+       token_t t = real_decl_type(func->type)->type;
+
+       array_init(return_value);
+       ret_val = deref_impl_val(0, ret_val, func);
+       for (i = 0; i < func->var->array_size; ++i) {
+               impl_val *ptr = iterate(ret_val, t, i, &tmp);
+
+               switch (t) {
+               case PSI_T_FLOAT:
+               case PSI_T_DOUBLE:
+                       ZVAL_DOUBLE(&ele, ptr->dval);
+                       break;
+               default:
+                       ZVAL_LONG(&ele, ptr->lval);
+                       break;
+               }
+
+               add_next_index_zval(return_value, &ele);
+       }
+}
+
 ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, impl *impl)
 {
        impl_arg *iarg;
@@ -184,6 +263,9 @@ ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, impl *impl)
                        } else if (iarg->def) {
                                iarg->val.str = zend_string_init(str.val, str.len, 0);
                        }
+               } else if (PSI_T_ARRAY == iarg->type->type) {
+                       /* handled as _zv in let or set */
+                       Z_PARAM_PROLOGUE(0);
                } else {
                        error_code = ZPP_ERROR_FAILURE;
                        break;
@@ -203,8 +285,16 @@ impl_val *psi_do_let(decl_arg *darg)
        impl_arg *iarg = darg->let->arg;
 
        if (!iarg) {
-               /* let foo = NULL */
-               memset(arg_val, 0, sizeof(*arg_val));
+               /*
+                * let foo = NULL;
+                * let foo;
+                */
+               if (darg->var->array_size) {
+                       arg_val->ptr = ecalloc(darg->var->array_size, sizeof(*arg_val));
+                       darg->let->mem = arg_val->ptr;
+               } else {
+                       memset(arg_val, 0, sizeof(*arg_val));
+               }
                return arg_val;
        }
        switch (darg->let->val->func->type) {
@@ -244,6 +334,10 @@ impl_val *psi_do_let(decl_arg *darg)
                        zend_string_release(zs);
                }
                break;
+       case PSI_T_CALLOC:
+               arg_val->ptr = calloc(1, darg->let->val->func->size);
+               darg->let->mem = arg_val->ptr;
+               break;
        EMPTY_SWITCH_DEFAULT_CASE();
        }
 
@@ -261,6 +355,9 @@ void psi_do_set(zval *return_value, set_func *func, decl_vars *vars)
        case PSI_T_TO_STRING:
                psi_to_string(val, vars->vars[0]->arg, return_value);
                break;
+       case PSI_T_TO_ARRAY:
+               psi_to_array(val, vars->vars[0]->arg, return_value);
+               break;
        EMPTY_SWITCH_DEFAULT_CASE();
        }
 }
index 4e5e064..fe3ff8e 100644 (file)
@@ -405,12 +405,14 @@ static inline void free_impl_func(impl_func *f) {
 typedef struct let_func {
        token_t type;
        char *name;
+       size_t size;
 } let_func;
 
-static inline let_func *init_let_func(token_t type, char *name) {
+static inline let_func *init_let_func(token_t type, char *name, size_t size) {
        let_func *func = malloc(sizeof(*func));
        func->type = type;
-       func->name = (char *) strdup((const char *) name);
+       func->name = strdup(name);
+       func->size = size;
        return func;
 }
 
index f1fb9b5..9cd39fa 100644 (file)
@@ -212,6 +212,8 @@ token_t PSI_ParserScan(PSI_Parser *P)
                INTVAL = 'intval';
                FLOATVAL = 'floatval';
                BOOLVAL = 'boolval';
+               CALLOC = 'calloc';
+               TO_ARRAY = 'to_array';
                TO_STRING = 'to_string';
                TO_INT = 'to_int';
                TO_FLOAT = 'to_float';
@@ -269,6 +271,8 @@ token_t PSI_ParserScan(PSI_Parser *P)
                INTVAL {RETURN(PSI_T_INTVAL);}
                FLOATVAL {RETURN(PSI_T_FLOATVAL);}
                BOOLVAL {RETURN(PSI_T_BOOLVAL);}
+               CALLOC {RETURN(PSI_T_CALLOC);}
+               TO_ARRAY {RETURN(PSI_T_TO_ARRAY);}
                TO_STRING {RETURN(PSI_T_TO_STRING);}
                TO_INT {RETURN(PSI_T_TO_INT);}
                TO_FLOAT {RETURN(PSI_T_TO_FLOAT);}
index b6d8c28..492a681 100644 (file)
 #define PSI_T_FALSE                           41
 #define PSI_T_DOLLAR                          42
 #define PSI_T_LET                             43
-#define PSI_T_STRLEN                          44
-#define PSI_T_STRVAL                          45
-#define PSI_T_INTVAL                          46
-#define PSI_T_FLOATVAL                        47
-#define PSI_T_BOOLVAL                         48
-#define PSI_T_SET                             49
-#define PSI_T_TO_STRING                       50
-#define PSI_T_TO_INT                          51
-#define PSI_T_TO_FLOAT                        52
-#define PSI_T_TO_BOOL                         53
-#define PSI_T_RETURN                          54
-#define PSI_T_FREE                            55
-#define PSI_T_MIXED                           56
-#define PSI_T_ARRAY                           57
-#define PSI_T_POINTER                         58
+#define PSI_T_CALLOC                          44
+#define PSI_T_STRLEN                          45
+#define PSI_T_STRVAL                          46
+#define PSI_T_INTVAL                          47
+#define PSI_T_FLOATVAL                        48
+#define PSI_T_BOOLVAL                         49
+#define PSI_T_SET                             50
+#define PSI_T_TO_ARRAY                        51
+#define PSI_T_TO_STRING                       52
+#define PSI_T_TO_INT                          53
+#define PSI_T_TO_FLOAT                        54
+#define PSI_T_TO_BOOL                         55
+#define PSI_T_RETURN                          56
+#define PSI_T_FREE                            57
+#define PSI_T_MIXED                           58
+#define PSI_T_ARRAY                           59
+#define PSI_T_POINTER                         60
index 3bdcc22..fb7f53b 100644 (file)
@@ -291,11 +291,24 @@ impl_stmt(stmt) ::= free_stmt(free). {
 }
 
 %type let_stmt {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, val);
 }
 
 %type let_value {let_value*}
+let_value(val) ::= CALLOC(F) LPAREN NUMBER(N) COMMA decl_type(t) RPAREN. {
+       val = init_let_value(
+               init_let_func(F->type, F->text,
+                       atol(N->text) * psi_t_size(real_decl_type(t)->type)
+               ), NULL, 0
+       );
+       free_decl_type(t);
+       free(F);
+       free(N);
+}
 let_value(val) ::= let_func(func) LPAREN impl_var(var) RPAREN. {
        val = init_let_value(func, var, 0);
 }
@@ -311,23 +324,23 @@ let_value(val) ::= NULL. {
 
 %type let_func {let_func*}
 let_func(func) ::= STRLEN(T). {
-       func = init_let_func(T->type, T->text);
+       func = init_let_func(T->type, T->text, 0);
        free(T);
 }
 let_func(func) ::= STRVAL(T). {
-       func = init_let_func(T->type, T->text);
+       func = init_let_func(T->type, T->text, 0);
        free(T);
 }
 let_func(func) ::= INTVAL(T). {
-       func = init_let_func(T->type, T->text);
+       func = init_let_func(T->type, T->text, 0);
        free(T);
 }
 let_func(func) ::= FLOATVAL(T). {
-       func = init_let_func(T->type, T->text);
+       func = init_let_func(T->type, T->text, 0);
        free(T);
 }
 let_func(func) ::= BOOLVAL(T). {
-       func = init_let_func(T->type, T->text);
+       func = init_let_func(T->type, T->text, 0);
        free(T);
 }
 
@@ -342,6 +355,10 @@ set_value(val) ::= set_func(func) LPAREN decl_vars(vars) RPAREN. {
 }
 
 %type set_func {set_func*}
+set_func(func) ::= TO_ARRAY(T). {
+       func = init_set_func(T->type, T->text);
+       free(T);
+}
 set_func(func) ::= TO_STRING(T). {
        func = init_set_func(T->type, T->text);
        free(T);
index 7222a57..6bfd4e4 100644 (file)
@@ -282,7 +282,7 @@ static inline int validate_impl_stmts(PSI_Validator *V, impl *impl, impl_stmts *
                let_stmt *let = stmts->let.list[i];
                int check = 0;
 
-               if (let->val->var) {
+               if (let->val && let->val->var) {
                        for (j = 0; j < impl->func->args->count; ++j) {
                                impl_arg *iarg = impl->func->args->args[j];
 
diff --git a/tests/pipe/pipe.psi b/tests/pipe/pipe.psi
new file mode 100644 (file)
index 0000000..5bc3cd6
--- /dev/null
@@ -0,0 +1,8 @@
+
+extern int pipe(int fds[2]);
+
+function \pipe(array &$fds = null) : int {
+       return to_int(pipe);
+       let fds = calloc(2, int);
+       set $fds = to_array(fds);
+}
diff --git a/tests/pipe/pipe001.phpt b/tests/pipe/pipe001.phpt
new file mode 100644 (file)
index 0000000..a6461c4
--- /dev/null
@@ -0,0 +1,27 @@
+--TEST--
+pipe
+--SKIPIF--
+<?php
+extension_loaded("psi") or die("skip - need ext/psi");
+?>
+--INI--
+psi.directory={PWD}
+--FILE--
+===TEST===
+<?php 
+
+var_dump(pipe($pipes));
+$r = fopen("php://fd/".$pipes[0], "r");
+$w = fopen("php://fd/".$pipes[1], "w");
+
+fputs($w, "Hello World!\n");
+var_dump(fgets($r));
+
+?>
+===DONE===
+--EXPECT--
+===TEST===
+int(0)
+string(13) "Hello World!
+"
+===DONE===
\ No newline at end of file