Example #1
0
 /**
  * Compiles traversing of hash values
  *
  * - Evaluated expression must be a zval
  * - A key must be a zval
  * - A value must be a zval
  *
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @param Variable $exprVariable
  */
 public function compileHashTraverse($expression, CompilationContext $compilationContext, Variable $exprVariable)
 {
     $codePrinter = $compilationContext->codePrinter;
     /**
      * Initialize 'key' variable
      */
     if (isset($this->_statement['key'])) {
         if ($this->_statement['key'] != '_') {
             $keyVariable = $compilationContext->symbolTable->getVariableForWrite($this->_statement['key'], $compilationContext, $this->_statement['expr']);
             if ($keyVariable->getType() != 'variable') {
                 throw new CompilerException("Cannot use variable: " . $this->_statement['key'] . " type: " . $keyVariable->getType() . " as key in hash traversal", $this->_statement['expr']);
             }
         } else {
             $keyVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
         }
         $keyVariable->setMustInitNull(true);
         $keyVariable->setIsInitialized(true, $compilationContext, $this->_statement);
         $keyVariable->setDynamicTypes('undefined');
     }
     /**
      * Initialize 'value' variable
      */
     if (isset($this->_statement['value'])) {
         if ($this->_statement['value'] != '_') {
             $variable = $compilationContext->symbolTable->getVariableForWrite($this->_statement['value'], $compilationContext, $this->_statement['expr']);
             if ($variable->getType() != 'variable') {
                 throw new CompilerException("Cannot use variable: " . $this->_statement['value'] . " type: " . $variable->getType() . " as value in hash traversal", $this->_statement['expr']);
             }
         } else {
             $variable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
         }
         $variable->setMustInitNull(true);
         $variable->setIsInitialized(true, $compilationContext, $this->_statement);
         $variable->setDynamicTypes('undefined');
     }
     /**
      * Variables are initialized in a different way inside cycle
      */
     $compilationContext->insideCycle++;
     $compilationContext->headersManager->add('kernel/hash');
     $duplicateHash = '0';
     $duplicateKey = true;
     /**
      * We have to check if hashes are modified within the for's block
      */
     if (isset($this->_statement['statements'])) {
         /**
          * Create the statements block here to obtain the last use line
          */
         $st = new StatementsBlock($this->_statement['statements']);
         $detector = new ForValueUseDetector();
         if ($detector->detect($exprVariable->getName(), $this->_statement['statements'])) {
             $duplicateHash = '1';
         }
         /**
          * Detect if the key is modified or passed to an external scope
          */
         if (isset($this->_statement['key'])) {
             if (!$keyVariable->isTemporal()) {
                 $detector->setDetectionFlags(ForValueUseDetector::DETECT_ALL);
                 if ($detector->detect($keyVariable->getName(), $this->_statement['statements'])) {
                     $loopContext = $compilationContext->currentMethod->getLocalContextPass();
                     //echo $st->getLastLine();
                     //echo $loopContext->getLastVariableUseLine($keyVariable->getName());
                     $duplicateKey = true;
                 }
             }
         }
     }
     $compilationContext->backend->forStatement($exprVariable, isset($this->_statement['key']) ? $keyVariable : null, isset($this->_statement['value']) ? $variable : null, $duplicateKey, $duplicateHash, $this->_statement, $st, $compilationContext);
     /**
      * Restore the cycle counter
      */
     $compilationContext->insideCycle--;
 }
Example #2
0
 /**
  * Compiles traversing of hash values
  * - Evaluated expression must be a zval
  * - Every key must be a zval
  * - Every value must be a zval
  *
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @param Variable $exprVariable
  */
 public function compileHashTraverse($expression, $compilationContext, $exprVariable)
 {
     $codePrinter = $compilationContext->codePrinter;
     /**
      * Initialize 'key' variable
      */
     if (isset($this->_statement['key'])) {
         $keyVariable = $compilationContext->symbolTable->getVariableForWrite($this->_statement['key'], $compilationContext, $this->_statement['expr']);
         if ($keyVariable->getType() != 'variable') {
             throw new CompilerException("Cannot use variable: " . $this->_statement['key'] . " type: " . $keyVariable->getType() . " as key in hash traversal", $this->_statement['expr']);
         }
         $keyVariable->setMustInitNull(true);
         $keyVariable->setIsInitialized(true, $compilationContext, $this->_statement);
         $keyVariable->setDynamicTypes('undefined');
     }
     /**
      * Initialize 'value' variable
      */
     if (isset($this->_statement['value'])) {
         $variable = $compilationContext->symbolTable->getVariableForWrite($this->_statement['value'], $compilationContext, $this->_statement['expr']);
         if ($variable->getType() != 'variable') {
             throw new CompilerException("Cannot use variable: " . $this->_statement['value'] . " type: " . $variable->getType() . " as value in hash traversal", $this->_statement['expr']);
         }
         $variable->setMustInitNull(true);
         $variable->setIsInitialized(true, $compilationContext, $this->_statement);
         $variable->setDynamicTypes('undefined');
     }
     /**
      * Variables are initialized in a different way inside cycle
      */
     $compilationContext->insideCycle++;
     /**
      * Create a hash table and hash pointer temporary variables
      */
     $arrayPointer = $compilationContext->symbolTable->addTemp('HashPosition', $compilationContext);
     $arrayHash = $compilationContext->symbolTable->addTemp('HashTable', $compilationContext);
     /**
      * Create a temporary zval to fetch the items from the hash
      */
     $tempVariable = $compilationContext->symbolTable->addTemp('variable', $compilationContext);
     $tempVariable->setIsDoublePointer(true);
     $compilationContext->headersManager->add('kernel/hash');
     /**
      * We have to check if hashes are modified within the for's block
      */
     $duplicateHash = '0';
     if (isset($this->_statement['statements'])) {
         $detector = new ForValueUseDetector();
         if ($detector->detect($exprVariable->getName(), $this->_statement['statements'])) {
             $duplicateHash = '1';
         }
     }
     $codePrinter->output('zephir_is_iterable(' . $expression->getCode() . ', &' . $arrayHash->getName() . ', &' . $arrayPointer->getName() . ', ' . $duplicateHash . ', ' . $this->_statement['reverse'] . ', "' . Compiler::getShortUserPath($this->_statement['file']) . '", ' . $this->_statement['line'] . ');');
     $codePrinter->output('for (');
     $codePrinter->output('  ; zephir_hash_get_current_data_ex(' . $arrayHash->getName() . ', (void**) &' . $tempVariable->getName() . ', &' . $arrayPointer->getName() . ') == SUCCESS');
     if ($this->_statement['reverse']) {
         $codePrinter->output('  ; zephir_hash_move_backwards_ex(' . $arrayHash->getName() . ', &' . $arrayPointer->getName() . ')');
     } else {
         $codePrinter->output('  ; zephir_hash_move_forward_ex(' . $arrayHash->getName() . ', &' . $arrayPointer->getName() . ')');
     }
     $codePrinter->output(') {');
     if (isset($this->_statement['key'])) {
         $compilationContext->symbolTable->mustGrownStack(true);
         $codePrinter->output("\t" . 'ZEPHIR_GET_HMKEY(' . $this->_statement['key'] . ', ' . $arrayHash->getName() . ', ' . $arrayPointer->getName() . ');');
     }
     if (isset($this->_statement['value'])) {
         $compilationContext->symbolTable->mustGrownStack(true);
         $codePrinter->output("\t" . 'ZEPHIR_GET_HVALUE(' . $this->_statement['value'] . ', ' . $tempVariable->getName() . ');');
     }
     /**
      * Compile statements in the 'for' block
      */
     if (isset($this->_statement['statements'])) {
         $st = new StatementsBlock($this->_statement['statements']);
         $st->compile($compilationContext);
     }
     /**
      * Restore the cycle counter
      */
     $compilationContext->insideCycle--;
     $codePrinter->output('}');
 }