Пример #1
0
 /**
  * Compiles a type cast operation
  *
  * @param $expression
  * @param CompilationContext $compilationContext
  * @return bool|CompiledExpression
  * @throws CompilerException
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     $expr = new Expression($expression['right']);
     $resolved = $expr->compile($compilationContext);
     switch ($expression['left']) {
         case 'int':
             switch ($resolved->getType()) {
                 case 'null':
                     return new CompiledExpression('int', 0, $expression);
                 case 'int':
                     return new CompiledExpression('int', $resolved->getCode(), $expression);
                 case 'double':
                     return new CompiledExpression('int', '(int) ' . $resolved->getCode(), $expression);
                 case 'bool':
                     return new CompiledExpression('int', $resolved->getBooleanCode(), $expression);
                 case 'string':
                     $compilationContext->headersManager->add('kernel/operators');
                     /**
                      * zephir_get_intval_ex use zval variable
                      * before use with it we create a new variable and assign value of literal
                      *
                      * @todo Optimize by creating native function for string without zval using
                      */
                     $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('string', $compilationContext);
                     $let = new LetVariable();
                     $original = $resolved->getOriginal();
                     $original['operator'] = 'assign';
                     $let->assign($symbolVariable->getName(), $symbolVariable, $resolved, new ReadDetector(), $compilationContext, $original);
                     $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
                     return new CompiledExpression('int', 'zephir_get_intval_ex(' . $symbol . ')', $expression);
                 case 'array':
                     $compilationContext->headersManager->add('kernel/operators');
                     $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                     $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
                     return new CompiledExpression('int', 'zephir_get_intval(' . $symbol . ')', $expression);
                 case 'variable':
                     $compilationContext->headersManager->add('kernel/operators');
                     $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                     switch ($symbolVariable->getType()) {
                         case 'int':
                             return new CompiledExpression('int', $symbolVariable->getName(), $expression);
                         case 'double':
                             return new CompiledExpression('int', '(int) (' . $symbolVariable->getName() . ')', $expression);
                         case 'bool':
                             return new CompiledExpression('int', '(int) (' . $symbolVariable->getName() . ')', $expression);
                         case 'array':
                         case 'variable':
                         case 'string':
                             $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
                             return new CompiledExpression('int', 'zephir_get_intval(' . $symbol . ')', $expression);
                         default:
                             throw new CompilerException("Cannot cast: " . $resolved->getType() . "(" . $symbolVariable->getType() . ") to " . $expression['left'], $expression);
                     }
                     break;
                 default:
                     throw new CompilerException("Cannot cast: " . $resolved->getType() . " to " . $expression['left'], $expression);
             }
             break;
         case 'long':
             switch ($resolved->getType()) {
                 case 'int':
                     return new CompiledExpression('long', $resolved->getCode(), $expression);
                 case 'double':
                     return new CompiledExpression('long', '(long) ' . $resolved->getCode(), $expression);
                 case 'bool':
                     return new CompiledExpression('long', $resolved->getBooleanCode(), $expression);
                 case 'array':
                     $compilationContext->headersManager->add('kernel/operators');
                     $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                     return new CompiledExpression('long', 'zephir_get_intval(' . $symbolVariable->getName() . ')', $expression);
                 case 'variable':
                     $compilationContext->headersManager->add('kernel/operators');
                     $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                     switch ($symbolVariable->getType()) {
                         case 'int':
                             return new CompiledExpression('long', $symbolVariable->getName(), $expression);
                         case 'double':
                             return new CompiledExpression('long', '(long) (' . $symbolVariable->getName() . ')', $expression);
                         case 'variable':
                             $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
                             return new CompiledExpression('long', 'zephir_get_intval(' . $symbol . ')', $expression);
                         default:
                             throw new CompilerException("Cannot cast: " . $resolved->getType() . "(" . $symbolVariable->getType() . ") to " . $expression['left'], $expression);
                     }
                     break;
                 default:
                     throw new CompilerException("Cannot cast: " . $resolved->getType() . " to " . $expression['left'], $expression);
             }
             break;
         case 'double':
             switch ($resolved->getType()) {
                 case 'null':
                     return new CompiledExpression('double', 0, $expression);
                 case 'bool':
                     return new CompiledExpression('double', $resolved->getBooleanCode(), $expression);
                 case 'double':
                     return new CompiledExpression('double', $resolved->getCode(), $expression);
                 case 'array':
                     $compilationContext->headersManager->add('kernel/operators');
                     $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                     $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
                     return new CompiledExpression('double', 'zephir_get_doubleval(' . $symbol . ')', $expression);
                 case 'variable':
                     $compilationContext->headersManager->add('kernel/operators');
                     $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                     switch ($symbolVariable->getType()) {
                         case 'int':
                             return new CompiledExpression('double', $symbolVariable->getName(), $expression);
                         case 'double':
                             return new CompiledExpression('double', '(double) (' . $symbolVariable->getName() . ')', $expression);
                         case 'bool':
                             return new CompiledExpression('double', '(double) (' . $symbolVariable->getName() . ')', $expression);
                         case 'array':
                         case 'variable':
                             $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
                             return new CompiledExpression('double', 'zephir_get_doubleval(' . $symbol . ')', $expression);
                         default:
                             throw new CompilerException("Cannot cast: " . $resolved->getType() . "(" . $symbolVariable->getType() . ") to " . $expression['left'], $expression);
                     }
                     break;
                 default:
                     throw new CompilerException("Cannot cast: " . $resolved->getType() . " to " . $expression['left'], $expression);
             }
             break;
         case 'bool':
             switch ($resolved->getType()) {
                 case 'int':
                     return new CompiledExpression('bool', '(zend_bool) ' . $resolved->getCode(), $expression);
                 case 'bool':
                     return new CompiledExpression('bool', $resolved->getCode(), $expression);
                 case 'variable':
                     $compilationContext->headersManager->add('kernel/operators');
                     $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                     $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
                     if ($symbolVariable->isTemporal()) {
                         $symbolVariable->setIdle(true);
                     }
                     switch ($symbolVariable->getType()) {
                         case 'variable':
                             return new CompiledExpression('bool', 'zephir_get_boolval(' . $symbol . ')', $expression);
                         default:
                             throw new CompilerException("Cannot cast: " . $resolved->getType() . "(" . $symbolVariable->getType() . ") to " . $expression['left'], $expression);
                     }
                     break;
                 default:
                     throw new CompilerException("Cannot cast: " . $resolved->getType() . " to " . $expression['left'], $expression);
             }
             break;
         case 'char':
             switch ($resolved->getType()) {
                 case 'variable':
                     $compilationContext->headersManager->add('kernel/operators');
                     $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('char', $compilationContext);
                     $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                     $variableCode = $compilationContext->backend->getVariableCode($symbolVariable);
                     $compilationContext->codePrinter->output($tempVariable->getName() . ' = (char) zephir_get_intval(' . $variableCode . ');');
                     return new CompiledExpression('variable', $tempVariable->getName(), $expression);
                 default:
                     throw new CompilerException("Cannot cast: " . $resolved->getType() . " to " . $expression['left'], $expression);
             }
             break;
         case 'string':
             switch ($resolved->getType()) {
                 case 'variable':
                     $compilationContext->headersManager->add('kernel/operators');
                     $compilationContext->symbolTable->mustGrownStack(true);
                     $symbolVariable = $compilationContext->symbolTable->getTempVariable('string', $compilationContext);
                     $symbolVariable->setMustInitNull(true);
                     $symbolVariable->setIsInitialized(true, $compilationContext);
                     $symbolVariable->increaseUses();
                     $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
                     $resolvedVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext);
                     $resolvedCode = $compilationContext->backend->getVariableCode($resolvedVariable);
                     $compilationContext->codePrinter->output('zephir_get_strval(' . $symbol . ', ' . $resolvedCode . ');');
                     if ($symbolVariable->isTemporal()) {
                         $symbolVariable->setIdle(true);
                     }
                     return new CompiledExpression('variable', $symbolVariable->getName(), $expression);
                 default:
                     throw new CompilerException("Cannot cast: " . $resolved->getType() . " to " . $expression['left'], $expression);
             }
             break;
         case 'array':
             switch ($resolved->getType()) {
                 case 'variable':
                     $compilationContext->headersManager->add('kernel/operators');
                     $compilationContext->symbolTable->mustGrownStack(true);
                     $symbolVariable = $compilationContext->symbolTable->getTempVariable('array', $compilationContext, $expression);
                     $symbolVariable->setMustInitNull(true);
                     $symbolVariable->setIsInitialized(true, $compilationContext, $expression);
                     $symbolVariable->increaseUses();
                     $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
                     $resolvedVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext);
                     $resolvedCode = $compilationContext->backend->getVariableCode($resolvedVariable);
                     $compilationContext->codePrinter->output('zephir_get_arrval(' . $symbol . ', ' . $resolvedCode . ');');
                     if ($symbolVariable->isTemporal()) {
                         $symbolVariable->setIdle(true);
                     }
                     return new CompiledExpression('variable', $symbolVariable->getName(), $expression);
                 default:
                     throw new CompilerException("Cannot cast: " . $resolved->getType() . " to " . $expression['left'], $expression);
             }
             break;
         case 'object':
             switch ($resolved->getType()) {
                 case 'int':
                 case 'double':
                 case 'bool':
                 case 'null':
                 case 'string':
                 case 'array':
                     $compilationContext->headersManager->add('kernel/operators');
                     $compilationContext->symbolTable->mustGrownStack(true);
                     $symbolVariable = $compilationContext->symbolTable->getTempVariable('variable', $compilationContext);
                     $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
                     /**
                      * zephir_convert_to_object use zval variable
                      * before use with it we create a new variable and assign value of literal
                      */
                     $let = new LetVariable();
                     $original = $resolved->getOriginal();
                     $original['operator'] = 'assign';
                     $let->assign($symbolVariable->getName(), $symbolVariable, $resolved, new ReadDetector(), $compilationContext, $original);
                     $compilationContext->codePrinter->output('zephir_convert_to_object(' . $symbol . ');');
                     return new CompiledExpression('variable', $symbolVariable->getName(), $expression);
                 case 'variable':
                     $compilationContext->headersManager->add('kernel/operators');
                     $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                     $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
                     if ($symbolVariable->isTemporal()) {
                         $symbolVariable->setIdle(true);
                     }
                     $compilationContext->codePrinter->output('zephir_convert_to_object(' . $symbol . ');');
                     return new CompiledExpression('variable', $symbolVariable->getName(), $expression);
                 default:
                     throw new CompilerException("Cannot cast: " . $resolved->getType() . " to " . $expression['left'], $expression);
             }
             break;
         default:
             throw new CompilerException("Cannot cast: " . $resolved->getType() . " to " . $expression['left'], $expression);
     }
 }
Пример #2
0
 /**
  * @param CompilationContext $compilationContext
  * @throws CompilerException
  */
 public function compile(CompilationContext $compilationContext)
 {
     $readDetector = new ReadDetector();
     $statement = $this->_statement;
     foreach ($statement['assignments'] as $assignment) {
         $variable = $assignment['variable'];
         /**
          * Get the symbol from the symbol table if necessary
          */
         switch ($assignment['assign-type']) {
             case 'static-property':
             case 'static-property-append':
             case 'static-property-array-index':
             case 'static-property-array-index-append':
             case 'dynamic-variable-string':
                 $symbolVariable = null;
                 break;
             case 'array-index':
             case 'variable-append':
             case 'object-property':
             case 'array-index-append':
             case 'string-dynamic-object-property':
             case 'variable-dynamic-object-property':
                 $symbolVariable = $compilationContext->symbolTable->getVariableForUpdate($variable, $compilationContext, $assignment);
                 break;
             default:
                 $symbolVariable = $compilationContext->symbolTable->getVariableForWrite($variable, $compilationContext, $assignment);
                 break;
         }
         /**
          * Incr/Decr assignments don't require an expression
          */
         if (isset($assignment['expr'])) {
             $expr = new Expression($assignment['expr']);
             switch ($assignment['assign-type']) {
                 case 'variable':
                     if (!$readDetector->detect($variable, $assignment['expr'])) {
                         if (isset($assignment['operator'])) {
                             if ($assignment['operator'] == 'assign') {
                                 $expr->setExpectReturn(true, $symbolVariable);
                             }
                         } else {
                             $expr->setExpectReturn(true, $symbolVariable);
                         }
                     } else {
                         if (isset($assignment['operator'])) {
                             if ($assignment['operator'] == 'assign') {
                                 $expr->setExpectReturn(true);
                             }
                         } else {
                             $expr->setExpectReturn(true);
                         }
                     }
                     break;
             }
             switch ($assignment['expr']['type']) {
                 case 'property-access':
                 case 'array-access':
                 case 'type-hint':
                     $expr->setReadOnly(true);
                     break;
             }
             $resolvedExpr = $expr->compile($compilationContext);
             /**
              * Bad implemented operators could return values different than objects
              */
             if (!is_object($resolvedExpr)) {
                 throw new CompilerException("Resolved expression is not valid", $assignment['expr']);
             }
         }
         /**
          * There are four types of assignments
          */
         switch ($assignment['assign-type']) {
             case 'variable':
                 $let = new LetVariable();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $readDetector, $compilationContext, $assignment);
                 break;
             case 'variable-append':
                 $let = new LetVariableAppend();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'object-property':
                 $let = new LetObjectProperty();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'variable-dynamic-object-property':
                 $let = new LetObjectDynamicProperty();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'string-dynamic-object-property':
                 $let = new LetObjectDynamicStringProperty();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'static-property':
                 $let = new LetStaticProperty();
                 $let->assignStatic($variable, $assignment['property'], $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'static-property-append':
                 $let = new LetStaticPropertyAppend();
                 $let->assignStatic($variable, $assignment['property'], $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'static-property-array-index':
                 $let = new LetStaticPropertyArrayIndex();
                 $let->assignStatic($variable, $assignment['property'], $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'static-property-array-index-append':
                 $let = new LetStaticPropertyArrayIndexAppend();
                 $let->assignStatic($variable, $assignment['property'], $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'array-index':
                 $let = new LetArrayIndex();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'array-index-append':
                 $let = new LetArrayIndexAppend();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'object-property-append':
                 $let = new LetObjectPropertyAppend();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'object-property-array-index':
                 $let = new LetObjectPropertyArrayIndex();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'object-property-array-index-append':
                 $let = new LetObjectPropertyArrayIndexAppend();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'incr':
                 $let = new LetIncr();
                 $let->assign($variable, $symbolVariable, $compilationContext, $assignment);
                 break;
             case 'decr':
                 $let = new LetDecr();
                 $let->assign($variable, $symbolVariable, $compilationContext, $assignment);
                 break;
             case 'object-property-incr':
                 $let = new LetObjectPropertyIncr();
                 $let->assign($variable, $assignment['property'], $symbolVariable, $compilationContext, $assignment);
                 break;
             case 'object-property-decr':
                 $let = new LetObjectPropertyDecr();
                 $let->assign($variable, $assignment['property'], $symbolVariable, $compilationContext, $assignment);
                 break;
             case 'dynamic-variable':
                 $let = new LetExportSymbol();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             case 'dynamic-variable-string':
                 $let = new LetExportSymbolString();
                 $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment);
                 break;
             default:
                 throw new CompilerException("Unknown assignment: " . $assignment['assign-type'], $assignment);
         }
     }
 }