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.
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.
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.
To keep things clean two new functions are introduced:
zend_clean_and_cache_symbol_table(HashTable *symbol_table)
zend_free_compiled_variables(zval ***CVs, int num)
If the generator is closed before it has finished running, it may happen
that some FREE or SWITCH_FREE opcodes haven't been executed and memory is
leaked.
This fixes it by walking the brk_cont_array and manually freeing the
variables.
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;.
This adds another function execute_ex(), which accepts a zend_execute_data
struct to run (contrary to execute(), which accepts a zend_op_array from
which it initialized the execute_data).
This needs a bit more cleanup.
Generators need to switch the execute_data very often. If the execute_data
is allocated on the VM stack this operation would require to always copy
the structure (which is quite large). That's why the execution context is
allocated on the heap instead (only for generators obviously).