public function convert(Project $project, File $file) : string
{
$tokens = token_get_all($file->getSource());
$output = '';
$outsideFunctionSignature = false;
$insideFunctionSignature = false;
$insideNamespace = false;
$objectType = self::OBJECT_FUNCTION;
$outputTypeHint = true;
$outputDefaultValue = false;
$outputReturn = true;
$namespace = null;
$object = null;
$function = null;
$level = 0;
foreach ($tokens as $token) {
if (is_string($token)) {
switch ($token) {
case '(':
if ($outsideFunctionSignature) {
$insideFunctionSignature = true;
$outsideFunctionSignature = false;
}
break;
case ':':
if (null !== $function) {
$outputReturn = false;
}
break;
case ')':
if ($insideFunctionSignature) {
if ($outputDefaultValue) {
$output .= ' = null';
}
$insideFunctionSignature = false;
}
break;
case ',':
if ($insideFunctionSignature && $outputDefaultValue) {
$output .= ' = null';
}
break;
case '=':
if ($insideFunctionSignature) {
$outputDefaultValue = false;
}
break;
case ';':
case '{':
if (null !== $function && $outputReturn) {
$return = $this->getReturn($project, $objectType, $namespace, $object, $function);
if ($return && $return[0] && !$return[1]) {
if ($endsInNewLine = $this->endsInNewLine($output)) {
$output = substr($output, 0, -strlen($endsInNewLine));
}
$output .= sprintf(': %s', $return[0]);
if ($endsInNewLine) {
$output .= $endsInNewLine;
}
}
$function = null;
$outputReturn = false;
}
if ('{' === $token) {
++$level;
}
if (';' === $token && $insideNamespace) {
$insideNamespace = false;
}
break;
case '}':
--$level;
if (0 === $level) {
$objectType = self::OBJECT_FUNCTION;
}
break;
}
$output .= $token;
continue;
}
list($id, $text) = $token;
switch ($id) {
case T_NAMESPACE:
$insideNamespace = true;
$namespace = '\\';
break;
case T_STRING:
if ($outsideFunctionSignature) {
$function = $text;
}
if (null === $object && $objectType !== self::OBJECT_FUNCTION) {
$object = $text;
}
// No break
// No break
case T_NS_SEPARATOR:
case T_STRING:
if ($insideNamespace) {
$namespace .= $text;
}
// No break
// No break
case T_STRING:
case T_ARRAY:
case T_CALLABLE:
if ($insideFunctionSignature) {
$outputTypeHint = false;
}
break;
case T_CLASS:
$objectType = self::OBJECT_CLASS;
$object = null;
$level = 0;
break;
case T_INTERFACE:
$objectType = self::OBJECT_INTERFACE;
$object = null;
$level = 0;
break;
case T_TRAIT:
$objectType = self::OBJECT_TRAIT;
$object = null;
$level = 0;
break;
case T_FUNCTION:
$outsideFunctionSignature = true;
$outputDefaultValue = false;
$outputReturn = true;
break;
case T_VARIABLE:
if ($insideFunctionSignature) {
$outputDefaultValue = false;
if (null !== $function && $outputTypeHint) {
$parameter = $this->getParameter($project, $objectType, $namespace, $object, $function, $text);
if ($parameter) {
$output .= $parameter[0] . ' ';
$outputDefaultValue = (bool) $parameter[1];
}
$output .= $text;
$outputTypeHint = true;
continue 2;
}
$outputTypeHint = true;
}
break;
}
$output .= $text;
}
return $output;
}