/**
  * Returns a FunctionDefinition from a token array.
  *
  * This method will use a set of other methods to parse a token array and retrieve any
  * possible information from it. This information will be entered into a FunctionDefinition object.
  *
  * @param array   $tokens       The token array
  * @param boolean $getRecursive Do we have to get the ancestral conditions as well?
  *
  * @return \AppserverIo\Doppelgaenger\Entities\Definitions\FunctionDefinition
  */
 protected function getDefinitionFromTokens(array $tokens, $getRecursive)
 {
     // First of all we need a new FunctionDefinition to fill
     $functionDefinition = new FunctionDefinition();
     // For our next step we would like to get the doc comment (if any)
     $functionDefinition->setDocBlock($this->getDocBlock($tokens, T_FUNCTION));
     // Get start and end line
     $functionDefinition->setStartLine($this->getStartLine($tokens));
     $functionDefinition->setEndLine($this->getEndLine($tokens));
     // Get the function signature
     $functionDefinition->setIsFinal($this->hasSignatureToken($tokens, T_FINAL, T_FUNCTION));
     $functionDefinition->setIsAbstract($this->hasSignatureToken($tokens, T_ABSTRACT, T_FUNCTION));
     $functionDefinition->setVisibility($this->getFunctionVisibility($tokens));
     $functionDefinition->setIsStatic($this->hasSignatureToken($tokens, T_STATIC, T_FUNCTION));
     $functionDefinition->setName($this->getFunctionName($tokens));
     $functionDefinition->setStructureName($this->currentDefinition->getQualifiedName());
     // Lets also get out parameters
     $functionDefinition->setParameterDefinitions($this->getParameterDefinitionList($tokens));
     // Do we have a private context here? If so we have to tell the annotation parser
     $privateContext = false;
     if ($functionDefinition->getVisibility() === 'private') {
         $privateContext = true;
     }
     // So we got our docBlock, now we can parse the precondition annotations from it
     $annotationParser = new AnnotationParser($this->file, $this->config, $this->tokens, $this->currentDefinition);
     $functionDefinition->setPreconditions($annotationParser->getConditions($functionDefinition->getDocBlock(), Requires::ANNOTATION, $privateContext));
     // get the advices
     $functionDefinition->getPointcutExpressions()->attach($annotationParser->getPointcutExpressions($functionDefinition->getDocBlock(), Joinpoint::TARGET_METHOD, $functionDefinition->getName()));
     // Does this method require the use of our "old" mechanism?
     $functionDefinition->setUsesOld($this->usesKeyword($functionDefinition->getDocBlock(), ReservedKeywords::OLD));
     // We have to get the body of the function, so we can recreate it
     $functionDefinition->setBody($this->getFunctionBody($tokens));
     // So we got our docBlock, now we can parse the postcondition annotations from it
     $functionDefinition->setPostconditions($annotationParser->getConditions($functionDefinition->getDocBlock(), Ensures::ANNOTATION, $privateContext));
     // If we have to parse the definition in a recursive manner, we have to get the parent invariants
     if ($getRecursive === true) {
         // Add all the assertions we might get from ancestral dependencies
         $this->addAncestralAssertions($functionDefinition);
     }
     return $functionDefinition;
 }