protected function compile($expr, Context $context)
{
$expressionCompiler = $context->getExpressionCompiler();
$fNameExpression = $expressionCompiler->compile($expr->name);
$name = $fNameExpression->getValue();
$compiler = $context->application->compiler;
$exists = false;
$arguments = $this->parseArgs($expr, clone $context);
// is it a Closure
if ($fNameExpression->isCallable() && $name instanceof ClosureDefinition) {
return $name->run($this->parseArgs($expr, clone $context), $context);
}
// is the function name a correct string
if (!$fNameExpression->isString() || !$fNameExpression->isCorrectValue()) {
$context->debug('Unexpected function name type ' . $fNameExpression->getTypeName(), $expr->name);
return new CompiledExpression();
}
// namespace check for correct functionDefinition
if ($context->scope) {
$functionDefinition = $compiler->getFunctionNS($name, $context->scope->getNamespace());
} else {
$functionDefinition = $compiler->getFunction($name);
}
// does the function exist
if ($functionDefinition) {
if (!$functionDefinition->isCompiled()) {
$functionDefinition->compile(clone $context);
}
$exists = true;
} else {
$exists = function_exists($name);
}
if (!$exists) {
$context->notice('language_error', sprintf('Function %s() does not exist', $expr->name->parts[0]), $expr);
} else {
$reflector = new Reflector(Reflector::manuallyFactory());
$functionReflection = $reflector->getFunction($name);
if ($functionReflection) {
$argumentsSuccessPass = $this->checkArguments($arguments, $functionReflection);
// when everything is ok we run the function
if ($argumentsSuccessPass && $functionReflection->isRunnable()) {
array_walk($arguments, function (&$item) {
/** @var CompiledExpression $item */
$item = $item->getValue();
});
return new CompiledExpression($functionReflection->getReturnType(), $functionReflection->run($arguments));
}
return new CompiledExpression($functionReflection->getReturnType());
}
}
return new CompiledExpression();
}