Permalink
Browse files

Remove asterix modifier (*) for generators

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).
  • Loading branch information...
1 parent 85f077c commit c9709bfbd7a71a42e0472abaf9c7d30598e264bf @nikic nikic committed Jul 19, 2012
Showing with 247 additions and 324 deletions.
  1. +1 −1 Zend/tests/generators/auto_incrementing_keys.phpt
  2. +2 −1 Zend/tests/generators/backtrace.phpt
  3. +1 −1 Zend/tests/generators/clone.phpt
  4. +1 −1 Zend/tests/generators/clone_with_foreach.phpt
  5. +1 −1 Zend/tests/generators/clone_with_stack.phpt
  6. +1 −1 Zend/tests/generators/clone_with_symbol_table.phpt
  7. +2 −2 Zend/tests/generators/clone_with_this.phpt
  8. +1 −1 Zend/tests/generators/close_inside_generator.phpt
  9. +1 −1 Zend/tests/generators/dynamic_call.phpt
  10. +2 −1 Zend/tests/generators/errors/generator_cannot_return_error.phpt
  11. +1 −1 Zend/tests/generators/errors/non_ref_generator_iterated_by_ref_error.phpt
  12. +1 −1 Zend/tests/generators/errors/yield_const_by_ref_error.phpt
  13. +0 −12 Zend/tests/generators/errors/yield_in_normal_function_error.phpt
  14. +1 −1 Zend/tests/generators/errors/yield_non_ref_function_call_by_ref_error.phpt
  15. +1 −1 Zend/tests/generators/errors/yield_outside_function_error.phpt
  16. +2 −1 Zend/tests/generators/func_get_args.phpt
  17. +1 −1 Zend/tests/generators/generator_close.phpt
  18. +1 −1 Zend/tests/generators/generator_method.phpt
  19. +1 −1 Zend/tests/generators/generator_method_by_ref.phpt
  20. +4 −2 Zend/tests/generators/generator_returns_generator.phpt
  21. +1 −1 Zend/tests/generators/generator_send.phpt
  22. +1 −1 Zend/tests/generators/generator_throwing_during_function_call.phpt
  23. +1 −1 Zend/tests/generators/generator_throwing_exception.phpt
  24. +1 −1 Zend/tests/generators/generator_with_keys.phpt
  25. +1 −1 Zend/tests/generators/no_foreach_var_leaks.phpt
  26. +4 −4 Zend/tests/generators/send_after_close.phpt
  27. +1 −1 Zend/tests/generators/send_returns_current.phpt
  28. +1 −1 Zend/tests/generators/unused_return_value.phpt
  29. +1 −1 Zend/tests/generators/xrange.phpt
  30. +1 −1 Zend/tests/generators/yield_by_reference.phpt
  31. +1 −1 Zend/tests/generators/yield_during_function_call.phpt
  32. +1 −1 Zend/tests/generators/yield_during_method_call.phpt
  33. +1 −1 Zend/tests/generators/yield_ref_function_call_by_reference.phpt
  34. +1 −1 Zend/tests/generators/yield_without_value.phpt
  35. +11 −27 Zend/zend_compile.c
  36. +2 −3 Zend/zend_compile.h
  37. +1 −0 Zend/zend_execute.h
  38. +8 −1 Zend/zend_execute_API.c
  39. +50 −3 Zend/zend_generators.c
  40. +1 −0 Zend/zend_generators.h
  41. +11 −16 Zend/zend_language_parser.y
  42. +11 −98 Zend/zend_vm_def.h
  43. +106 −122 Zend/zend_vm_execute.h
  44. +1 −1 Zend/zend_vm_execute.skl
  45. +2 −3 Zend/zend_vm_opcodes.h
@@ -3,7 +3,7 @@ Generator keys are auto-incrementing by default
--FILE--
<?php
-function *gen() {
+function gen() {
yield 'foo';
yield 'bar';
yield 5 => 'rab';
@@ -7,8 +7,9 @@ function f1() {
debug_print_backtrace();
}
-function *f2($arg1, $arg2) {
+function f2($arg1, $arg2) {
f1();
+ yield; // force generator
}
function f3($gen) {
@@ -3,7 +3,7 @@ Generators can be cloned
--FILE--
<?php
-function *firstN($end) {
+function firstN($end) {
for ($i = 0; $i < $end; ++$i) {
yield $i;
}
@@ -3,7 +3,7 @@ Cloning a generator with a foreach loop properly adds a ref for the loop var
--FILE--
<?php
-function *gen() {
+function gen() {
foreach ([1, 2, 3] as $i) {
yield $i;
}
@@ -3,7 +3,7 @@ A generator with an active stack can be cloned
--FILE--
<?php
-function *gen() {
+function gen() {
var_dump(str_repeat("x", yield));
}
@@ -3,7 +3,7 @@ A generator using a symbol table can be cloned
--FILE--
<?php
-function *gen() {
+function gen() {
// force compiled variable for $foo
$foo = 'foo';
@@ -1,12 +1,12 @@
--TEST--
-Cloning a generator method (with this)
+Cloning a generator method (with $this)
--FILE--
<?php
class Test {
protected $foo;
- public function *gen() {
+ public function gen() {
$this->foo = 'bar';
yield; // interrupt
var_dump($this->foo);
@@ -3,7 +3,7 @@ Calling close() during the exectution of the generator
--FILE--
<?php
-function *gen() {
+function gen() {
/* Pass the generator object itself in */
$gen = yield;
@@ -3,7 +3,7 @@ It's possible to invoke a generator dynamically
--FILE--
<?php
-function *gen($foo, $bar) {
+function gen($foo, $bar) {
yield $foo;
yield $bar;
}
@@ -3,7 +3,8 @@ Generators cannot return values
--FILE--
<?php
-function *gen() {
+function gen() {
+ yield;
return $abc;
}
@@ -3,7 +3,7 @@ Non-ref generators cannot be iterated by-ref
--FILE--
<?php
-function *gen() { }
+function gen() { yield; }
$gen = gen();
foreach ($gen as &$value) { }
@@ -3,7 +3,7 @@ A notice is thrown when yielding a constant value by reference
--FILE--
<?php
-function *&gen() {
+function &gen() {
yield "foo";
}
@@ -1,12 +0,0 @@
---TEST--
-Yield cannot be used in normal (non-generator) functions
---FILE--
-<?php
-
-function foo() {
- yield "Test";
-}
-
-?>
---EXPECTF--
-Fatal error: The "yield" expression can only be used inside a generator function in %s on line %d
@@ -7,7 +7,7 @@ function foo() {
return "bar";
}
-function *&gen() {
+function &gen() {
yield foo();
}
@@ -7,4 +7,4 @@ yield "Test";
?>
--EXPECTF--
-Fatal error: The "yield" expression can only be used inside a generator function in %s on line %d
+Fatal error: The "yield" expression can only be used inside a function in %s on line %d
@@ -3,8 +3,9 @@ func_get_args() can be used inside generator functions
--FILE--
<?php
-function *gen() {
+function gen() {
var_dump(func_get_args());
+ yield; // trigger generator
}
$gen = gen("foo", "bar");
@@ -3,7 +3,7 @@ Generator can be closed by calling ->close()
--FILE--
<?php
-function *allNumbers() {
+function allNumbers() {
for ($i = 0; true; ++$i) {
yield $i;
}
@@ -10,7 +10,7 @@ class Test implements IteratorAggregate {
$this->data = $data;
}
- public function *getIterator() {
+ public function getIterator() {
foreach ($this->data as $value) {
yield $value;
}
@@ -14,7 +14,7 @@ class Test implements IteratorAggregate {
return $this->data;
}
- public function *&getIterator() {
+ public function &getIterator() {
foreach ($this->data as $key => &$value) {
yield $key => $value;
}
@@ -3,12 +3,14 @@ A generator function returns a Generator object
--FILE--
<?php
-function* foo() {
+function gen() {
// execution is suspended here, so the following never gets run:
echo "Foo";
+ // trigger a generator
+ yield;
}
-$generator = foo();
+$generator = gen();
var_dump($generator instanceof Generator);
?>
@@ -3,7 +3,7 @@ Values can be sent back to the generator
--FILE--
<?php
-function *gen() {
+function gen() {
var_dump(yield "yield foo");
var_dump(yield "yield bar");
}
@@ -7,7 +7,7 @@ function throwException() {
throw new Exception('test');
}
-function *gen() {
+function gen() {
yield 'foo';
strlen("foo", "bar", throwException());
yield 'bar';
@@ -3,7 +3,7 @@ Generators can throw exceptions
--FILE--
<?php
-function *gen() {
+function gen() {
yield 'foo';
throw new Exception('test');
yield 'bar';
@@ -3,7 +3,7 @@ Generators can also yield keys
--FILE--
<?php
-function *reverse(array $array) {
+function reverse(array $array) {
end($array);
while (null !== $key = key($array)) {
yield $key => current($array);
@@ -3,7 +3,7 @@ foreach() (and other) variables aren't leaked on premature close
--FILE--
<?php
-function *gen(array $array) {
+function gen(array $array) {
foreach ($array as $value) {
yield $value;
}
@@ -3,12 +3,12 @@ Calls to send() after close should do nothing
--FILE--
<?php
-function *gen() { }
+function gen() { var_dump(yield); }
$gen = gen();
-$gen->send("Test");
+$gen->send('foo');
+$gen->send('bar');
?>
-===DONE===
--EXPECT--
-===DONE===
+string(3) "foo"
@@ -3,7 +3,7 @@ $generator->send() returns the yielded value
--FILE--
<?php
-function *reverseEchoGenerator() {
+function reverseEchoGenerator() {
$data = yield;
while (true) {
$data = yield strrev($data);
@@ -3,7 +3,7 @@ There shouldn't be any leaks when the genertor's return value isn't used
--FILE--
<?php
-function *gen($foo) {}
+function gen($foo) { yield; }
gen('foo'); // return value not used
@@ -3,7 +3,7 @@ Simple generator xrange() test
--FILE--
<?php
-function *xrange($start, $end, $step = 1) {
+function xrange($start, $end, $step = 1) {
for ($i = $start; $i <= $end; $i += $step) {
yield $i;
}
@@ -3,7 +3,7 @@ Generators can yield by-reference
--FILE--
<?php
-function *&iter(array &$array) {
+function &iter(array &$array) {
foreach ($array as $key => &$value) {
yield $key => $value;
}
@@ -3,7 +3,7 @@
--FILE--
<?php
-function *gen() {
+function gen() {
var_dump(str_repeat("x", yield));
}
@@ -9,7 +9,7 @@ class A {
}
}
-function *gen() {
+function gen() {
$a = new A;
$a->b(yield);
}
@@ -7,7 +7,7 @@ function &nop(&$var) {
return $var;
}
-function *&gen(&$var) {
+function &gen(&$var) {
yield nop($var);
}
@@ -3,7 +3,7 @@ yield can be used without a value
--FILE--
<?php
-function *recv() {
+function recv() {
while (true) {
var_dump(yield);
}
Oops, something went wrong. Retry.

0 comments on commit c9709bf

Please sign in to comment.