Exemplo n.º 1
0
 /**
  * @param CompilationContext $compilationContext
  */
 public function compile(CompilationContext $compilationContext)
 {
     $exprRaw = $this->_statement['expr'];
     $codePrinter = $compilationContext->codePrinter;
     $codePrinter->output('do {');
     /**
      * Variables are initialized in a different way inside cycle
      */
     $compilationContext->insideCycle++;
     /**
      * Compile statements in the 'while' block
      */
     if (isset($this->_statement['statements'])) {
         $st = new StatementsBlock($this->_statement['statements']);
         $st->compile($compilationContext);
     }
     $compilationContext->codePrinter->increaseLevel();
     $expr = new EvalExpression();
     $condition = $expr->optimize($exprRaw, $compilationContext);
     $compilationContext->codePrinter->decreaseLevel();
     /**
      * Restore the cycle counter
      */
     $compilationContext->insideCycle--;
     /**
      * Compound conditions can be evaluated in a single line of the C-code
      */
     $codePrinter->output('} while (' . $condition . ');');
 }
Exemplo n.º 2
0
 /**
  * @param CompilationContext $compilationContext
  */
 public function compile(CompilationContext $compilationContext)
 {
     $codePrinter = $compilationContext->codePrinter;
     $compilationContext->insideTryCatch++;
     $currentTryCatch = ++$compilationContext->currentTryCatch;
     $codePrinter->outputBlankLine();
     $codePrinter->output('/* try_start_' . $currentTryCatch . ': */');
     $codePrinter->outputBlankLine();
     if (isset($this->_statement['statements'])) {
         $st = new StatementsBlock($this->_statement['statements']);
         $st->compile($compilationContext);
     }
     $codePrinter->outputBlankLine();
     $codePrinter->output('try_end_' . $currentTryCatch . ':');
     /**
      * If 'try' is the latest statement add a 'dummy' statement to avoid compilation errors
      */
     $codePrinter->outputBlankLine();
     $compilationContext->insideTryCatch--;
     if (isset($this->_statement['catches'])) {
         /**
          * Check if there was an exception
          */
         $codePrinter->output('if (EG(exception)) {');
         $codePrinter->increaseLevel();
         $exprBuilder = BuilderFactory::getInstance();
         foreach ($this->_statement['catches'] as $catch) {
             if (isset($catch['variable'])) {
                 $variable = $compilationContext->symbolTable->getVariableForWrite($catch['variable']['value'], $compilationContext, $catch['variable']);
                 if ($variable->getType() != 'variable') {
                     throw new CompilerException('Only dynamic variables can be used to catch exceptions', $catch['exception']);
                 }
             } else {
                 $variable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $compilationContext);
             }
             $compilationContext->backend->copyOnWrite($variable, 'EG(exception)', $compilationContext);
             /**
              * @TODO, use a builder here
              */
             $variable->setIsInitialized(true, $compilationContext, $catch);
             $variable->setMustInitNull(true);
             /**
              * Check if any of the classes in the catch block match the thrown exception
              */
             foreach ($catch['classes'] as $class) {
                 $ifCheck = $exprBuilder->statements()->ifX()->setCondition($exprBuilder->operators()->binary(BinaryOperator::OPERATOR_INSTANCEOF, $exprBuilder->variable($variable->getName()), $exprBuilder->variable($class['value'])))->setStatements($exprBuilder->statements()->block(array_merge(array($exprBuilder->statements()->rawC('zend_clear_exception(TSRMLS_C);')), isset($catch['statements']) ? $catch['statements'] : array())));
                 $ifStatement = new IfStatement($ifCheck->build());
                 $ifStatement->compile($compilationContext);
             }
             if ($variable->isTemporal()) {
                 $variable->setIdle(true);
             }
         }
         $codePrinter->decreaseLevel();
         $codePrinter->output('}');
     } else {
         $codePrinter->output('zend_clear_exception(TSRMLS_C);');
     }
 }
Exemplo n.º 3
0
 /**
  * @param CompilationContext $compilationContext
  */
 public function compile(CompilationContext $compilationContext)
 {
     $codePrinter = $compilationContext->codePrinter;
     $compilationContext->insideTryCatch++;
     $currentTryCatch = ++$compilationContext->currentTryCatch;
     $codePrinter->outputBlankLine();
     $codePrinter->output('/* try_start_' . $currentTryCatch . ': */');
     $codePrinter->outputBlankLine();
     if (isset($this->_statement['statements'])) {
         $st = new StatementsBlock($this->_statement['statements']);
         $st->compile($compilationContext);
     }
     $codePrinter->outputBlankLine();
     $codePrinter->output('try_end_' . $currentTryCatch . ':');
     /**
      * If 'try' is the latest statement add a 'dummy' statement to avoid compilation errors
      */
     $codePrinter->outputBlankLine();
     $compilationContext->insideTryCatch--;
     if (isset($this->_statement['catches'])) {
         /**
          * Check if there was an exception
          */
         $codePrinter->output('if (EG(exception)) {');
         $codePrinter->increaseLevel();
         foreach ($this->_statement['catches'] as $catch) {
             if (isset($catch['variable'])) {
                 $variable = $compilationContext->symbolTable->getVariableForWrite($catch['variable']['value'], $compilationContext, $catch['variable']);
                 if ($variable->getType() != 'variable') {
                     throw new CompilerException('Only dynamic variables can be used to catch exceptions', $catch['exception']);
                 }
             } else {
                 $variable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $compilationContext);
             }
             $codePrinter->output('ZEPHIR_CPY_WRT(' . $variable->getName() . ', EG(exception));');
             /**
              * @TODO, use a builder here
              */
             $variable->setIsInitialized(true, $compilationContext, $catch);
             $variable->setMustInitNull(true);
             /**
              * Check if any of the classes in the catch block match the thrown exception
              */
             foreach ($catch['classes'] as $class) {
                 $ifCheck = new IfStatementBuilder(new BinaryOperatorBuilder('instanceof', new VariableBuilder($variable->getName()), new VariableBuilder($class['value'])), new StatementsBlockBuilder(array_merge(array(array('type' => 'cblock', 'value' => 'zend_clear_exception(TSRMLS_C);')), isset($catch['statements']) ? $catch['statements'] : array()), true));
                 $ifStatement = new IfStatement($ifCheck->get());
                 $ifStatement->compile($compilationContext);
             }
             if ($variable->isTemporal()) {
                 $variable->setIdle(true);
             }
         }
         $codePrinter->decreaseLevel();
         $codePrinter->output('}');
     } else {
         $codePrinter->output('zend_clear_exception(TSRMLS_C);');
     }
 }
Exemplo n.º 4
0
 /**
  * @param CompilationContext $compilationContext
  */
 public function compile(CompilationContext $compilationContext)
 {
     $exprRaw = $this->_statement['expr'];
     $expr = new EvalExpression();
     $condition = $expr->optimize($exprRaw, $compilationContext);
     /**
      * This pass tries to move dynamic variable initialization out of the if/else branch
      */
     if (isset($this->_statement['statements']) && isset($this->_statement['else_statements'])) {
         $skipVariantInit = new SkipVariantInit();
         $skipVariantInit->setVariablesToSkip(0, $expr->getUsedVariables());
         $skipVariantInit->setVariablesToSkip(1, $expr->getUsedVariables());
         $skipVariantInit->pass(0, new StatementsBlock($this->_statement['statements']));
         $skipVariantInit->pass(1, new StatementsBlock($this->_statement['else_statements']));
         $symbolTable = $compilationContext->symbolTable;
         foreach ($skipVariantInit->getVariables() as $variable) {
             if ($symbolTable->hasVariable($variable)) {
                 $symbolVariable = $symbolTable->getVariable($variable);
                 if ($symbolVariable->getType() == 'variable') {
                     $symbolVariable->initVariant($compilationContext);
                     $symbolVariable->skipInitVariant(2);
                 }
             }
         }
     }
     $compilationContext->codePrinter->output('if (' . $condition . ') {');
     $this->_evalExpression = $expr;
     /**
      * Try to mark lastest temporary variable used as idle
      */
     $evalVariable = $expr->getEvalVariable();
     if (is_object($evalVariable)) {
         if ($evalVariable->isTemporal()) {
             $evalVariable->setIdle(true);
         }
     }
     /**
      * Compile statements in the 'if' block
      */
     if (isset($this->_statement['statements'])) {
         $st = new StatementsBlock($this->_statement['statements']);
         $branch = $st->compile($compilationContext, $expr->isUnreachable(), Branch::TYPE_CONDITIONAL_TRUE);
         $branch->setRelatedStatement($this);
     }
     /**
      * Compile statements in the 'else' block
      */
     if (isset($this->_statement['else_statements'])) {
         $compilationContext->codePrinter->output('} else {');
         $st = new StatementsBlock($this->_statement['else_statements']);
         $branch = $st->compile($compilationContext, $expr->isUnreachableElse(), Branch::TYPE_CONDITIONAL_FALSE);
         $branch->setRelatedStatement($this);
     }
     $compilationContext->codePrinter->output('}');
 }
Exemplo n.º 5
0
 /**
  * Do the compilation pass
  *
  * @param StatementsBlock $block
  */
 public function pass(StatementsBlock $block)
 {
     $this->passStatementBlock($block->getStatements());
 }
Exemplo n.º 6
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('}');
 }
Exemplo n.º 7
0
 /**
  * Do the compilation pass
  *
  * @param int $branchNumber
  * @param StatementsBlock $block
  */
 public function pass($branchNumber, StatementsBlock $block)
 {
     $this->passStatementBlock($branchNumber, $block->getStatements());
     $this->branches[$branchNumber] = 0;
 }
Exemplo n.º 8
0
 /**
  * Creates the initialization method
  *
  * @param StatementsBlock $statementsBlock
  */
 public function addInitMethod(StatementsBlock $statementsBlock)
 {
     if (!$statementsBlock->isEmpty()) {
         $initClassName = $this->getCNamespace() . '_' . $this->getName();
         $classMethod = new ClassMethod($this, array('internal'), 'zephir_init_properties_' . $initClassName, null, $statementsBlock);
         $classMethod->setIsInitializer(true);
         $this->addMethod($classMethod);
     }
 }
Exemplo n.º 9
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('}');
 }
Exemplo n.º 10
0
 /**
  * @param CompilationContext $compilationContext
  */
 public function compile(CompilationContext $compilationContext)
 {
     $exprRaw = $this->_statement['expr'];
     $codePrinter = $compilationContext->codePrinter;
     $compilationContext->insideSwitch++;
     $exprEval = new Expression($exprRaw);
     $exprEval->setReadOnly(true);
     $resolvedExpr = $exprEval->compile($compilationContext);
     if (isset($this->_statement['clauses'])) {
         $evalExpr = new EvalExpression();
         $codePrinter->output('do {');
         $compilationContext->codePrinter->increaseLevel();
         if ($resolvedExpr->getType() != 'variable') {
             /**
              * Create a temporary variable
              */
             $tempVariable = $compilationContext->symbolTable->getTempVariable($resolvedExpr->getType(), $compilationContext);
             /**
              * Simulate an assignment to the temporary variable
              */
             $statement = new LetStatement(array('type' => 'let', 'assignments' => array(array('assign-type' => 'variable', 'operator' => 'assign', 'variable' => $tempVariable->getName(), 'expr' => array('type' => $resolvedExpr->getType(), 'value' => $resolvedExpr->getCode(), 'file' => $exprRaw['file'], 'line' => $exprRaw['line'], 'char' => $exprRaw['char']), 'file' => $exprRaw['file'], 'line' => $exprRaw['line'], 'char' => $exprRaw['char']))));
             $statement->compile($compilationContext);
         } else {
             $tempVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $exprRaw);
         }
         $clauses = $this->normalizeClauses($this->_statement['clauses']);
         $tempLeft = array('type' => 'variable', 'value' => $tempVariable->getRealName());
         /**
          * In the first round we group case clauses that have block statements
          * with the ones that does not have one
          */
         $blocks = array();
         $exprStack = array();
         $defaultBlock = null;
         foreach ($clauses as $clause) {
             if ($clause['type'] == 'case') {
                 $expr = array('type' => 'equals', 'left' => $tempLeft, 'right' => $clause['expr']);
                 if (!isset($clause['statements'])) {
                     $exprStack[] = $expr;
                 } else {
                     $exprStack[] = $expr;
                     $blocks[] = array('expr' => $exprStack, 'block' => $clause['statements']);
                     $exprStack = array();
                 }
             } else {
                 if ($clause['type'] == 'default') {
                     $defaultBlock = $clause['statements'];
                 }
             }
         }
         /**
          * In the second round we generate the conditions with their blocks
          * grouping 'cases' without a statement block using an 'or'
          */
         foreach ($blocks as $block) {
             $expressions = $block['expr'];
             if (count($expressions) == 1) {
                 $condition = $evalExpr->optimize($expressions[0], $compilationContext);
                 $codePrinter->output('if (' . $condition . ') {');
             } else {
                 $orConditions = array();
                 foreach ($expressions as $expression) {
                     $orConditions[] = $evalExpr->optimize($expression, $compilationContext);
                 }
                 $codePrinter->output('if (' . join(' || ', $orConditions) . ') {');
             }
             if (isset($block['block'])) {
                 $st = new StatementsBlock($block['block']);
                 $branch = $st->compile($compilationContext, false, Branch::TYPE_SWITCH);
                 $branch->setRelatedStatement($this);
             }
             $codePrinter->output('}');
         }
         $compilationContext->codePrinter->decreaseLevel();
         /**
          * The default block is resolved at the end of the 'switch'
          */
         if ($defaultBlock) {
             $st = new StatementsBlock($defaultBlock);
             $st->compile($compilationContext);
         }
         $compilationContext->insideSwitch--;
         $codePrinter->output('} while(0);');
         $codePrinter->outputBlankLine();
     }
 }