1
0
mirror of https://github.com/danog/amp.git synced 2024-11-30 04:29:08 +01:00

Minor coroutine refactoring/optimization; add makeGeneratorError()

This commit is contained in:
Daniel Lowrey 2015-06-16 10:59:44 -04:00
parent 1d777c7e3e
commit 40fbb6e16d

View File

@ -527,7 +527,7 @@ function wait(Promise $promise, Reactor $reactor = null) {
*/ */
function coroutine(callable $func, Reactor $reactor = null) { function coroutine(callable $func, Reactor $reactor = null) {
return function() use ($func, $reactor) { return function() use ($func, $reactor) {
$result = \call_user_func_array($func, func_get_args()); $result = \call_user_func_array($func, \func_get_args());
return ($result instanceof \Generator) return ($result instanceof \Generator)
? resolve($result, $reactor) ? resolve($result, $reactor)
: $result; : $result;
@ -550,7 +550,6 @@ function resolve(\Generator $generator, Reactor $reactor = null) {
$cs->generator = $generator; $cs->generator = $generator;
$cs->returnValue = null; $cs->returnValue = null;
$cs->currentPromise = null; $cs->currentPromise = null;
$cs->isResolved = false;
__coroutineAdvance($cs); __coroutineAdvance($cs);
@ -572,28 +571,30 @@ function __coroutineAdvance($cs) {
} }
} elseif (($key = $cs->generator->key()) === "return") { } elseif (($key = $cs->generator->key()) === "return") {
$cs->returnValue = $yielded; $cs->returnValue = $yielded;
$cs->reactor->immediately("Amp\__coroutineNextTick", ["cb_data" => $cs]); __coroutineSend(null, null, $cs);
} elseif ($yielded instanceof Promise) { } elseif ($yielded instanceof Promise) {
$cs->currentPromise = $yielded; $cs->currentPromise = $yielded;
$cs->reactor->immediately("Amp\__coroutineNextTick", ["cb_data" => $cs]); $cs->reactor->immediately("Amp\__coroutineNextTick", ["cb_data" => $cs]);
} else { } else {
$cs->isResolved = true; $error = makeGeneratorError($cs->generator, sprintf(
$cs->promisor->fail(new \DomainException( 'Unexpected yield (Promise|null|"return" expected); %s yielded at key %s',
__coroutineYieldError($cs->generator, $key, $yielded) is_object($yielded) ? get_class($yielded) : gettype($yielded),
$key
)); ));
$cs->reactor->immediately(function() use ($cs, $error) {
$cs->promisor->fail(new \DomainException($error));
});
} }
} catch (\Exception $uncaught) { } catch (\Exception $uncaught) {
if ($cs->isResolved) { $cs->reactor->immediately(function() use ($cs, $uncaught) {
throw new \RuntimeException("", 0, $uncaught);
} else {
$cs->isResolved = true;
$cs->promisor->fail($uncaught); $cs->promisor->fail($uncaught);
} });
} }
} }
function __coroutineNextTick($reactor, $watcherId, $cs) { function __coroutineNextTick($reactor, $watcherId, $cs) {
if ($promise = $cs->currentPromise) { if ($cs->currentPromise) {
$promise = $cs->currentPromise;
$cs->currentPromise = null; $cs->currentPromise = null;
$promise->when("Amp\__coroutineSend", $cs); $promise->when("Amp\__coroutineSend", $cs);
} else { } else {
@ -610,32 +611,32 @@ function __coroutineSend($error, $result, $cs) {
} }
__coroutineAdvance($cs); __coroutineAdvance($cs);
} catch (\Exception $uncaught) { } catch (\Exception $uncaught) {
if ($cs->isResolved) { $cs->reactor->immediately(function() use ($cs, $uncaught) {
throw new \RuntimeException("", 0, $uncaught);
} else {
$cs->isResolved = true;
$cs->promisor->fail($uncaught); $cs->promisor->fail($uncaught);
} });
} }
} }
function __coroutineYieldError($generator, $key, $yielded) { /**
$type = is_object($yielded) ? get_class($yielded) : gettype($yielded); * A general purpose function for creating error messages from generator yields
$msg = "Unexpected Generator yield (Promise|\"return\"|null expected); {$type} yielded at key {$key}"; *
if (PHP_MAJOR_VERSION < 7) { * @param \Generator $generator
return $msg; * @param string $prefix
* @return string
*/
function makeGeneratorError(\Generator $generator, $prefix = "Generator error") {
if (PHP_MAJOR_VERSION < 7 || !$generator->valid()) {
return $prefix;
} }
$reflGen = new \ReflectionGenerator($generator); $reflGen = new \ReflectionGenerator($generator);
$exeGen = $reflGen->getExecutingGenerator(); $exeGen = $reflGen->getExecutingGenerator();
if ($exeGen !== $generator) { if ($isSubgenerator = ($exeGen !== $generator)) {
// We're executing a subgenerator; use the correct reflection
$reflGen = new \ReflectionGenerator($exeGen); $reflGen = new \ReflectionGenerator($exeGen);
} }
return sprintf( return sprintf(
"%s on line %s in %s", "{$prefix} on line %s in %s",
$msg,
$reflGen->getExecutingLine(), $reflGen->getExecutingLine(),
$reflGen->getExecutingFile() $reflGen->getExecutingFile()
); );