Skip to content

Commit

Permalink
Implement return for generators
Browse files Browse the repository at this point in the history
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 5bb3a99
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 0 deletions.
12 changes: 12 additions & 0 deletions Zend/tests/generators/errors/generator_cannot_return_error.phpt
@@ -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
4 changes: 4 additions & 0 deletions Zend/zend_compile.c
Expand Up @@ -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);
Expand Down
11 changes: 11 additions & 0 deletions Zend/zend_generators.c
Expand Up @@ -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 */
}
/* }}} */

Expand All @@ -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);
}
/* }}} */

Expand All @@ -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);
}
}
/* }}} */

Expand Down Expand Up @@ -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);
}
/* }}} */

Expand Down
5 changes: 5 additions & 0 deletions Zend/zend_vm_def.h
Expand Up @@ -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);

Expand Down
20 changes: 20 additions & 0 deletions Zend/zend_vm_execute.h
Expand Up @@ -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;

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down

0 comments on commit 5bb3a99

Please sign in to comment.