Commit:    ad525c288ad83df497ed1a0668915cad61d72e26
Author:    Nikita Popov <ni...@php.net>         Tue, 29 May 2012 17:53:11 +0200
Parents:   3600914ced52eb4f6db10410ba887c8e2a2acfe1
Branches:  master

Link:       
http://git.php.net/?p=php-src.git;a=commitdiff;h=ad525c288ad83df497ed1a0668915cad61d72e26

Log:
Allow to use yield without value

If the generator is used as a coroutine it often doesn't make sense to yield
anything. In this case one can simply receive values using

    $value = yield;

The yield here will simply yield NULL.

Changed paths:
  A  Zend/tests/generators/yield_without_value.phpt
  M  Zend/zend_compile.c
  M  Zend/zend_language_parser.y
  M  Zend/zend_vm_def.h
  M  Zend/zend_vm_execute.h

diff --git a/Zend/tests/generators/yield_without_value.phpt 
b/Zend/tests/generators/yield_without_value.phpt
new file mode 100644
index 0000000..dc467a8
--- /dev/null
+++ b/Zend/tests/generators/yield_without_value.phpt
@@ -0,0 +1,27 @@
+--TEST--
+yield can be used without a value
+--FILE--
+<?php
+
+function *recv() {
+    while (true) {
+        var_dump(yield);
+    }
+}
+
+$reciever = recv();
+var_dump($reciever->current());
+$reciever->send(1);
+var_dump($reciever->current());
+$reciever->send(2);
+var_dump($reciever->current());
+$reciever->send(3);
+
+?>
+--EXPECT--
+NULL
+int(1)
+NULL
+int(2)
+NULL
+int(3)
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 37e4901..89549bb 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -2673,8 +2673,12 @@ void zend_do_yield(znode *result, const znode *expr 
TSRMLS_DC) /* {{{ */
        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
 
        opline->opcode = ZEND_YIELD;
-       SET_NODE(opline->op1, expr);
-       SET_UNUSED(opline->op2);
+
+       if (expr) {
+               SET_NODE(opline->op1, expr);
+       } else {
+               SET_UNUSED(opline->op2);
+       }
 
        opline->result_type = IS_VAR;
        opline->result.var = get_temporary_variable(CG(active_op_array));
diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y
index ea8ac41..ac22e7f 100644
--- a/Zend/zend_language_parser.y
+++ b/Zend/zend_language_parser.y
@@ -801,6 +801,7 @@ expr_without_variable:
        |       combined_scalar { $$ = $1; }
        |       '`' backticks_expr '`' { zend_do_shell_exec(&$$, &$2 
TSRMLS_CC); }
        |       T_PRINT expr  { zend_do_print(&$$, &$2 TSRMLS_CC); }
+       |       T_YIELD { zend_do_yield(&$$, NULL TSRMLS_CC); }
        |       T_YIELD expr { zend_do_yield(&$$, &$2 TSRMLS_CC); }
        |       function is_generator is_reference { 
zend_do_begin_lambda_function_declaration(&$$, &$1, $2.op_type, $3.op_type, 0 
TSRMLS_CC); }
                '(' parameter_list ')' lexical_vars { 
zend_do_suspend_if_generator(TSRMLS_C); }
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 8c810cd..6761030 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -5258,7 +5258,7 @@ ZEND_VM_HANDLER(159, ZEND_SUSPEND_AND_RETURN_GENERATOR, 
ANY, ANY)
        ZEND_VM_RETURN();
 }
 
-ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV, ANY)
+ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, ANY)
 {
        USE_OPLINE
 
@@ -5271,7 +5271,7 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV, ANY)
        }
 
        /* Set the new yielded value */
-       {
+       if (OP1_TYPE != IS_UNUSED) {
                zend_free_op free_op1;
                zval *value = GET_OP1_ZVAL_PTR(BP_VAR_R);
 
@@ -5291,11 +5291,15 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV, ANY)
 
                        generator->value = copy;
                } else {
-                       generator->value = value;
                        Z_ADDREF_P(value);
+                       generator->value = value;
                }
 
                FREE_OP1_IF_VAR();
+       } else {
+               /* If no value way specified yield null */
+               Z_ADDREF(EG(uninitialized_zval));
+               generator->value = &EG(uninitialized_zval);
        }
 
        /* If a value is sent it should go into the result var */
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index fa07733..efe0812 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -3047,7 +3047,7 @@ static int ZEND_FASTCALL  
ZEND_YIELD_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS
        }
 
        /* Set the new yielded value */
-       {
+       if (IS_CONST != IS_UNUSED) {
 
                zval *value = opline->op1.zv;
 
@@ -3067,10 +3067,14 @@ static int ZEND_FASTCALL  
ZEND_YIELD_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS
 
                        generator->value = copy;
                } else {
-                       generator->value = value;
                        Z_ADDREF_P(value);
+                       generator->value = value;
                }
 
+       } else {
+               /* If no value way specified yield null */
+               Z_ADDREF(EG(uninitialized_zval));
+               generator->value = &EG(uninitialized_zval);
        }
 
        /* If a value is sent it should go into the result var */
@@ -7697,7 +7701,7 @@ static int ZEND_FASTCALL  
ZEND_YIELD_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        }
 
        /* Set the new yielded value */
-       {
+       if (IS_TMP_VAR != IS_UNUSED) {
                zend_free_op free_op1;
                zval *value = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), 
&free_op1 TSRMLS_CC);
 
@@ -7717,10 +7721,14 @@ static int ZEND_FASTCALL  
ZEND_YIELD_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 
                        generator->value = copy;
                } else {
-                       generator->value = value;
                        Z_ADDREF_P(value);
+                       generator->value = value;
                }
 
+       } else {
+               /* If no value way specified yield null */
+               Z_ADDREF(EG(uninitialized_zval));
+               generator->value = &EG(uninitialized_zval);
        }
 
        /* If a value is sent it should go into the result var */
@@ -12424,7 +12432,7 @@ static int ZEND_FASTCALL  
ZEND_YIELD_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        }
 
        /* Set the new yielded value */
-       {
+       if (IS_VAR != IS_UNUSED) {
                zend_free_op free_op1;
                zval *value = _get_zval_ptr_var(opline->op1.var, EX_Ts(), 
&free_op1 TSRMLS_CC);
 
@@ -12444,11 +12452,15 @@ static int ZEND_FASTCALL  
ZEND_YIELD_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 
                        generator->value = copy;
                } else {
-                       generator->value = value;
                        Z_ADDREF_P(value);
+                       generator->value = value;
                }
 
                if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
+       } else {
+               /* If no value way specified yield null */
+               Z_ADDREF(EG(uninitialized_zval));
+               generator->value = &EG(uninitialized_zval);
        }
 
        /* If a value is sent it should go into the result var */
@@ -22080,6 +22092,63 @@ static int ZEND_FASTCALL  
ZEND_EXIT_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS
        ZEND_VM_NEXT_OPCODE(); /* Never reached */
 }
 
+static int ZEND_FASTCALL  
ZEND_YIELD_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+       USE_OPLINE
+
+       /* The generator object is stored in return_value_ptr_ptr */
+       zend_generator *generator = (zend_generator *) 
zend_object_store_get_object(*EG(return_value_ptr_ptr) TSRMLS_CC);
+
+       /* Destroy the previously yielded value */
+       if (generator->value) {
+               zval_ptr_dtor(&generator->value);
+       }
+
+       /* Set the new yielded value */
+       if (IS_UNUSED != IS_UNUSED) {
+
+               zval *value = NULL;
+
+               /* Consts, temporary variables and references need copying */
+               if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR
+                       || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+               ) {
+                       zval *copy;
+
+                       ALLOC_ZVAL(copy);
+                       INIT_PZVAL_COPY(copy, value);
+
+                       /* Temporary variables don't need ctor copying */
+                       if (!0) {
+                               zval_copy_ctor(copy);
+                       }
+
+                       generator->value = copy;
+               } else {
+                       Z_ADDREF_P(value);
+                       generator->value = value;
+               }
+
+       } else {
+               /* If no value way specified yield null */
+               Z_ADDREF(EG(uninitialized_zval));
+               generator->value = &EG(uninitialized_zval);
+       }
+
+       /* If a value is sent it should go into the result var */
+       generator->send_target = &EX_T(opline->result.var);
+
+       /* Initialize the sent value to NULL */
+       Z_ADDREF(EG(uninitialized_zval));
+       AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+
+       /* The GOTO VM uses a local opline variable. We need to set the opline
+        * variable in execute_data so we don't resume at an old position. */
+       SAVE_OPLINE();
+
+       ZEND_VM_RETURN();
+}
+
 static int ZEND_FASTCALL 
zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(int (*binary_op)(zval 
*result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
@@ -28323,7 +28392,7 @@ static int ZEND_FASTCALL  
ZEND_YIELD_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        }
 
        /* Set the new yielded value */
-       {
+       if (IS_CV != IS_UNUSED) {
 
                zval *value = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), 
opline->op1.var TSRMLS_CC);
 
@@ -28343,10 +28412,14 @@ static int ZEND_FASTCALL  
ZEND_YIELD_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 
                        generator->value = copy;
                } else {
-                       generator->value = value;
                        Z_ADDREF_P(value);
+                       generator->value = value;
                }
 
+       } else {
+               /* If no value way specified yield null */
+               Z_ADDREF(EG(uninitialized_zval));
+               generator->value = &EG(uninitialized_zval);
        }
 
        /* If a value is sent it should go into the result var */
@@ -41168,11 +41241,11 @@ void zend_init_opcodes_handlers(void)
        ZEND_YIELD_SPEC_VAR_HANDLER,
        ZEND_YIELD_SPEC_VAR_HANDLER,
        ZEND_YIELD_SPEC_VAR_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
-       ZEND_NULL_HANDLER,
+       ZEND_YIELD_SPEC_UNUSED_HANDLER,
+       ZEND_YIELD_SPEC_UNUSED_HANDLER,
+       ZEND_YIELD_SPEC_UNUSED_HANDLER,
+       ZEND_YIELD_SPEC_UNUSED_HANDLER,
+       ZEND_YIELD_SPEC_UNUSED_HANDLER,
        ZEND_YIELD_SPEC_CV_HANDLER,
        ZEND_YIELD_SPEC_CV_HANDLER,
        ZEND_YIELD_SPEC_CV_HANDLER,
-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to