private function doInvoke(BytesIO $stream, stdClass $context)
{
$results = array();
$reader = new Reader($stream);
do {
$reader->reset();
$name = $reader->readString();
$alias = strtolower($name);
$cc = new stdClass();
$cc->isMissingMethod = false;
foreach ($context as $key => $value) {
$cc->{$key} = $value;
}
if (isset($this->calls[$alias])) {
$call = $this->calls[$alias];
} else {
if (isset($this->calls['*'])) {
$call = $this->calls['*'];
$cc->isMissingMethod = true;
}
}
if ($call) {
foreach ($call as $key => $value) {
$cc->{$key} = $value;
}
}
$args = array();
$cc->byref = false;
$tag = $stream->getc();
if ($tag === Tags::TagList) {
$reader->reset();
$args = $reader->readListWithoutTag();
$tag = $stream->getc();
if ($tag === Tags::TagTrue) {
$cc->byref = true;
$tag = $stream->getc();
}
}
if ($tag !== Tags::TagEnd && $tag !== Tags::TagCall) {
$data = $stream->toString();
throw new Exception("Unknown tag: {$tag}\r\nwith following data: {$data}");
}
if ($call) {
$results[] = $this->beforeInvoke($name, $args, $cc);
} else {
$results[] = $this->sendError(new Exception("Can\\'t find this function {$name}()."), $cc);
}
} while ($tag === Tags::TagCall);
return Future\reduce($results, function ($stream, $result) {
$stream->write($result);
return $stream;
}, new BytesIO())->then(function ($stream) {
$stream->write(Tags::TagEnd);
$data = $stream->toString();
$stream->close();
return $data;
});
}