/**
  * Will inject enforcement processing for a certain function.
  * Will take default processing code into account and check for custom processing configurations
  *
  * @param string             $bucketData         Payload of the currently filtered bucket
  * @param string             $structureName      The name of the structure for which we create the enforcement code
  * @param string             $structurePath      Path to the file containing the structure
  * @param string             $preconditionCode   Default precondition processing code
  * @param string             $postconditionCode  Default post-condition processing code
  * @param FunctionDefinition $functionDefinition Function definition to create the code for
  *
  * @return null
  */
 protected function injectFunctionEnforcement(&$bucketData, $structureName, $structurePath, $preconditionCode, $postconditionCode, FunctionDefinition $functionDefinition)
 {
     $functionName = $functionDefinition->getName();
     // try to find a local enforcement processing configuration, if we find something we have to
     // create new enforcement code based on that information
     $localType = $this->filterLocalProcessing($functionDefinition->getDocBlock());
     if ($localType !== false) {
         // we found something, make a backup of default enforcement and generate the new code
         $preconditionCode = $this->generateCode($structureName, 'precondition', $localType, $structurePath);
         $postconditionCode = $this->generateCode($structureName, 'postcondition', $localType, $structurePath);
     }
     // Insert the code for the static processing placeholders
     $bucketData = str_replace(array(Placeholders::ENFORCEMENT . $functionName . 'precondition' . Placeholders::PLACEHOLDER_CLOSE, Placeholders::ENFORCEMENT . $functionName . 'postcondition' . Placeholders::PLACEHOLDER_CLOSE), array($preconditionCode, $postconditionCode), $bucketData);
 }
 /**
  * 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;
 }
 /**
  * Will generate the skeleton code for the passed function definition.
  * Will result in a string resembling the following example:
  *
  *      <FUNCTION_DOCBLOCK>
  *      <FUNCTION_MODIFIERS> function <FUNCTION_NAME>(<FUNCTION_PARAMS>)
  *      {
  *          $dgStartLine = <FUNCTION_START_LINE>;
  *          $dgEndLine = <FUNCTION_END_LINE>;
  *          / DOPPELGAENGER_FUNCTION_BEGIN_PLACEHOLDER <FUNCTION_NAME> /
  *          / DOPPELGAENGER_BEFORE_JOINPOINT <FUNCTION_NAME> /
  *          $dgOngoingContract = \AppserverIo\Doppelgaenger\ContractContext::open();
  *          / DOPPELGAENGER_INVARIANT_PLACEHOLDER /
  *          / DOPPELGAENGER_PRECONDITION_PLACEHOLDER <FUNCTION_NAME> /
  *          / DOPPELGAENGER_OLD_SETUP_PLACEHOLDER <FUNCTION_NAME> /
  *          $dgResult = null;
  *          try {
  *              / DOPPELGAENGER_AROUND_JOINPOINT <FUNCTION_NAME> /
  *
  *          } catch (\Exception $dgThrownExceptionObject) {
  *              / DOPPELGAENGER_AFTERTHROWING_JOINPOINT <FUNCTION_NAME> /
  *
  *              // rethrow the exception
  *              throw $dgThrownExceptionObject;
  *
  *          } finally {
  *              / DOPPELGAENGER_AFTER_JOINPOINT <FUNCTION_NAME> /
  *
  *          }
  *          / DOPPELGAENGER_POSTCONDITION_PLACEHOLDER <FUNCTION_NAME> /
  *          / DOPPELGAENGER_INVARIANT_PLACEHOLDER /
  *          if ($dgOngoingContract) {
  *              \AppserverIo\Doppelgaenger\ContractContext::close();
  *          } / DOPPELGAENGER_AFTERRETURNING_JOINPOINT <FUNCTION_NAME> /
  *
  *          return $dgResult;
  *      }
  *
  * @param boolean            $injectNeeded       Determine if we have to use a try...catch block
  * @param FunctionDefinition $functionDefinition The function definition object
  *
  * @return string
  */
 protected function generateSkeletonCode($injectNeeded, FunctionDefinition $functionDefinition)
 {
     // first of all: the docblock
     $code = '
     ' . $functionDefinition->getDocBlock() . '
     ' . $functionDefinition->getHeader('definition') . '
     {
         ' . ReservedKeywords::START_LINE_VARIABLE . ' = ' . (int) $functionDefinition->getStartLine() . ';
         ' . ReservedKeywords::END_LINE_VARIABLE . ' = ' . (int) $functionDefinition->getEndLine() . ';
         ' . Placeholders::FUNCTION_BEGIN . $functionDefinition->getName() . Placeholders::PLACEHOLDER_CLOSE . '
         ';
     // right after: the "before" join-point
     $code .= Placeholders::BEFORE_JOINPOINT . $functionDefinition->getName() . Placeholders::PLACEHOLDER_CLOSE . '
         ';
     // open the contract context so we are able to avoid endless recursion
     $code .= ReservedKeywords::CONTRACT_CONTEXT . ' = \\AppserverIo\\Doppelgaenger\\ContractContext::open();
         ';
     // Invariant is not needed in private or static functions.
     // Also make sure that there is none in front of the constructor check
     if ($functionDefinition->getVisibility() !== 'private' && !$functionDefinition->isStatic() && $functionDefinition->getName() !== '__construct') {
         $code .= Placeholders::INVARIANT_CALL_START . '
         ';
     }
     $code .= Placeholders::PRECONDITION . $functionDefinition->getName() . Placeholders::PLACEHOLDER_CLOSE . '
         ' . Placeholders::OLD_SETUP . $functionDefinition->getName() . Placeholders::PLACEHOLDER_CLOSE . '
         ';
     // we will wrap code execution in order to provide a "finally" and "after throwing" placeholder hook.
     // we will also predefine the result as NULL to avoid warnings
     $code .= ReservedKeywords::RESULT . ' = null;
         try {
             ' . Placeholders::AROUND_JOINPOINT . $functionDefinition->getName() . Placeholders::PLACEHOLDER_CLOSE . '
     ';
     // add the second part of the try/catch/finally block
     $code .= '
         } catch (\\Exception ' . ReservedKeywords::THROWN_EXCEPTION_OBJECT . ') {
             ' . Placeholders::AFTERTHROWING_JOINPOINT . $functionDefinition->getName() . Placeholders::PLACEHOLDER_CLOSE . '
             // rethrow the exception
             throw ' . ReservedKeywords::THROWN_EXCEPTION_OBJECT . ';
         } finally {
     ';
     // if we have to inject additional code, we might do so here
     if ($injectNeeded === true) {
         $code .= Placeholders::METHOD_INJECT . $functionDefinition->getName() . Placeholders::PLACEHOLDER_CLOSE;
     }
     // finish of the block
     $code .= '        ' . Placeholders::AFTER_JOINPOINT . $functionDefinition->getName() . Placeholders::PLACEHOLDER_CLOSE . '
         }
     ';
     // now just place all the other placeholder for other filters to come
     $code .= '    ' . Placeholders::POSTCONDITION . $functionDefinition->getName() . Placeholders::PLACEHOLDER_CLOSE;
     // Invariant is not needed in private or static functions
     if ($functionDefinition->getVisibility() !== 'private' && !$functionDefinition->isStatic()) {
         $code .= '
         ' . Placeholders::INVARIANT_CALL_END . '
         ';
     }
     // close of the contract context
     $code .= 'if (' . ReservedKeywords::CONTRACT_CONTEXT . ') {
             \\AppserverIo\\Doppelgaenger\\ContractContext::close();
         }
     ';
     // last of all: the "after returning" join-point and the final return from the proxy
     $code .= '    ' . Placeholders::AFTERRETURNING_JOINPOINT . $functionDefinition->getName() . Placeholders::PLACEHOLDER_CLOSE . '
         return ' . ReservedKeywords::RESULT . ';
     }
     ';
     return $code;
 }