generator = $generator; /** * @param \Throwable|\Exception|null $exception Exception to be thrown into the generator. * @param mixed $value The value to send to the generator. */ $this->when = function ($exception, $value) { if (self::MAX_CONTINUATION_DEPTH < $this->depth) { // Defer continuation to avoid blowing up call stack. Loop::defer(function () use ($exception, $value) { $when = $this->when; $when($exception, $value); }); return; } try { if ($exception) { // Throw exception at current execution point. $this->next($this->generator->throw($exception)); return; } // Send the new value and execute to next yield statement. $this->next($this->generator->send($value)); } catch (\Throwable $exception) { $this->fail($exception); } catch (\Exception $exception) { $this->fail($exception); } }; try { $this->next($this->generator->current()); } catch (\Throwable $exception) { $this->fail($exception); } catch (\Exception $exception) { $this->fail($exception); } } /** * Examines the value yielded from the generator and prepares the next step in iteration. * * @param mixed $yielded Value yielded from generator. */ private function next($yielded) { if (!$this->generator->valid()) { $this->resolve(PHP_MAJOR_VERSION >= 7 ? $this->generator->getReturn() : null); return; } ++$this->depth; if ($yielded instanceof Awaitable) { $yielded->when($this->when); } elseif ($yielded instanceof Internal\CoroutineResult) { // @todo Necessary for returning values in PHP 5.x. Remove once PHP 7 is required. $yielded = $yielded->getValue(); try { $value = $this->generator->send($yielded); if ($this->generator->valid()) { $exception = new InvalidYieldException( $this->generator, $value, "Unexpected yield after coroutine result" ); do { $this->generator->throw($exception); } while ($this->generator->valid()); throw $exception; } else { $this->resolve($yielded); } } catch (\Throwable $exception) { $this->fail($exception); } catch (\Exception $exception) { $this->fail($exception); } } else { throw new InvalidYieldException( $this->generator, $yielded, \sprintf("Unexpected yield (%s expected)", Awaitable::class) ); } --$this->depth; } /** * Return a value from a coroutine. Required for PHP 5.x only. Use the return keyword in PHP 7. * * @param mixed $value * * @return \Amp\Internal\CoroutineResult */ public static function result($value) { return new Internal\CoroutineResult($value); } }