private function processFunction()
{
$current = $this->id;
$functionId = $this->addAtom('Function');
$this->toggleContext(self::CONTEXT_FUNCTION);
$fullcode = array();
foreach ($this->optionsTokens as $name => $optionId) {
$this->addLink($functionId, $optionId, strtoupper($name));
$fullcode[] = $this->atoms[$optionId]['fullcode'];
}
$this->optionsTokens = array();
if ($this->tokens[$this->id + 1][0] === T_AND) {
++$this->id;
$this->setAtom($functionId, array('reference' => true));
} else {
$this->setAtom($functionId, array('reference' => false));
}
if ($this->tokens[$this->id + 1][0] === T_OPEN_PARENTHESIS) {
$isClosure = true;
$nameId = $this->addAtomVoid();
} else {
$isClosure = false;
$nameId = $this->processNextAsIdentifier();
}
$this->addLink($functionId, $nameId, 'NAME');
// Process arguments
++$this->id;
// Skip arguments
$argumentsId = $this->processArguments(array(T_CLOSE_PARENTHESIS), true);
$this->addLink($functionId, $argumentsId, 'ARGUMENTS');
// Process use
if ($this->tokens[$this->id + 1][0] === T_USE) {
++$this->id;
// Skip use
++$this->id;
// Skip (
$useId = $this->processArguments();
$this->addLink($functionId, $useId, 'USE');
}
// Process return type
if ($this->tokens[$this->id + 1][0] === T_COLON) {
++$this->id;
if ($this->tokens[$this->id + 1][0] === T_QUESTION) {
$nullableId = $this->processNextAsIdentifier();
$this->addLink($functionId, $nullableId, 'NULLABLE');
}
$returnTypeId = $this->processOneNsname();
$this->addLink($functionId, $returnTypeId, 'RETURNTYPE');
}
// Process block
if ($this->tokens[$this->id + 1][0] === T_SEMICOLON) {
$voidId = $this->addAtomVoid();
$this->addLink($functionId, $voidId, 'BLOCK');
++$this->id;
// skip the next ;
} else {
$blockId = $this->processFollowingBlock(array(T_CLOSE_CURLY));
$this->popExpression();
$this->addLink($functionId, $blockId, 'BLOCK');
}
if (!empty($fullcode)) {
$fullcode[] = '';
}
if ($isClosure === false && !$this->isContext(self::CONTEXT_CLASS) && !$this->isContext(self::CONTEXT_TRAIT) && !$this->isContext(self::CONTEXT_INTERFACE)) {
$fullnspath = $this->getFullnspath($nameId);
$this->addDefinition('function', $fullnspath, $functionId);
} else {
$fullnspath = '';
}
$this->setAtom($functionId, array('code' => $this->atoms[$nameId]['fullcode'], 'fullcode' => implode(' ', $fullcode) . $this->tokens[$current][1] . ' ' . ($this->atoms[$functionId]['reference'] ? '&' : '') . ($this->atoms[$nameId]['atom'] === 'Void' ? '' : $this->atoms[$nameId]['fullcode']) . '(' . $this->atoms[$argumentsId]['fullcode'] . ')' . (isset($useId) ? ' use (' . $this->atoms[$useId]['fullcode'] . ')' : '') . (isset($returnTypeId) ? ' : ' . (isset($nullableId) ? '?' : '') . $this->atoms[$returnTypeId]['fullcode'] : '') . (isset($blockId) ? self::FULLCODE_BLOCK : ' ;'), 'line' => $this->tokens[$current][2], 'token' => $this->getToken($this->tokens[$current][0]), 'fullnspath' => $fullnspath));
$this->pushExpression($functionId);
if ($this->atoms[$nameId]['atom'] !== 'Void') {
$this->processSemicolon();
}
if (!$this->isContext(self::CONTEXT_NOSEQUENCE) && $this->tokens[$this->id + 1][0] === T_CLOSE_TAG) {
$this->processSemicolon();
}
$this->toggleContext(self::CONTEXT_FUNCTION);
return $functionId;
}