* generators: (70 commits)
Fix typos
Fix segfault when traversing a by-ref generator twice
Make sure that exception is thrown on rewind() after closing too
Remove implementation stubs for yield delegation
Fix several issues and allow rewind only at/before first yield
Run finally if generator is closed before finishing
Finally with return now works in generators too
Add dedicated opcode for returns from a generator
Disallow serialization and unserialization
Fix zts build (typo)
Drop Generator::close() method
Forgot to add test
Support trivial finally in generators (no yield, no return)
Fix implementation of Iterator interface
Add T_YIELD in tokenizer_data.c
Throw error also for return occuring before yield
Fix throwing of exceptions within a generator
Remove reference restrictions from foreach
Require parenthesis around yield expressions
Add some more tests
...
This is just an intial merge. It does not yet make generators and finally
work together.
Conflicts:
Zend/zend_language_scanner.c
Zend/zend_language_scanner_defs.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
Zend/zend_vm_execute.skl
Zend/zend_vm_opcodes.h
If yield is used in an expression context parenthesis are now required.
This ensures that the code is unambiguos.
Yield statements can still be used without parenthesis (which should be
the most common case).
Also yield expressions without value can be used without parenthesis,
too (this should be the most common case for coroutines).
If the yield expression is used in a context where parenthesis are required
anyway, no additional parenthesis have to be inserted.
Examples:
// Statements don't need parenthesis
yield $foo;
yield $foo => $bar;
// Yield without value doesn't need parenthesis either
$data = yield;
// Parentheses don't have to be duplicated
foo(yield $bar);
if (yield $bar) { ... }
// But we have to use parentheses here
$foo = (yield $bar);
This commit also fixes an issue with by-ref passing of $foo[0] like
variables. They previously weren't properly fetched for write.
Additionally this fixes valgrind warnings which were caused by access to
uninitialized memory in zend_is_function_or_method_call().
Generators are now automatically detected by the presence of a `yield`
expression in their body.
This removes the ZEND_SUSPEND_AND_RETURN_GENERATOR opcode. Instead
additional checks for ZEND_ACC_GENERATOR are added to the fcall_common
helper and zend_call_function.
This also adds a new function zend_generator_create_zval, which handles
the actual creation of the generator zval from an op array.
I feel like I should deglobalize the zend_create_execute_data_from_op_array
code a bit. It currently changes EG(current_execute_data) and
EG(opline_ptr) which is somewhat confusing (given the name).
Keys are yielded using the
yield $key => $value
syntax. Currently this is implemented as a statement only and not as an
expression, because conflicts arise considering nesting and use in arrays:
yield yield $a => $b;
// could be either
yield (yield $a) => $b;
// or
yield (yield $a => $b);
Once I find some way to resolve these conflicts this should be available
as an expression too.
Also the key yielding code is rather copy-and-past-y for the value yielding
code, so that should be factored out.
Yield now is an expression and the return value is the value passed to
$generator->send(). By default (i.e. if ->next() is called) the value is
NULL.
Unlike in Python ->send() can be run without priming the generator with a
->next() call first.
Generator functions have to specify the * (asterix) modifier after the
function keyword. If they do so the ZEND_ACC_GENERATOR flag is added to
the fn_flags.