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