/**
  * Will generate the code needed to enforce made invariant assertions
  *
  * @param \AppserverIo\Doppelgaenger\Entities\Lists\TypedListList $assertionLists List of assertion lists
  *
  * @return string
  */
 protected function generateFunctionCode(TypedListList $assertionLists)
 {
     $code = 'protected function ' . ReservedKeywords::CLASS_INVARIANT . '(' . ReservedKeywords::INVARIANT_CALLER_VARIABLE . ', ' . ReservedKeywords::ERROR_LINE_VARIABLE . ') {
         ' . ReservedKeywords::CONTRACT_CONTEXT . ' = \\AppserverIo\\Doppelgaenger\\ContractContext::open();
         if (' . ReservedKeywords::CONTRACT_CONTEXT . ') {
             ' . ReservedKeywords::FAILURE_VARIABLE . ' = array();
             ' . ReservedKeywords::UNWRAPPED_FAILURE_VARIABLE . ' = array();';
     $conditionCounter = 0;
     $invariantIterator = $assertionLists->getIterator();
     for ($i = 0; $i < $invariantIterator->count(); $i++) {
         // Create the inner loop for the different assertions
         if ($invariantIterator->current()->count() !== 0) {
             $assertionIterator = $invariantIterator->current()->getIterator();
             // collect all assertion code for assertions of this instance
             for ($j = 0; $j < $assertionIterator->count(); $j++) {
                 // Code to catch failed assertions
                 $code .= $assertionIterator->current()->toCode();
                 $assertionIterator->next();
                 $conditionCounter++;
             }
             // generate the check for assertions results
             if ($conditionCounter > 0) {
                 $code .= 'if (!empty(' . ReservedKeywords::FAILURE_VARIABLE . ') || !empty(' . ReservedKeywords::UNWRAPPED_FAILURE_VARIABLE . ')) {
                     ' . Placeholders::ENFORCEMENT . 'invariant' . Placeholders::PLACEHOLDER_CLOSE . '
                 }';
             }
         }
         // increment the outer loop
         $invariantIterator->next();
     }
     $code .= '}
         \\AppserverIo\\Doppelgaenger\\ContractContext::close();
     }';
     return $code;
 }
    /**
     * Will generate the code needed to enforce made postcondition assertions
     *
     * @param \AppserverIo\Doppelgaenger\Entities\Lists\TypedListList $assertionLists List of assertion lists
     * @param string                                                  $functionName   The name of the function for which we create the enforcement code
     *
     * @return string
     */
    protected function generateCode(TypedListList $assertionLists, $functionName)
    {
        // We only use contracting if we're not inside another contract already
        $code = '/* BEGIN OF POSTCONDITION ENFORCEMENT */
            if (' . ReservedKeywords::CONTRACT_CONTEXT . ') {
                ' . ReservedKeywords::FAILURE_VARIABLE . ' = array();
                ' . ReservedKeywords::UNWRAPPED_FAILURE_VARIABLE . ' = array();

                ';
        // We need a counter to check how much conditions we got
        $conditionCounter = 0;
        $listIterator = $assertionLists->getIterator();
        for ($i = 0; $i < $listIterator->count(); $i++) {
            // Create the inner loop for the different assertions
            $assertionIterator = $listIterator->current()->getIterator();
            // Only act if we got actual entries
            if ($assertionIterator->count() === 0) {
                // increment the outer loop
                $listIterator->next();
                continue;
            }
            // collect all assertion code for assertions of this instance
            for ($j = 0; $j < $assertionIterator->count(); $j++) {
                // Code to catch failed assertions
                $code .= $assertionIterator->current()->toCode();
                $assertionIterator->next();
                $conditionCounter++;
            }
            // generate the check for assertions results
            if ($conditionCounter > 0) {
                $code .= '    if (!empty(' . ReservedKeywords::FAILURE_VARIABLE . ') || !empty(' . ReservedKeywords::UNWRAPPED_FAILURE_VARIABLE . ')) {
                    ' . Placeholders::ENFORCEMENT . $functionName . 'postcondition' . Placeholders::PLACEHOLDER_CLOSE . '
                }
            ';
            }
            // increment the outer loop
            $listIterator->next();
        }
        // Closing bracket for contract depth check
        $code .= '}
            ' . '/* END OF POSTCONDITION ENFORCEMENT */';
        // Did we get anything at all? If not only give back a comment.
        if ($conditionCounter === 0) {
            $code = '/* No postconditions for this function/method */';
        }
        return $code;
    }
 /**
  * Retrieves class attributes from token array.
  *
  * This method will search for any attributes a class might have. Just pass the token array of the class.
  * Work is done using token definitions and common sense in regards to PHP syntax.
  * To retrieve the different properties of an attribute it relies on getAttributeProperties().
  * We need the list of invariants to mark attributes wo are under surveillance.
  *
  * @param array         $tokens     Array of tokens for this class
  * @param TypedListList $invariants List of invariants so we can compare the attributes to
  *
  * @return AttributeDefinitionList
  */
 public function getAttributes(array $tokens, TypedListList $invariants = null)
 {
     // Check the tokens
     $attributes = new AttributeDefinitionList();
     for ($i = 0; $i < count($tokens); $i++) {
         // If we got a variable we will check if there is any function definition above it.
         // If not, we got an attribute, if so we will check if there is an even number of closing and opening
         // brackets above it, which would mean we are not in the function.
         if (is_array($tokens[$i]) && $tokens[$i][0] === T_VARIABLE) {
             for ($j = $i - 1; $j >= 0; $j--) {
                 if (is_array($tokens[$j]) && $tokens[$j][0] === T_FUNCTION) {
                     // Initialize our counter and also the check if we even started counting
                     $bracketCounter = 0;
                     $usedCounter = false;
                     // We got something, lets count the brackets between it and our variable's position
                     for ($k = $j + 1; $k < $i; $k++) {
                         if ($tokens[$k] === '{' || $tokens[$k][0] === T_CURLY_OPEN) {
                             $usedCounter = true;
                             $bracketCounter++;
                         } elseif ($tokens[$k] === '}') {
                             $usedCounter = true;
                             $bracketCounter--;
                         }
                     }
                     // If we got an even number of brackets (the counter is 0 and got used), we got an attribute
                     if ($bracketCounter === 0 && $usedCounter === true) {
                         $attributes->set($tokens[$i][1], $this->getAttributeProperties($tokens, $i));
                     }
                     break;
                 } elseif (is_array($tokens[$j]) && $tokens[$j][0] === $this->getToken()) {
                     // If we reach the class definition without passing a function we definitely got an attribute
                     $attributes->set($tokens[$i][1], $this->getAttributeProperties($tokens, $i));
                     break;
                 }
             }
         }
     }
     // If we got invariants we will check if our attributes are used in invariants
     if ($invariants !== null) {
         // Lets iterate over all the attributes and check them against the invariants we got
         $listIterator = $invariants->getIterator();
         $listCount = $listIterator->count();
         $attributeIterator = $attributes->getIterator();
         $attributeCount = $attributeIterator->count();
         for ($i = 0; $i < $attributeCount; $i++) {
             // Do we have any of these attributes in our invariants?
             $listIterator = $invariants->getIterator();
             for ($j = 0; $j < $listCount; $j++) {
                 // Did we get anything useful?
                 if ($listIterator->current() === null) {
                     continue;
                 }
                 /** @var \AppserverIo\Doppelgaenger\Interfaces\TypedListInterface|\Iterator $invariantIterator */
                 $invariantIterator = $listIterator->current()->getIterator();
                 $invariantCount = $invariantIterator->count();
                 for ($k = 0; $k < $invariantCount; $k++) {
                     $attributePosition = strpos($invariantIterator->current()->getString(), '$this->' . ltrim($attributeIterator->current()->getName(), '$'));
                     if ($attributePosition !== false) {
                         // Tell them we were mentioned and persist it
                         $attributeIterator->current()->setInInvariant(true);
                     }
                     $invariantIterator->next();
                 }
                 $listIterator->next();
             }
             $attributeIterator->next();
         }
     }
     return $attributes;
 }
 /**
  * Will generate the code needed to enforce made precondition assertions
  *
  * @param \AppserverIo\Doppelgaenger\Entities\Lists\TypedListList $assertionLists List of assertion lists
  * @param string                                                  $functionName   The name of the function for which we create the enforcement code
  *
  * @return string
  */
 protected function generateCode(TypedListList $assertionLists, $functionName)
 {
     // We only use contracting if we're not inside another contract already
     $code = '/* BEGIN OF PRECONDITION ENFORCEMENT */
         if (' . ReservedKeywords::CONTRACT_CONTEXT . ') {
             ' . ReservedKeywords::PASSED_ASSERTION_FLAG . ' = false;
             ' . ReservedKeywords::FAILURE_VARIABLE . ' = array();
             ' . ReservedKeywords::UNWRAPPED_FAILURE_VARIABLE . ' = array();
             ';
     // We need a counter to check how much conditions we got
     $conditionCounter = 0;
     $listIterator = $assertionLists->getIterator();
     for ($i = 0; $i < $listIterator->count(); $i++) {
         // Create the inner loop for the different assertions
         $assertionIterator = $listIterator->current()->getIterator();
         // Only act if we got actual entries
         if ($assertionIterator->count() === 0) {
             // increment the outer loop
             $listIterator->next();
             continue;
         }
         // create a wrap around assuring that inherited conditions get or-combined
         $code .= '
             if (' . ReservedKeywords::PASSED_ASSERTION_FLAG . ' === false) {
                 ';
         // iterate through the conditions for this certain instance
         for ($j = 0; $j < $assertionIterator->count(); $j++) {
             $conditionCounter++;
             // Code to catch failed assertions
             $code .= $assertionIterator->current()->toCode();
             $assertionIterator->next();
         }
         // close the or-combined wrap
         $code .= '    if (empty(' . ReservedKeywords::FAILURE_VARIABLE . ') && empty(' . ReservedKeywords::UNWRAPPED_FAILURE_VARIABLE . ')) {
                     ' . ReservedKeywords::PASSED_ASSERTION_FLAG . ' = true;
                 }
             }
             ';
         // increment the outer loop
         $listIterator->next();
     }
     // Preconditions need or-ed conditions so we make sure only one condition list gets checked
     $code .= 'if (' . ReservedKeywords::PASSED_ASSERTION_FLAG . ' === false){
                 ' . Placeholders::ENFORCEMENT . $functionName . 'precondition' . Placeholders::PLACEHOLDER_CLOSE . '
             }
         }
         /* END OF PRECONDITION ENFORCEMENT */';
     // If there were no assertions we will just return a comment
     if ($conditionCounter === 0) {
         return '/* No preconditions for this function/method */';
     }
     return $code;
 }