Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add generators support #177

Merged
merged 74 commits into from
Sep 1, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
9b101ac
Add T_YIELD "yield" keyword
nikic May 15, 2012
252f623
Add flag for generator functions
nikic May 19, 2012
9b51a3b
Minor code cleanup
nikic May 19, 2012
fd2a109
Add error if yield is used outside a generator
nikic May 19, 2012
e14cfaf
Add zend_do_suspend_if_generator calls
nikic May 19, 2012
1cec3f1
Add ZEND_SUSPEND_AND_RETURN_GENERATOR opcode
nikic May 19, 2012
ca59e54
Add empty Generator class
nikic May 19, 2012
40b7533
Add some boilerplate code for Generator class
nikic May 20, 2012
46fa26a
Make generator functions return a Generator object
nikic May 20, 2012
5e763d9
Allocate execute_data using malloc for generators
nikic May 22, 2012
9ce9a7e
Add initial code for suspending execution
nikic May 23, 2012
2c5ecb4
Add dummy Iterator implementation
nikic May 23, 2012
ececcbc
Allow calling zend_vm_gen from everywhere
nikic May 23, 2012
f627be5
Add support for executing a zend_execute_data
nikic May 26, 2012
1a99d1c
Add way to pass generator object to opcode handlers
nikic May 26, 2012
fafce58
Add YIELD opcode implementation
nikic May 26, 2012
5bb3a99
Implement return for generators
nikic May 26, 2012
d49d397
Close generator on return
nikic May 26, 2012
cbfa96c
Remove wrong dtor call
nikic May 26, 2012
39d3d5e
Add first real generator test
nikic May 26, 2012
247bb73
Add support for generator methods
nikic May 27, 2012
64a643a
Free loop variables
nikic May 27, 2012
9f52c5c
Fix generator creation when execute_data is not nested
nikic May 27, 2012
bcc7d97
Set EG(current_execute_data)
nikic May 27, 2012
4aab08b
Properly free resources when generator return value not used
nikic May 28, 2012
b770b22
Make the GOTO and SWITCH VMs work again
nikic May 29, 2012
3600914
Add support for $generator->send()
nikic May 29, 2012
ad525c2
Allow to use yield without value
nikic May 29, 2012
12e9283
Fix segfault when send()ing to a closed generator
nikic May 29, 2012
72a91d0
Add $generator->close() method
nikic May 29, 2012
bc08c2c
Add support for yielding keys
nikic May 30, 2012
8790160
Add auto-increment keys
nikic May 30, 2012
0033a52
Allow throwing exceptions from generators
nikic May 30, 2012
ee89e22
Allow yielding during function calls
nikic May 30, 2012
1477be9
Make $generator->send() return the current value
nikic May 31, 2012
6117f4c
Add cloning support for generators
nikic Jun 2, 2012
7b3bfa5
Improve backtraces from generators
nikic Jun 3, 2012
bf82f46
Properly handle yield during method calls
nikic Jun 3, 2012
40760ec
Fix cloning of generator methods
nikic Jun 3, 2012
f169b26
Fix backtraces and func_get_args()
nikic Jun 8, 2012
d939d2d
Add sceleton for yield* expression
nikic Jun 11, 2012
6233408
Fix thread safe build
nikic Jun 20, 2012
1d3f37d
Fix segfault in method test
nikic Jun 22, 2012
04e781f
Implement get_iterator
nikic Jun 22, 2012
14766e1
Pass zend_generator directly to Zend VM
nikic Jun 23, 2012
ab75ed6
Disallow closing a generator during its execution
nikic Jun 23, 2012
5a9bddb
Forgot to git add two tests
nikic Jun 25, 2012
85f077c
Add support by yielding by-reference
nikic Jul 17, 2012
c9709bf
Remove asterix modifier (*) for generators
nikic Jul 19, 2012
612c249
Move a variable
nikic Jul 20, 2012
1f70a4c
Add some more tests
nikic Jul 20, 2012
8074863
Require parenthesis around yield expressions
nikic Jul 21, 2012
de80e3c
Remove reference restrictions from foreach
nikic Jul 22, 2012
94b2cca
Fix throwing of exceptions within a generator
nikic Jul 22, 2012
1340893
Throw error also for return occuring before yield
nikic Jul 22, 2012
99f93dd
Add T_YIELD in tokenizer_data.c
nikic Jul 22, 2012
268740d
Fix implementation of Iterator interface
nikic Jul 26, 2012
f4ce364
Merge remote-tracking branch 'php-src/master' into addGeneratorsSupport
nikic Aug 13, 2012
ae71693
Support trivial finally in generators (no yield, no return)
nikic Aug 13, 2012
7195a5b
Forgot to add test
nikic Aug 13, 2012
05f1048
Drop Generator::close() method
nikic Aug 20, 2012
9003cd1
Fix zts build (typo)
nikic Aug 20, 2012
1823b16
Merge remote-tracking branch 'php-src/master' into addGeneratorsSupport
nikic Aug 20, 2012
f45a0f3
Disallow serialization and unserialization
nikic Aug 20, 2012
6517ed0
Merge remote-tracking branch 'php-src/master' into addGeneratorsSupport
nikic Aug 24, 2012
68c1e1c
Add dedicated opcode for returns from a generator
nikic Aug 24, 2012
7cdf636
Finally with return now works in generators too
nikic Aug 24, 2012
4d8edda
Run finally if generator is closed before finishing
nikic Aug 24, 2012
f53225a
Fix several issues and allow rewind only at/before first yield
nikic Aug 25, 2012
bd70d15
Remove implementation stubs for yield delegation
nikic Aug 25, 2012
d60e3c6
Merge remote-tracking branch 'php-src/master' into addGeneratorsSupport
nikic Aug 25, 2012
cc07038
Make sure that exception is thrown on rewind() after closing too
nikic Aug 29, 2012
bef7958
Fix segfault when traversing a by-ref generator twice
nikic Aug 29, 2012
dbc7809
Fix typos
nikic Aug 29, 2012
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Zend/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ libZend_la_SOURCES=\
zend_objects_API.c zend_ts_hash.c zend_stream.c \
zend_default_classes.c \
zend_iterators.c zend_interfaces.c zend_exceptions.c \
zend_strtod.c zend_closures.c zend_float.c zend_string.c zend_signal.c
zend_strtod.c zend_closures.c zend_float.c zend_string.c zend_signal.c \
zend_generators.c

libZend_la_LDFLAGS =
libZend_la_LIBADD = @ZEND_EXTRA_LIBS@
Expand Down
4 changes: 4 additions & 0 deletions Zend/Zend.dsp

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Zend/ZendTS.dsp

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 0 additions & 12 deletions Zend/tests/errmsg_043.phpt

This file was deleted.

18 changes: 18 additions & 0 deletions Zend/tests/foreach_temp_array_expr_with_refs.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
Temporary array expressions can be iterated by reference
--FILE--
<?php

$a = 'a';
$b = 'b';

foreach ([&$a, &$b] as &$value) {
$value .= '-foo';
}

var_dump($a, $b);

?>
--EXPECT--
string(5) "a-foo"
string(5) "b-foo"
22 changes: 22 additions & 0 deletions Zend/tests/generators/auto_incrementing_keys.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
Generator keys are auto-incrementing by default
--FILE--
<?php

function gen() {
yield 'foo';
yield 'bar';
yield 5 => 'rab';
yield 'oof';
}

foreach (gen() as $k => $v) {
echo $k, ' => ', $v, "\n";
}

?>
--EXPECT--
0 => foo
1 => bar
5 => rab
6 => oof
27 changes: 27 additions & 0 deletions Zend/tests/generators/backtrace.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--TEST--
Printing the stack trace in a generator
--FILE--
<?php

function f1() {
debug_print_backtrace();
}

function f2($arg1, $arg2) {
f1();
yield; // force generator
}

function f3($gen) {
$gen->rewind(); // trigger run
}

$gen = f2('foo', 'bar');
f3($gen);

?>
--EXPECTF--
#0 f1() called at [%s:%d]
#1 f2(foo, bar)
#2 Generator->rewind() called at [%s:%d]
#3 f3(Generator Object ()) called at [%s:%d]
32 changes: 32 additions & 0 deletions Zend/tests/generators/clone.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
--TEST--
Generators can be cloned
--FILE--
<?php

function firstN($end) {
for ($i = 0; $i < $end; ++$i) {
yield $i;
}
}

$g1 = firstN(5);
var_dump($g1->current());
$g1->next();

$g2 = clone $g1;
var_dump($g2->current());
$g2->next();

var_dump($g2->current());
var_dump($g1->current());

$g1->next();
var_dump($g1->current());

?>
--EXPECT--
int(0)
int(1)
int(2)
int(1)
int(2)
33 changes: 33 additions & 0 deletions Zend/tests/generators/clone_with_foreach.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
--TEST--
Cloning a generator with a foreach loop properly adds a ref for the loop var
--FILE--
<?php

function gen() {
foreach ([1, 2, 3] as $i) {
yield $i;
}
}

$g1 = gen();
var_dump($g1->current());

$g2 = clone $g1;
var_dump($g2->current());

$g1->next();
$g2->next();
var_dump($g1->current());
var_dump($g2->current());

unset($g1);
$g2->next();
var_dump($g2->current());

?>
--EXPECT--
int(1)
int(1)
int(2)
int(2)
int(3)
18 changes: 18 additions & 0 deletions Zend/tests/generators/clone_with_stack.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
A generator with an active stack can be cloned
--FILE--
<?php

function gen() {
var_dump(str_repeat("x", yield));
}

$g1 = gen();
$g1->rewind();
$g2 = clone $g1;
unset($g1);
$g2->send(10);

?>
--EXPECT--
string(10) "xxxxxxxxxx"
27 changes: 27 additions & 0 deletions Zend/tests/generators/clone_with_symbol_table.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--TEST--
A generator using a symbol table can be cloned
--FILE--
<?php

function gen() {
// force compiled variable for $foo
$foo = 'foo';

// force symbol table
extract(['foo' => 'bar']);

// interrupt
yield;

var_dump($foo);
}

$g1 = gen();
$g1->rewind();
$g2 = clone $g1;
unset($g1);
$g2->next();

?>
--EXPECT--
string(3) "bar"
24 changes: 24 additions & 0 deletions Zend/tests/generators/clone_with_this.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
--TEST--
Cloning a generator method (with $this)
--FILE--
<?php

class Test {
protected $foo;

public function gen() {
$this->foo = 'bar';
yield; // interrupt
var_dump($this->foo);
}
}

$g1 = (new Test)->gen();
$g1->rewind(); // goto yield
$g2 = clone $g1;
unset($g1);
$g2->next();

?>
--EXPECT--
string(3) "bar"
19 changes: 19 additions & 0 deletions Zend/tests/generators/dynamic_call.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
It's possible to invoke a generator dynamically
--FILE--
<?php

function gen($foo, $bar) {
yield $foo;
yield $bar;
}

$gen = call_user_func('gen', 'bar', 'foo');
foreach ($gen as $value) {
var_dump($value);
}

?>
--EXPECT--
string(3) "bar"
string(3) "foo"
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--TEST--
Generators cannot return values (even before yield)
--FILE--
<?php

function gen() {
return $foo;
yield;
}

?>
--EXPECTF--
Fatal error: Generators cannot return values using "return" in %s on line 4
13 changes: 13 additions & 0 deletions Zend/tests/generators/errors/generator_cannot_return_error.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--TEST--
Generators cannot return values
--FILE--
<?php

function gen() {
yield;
return $abc;
}

?>
--EXPECTF--
Fatal error: Generators cannot return values using "return" in %s on line 5
10 changes: 10 additions & 0 deletions Zend/tests/generators/errors/generator_extend_error.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--TEST--
The Generator class cannot be extended
--FILE--
<?php

class ExtendedGenerator extends Generator { }

?>
--EXPECTF--
Fatal error: Class ExtendedGenerator may not inherit from final class (Generator) in %s on line %d
10 changes: 10 additions & 0 deletions Zend/tests/generators/errors/generator_instantiate_error.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--TEST--
It's not possible to directly instantiate the Generator class
--FILE--
<?php

new Generator;

?>
--EXPECTF--
Catchable fatal error: The "Generator" class is reserved for internal use and cannot be manually instantiated in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
Non-ref generators cannot be iterated by-ref
--FILE--
<?php

function gen() { yield; }

$gen = gen();
foreach ($gen as &$value) { }

?>
--EXPECTF--
Fatal error: Uncaught exception 'Exception' with message 'You can only iterate a generator by-reference if it declared that it yields by-reference' in %s:%d
Stack trace:
#0 %s(%d): unknown()
#1 {main}
thrown in %s on line %d

17 changes: 17 additions & 0 deletions Zend/tests/generators/errors/resume_running_generator_error.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
It is not possible to resume an already running generator
--FILE--
<?php

function gen() {
$gen = yield;
$gen->next();
}

$gen = gen();
$gen->send($gen);
$gen->next();

?>
--EXPECTF--
Fatal error: Cannot resume an already running generator in %s on line %d
Loading