Permalink
Browse files

Implement return for generators

For generators ZEND_RETURN directly calls ZEND_VM_RETURN(), thus passing
execution back to the caller (zend_generator_resume).

This commit also adds a check that only return; is used in generators and
not return $value;.
  • Loading branch information...
nikic committed May 26, 2012
1 parent fafce58 commit 5bb3a995c2ad1a41c22a88e17dc46fef22ab1849
@@ -0,0 +1,12 @@
+--TEST--
+Generators cannot return values
+--FILE--
+<?php
+
+function *gen() {
+ return $abc;
+}
+
+?>
+--EXPECTF--
+Fatal error: Generators cannot return values using "return" in %s on line %d
View
@@ -2615,6 +2615,10 @@ void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC) /* {{{ */
zend_op *opline;
int start_op_number, end_op_number;
+ if ((CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) && expr != NULL) {
+ zend_error(E_COMPILE_ERROR, "Generators cannot return values using \"return\"");
+ }
+
if (do_end_vparse) {
if ((CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) && !zend_is_function_or_method_call(expr)) {
zend_do_end_variable_parse(expr, BP_VAR_W, 0 TSRMLS_CC);
View
@@ -140,6 +140,9 @@ ZEND_METHOD(Generator, rewind)
generator = (zend_generator *) zend_object_store_get_object(object TSRMLS_CC);
zend_generator_ensure_initialized(object, generator TSRMLS_CC);
+
+ /* Generators aren't rewindable, so rewind() only has to make sure that
+ * the generator is initialized, nothing more */
}
/* }}} */
@@ -158,6 +161,8 @@ ZEND_METHOD(Generator, valid)
generator = (zend_generator *) zend_object_store_get_object(object TSRMLS_CC);
zend_generator_ensure_initialized(object, generator TSRMLS_CC);
+
+ RETURN_BOOL(generator->value != NULL);
}
/* }}} */
@@ -176,6 +181,10 @@ ZEND_METHOD(Generator, current)
generator = (zend_generator *) zend_object_store_get_object(object TSRMLS_CC);
zend_generator_ensure_initialized(object, generator TSRMLS_CC);
+
+ if (generator->value) {
+ RETURN_ZVAL(generator->value, 1, 1);
+ }
}
/* }}} */
@@ -212,6 +221,8 @@ ZEND_METHOD(Generator, next)
generator = (zend_generator *) zend_object_store_get_object(object TSRMLS_CC);
zend_generator_ensure_initialized(object, generator TSRMLS_CC);
+
+ zend_generator_resume(object, generator TSRMLS_CC);
}
/* }}} */
View
@@ -2840,6 +2840,11 @@ ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY)
zval *retval_ptr;
zend_free_op free_op1;
+ /* For generators return means to simply stop executing */
+ if (EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) {
+ ZEND_VM_RETURN();
+ }
+
SAVE_OPLINE();
retval_ptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
View
@@ -2321,6 +2321,11 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG
zval *retval_ptr;
+ /* For generators return means to simply stop executing */
+ if (EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) {
+ ZEND_VM_RETURN();
+ }
+
SAVE_OPLINE();
retval_ptr = opline->op1.zv;
@@ -6894,6 +6899,11 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
zval *retval_ptr;
zend_free_op free_op1;
+ /* For generators return means to simply stop executing */
+ if (EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) {
+ ZEND_VM_RETURN();
+ }
+
SAVE_OPLINE();
retval_ptr = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
@@ -11372,6 +11382,11 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
zval *retval_ptr;
zend_free_op free_op1;
+ /* For generators return means to simply stop executing */
+ if (EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) {
+ ZEND_VM_RETURN();
+ }
+
SAVE_OPLINE();
retval_ptr = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
@@ -27406,6 +27421,11 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
zval *retval_ptr;
+ /* For generators return means to simply stop executing */
+ if (EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) {
+ ZEND_VM_RETURN();
+ }
+
SAVE_OPLINE();
retval_ptr = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC);

0 comments on commit 5bb3a99

Please sign in to comment.