Esempio n. 1
0
 /**
  * Compiles traversing of string values
  * - Evaluated expression must be a string
  * - Every key must be an integer or compatible
  * - Every value must be a char/integer or compatible
  *
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @param Variable $exprVariable
  */
 public function compileStringTraverse($expression, CompilationContext $compilationContext, $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']);
             switch ($keyVariable->getType()) {
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                 case 'char':
                 case 'uchar':
                     break;
                 default:
                     throw new CompilerException("Cannot use variable: " . $this->_statement['key'] . " type: " . $keyVariable->getType() . " as key in string traversal", $this->_statement['expr']);
             }
         } else {
             $keyVariable = $compilationContext->symbolTable->getTempVariableForWrite('int', $compilationContext);
             $keyVariable->increaseUses();
         }
         $keyVariable->setMustInitNull(true);
         $keyVariable->setIsInitialized(true, $compilationContext, $this->_statement);
     }
     /**
      * Initialize 'value' variable
      */
     if (isset($this->_statement['value'])) {
         if ($this->_statement['value'] != '_') {
             $variable = $compilationContext->symbolTable->getVariableForWrite($this->_statement['value'], $compilationContext, $this->_statement['expr']);
             switch ($variable->getType()) {
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                 case 'char':
                 case 'uchar':
                     break;
                 default:
                     throw new CompilerException("Cannot use variable: " . $this->_statement['value'] . " type: " . $variable->getType() . " as value in string traversal", $this->_statement['expr']);
             }
         } else {
             $variable = $compilationContext->symbolTable->getTempVariableForWrite('char', $compilationContext);
             $variable->increaseUses();
         }
         $variable->setMustInitNull(true);
         $variable->setIsInitialized(true, $compilationContext, $this->_statement);
     }
     $tempVariable = $compilationContext->symbolTable->addTemp('long', $compilationContext);
     /**
      * Create a temporary value to store the constant string
      */
     if ($expression->getType() == 'string') {
         $constantVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $this->_statement);
         $compilationContext->backend->assignString($constantVariable, Utils::addSlashes($expression->getCode()), $compilationContext, true, false);
         $stringVariable = $constantVariable;
     } else {
         $stringVariable = $exprVariable;
     }
     $stringVariableCode = $compilationContext->backend->getVariableCode($stringVariable);
     if ($this->_statement['reverse']) {
         $codePrinter->output('for (' . $tempVariable->getName() . ' = Z_STRLEN_P(' . $stringVariableCode . '); ' . $tempVariable->getName() . ' >= 0; ' . $tempVariable->getName() . '--) {');
     } else {
         $codePrinter->output('for (' . $tempVariable->getName() . ' = 0; ' . $tempVariable->getName() . ' < Z_STRLEN_P(' . $stringVariableCode . '); ' . $tempVariable->getName() . '++) {');
     }
     if (isset($this->_statement['key'])) {
         $codePrinter->output("\t" . $keyVariable->getName() . ' = ' . $tempVariable->getName() . '; ');
     }
     $compilationContext->headersManager->add('kernel/operators');
     $codePrinter->output("\t" . $variable->getName() . ' = ZEPHIR_STRING_OFFSET(' . $stringVariableCode . ', ' . $tempVariable->getName() . ');');
     /**
      * Variables are initialized in a different way inside cycle
      */
     $compilationContext->insideCycle++;
     /**
      * Compile statements in the 'for' block
      */
     if (isset($this->_statement['statements'])) {
         $st = new StatementsBlock($this->_statement['statements']);
         $st->isLoop(true);
         if (isset($this->_statement['key'])) {
             $st->getMutateGatherer()->increaseMutations($this->_statement['key']);
         }
         $st->getMutateGatherer()->increaseMutations($this->_statement['value']);
         $st->compile($compilationContext);
     }
     $compilationContext->insideCycle--;
     $codePrinter->output('}');
 }
Esempio n. 2
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++;
     /**
      * 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');
     $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;
                 }
             }
         }
     }
     $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'])) {
         if ($duplicateKey) {
             $compilationContext->symbolTable->mustGrownStack(true);
             $codePrinter->output("\t" . 'ZEPHIR_GET_HMKEY(' . $keyVariable->getName() . ', ' . $arrayHash->getName() . ', ' . $arrayPointer->getName() . ');');
         } else {
             $codePrinter->output("\t" . 'ZEPHIR_GET_HKEY(' . $keyVariable->getName() . ', ' . $arrayHash->getName() . ', ' . $arrayPointer->getName() . ');');
         }
     }
     if (isset($this->_statement['value'])) {
         $compilationContext->symbolTable->mustGrownStack(true);
         $codePrinter->output("\t" . 'ZEPHIR_GET_HVALUE(' . $variable->getName() . ', ' . $tempVariable->getName() . ');');
     }
     /**
      * Compile statements in the 'for' block
      */
     if (isset($this->_statement['statements'])) {
         $st->isLoop(true);
         if (isset($this->_statement['key'])) {
             $st->getMutateGatherer()->increaseMutations($this->_statement['key']);
         }
         $st->getMutateGatherer()->increaseMutations($this->_statement['value']);
         $st->compile($compilationContext);
     }
     /**
      * Restore the cycle counter
      */
     $compilationContext->insideCycle--;
     $codePrinter->output('}');
 }