/**
  * Compiles foo[y][x][] = {expr} (multiple offset)
  *
  * @param string $variable
  * @param ZephirVariable $symbolVariable
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext
  * @param array $statement
  */
 protected function _assignArrayIndexMultiple($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement)
 {
     $codePrinter = $compilationContext->codePrinter;
     $offsetExprs = array();
     foreach ($statement['index-expr'] as $indexExpr) {
         $expression = new Expression($indexExpr);
         $expression->setReadOnly(true);
         $exprIndex = $expression->compile($compilationContext);
         switch ($exprIndex->getType()) {
             case 'int':
             case 'uint':
             case 'long':
             case 'ulong':
             case 'string':
             case 'variable':
                 break;
             default:
                 throw new CompilerException("Index: " . $exprIndex->getType() . " cannot be used as array index in assignment without cast", $indexExpr);
         }
         $offsetExprs[] = $exprIndex;
     }
     $compilationContext->headersManager->add('kernel/array');
     /**
      * Create a temporal zval (if needed)
      */
     $symbolVariable = $this->_getResolvedArrayItem($resolvedExpr, $compilationContext);
     $targetVariable = $compilationContext->symbolTable->getVariableForWrite($variable, $compilationContext, $statement);
     $offsetExprs[] = 'a';
     $compilationContext->backend->assignArrayMulti($targetVariable, $symbolVariable, $offsetExprs, $compilationContext);
 }
Beispiel #2
0
 /**
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  */
 public function compile(array $expression, CompilationContext $compilationContext)
 {
     $expr = new Expression($expression['left']);
     $expr->setReadOnly(true);
     $expr->setExpectReturn(true);
     $exprPath = $expr->compile($compilationContext);
     if ($exprPath->getType() == 'variable') {
         $exprVariable = $compilationContext->symbolTable->getVariableForRead($exprPath->getCode(), $compilationContext, $expression);
         if ($exprVariable->getType() == 'variable') {
             if ($exprVariable->hasDifferentDynamicType(array('undefined', 'string'))) {
                 $compilationContext->logger->warning('Possible attempt to use invalid type as path in "require" operator', 'non-valid-require', $expression);
             }
         }
     }
     $symbolVariable = false;
     if ($this->isExpecting()) {
         $symbolVariable = $compilationContext->symbolTable->getTempVariableForObserveOrNullify('variable', $compilationContext, $expression);
     }
     $compilationContext->headersManager->add('kernel/memory');
     $compilationContext->headersManager->add('kernel/require');
     $codePrinter = $compilationContext->codePrinter;
     if ($symbolVariable) {
         $codePrinter->output('ZEPHIR_OBSERVE_OR_NULLIFY_PPZV(&' . $symbolVariable->getName() . ');');
         $codePrinter->output('if (zephir_require_zval_ret(&' . $symbolVariable->getName() . ', ' . $exprPath->getCode() . ' TSRMLS_CC) == FAILURE) {');
     } else {
         $codePrinter->output('if (zephir_require_zval(' . $exprPath->getCode() . ' TSRMLS_CC) == FAILURE) {');
     }
     $codePrinter->output("\t" . 'RETURN_MM_NULL();');
     $codePrinter->output('}');
     if ($symbolVariable) {
         return new CompiledExpression('variable', $symbolVariable->getName(), $expression);
     }
     return new CompiledExpression('null', null, $expression);
 }
Beispiel #3
0
 /**
  * @param CompilationContext $compilationContext
  * @throws CompilerException
  */
 public function compile(CompilationContext $compilationContext)
 {
     $expression = array('type' => 'require', 'left' => $this->_statement['expr'], 'file' => $this->_statement['file'], 'line' => $this->_statement['line'], 'char' => $this->_statement['char']);
     $expr = new Expression($expression);
     $expr->setExpectReturn(false, null);
     $expr->compile($compilationContext);
 }
 /**
  * @param $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  * @throws Exception
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     if (!isset($expression['left'])) {
         throw new CompilerException("Missing left part of the expression", $expression);
     }
     $leftExpr = new Expression($expression['left']);
     $leftExpr->setReadOnly($this->_readOnly);
     $left = $leftExpr->compile($compilationContext);
     switch ($left->getType()) {
         case 'bool':
         case 'int':
         case 'uint':
         case 'long':
         case 'ulong':
             return new CompiledExpression('int', '~(' . $left->getCode() . ')', $expression);
         case 'variable':
             $variable = $compilationContext->symbolTable->getVariableForRead($left->getCode(), $compilationContext, $expression['left']);
             switch ($variable->getType()) {
                 case 'bool':
                 case 'int':
                 case 'uint':
                 case 'long':
                     return new CompiledExpression('int', '~' . $variable->getName(), $expression);
                 case 'variable':
                     $compilationContext->headersManager->add('kernel/operators');
                     return new CompiledExpression('int', '~zephir_get_intval(' . $variable->getName() . ')', $expression);
                 default:
                     throw new CompilerException("Unknown type: " . $variable->getType(), $expression);
             }
             break;
         default:
             throw new CompilerException("Unknown type: " . $left->getType(), $expression);
     }
 }
 /**
  * Compiles x::y[a][b] = {expr} (multiple offset assignment)
  *
  * @param string $variable
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext,
  * @param array $statement
  */
 protected function _assignStaticPropertyArrayMultipleIndex($classEntry, $property, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement)
 {
     $codePrinter = $compilationContext->codePrinter;
     $property = $statement['property'];
     $compilationContext->headersManager->add('kernel/object');
     /**
      * Create a temporal zval (if needed)
      */
     $variableExpr = $this->_getResolvedArrayItem($resolvedExpr, $compilationContext);
     /**
      * Only string/variable/int
      */
     $offsetExprs = array();
     foreach ($statement['index-expr'] as $indexExpr) {
         $indexExpression = new Expression($indexExpr);
         $resolvedIndex = $indexExpression->compile($compilationContext);
         switch ($resolvedIndex->getType()) {
             case 'string':
             case 'int':
             case 'uint':
             case 'ulong':
             case 'long':
             case 'variable':
                 break;
             default:
                 throw new CompilerException("Expression: " . $resolvedIndex->getType() . " cannot be used as index without cast", $statement['index-expr']);
         }
         $offsetExprs[] = $resolvedIndex;
     }
     $compilationContext->backend->assignStaticPropertyArrayMulti($classEntry, $variableExpr, $property, $offsetExprs, $compilationContext);
     if ($variableExpr->isTemporal()) {
         $variableExpr->setIdle(true);
     }
 }
 /**
  * Executes the operator
  *
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  */
 public function compile(array $expression, CompilationContext $compilationContext)
 {
     if (!isset($expression['parameters'])) {
         throw new CompilerException("Invalid 'parameters' for new-type", $expression);
     }
     switch ($expression['internal-type']) {
         case 'array':
             $compilationContext->headersManager->add('kernel/array');
             $functionName = 'create_array';
             break;
         case 'string':
             $compilationContext->headersManager->add('kernel/string');
             $functionName = 'create_string';
             break;
         default:
             throw new CompilerException("Cannot build instance of type", $expression);
     }
     $builder = new FunctionCallBuilder($functionName, $expression['parameters'], 1, $expression['file'], $expression['line'], $expression['char']);
     /**
      * Implicit type coercing
      */
     $castBuilder = new CastOperatorBuilder($expression['internal-type'], $builder);
     $expression = new Expression($castBuilder->get());
     $expression->setReadOnly($this->_readOnly);
     return $expression->compile($compilationContext);
 }
Beispiel #7
0
 /**
  * Compile expression
  *
  * @param $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  * @throws Exception
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     if (!isset($expression['left'])) {
         throw new \Exception("Missing left part of the expression");
     }
     $leftExpr = new Expression($expression['left']);
     $leftExpr->setReadOnly($this->_readOnly);
     $left = $leftExpr->compile($compilationContext);
     switch ($left->getType()) {
         case 'int':
         case 'uint':
         case 'long':
         case 'ulong':
         case 'double':
             return new CompiledExpression($left->getType(), '+' . $left->getCode(), $expression);
         case 'variable':
             $variable = $compilationContext->symbolTable->getVariable($left->getCode());
             switch ($variable->getType()) {
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                 case 'double':
                     return new CompiledExpression($variable->getType(), '+' . $variable->getName(), $expression);
                 case 'variable':
                     return new CompiledExpression('variable', $variable->getName(), $expression);
                 default:
                     throw new CompilerException("Cannot operate plus with variable of '" . $left->getType() . "' type");
             }
             break;
         default:
             throw new CompilerException("Cannot operate plus with '" . $left->getType() . "' type");
     }
 }
Beispiel #8
0
 /**
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  */
 public function compile(array $expression, CompilationContext $compilationContext)
 {
     $compilationContext->headersManager->add('kernel/object');
     $exprVariable = new Expression($expression['left']);
     $exprVariable->setReadOnly(true);
     $exprVariable->setExpectReturn(true);
     $exprCompiledVariable = $exprVariable->compile($compilationContext);
     if ($exprCompiledVariable->getType() != 'variable') {
         throw new CompilerException("Expression type: " . $exprCompiledVariable->getType() . " cannot be used as array", $expression);
     }
     $clonedVariable = $compilationContext->symbolTable->getVariableForRead($exprCompiledVariable->getCode(), $compilationContext, $expression);
     if ($clonedVariable->getType() != 'variable') {
         throw new CompilerException("Variable type: " . $exprVariable->getType() . " cannot be cloned");
     }
     if ($clonedVariable->hasDifferentDynamicType(array('undefined', 'object', 'null'))) {
         $compilationContext->logger->warning('Possible attempt to use non array in "clone" operator', 'non-valid-clone', $expression);
     }
     $symbolVariable = $this->getExpected($compilationContext, $expression);
     if (!$symbolVariable->isVariable()) {
         throw new CompilerException("Objects can only be cloned into dynamic variables", $expression);
     }
     $symbolVariable->setDynamicTypes('object');
     $symbolVariable->setIsInitialized(true, $compilationContext, $expression);
     /* Inherit the dynamic type data from the cloned object */
     $symbolVariable->setDynamicTypes($clonedVariable->getDynamicTypes());
     $symbolVariable->setClassTypes($clonedVariable->getClassTypes());
     $compilationContext->codePrinter->output('if (zephir_clone(' . $symbolVariable->getName() . ', ' . $clonedVariable->getName() . ' TSRMLS_CC) == FAILURE) {');
     $compilationContext->codePrinter->output("\t" . 'RETURN_MM();');
     $compilationContext->codePrinter->output('}');
     return new CompiledExpression('variable', $symbolVariable->getName(), $expression);
 }
Beispiel #9
0
 /**
  * Transforms calls to method "toHex" to sprintf('%X') call
  *
  * @param object $caller
  * @param CompilationContext $compilationContext
  * @param Call $call
  * @param array $expression
  * @return bool|mixed|\Zephir\CompiledExpression
  */
 public function toHex($caller, CompilationContext $compilationContext, Call $call, array $expression)
 {
     $exprBuilder = BuilderFactory::getInstance();
     $functionCall = $exprBuilder->statements()->functionCall('sprintf', array($exprBuilder->literal(Types::STRING, '%X'), $caller))->setFile($expression['file'])->setLine($expression['line'])->setChar($expression['char']);
     $expression = new Expression($functionCall->build());
     return $expression->compile($compilationContext);
 }
 /**
  * Resolves the access to a property in an object
  *
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return \CompiledExpression
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     $codePrinter = $compilationContext->codePrinter;
     $propertyAccess = $expression;
     $expr = new Expression($propertyAccess['left']);
     $exprVariable = $expr->compile($compilationContext);
     switch ($exprVariable->getType()) {
         case 'variable':
             $variableVariable = $compilationContext->symbolTable->getVariableForRead($exprVariable->getCode(), $compilationContext, $expression);
             switch ($variableVariable->getType()) {
                 case 'variable':
                     break;
                 default:
                     throw new CompilerException("Variable type: " . $variableVariable->getType() . " cannot be used as object", $propertyAccess['left']);
             }
             break;
         default:
             throw new CompilerException("Cannot use expression: " . $exprVariable->getType() . " as an object", $propertyAccess['left']);
     }
     switch ($propertyAccess['right']['type']) {
         case 'variable':
             $propertyVariable = $compilationContext->symbolTable->getVariableForRead($propertyAccess['right']['value'], $compilationContext, $expression);
             break;
         case 'string':
             $propertyVariable = $compilationContext->symbolTable->getTempVariableForWrite('string', $compilationContext);
             $statement = new LetStatement(array('type' => 'let', 'assignments' => array(array('assign-type' => 'variable', 'variable' => $propertyVariable->getName(), 'operator' => 'assign', 'expr' => $expression['right']))));
             $statement->compile($compilationContext);
             break;
         default:
             throw new CompilerException("Variable type: " . $propertyAccess['right']['type'] . " cannot be used as object", $propertyAccess['left']);
     }
     /**
      * Resolves the symbol that expects the value
      */
     if ($this->_expecting) {
         if ($this->_expectingVariable) {
             $symbolVariable = $this->_expectingVariable;
             if ($symbolVariable->getName() != 'return_value') {
                 $symbolVariable->observeVariant($compilationContext);
             } else {
                 $symbolVariable = $compilationContext->symbolTable->getTempVariableForObserve('variable', $compilationContext, $expression);
             }
         } else {
             $symbolVariable = $compilationContext->symbolTable->getTempVariableForObserve('variable', $compilationContext, $expression);
         }
     }
     /**
      * Variable that receives a property value must be polymorphic
      */
     if ($symbolVariable->getType() != 'variable') {
         throw new CompilerException("Cannot use variable: " . $symbolVariable->getType() . " to assign property value", $expression);
     }
     /**
      * At this point, we don't know the exact dynamic type fetched from the property
      */
     $symbolVariable->setDynamicTypes('undefined');
     $compilationContext->headersManager->add('kernel/object');
     $codePrinter->output('zephir_read_property_zval(&' . $symbolVariable->getName() . ', ' . $variableVariable->getName() . ', ' . $propertyVariable->getName() . ', PH_NOISY_CC);');
     return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
 }
 /**
  * Resolves the access to a property in an object
  *
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return \CompiledExpression
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     $codePrinter = $compilationContext->codePrinter;
     $propertyAccess = $expression;
     $expr = new Expression($propertyAccess['left']);
     $exprVariable = $expr->compile($compilationContext);
     switch ($exprVariable->getType()) {
         case 'variable':
             $variableVariable = $compilationContext->symbolTable->getVariableForRead($exprVariable->getCode(), $compilationContext, $expression);
             switch ($variableVariable->getType()) {
                 case 'variable':
                     break;
                 default:
                     throw new CompilerException("Variable type: " . $variableVariable->getType() . " cannot be used as object", $propertyAccess['left']);
             }
             break;
         default:
             throw new CompilerException("Cannot use expression: " . $exprVariable->getType() . " as an object", $propertyAccess['left']);
     }
     switch ($propertyAccess['right']['type']) {
         case 'variable':
             $propertyVariable = $compilationContext->symbolTable->getVariableForRead($propertyAccess['right']['value'], $compilationContext, $expression);
             break;
         case 'string':
             $propertyVariable = null;
             break;
         default:
             throw new CompilerException("Variable type: " . $propertyAccess['right']['type'] . " cannot be used as object", $propertyAccess['left']);
     }
     /**
      * Resolves the symbol that expects the value
      */
     if ($this->_expecting) {
         if ($this->_expectingVariable) {
             $symbolVariable = $this->_expectingVariable;
             if ($symbolVariable->getName() != 'return_value') {
                 $symbolVariable->observeVariant($compilationContext);
             } else {
                 $symbolVariable = $compilationContext->symbolTable->getTempVariableForObserve('variable', $compilationContext, $expression);
             }
         } else {
             $symbolVariable = $compilationContext->symbolTable->getTempVariableForObserve('variable', $compilationContext, $expression);
         }
     }
     /**
      * Variable that receives a property value must be polymorphic
      */
     if ($symbolVariable && !$symbolVariable->isVariable()) {
         throw new CompilerException("Cannot use variable: " . $symbolVariable->getType() . " to assign property value", $expression);
     }
     /**
      * At this point, we don't know the exact dynamic type fetched from the property
      */
     $symbolVariable->setDynamicTypes('undefined');
     $compilationContext->headersManager->add('kernel/object');
     $property = $propertyVariable ? $propertyVariable : Utils::addSlashes($expression['right']['value']);
     $compilationContext->backend->fetchProperty($symbolVariable, $variableVariable, $property, false, $compilationContext, false);
     return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
 }
Beispiel #12
0
 /**
  * @param CompilationContext $compilationContext
  * @throws CompilerException
  */
 public function compile(CompilationContext $compilationContext)
 {
     $compilationContext->headersManager->add('kernel/exception');
     $codePrinter = $compilationContext->codePrinter;
     $statement = $this->_statement;
     $expr = $statement['expr'];
     /**
      * This optimizes throw new Exception("hello")
      */
     if (!$compilationContext->insideTryCatch) {
         if (isset($expr['class']) && isset($expr['parameters']) && count($expr['parameters']) == 1 && $expr['parameters'][0]['parameter']['type'] == 'string') {
             $className = Utils::getFullName($expr['class'], $compilationContext->classDefinition->getNamespace(), $compilationContext->aliasManager);
             if ($compilationContext->compiler->isClass($className)) {
                 $classDefinition = $compilationContext->compiler->getClassDefinition($className);
                 $message = $expr['parameters'][0]['parameter']['value'];
                 $class = $classDefinition->getClassEntry();
                 $this->throwStringException($codePrinter, $class, $message, $statement['expr']);
                 return;
             } else {
                 if ($compilationContext->compiler->isBundledClass($className)) {
                     $classEntry = $compilationContext->classDefinition->getClassEntryByClassName($className, $compilationContext, true);
                     if ($classEntry) {
                         $message = $expr['parameters'][0]['parameter']['value'];
                         $this->throwStringException($codePrinter, $classEntry, $message, $statement['expr']);
                         return;
                     }
                 }
             }
         } else {
             if (in_array($expr['type'], array('string', 'char', 'int', 'double'))) {
                 $class = $compilationContext->classDefinition->getClassEntryByClassName('Exception', $compilationContext);
                 $this->throwStringException($codePrinter, $class, $expr['value'], $expr);
                 return;
             }
         }
     }
     $throwExpr = new Expression($expr);
     $resolvedExpr = $throwExpr->compile($compilationContext);
     if (!in_array($resolvedExpr->getType(), array('variable', 'string'))) {
         throw new CompilerException("Expression '" . $resolvedExpr->getType() . '" cannot be used as exception', $expr);
     }
     $variableVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $expr);
     if (!in_array($variableVariable->getType(), array('variable', 'string'))) {
         throw new CompilerException("Variable '" . $variableVariable->getType() . "' cannot be used as exception", $expr);
     }
     $variableCode = $compilationContext->backend->getVariableCode($variableVariable);
     $codePrinter->output('zephir_throw_exception_debug(' . $variableCode . ', "' . Compiler::getShortUserPath($statement['expr']['file']) . '", ' . $statement['expr']['line'] . ' TSRMLS_CC);');
     if (!$compilationContext->insideTryCatch) {
         $codePrinter->output('ZEPHIR_MM_RESTORE();');
         $codePrinter->output('return;');
     } else {
         $codePrinter->output('goto try_end_' . $compilationContext->currentTryCatch . ';');
         $codePrinter->outputBlankLine();
     }
     if ($variableVariable->isTemporal()) {
         $variableVariable->setIdle(true);
     }
 }
Beispiel #13
0
 /**
  * @param $expression
  * @param CompilationContext $compilationContext
  * @return bool|CompiledExpression
  * @throws CompilerException
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     if (!isset($expression['left'])) {
         throw new CompilerException("Invalid 'left' operand for 'typeof' expression", $expression['left']);
     }
     $builder = new FunctionCallBuilder('gettype', array(array('parameter' => $expression['left'])));
     $expression = new Expression($builder->get());
     return $expression->compile($compilationContext);
 }
Beispiel #14
0
 /**
  * @param $expression
  * @param CompilationContext $compilationContext
  * @return bool|CompiledExpression
  * @throws CompilerException
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     if (!isset($expression['left'])) {
         throw new CompilerException("Invalid 'left' operand for 'typeof' expression", $expression['left']);
     }
     $functionCall = BuilderFactory::getInstance()->statements()->functionCall('gettype', array($expression['left']));
     $expression = new Expression($functionCall->build());
     return $expression->compile($compilationContext);
 }
Beispiel #15
0
 /**
  * @param CompilationContext $compilationContext
  * @throws CompilerException
  */
 public function compile(CompilationContext $compilationContext)
 {
     $compilationContext->headersManager->add('kernel/exception');
     $codePrinter = $compilationContext->codePrinter;
     $statement = $this->_statement;
     $expr = $statement['expr'];
     /**
      * This optimizes throw new Exception("hello")
      */
     if (!$compilationContext->insideTryCatch) {
         if (isset($expr['class'])) {
             if (isset($expr['parameters']) && count($expr['parameters']) == 1) {
                 if ($expr['parameters'][0]['parameter']['type'] == 'string') {
                     $className = Utils::getFullName($expr['class'], $compilationContext->classDefinition->getNamespace(), $compilationContext->aliasManager);
                     if ($compilationContext->compiler->isClass($className)) {
                         $classDefinition = $compilationContext->compiler->getClassDefinition($className);
                         $message = $expr['parameters'][0]['parameter']['value'];
                         $codePrinter->output('ZEPHIR_THROW_EXCEPTION_DEBUG_STR(' . $classDefinition->getClassEntry() . ', "' . Utils::addSlashes($message, true, Types::STRING) . '", "' . Compiler::getShortUserPath($statement['expr']['file']) . '", ' . $statement['expr']['line'] . ');');
                         $codePrinter->output('return;');
                         return;
                     } else {
                         if ($compilationContext->compiler->isInternalClass($className)) {
                             $classEntry = $compilationContext->classDefinition->getClassEntryByClassName($className, true);
                             if ($classEntry) {
                                 $message = $expr['parameters'][0]['parameter']['value'];
                                 $codePrinter->output('ZEPHIR_THROW_EXCEPTION_DEBUG_STR(' . $classEntry . ', "' . Utils::addSlashes($message, true, Types::STRING) . '", "' . Compiler::getShortUserPath($statement['expr']['file']) . '", ' . $statement['expr']['line'] . ');');
                                 $codePrinter->output('return;');
                                 return;
                             }
                         }
                     }
                 }
             }
         }
     }
     $throwExpr = new Expression($expr);
     $resolvedExpr = $throwExpr->compile($compilationContext);
     if ($resolvedExpr->getType() != 'variable') {
         throw new CompilerException("Expression '" . $resolvedExpr->getType() . '" cannot be used as exception', $expr);
     }
     $variableVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $expr);
     if ($variableVariable->getType() != 'variable') {
         throw new CompilerException("Variable '" . $variableVariable->getType() . "' cannot be used as exception", $expr);
     }
     $codePrinter->output('zephir_throw_exception_debug(' . $variableVariable->getName() . ', "' . Compiler::getShortUserPath($statement['expr']['file']) . '", ' . $statement['expr']['line'] . ' TSRMLS_CC);');
     if (!$compilationContext->insideTryCatch) {
         $codePrinter->output('ZEPHIR_MM_RESTORE();');
         $codePrinter->output('return;');
     } else {
         $codePrinter->output('goto try_end_' . $compilationContext->insideTryCatch . ';');
         $codePrinter->outputBlankLine();
     }
     if ($variableVariable->isTemporal()) {
         $variableVariable->setIdle(true);
     }
 }
Beispiel #16
0
 /**
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  */
 public function compile(array $expression, CompilationContext $compilationContext)
 {
     if (!isset($expression['left'])) {
         throw new CompilerException("Invalid 'left' operand for 'irange' expression", $expression['left']);
     }
     if (!isset($expression['right'])) {
         throw new CompilerException("Invalid 'right' operand for 'irange' expression", $expression['right']);
     }
     $builder = new FunctionCallBuilder('range', array(array('parameter' => $expression['left']), array('parameter' => $expression['right'])));
     /**
      * Implicit type coercing
      */
     $castBuilder = new CastOperatorBuilder('array', $builder);
     $expression = new Expression($castBuilder->get());
     $expression->setReadOnly($this->_readOnly);
     return $expression->compile($compilationContext);
 }
 /**
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  */
 public function compile(array $expression, CompilationContext $compilationContext)
 {
     if (!isset($expression['left'])) {
         throw new CompilerException("Invalid 'left' operand for 'irange' expression", $expression['left']);
     }
     if (!isset($expression['right'])) {
         throw new CompilerException("Invalid 'right' operand for 'irange' expression", $expression['right']);
     }
     $exprBuilder = Expression\Builder\BuilderFactory::getInstance();
     /**
      * Implicit type coercing
      */
     $castBuilder = $exprBuilder->operators()->cast(Types::ARRAY_, $exprBuilder->statements()->functionCall('range', array($expression['left'], $expression['right'])));
     $expression = new Expression($castBuilder->build());
     $expression->setReadOnly($this->_readOnly);
     return $expression->compile($compilationContext);
 }
Beispiel #18
0
 /**
  * Intercepts calls to built-in methods
  *
  * @param string $methodName
  * @param object $caller
  * @param CompilationContext $compilationContext
  * @param Call $call
  * @param array $expression
  * @throws CompilerException
  * @return bool|\Zephir\CompiledExpression
  */
 public function invokeMethod($methodName, $caller, CompilationContext $compilationContext, Call $call, array $expression)
 {
     if (method_exists($this, $methodName)) {
         return $this->{$methodName}($caller, $compilationContext, $call, $expression);
     }
     if (isset($this->methodMap[$methodName])) {
         if (isset($expression['parameters'])) {
             $parameters = $expression['parameters'];
             array_unshift($parameters, array('parameter' => $caller));
         } else {
             $parameters = array(array('parameter' => $caller));
         }
         $builder = new FunctionCallBuilder($this->methodMap[$methodName], $parameters, FunctionCall::CALL_NORMAL, $expression['file'], $expression['line'], $expression['char']);
         $expression = new Expression($builder->get());
         return $expression->compile($compilationContext);
     }
     throw new CompilerException(sprintf('Method "%s" is not a built-in method of type "%s"', $methodName, $this->getTypeName()), $expression);
 }
Beispiel #19
0
 /**
  *
  * @param array $expression
  * @param \CompilationContext $compilationContext
  * @return \CompiledExpression
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     $compilationContext->headersManager->add('kernel/operators');
     if (!isset($expression['left'])) {
         throw new CompilerException("Invalid 'left' operand for 'empty' expression", $expression['left']);
     }
     $leftExpr = new Expression($expression['left']);
     $leftExpr->setReadOnly(true);
     $left = $leftExpr->compile($compilationContext);
     if ($left->getType() != 'variable') {
         throw new CompilerException("'empty' operand only can be a variable", $expression['left']);
     }
     $variableLeft = $compilationContext->symbolTable->getVariableForRead($left->getCode(), $compilationContext, $expression['left']);
     if ($variableLeft->isNotVariableAndString()) {
         throw new CompilerException("Only dynamic/string variables can be used in 'empty' operators", $expression['left']);
     }
     return new CompiledExpression('bool', 'ZEPHIR_IS_EMPTY(' . $variableLeft->getName() . ')', $expression);
 }
Beispiel #20
0
 /**
  * @param CompilationContext $compilationContext
  * @throws CompilerException
  */
 public function compile(CompilationContext $compilationContext)
 {
     $compilationContext->headersManager->add('kernel/array');
     $expression = $this->_statement['expr'];
     $flags = 'PH_SEPARATE';
     if ($expression['type'] == 'list') {
         $expression = $expression['left'];
     }
     switch ($expression['type']) {
         case 'array-access':
             $expr = new Expression($expression['left']);
             $expr->setReadOnly(true);
             $exprVar = $expr->compile($compilationContext);
             $variable = $compilationContext->symbolTable->getVariableForWrite($exprVar->getCode(), $compilationContext, $this->_statement);
             $expr = new Expression($expression['right']);
             $expr->setReadOnly(true);
             $exprIndex = $expr->compile($compilationContext);
             break;
         case 'property-access':
             $expr = new Expression($expression['left']);
             $expr->setReadOnly(true);
             $exprVar = $expr->compile($compilationContext);
             $variable = $compilationContext->symbolTable->getVariableForWrite($exprVar->getCode(), $compilationContext, $this->_statement);
             $variableCode = $compilationContext->backend->getVariableCode($variable);
             $compilationContext->headersManager->add('kernel/object');
             $compilationContext->codePrinter->output('zephir_unset_property(' . $variableCode . ', "' . $expression['right']['value'] . '" TSRMLS_CC);');
             return true;
         case 'property-dynamic-access':
             //@todo fix it
         //@todo fix it
         default:
             throw new CompilerException('Cannot use expression type: ' . $expression['type'] . ' in "unset"', $expression);
     }
     if (!in_array($variable->getType(), array('variable', 'array'))) {
         throw new CompilerException('Cannot use variable type: ' . $variable->gettype() . ' in "unset"', $expression['left']);
     }
     if ($variable->hasDifferentDynamicType(array('undefined', 'array', 'object', 'null'))) {
         $compilationContext->logger->warning('Possible attempt to use non array/object in unset operator', 'non-valid-unset', $expression['left']);
     }
     $compilationContext->backend->arrayUnset($variable, $exprIndex, $flags, $compilationContext);
 }
Beispiel #21
0
 /**
  * Intercepts calls to built-in methods
  *
  * @param string $methodName
  * @param object $caller
  * @param CompilationContext $compilationContext
  * @param Call $call
  * @param array $expression
  * @throws CompilerException
  * @return bool|\Zephir\CompiledExpression
  */
 public function invokeMethod($methodName, $caller, CompilationContext $compilationContext, Call $call, array $expression)
 {
     /**
      * Checks first whether the method exist in the array type definition
      */
     if (method_exists($this, $methodName)) {
         return $this->{$methodName}($caller, $compilationContext, $call, $expression);
     }
     /**
      * Check the method map
      */
     if (isset($this->methodMap[$methodName])) {
         $paramNumber = $this->getNumberParam($methodName);
         if ($paramNumber == 0) {
             if (isset($expression['parameters'])) {
                 $parameters = $expression['parameters'];
                 array_unshift($parameters, array('parameter' => $caller));
             } else {
                 $parameters = array(array('parameter' => $caller));
             }
         } else {
             if (isset($expression['parameters'])) {
                 $parameters = array();
                 foreach ($expression['parameters'] as $number => $parameter) {
                     if ($number == $paramNumber) {
                         $parameters[] = null;
                     }
                     $parameters[] = $parameter;
                 }
                 $parameters[$paramNumber] = array('parameter' => $caller);
             } else {
                 $parameters = array(array('parameter' => $caller));
             }
         }
         $builder = new FunctionCallBuilder($this->methodMap[$methodName], $parameters, FunctionCall::CALL_NORMAL, $expression['file'], $expression['line'], $expression['char']);
         $expression = new Expression($builder->get());
         return $expression->compile($compilationContext);
     }
     throw new CompilerException(sprintf('Method "%s" is not a built-in method of type "%s"', $methodName, $this->getTypeName()), $expression);
 }
Beispiel #22
0
 public function compile($expression, CompilationContext $compilationContext)
 {
     if (!isset($expression['left'])) {
         throw new CompilerException("Invalid 'left' operand for 'unlikely' expression", $expression['left']);
     }
     $leftExpr = new Expression($expression['left']);
     $leftExpr->setReadOnly(true);
     $left = $leftExpr->compile($compilationContext);
     if ($left->getType() == 'bool') {
         return new CompiledExpression('bool', 'unlikely(' . $left->getCode() . ')', $expression);
     }
     if ($left->getType() == 'variable') {
         $variable = $compilationContext->symbolTable->getVariableForRead($left->getCode(), $compilationContext, $expression['left']);
         switch ($variable->getType()) {
             case 'bool':
                 return new CompiledExpression('bool', 'unlikely(' . $variable->getName() . ')', $expression);
             default:
                 return new CompiledExpression('bool', 'unlikely(zephir_is_true(' . $variable->getName() . '))', $expression);
         }
     }
     throw new CompilerException("Cannot use expression type: '" . $left->getType() . "' in 'unlikely' operator", $expression['left']);
 }
Beispiel #23
0
 /**
  * Compile expression
  *
  * @param $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  * @throws CompilerException
  * @throws Exception
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     if (!isset($expression['left'])) {
         throw new \Exception("Missing left part of the expression");
     }
     $leftExpr = new Expression($expression['left']);
     $leftExpr->setReadOnly($this->_readOnly);
     $left = $leftExpr->compile($compilationContext);
     switch ($left->getType()) {
         case 'int':
         case 'uint':
         case 'long':
         case 'ulong':
         case 'double':
             return new CompiledExpression($left->getType(), '-' . $left->getCode(), $expression);
         case 'variable':
             $variable = $compilationContext->symbolTable->getVariable($left->getCode());
             switch ($variable->getType()) {
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                 case 'double':
                     return new CompiledExpression($variable->getType(), '-' . $variable->getName(), $expression);
                 case 'variable':
                     $compilationContext->headersManager->add('kernel/operators');
                     $compilationContext->codePrinter->output('zephir_negate(' . $compilationContext->backend->getVariableCode($variable) . ' TSRMLS_CC);');
                     return new CompiledExpression('variable', $variable->getName(), $expression);
                 default:
                     throw new CompilerException("Cannot operate minus with variable of '" . $left->getType() . "' type");
             }
             break;
         default:
             throw new CompilerException("Cannot operate minus with '" . $left->getType() . "' type");
     }
 }
Beispiel #24
0
 /**
  * @param CompilationContext $compilationContext
  * @param boolean $unreachable
  * @param int $branchType
  * @return Branch
  */
 public function compile(CompilationContext $compilationContext, $unreachable = false, $branchType = Branch::TYPE_UNKNOWN)
 {
     $compilationContext->codePrinter->increaseLevel();
     $compilationContext->currentBranch++;
     /**
      * Create a new branch
      */
     $currentBranch = new Branch();
     $currentBranch->setType($branchType);
     $currentBranch->setUnreachable($unreachable);
     /**
      * Activate branch in the branch manager
      */
     $compilationContext->branchManager->addBranch($currentBranch);
     $this->_unreachable = $unreachable;
     $statements = $this->_statements;
     foreach ($statements as $statement) {
         /**
          * Generate GDB hints
          */
         if ($this->_debug) {
             if (isset($statement['file'])) {
                 if ($statement['type'] != 'declare' && $statement['type'] != 'comment') {
                     $compilationContext->codePrinter->outputNoIndent('#line ' . $statement['line'] . ' "' . $statement['file'] . '"');
                 }
             }
         }
         /**
          * Show warnings if code is generated when the 'unreachable state' is 'on'
          */
         if ($this->_unreachable === true) {
             switch ($statement['type']) {
                 case 'echo':
                     $compilationContext->logger->warning('Unreachable code', "unreachable-code", $statement['expressions'][0]);
                     break;
                 case 'let':
                     $compilationContext->logger->warning('Unreachable code', "unreachable-code", $statement['assignments'][0]);
                     break;
                 case 'fetch':
                 case 'fcall':
                 case 'mcall':
                 case 'scall':
                 case 'if':
                 case 'while':
                 case 'do-while':
                 case 'switch':
                 case 'for':
                 case 'return':
                 case 'c-block':
                     if (isset($statement['expr'])) {
                         $compilationContext->logger->warning('Unreachable code', "unreachable-code", $statement['expr']);
                     } else {
                         $compilationContext->logger->warning('Unreachable code', "unreachable-code", $statement);
                     }
                     break;
                 default:
                     $compilationContext->logger->warning('Unreachable code', "unreachable-code", $statement);
             }
         }
         switch ($statement['type']) {
             case 'let':
                 $letStatement = new LetStatement($statement);
                 $letStatement->compile($compilationContext);
                 break;
             case 'echo':
                 $echoStatement = new EchoStatement($statement);
                 $echoStatement->compile($compilationContext);
                 break;
             case 'declare':
                 $declareStatement = new DeclareStatement($statement);
                 $declareStatement->compile($compilationContext);
                 break;
             case 'if':
                 $ifStatement = new IfStatement($statement);
                 $ifStatement->compile($compilationContext);
                 break;
             case 'while':
                 $whileStatement = new WhileStatement($statement);
                 $whileStatement->compile($compilationContext);
                 break;
             case 'do-while':
                 $doWhileStatement = new DoWhileStatement($statement);
                 $doWhileStatement->compile($compilationContext);
                 break;
             case 'switch':
                 $switchStatement = new SwitchStatement($statement);
                 $switchStatement->compile($compilationContext);
                 break;
             case 'for':
                 $forStatement = new ForStatement($statement);
                 $forStatement->compile($compilationContext);
                 break;
             case 'return':
                 $returnStatement = new ReturnStatement($statement);
                 $returnStatement->compile($compilationContext);
                 $this->_unreachable = true;
                 break;
             case 'require':
                 $requireStatement = new RequireStatement($statement);
                 $requireStatement->compile($compilationContext);
                 break;
             case 'loop':
                 $loopStatement = new LoopStatement($statement);
                 $loopStatement->compile($compilationContext);
                 break;
             case 'break':
                 $breakStatement = new BreakStatement($statement);
                 $breakStatement->compile($compilationContext);
                 $this->_unreachable = true;
                 break;
             case 'continue':
                 $continueStatement = new ContinueStatement($statement);
                 $continueStatement->compile($compilationContext);
                 $this->_unreachable = true;
                 break;
             case 'unset':
                 $unsetStatement = new UnsetStatement($statement);
                 $unsetStatement->compile($compilationContext);
                 break;
             case 'throw':
                 $throwStatement = new ThrowStatement($statement);
                 $throwStatement->compile($compilationContext);
                 $this->_unreachable = true;
                 break;
             case 'try-catch':
                 $throwStatement = new TryCatchStatement($statement);
                 $throwStatement->compile($compilationContext);
                 $this->_unreachable = false;
                 break;
             case 'fetch':
                 $expr = new Expression($statement['expr']);
                 $expr->setExpectReturn(false);
                 $compiledExpression = $expr->compile($compilationContext);
                 $compilationContext->codePrinter->output($compiledExpression->getCode() . ';');
                 break;
             case 'mcall':
                 $methodCall = new MethodCall();
                 $expr = new Expression($statement['expr']);
                 $expr->setExpectReturn(false);
                 $methodCall->compile($expr, $compilationContext);
                 break;
             case 'fcall':
                 $functionCall = new FunctionCall();
                 $expr = new Expression($statement['expr']);
                 $expr->setExpectReturn(false);
                 $compiledExpression = $functionCall->compile($expr, $compilationContext);
                 switch ($compiledExpression->getType()) {
                     case 'int':
                     case 'double':
                     case 'uint':
                     case 'long':
                     case 'ulong':
                     case 'char':
                     case 'uchar':
                     case 'bool':
                         $compilationContext->codePrinter->output($compiledExpression->getCode() . ';');
                         break;
                 }
                 break;
             case 'scall':
                 $methodCall = new StaticCall();
                 $expr = new Expression($statement['expr']);
                 $expr->setExpectReturn(false);
                 $methodCall->compile($expr, $compilationContext);
                 break;
             case 'cblock':
                 $compilationContext->codePrinter->output($statement['value']);
                 break;
             case 'empty':
                 break;
             default:
                 throw new Exception('Unsupported statement: ' . $statement['type']);
         }
         if ($statement['type'] != 'comment') {
             $this->_lastStatement = $statement;
         }
     }
     /**
      * Traverses temporal variables created in a specific branch
      * marking them as idle
      */
     $compilationContext->symbolTable->markTemporalVariablesIdle($compilationContext);
     $compilationContext->branchManager->removeBranch($currentBranch);
     $compilationContext->currentBranch--;
     $compilationContext->codePrinter->decreaseLevel();
     return $currentBranch;
 }
Beispiel #25
0
 /**
  * Assigns a default value
  *
  * @param array $parameter
  * @param CompilationContext $compilationContext
  * @return string
  * @throws CompilerException
  */
 public function assignDefaultValue(array $parameter, CompilationContext $compilationContext)
 {
     if (isset($parameter['data-type'])) {
         $dataType = $parameter['data-type'];
     } else {
         $dataType = 'variable';
     }
     /**
      * Class-Hinted parameters only can be null?
      */
     if (isset($parameter['cast'])) {
         if ($parameter['default']['type'] != 'null') {
             throw new CompilerException('Class-Hinted parameters only can have "null" as default parameter', $parameter);
         }
     }
     $oldCodePrinter = $compilationContext->codePrinter;
     $codePrinter = new CodePrinter();
     $codePrinter->increaseLevel();
     $codePrinter->increaseLevel();
     $compilationContext->codePrinter = $codePrinter;
     $paramVariable = $compilationContext->symbolTable->getVariableForWrite($parameter['name'], $compilationContext);
     /**
      * @todo Refactoring this place, move to one - static-constant-access
      */
     switch ($dataType) {
         case 'int':
         case 'uint':
         case 'long':
         case 'ulong':
             switch ($parameter['default']['type']) {
                 case 'static-constant-access':
                     /**
                      * Now I can write code for easy use on Expression because code in this method don't write with codePrinter ;(
                      * @todo Rewrite all to codePrinter
                      */
                     $symbolVariable = $compilationContext->symbolTable->getVariableForWrite($parameter['name'], $compilationContext, $parameter['default']);
                     $expression = new Expression($parameter['default']);
                     $expression->setExpectReturn(true, $symbolVariable);
                     $compiledExpression = $expression->compile($compilationContext);
                     if ($compiledExpression->getType() != 'int') {
                         throw new CompilerException("Default parameter value type: " . $compiledExpression->getType() . " cannot be assigned to variable(int)", $parameter);
                     }
                     $parameter['default']['type'] = $compiledExpression->getType();
                     $parameter['default']['value'] = $compiledExpression->getCode();
                     $compilationContext->codePrinter = $oldCodePrinter;
                     return $this->assignDefaultValue($parameter, $compilationContext);
                     break;
                 case 'null':
                     $codePrinter->output($parameter['name'] . ' = 0;');
                     break;
                 case 'int':
                 case 'uint':
                 case 'long':
                     $codePrinter->output($parameter['name'] . ' = ' . $parameter['default']['value'] . ';');
                     break;
                 case 'double':
                     $codePrinter->output($parameter['name'] . ' = (int) ' . $parameter['default']['value'] . ';');
                     break;
                 default:
                     throw new CompilerException("Default parameter value type: " . $parameter['default']['type'] . " cannot be assigned to variable(int)", $parameter);
             }
             break;
         case 'double':
             switch ($parameter['default']['type']) {
                 case 'static-constant-access':
                     /**
                      * Now I can write code for easy use on Expression because code in this method don't write with codePrinter ;(
                      * @todo Rewrite all to codePrinter
                      */
                     $symbolVariable = $compilationContext->symbolTable->getVariableForWrite($parameter['name'], $compilationContext, $parameter['default']);
                     $expression = new Expression($parameter['default']);
                     $expression->setExpectReturn(true, $symbolVariable);
                     $compiledExpression = $expression->compile($compilationContext);
                     if ($compiledExpression->getType() != 'double') {
                         throw new CompilerException("Default parameter value type: " . $compiledExpression->getType() . " cannot be assigned to variable(double)", $parameter);
                     }
                     $parameter['default']['type'] = $compiledExpression->getType();
                     $parameter['default']['value'] = $compiledExpression->getCode();
                     $compilationContext->codePrinter = $oldCodePrinter;
                     return $this->assignDefaultValue($parameter, $compilationContext);
                     break;
                 case 'null':
                     $codePrinter->output($parameter['name'] . ' = 0;');
                     break;
                 case 'int':
                 case 'uint':
                 case 'long':
                     $codePrinter->output($parameter['name'] . ' = (double) ' . $parameter['default']['value'] . ';');
                     break;
                 case 'double':
                     $codePrinter->output($parameter['name'] . ' = ' . $parameter['default']['value'] . ';');
                     break;
                 default:
                     throw new CompilerException("Default parameter value type: " . $parameter['default']['type'] . " cannot be assigned to variable(double)", $parameter);
             }
             break;
         case 'bool':
             switch ($parameter['default']['type']) {
                 case 'static-constant-access':
                     /**
                      * Now I can write code for easy use on Expression because code in this method don't write with codePrinter ;(
                      * @todo Rewrite all to codePrinter
                      */
                     $symbolVariable = $compilationContext->symbolTable->getVariableForWrite($parameter['name'], $compilationContext, $parameter['default']);
                     $expression = new Expression($parameter['default']);
                     $expression->setExpectReturn(true, $symbolVariable);
                     $compiledExpression = $expression->compile($compilationContext);
                     if ($compiledExpression->getType() != 'bool') {
                         throw new CompilerException("Default parameter value type: " . $compiledExpression->getType() . " cannot be assigned to variable(bool)", $parameter);
                     }
                     $parameter['default']['type'] = $compiledExpression->getType();
                     $parameter['default']['value'] = $compiledExpression->getCode();
                     $compilationContext->codePrinter = $oldCodePrinter;
                     return $this->assignDefaultValue($parameter, $compilationContext);
                     break;
                 case 'null':
                     $codePrinter->output($parameter['name'] . ' = 0;');
                     break;
                 case 'bool':
                     if ($parameter['default']['value'] == 'true') {
                         $codePrinter->output($parameter['name'] . ' = 1;');
                     } else {
                         $codePrinter->output($parameter['name'] . ' = 0;');
                     }
                     break;
                 default:
                     throw new CompilerException("Default parameter value type: " . $parameter['default']['type'] . " cannot be assigned to variable(bool)", $parameter);
             }
             break;
         case 'string':
             $compilationContext->symbolTable->mustGrownStack(true);
             $compilationContext->headersManager->add('kernel/memory');
             switch ($parameter['default']['type']) {
                 case 'static-constant-access':
                     /**
                      * Now I can write code for easy use on Expression because code in this method don't write with codePrinter ;(
                      * @todo Rewrite all to codePrinter
                      */
                     $symbolVariable = $compilationContext->symbolTable->getVariableForWrite($parameter['name'], $compilationContext, $parameter['default']);
                     $expression = new Expression($parameter['default']);
                     $expression->setExpectReturn(true, $symbolVariable);
                     $compiledExpression = $expression->compile($compilationContext);
                     if ($compiledExpression->getType() != 'string') {
                         throw new CompilerException("Default parameter value type: " . $compiledExpression->getType() . " cannot be assigned to variable(string)", $parameter);
                     }
                     $parameter['default']['type'] = $compiledExpression->getType();
                     $parameter['default']['value'] = $compiledExpression->getCode();
                     $compilationContext->codePrinter = $oldCodePrinter;
                     return $this->assignDefaultValue($parameter, $compilationContext);
                     break;
                 case 'null':
                     $compilationContext->backend->initVar($paramVariable, $compilationContext);
                     $compilationContext->backend->assignString($paramVariable, null, $compilationContext);
                     break;
                 case 'string':
                     $compilationContext->backend->initVar($paramVariable, $compilationContext);
                     $compilationContext->backend->assignString($paramVariable, Utils::addSlashes($parameter['default']['value'], true), $compilationContext);
                     break;
                 default:
                     throw new CompilerException("Default parameter value type: " . $parameter['default']['type'] . " cannot be assigned to variable(string)", $parameter);
             }
             break;
         case 'array':
             $compilationContext->symbolTable->mustGrownStack(true);
             $compilationContext->headersManager->add('kernel/memory');
             switch ($parameter['default']['type']) {
                 case 'null':
                     $compilationContext->backend->initVar($paramVariable, $compilationContext);
                     $compilationContext->backend->initArray($paramVariable, $compilationContext, null);
                     break;
                 case 'empty-array':
                 case 'array':
                     $compilationContext->backend->initVar($paramVariable, $compilationContext);
                     $compilationContext->backend->initArray($paramVariable, $compilationContext, null);
                     break;
                 default:
                     throw new CompilerException("Default parameter value type: " . $parameter['default']['type'] . " cannot be assigned to variable(array)", $parameter);
             }
             break;
         case 'variable':
             $symbolVariable = $compilationContext->symbolTable->getVariableForWrite($parameter['name'], $compilationContext, $parameter['default']);
             switch ($parameter['default']['type']) {
                 case 'static-constant-access':
                     /**
                      * Now I can write code for easy use on Expression because code in this method don't write with codePrinter ;(
                      * @todo Rewrite all to codePrinter
                      */
                     $expression = new Expression($parameter['default']);
                     $expression->setExpectReturn(true, $symbolVariable);
                     $compiledExpression = $expression->compile($compilationContext);
                     $parameter['default']['type'] = $compiledExpression->getType();
                     $parameter['default']['value'] = $compiledExpression->getCode();
                     $compilationContext->codePrinter = $oldCodePrinter;
                     return $this->assignDefaultValue($parameter, $compilationContext);
                     break;
                 case 'int':
                 case 'uint':
                 case 'long':
                 case 'ulong':
                     $compilationContext->symbolTable->mustGrownStack(true);
                     $compilationContext->headersManager->add('kernel/memory');
                     $compilationContext->backend->initVar($symbolVariable, $compilationContext);
                     $compilationContext->backend->assignLong($symbolVariable, $parameter['default']['value'], $compilationContext);
                     break;
                 case 'double':
                     $compilationContext->symbolTable->mustGrownStack(true);
                     $compilationContext->headersManager->add('kernel/memory');
                     $compilationContext->backend->initVar($symbolVariable, $compilationContext);
                     $compilationContext->backend->assignDouble($symbolVariable, $parameter['default']['value'], $compilationContext);
                     break;
                 case 'string':
                     $compilationContext->symbolTable->mustGrownStack(true);
                     $compilationContext->headersManager->add('kernel/memory');
                     $compilationContext->backend->initVar($symbolVariable, $compilationContext);
                     $compilationContext->backend->assignString($paramVariable, Utils::addSlashes($parameter['default']['value'], true), $compilationContext);
                     break;
                 case 'bool':
                     $expectedMutations = $compilationContext->symbolTable->getExpectedMutations($parameter['name']);
                     if ($expectedMutations < 2) {
                         if ($parameter['default']['value'] == 'true') {
                             $compilationContext->backend->assignZval($paramVariable, $compilationContext->backend->resolveValue('true', $compilationContext), $compilationContext);
                         } else {
                             $compilationContext->backend->assignZval($paramVariable, $compilationContext->backend->resolveValue('false', $compilationContext), $compilationContext);
                         }
                     } else {
                         $compilationContext->symbolTable->mustGrownStack(true);
                         $compilationContext->headersManager->add('kernel/memory');
                         if ($parameter['default']['value'] == 'true') {
                             $compilationContext->backend->copyOnWrite($paramVariable, $compilationContext->backend->resolveValue('true', $compilationContext), $compilationContext);
                         } else {
                             $compilationContext->backend->copyOnWrite($paramVariable, $compilationContext->backend->resolveValue('false', $compilationContext), $compilationContext);
                         }
                     }
                     break;
                 case 'null':
                     $expectedMutations = $compilationContext->symbolTable->getExpectedMutations($parameter['name']);
                     if ($expectedMutations < 2) {
                         $compilationContext->backend->assignZval($symbolVariable, $compilationContext->backend->resolveValue('null', $compilationContext), $compilationContext);
                     } else {
                         $compilationContext->symbolTable->mustGrownStack(true);
                         $compilationContext->headersManager->add('kernel/memory');
                         $compilationContext->backend->copyOnWrite($paramVariable, $compilationContext->backend->resolveValue('null', $compilationContext), $compilationContext);
                     }
                     break;
                 case 'empty-array':
                     $compilationContext->symbolTable->mustGrownStack(true);
                     $compilationContext->headersManager->add('kernel/memory');
                     $compilationContext->backend->initVar($symbolVariable, $compilationContext);
                     $compilationContext->backend->initArray($symbolVariable, $compilationContext, null);
                     break;
                 default:
                     throw new CompilerException("Default parameter value type: " . $parameter['default']['type'] . " cannot be assigned to variable(variable)", $parameter);
             }
             break;
         default:
             throw new CompilerException("Default parameter type: " . $dataType, $parameter);
     }
     $compilationContext->codePrinter = $oldCodePrinter;
     return $codePrinter->getOutput();
 }
Beispiel #26
0
 /**
  * Compiles a reference to a value
  *
  * @param array $expression
  * @param CompilationContext $compilationContext
  * @return CompiledExpression
  */
 public function compile($expression, CompilationContext $compilationContext)
 {
     /**
      * Resolves the symbol that expects the value
      */
     if ($this->_expecting) {
         if ($this->_expectingVariable) {
             $symbolVariable = $this->_expectingVariable;
             if ($symbolVariable->getType() != 'variable') {
                 throw new CompilerException("Cannot use variable type: " . $symbolVariable->getType() . " to store a reference", $expression);
             }
         } else {
             $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $expression);
         }
     } else {
         $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $expression);
     }
     $leftExpr = new Expression($expression['left']);
     $leftExpr->setReadOnly($this->_readOnly);
     $left = $leftExpr->compile($compilationContext);
     switch ($left->getType()) {
         case 'variable':
         case 'string':
         case 'object':
         case 'array':
         case 'callable':
             break;
         default:
             throw new CompilerException("Cannot obtain a reference from type: " . $left->getType(), $expression);
     }
     $leftVariable = $compilationContext->symbolTable->getVariableForRead($left->getCode(), $compilationContext, $expression);
     switch ($leftVariable->getType()) {
         case 'variable':
         case 'string':
         case 'object':
         case 'array':
         case 'callable':
             break;
         default:
             throw new CompilerException("Cannot obtain reference from variable type: " . $leftVariable->getType(), $expression);
     }
     $symbolVariable->setMustInitNull(true);
     $compilationContext->symbolTable->mustGrownStack(true);
     $symbolVariable->increaseVariantIfNull();
     $compilationContext->codePrinter->output('ZEPHIR_MAKE_REFERENCE(' . $symbolVariable->getName() . ', ' . $leftVariable->getName() . ');');
     return new CompiledExpression('reference', $symbolVariable->getRealName(), $expression);
 }
Beispiel #27
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);
     }
 }
 /**
  * Compiles x::y[a][b][] = {expr} (multiple offset assignment)
  *
  * @param string $variable
  * @param CompiledExpression $resolvedExpr
  * @param CompilationContext $compilationContext,
  * @param array $statement
  */
 protected function _assignStaticPropertyArrayMultipleIndex($classEntry, $property, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement)
 {
     $codePrinter = $compilationContext->codePrinter;
     $property = $statement['property'];
     $compilationContext->headersManager->add('kernel/object');
     /**
      * Create a temporal zval (if needed)
      */
     $variableExpr = $this->_getResolvedArrayItem($resolvedExpr, $compilationContext);
     /**
      * Only string/variable/int
      */
     $offsetExprs = array();
     foreach ($statement['index-expr'] as $indexExpr) {
         $indexExpression = new Expression($indexExpr);
         $resolvedIndex = $indexExpression->compile($compilationContext);
         switch ($resolvedIndex->getType()) {
             case 'string':
             case 'int':
             case 'uint':
             case 'ulong':
             case 'long':
             case 'variable':
                 break;
             default:
                 throw new CompilerException("Expression: " . $resolvedIndex->getType() . " cannot be used as index without cast", $statement['index-expr']);
         }
         $offsetExprs[] = $resolvedIndex;
     }
     $keys = '';
     $numberParams = 1;
     $offsetItems = array();
     foreach ($offsetExprs as $offsetExpr) {
         switch ($offsetExpr->getType()) {
             case 'int':
             case 'uint':
             case 'long':
             case 'ulong':
                 $keys .= 'l';
                 $offsetItems[] = $offsetExpr->getCode();
                 $numberParams++;
                 break;
             case 'string':
                 $keys .= 's';
                 $offsetItems[] = 'SL("' . $offsetExpr->getCode() . '")';
                 $numberParams += 2;
                 break;
             case 'variable':
                 $variableIndex = $compilationContext->symbolTable->getVariableForRead($offsetExpr->getCode(), $compilationContext, $statement);
                 switch ($variableIndex->getType()) {
                     case 'int':
                     case 'uint':
                     case 'long':
                     case 'ulong':
                         $keys .= 'l';
                         $offsetItems[] = $variableIndex->getName();
                         $numberParams++;
                         break;
                     case 'string':
                     case 'variable':
                         $keys .= 'z';
                         $offsetItems[] = $variableIndex->getName();
                         $numberParams++;
                         break;
                     default:
                         throw new CompilerException("Variable: " . $variableIndex->getType() . " cannot be used as array index", $statement);
                 }
                 break;
             default:
                 throw new CompilerException("Value: " . $offsetExpr->getType() . " cannot be used as array index", $statement);
         }
     }
     $codePrinter->output('zephir_update_static_property_array_multi_ce(' . $classEntry . ', SL("' . $property . '"), &' . $variableExpr->getName() . ' TSRMLS_CC, SL("' . $keys . 'a"), ' . $numberParams . ', ' . join(', ', $offsetItems) . ');');
     if ($variableExpr->isTemporal()) {
         $variableExpr->setIdle(true);
     }
 }
Beispiel #29
0
 /**
  * Resolves an expression
  *
  * @param CompilationContext $compilationContext
  * @return bool|CompiledExpression|mixed
  * @throws CompilerException
  */
 public function compile(CompilationContext $compilationContext)
 {
     $expression = $this->_expression;
     $type = $expression['type'];
     $compilableExpression = null;
     switch ($type) {
         case 'null':
             return new LiteralCompiledExpression('null', null, $expression);
         case 'int':
         case 'integer':
             return new LiteralCompiledExpression('int', $expression['value'], $expression);
         case 'long':
         case 'double':
         case 'bool':
             return new LiteralCompiledExpression($type, $expression['value'], $expression);
         case 'string':
             if (!$this->_stringOperation) {
                 if (ctype_digit($expression['value'])) {
                     return new CompiledExpression('int', $expression['value'], $expression);
                 }
             }
             return new LiteralCompiledExpression('string', str_replace(PHP_EOL, '\\n', $expression['value']), $expression);
         case 'istring':
             return new LiteralCompiledExpression('istring', str_replace(PHP_EOL, '\\n', $expression['value']), $expression);
         case 'char':
             if (!strlen($expression['value'])) {
                 throw new CompilerException("Invalid empty char literal", $expression);
             }
             if (strlen($expression['value']) > 2) {
                 if (strlen($expression['value']) > 10) {
                     throw new CompilerException("Invalid char literal: '" . substr($expression['value'], 0, 10) . "...'", $expression);
                 } else {
                     throw new CompilerException("Invalid char literal: '" . $expression['value'] . "'", $expression);
                 }
             }
             return new LiteralCompiledExpression('char', $expression['value'], $expression);
         case 'variable':
             $var = $compilationContext->symbolTable->getVariable($expression['value']);
             if ($var) {
                 if ($var->getRealName() == 'this') {
                     $var = 'this';
                 } else {
                     $var = $var->getName();
                 }
             } else {
                 $var = $expression['value'];
             }
             return new CompiledExpression('variable', $var, $expression);
         case 'constant':
             $compilableExpression = new Constants();
             break;
         case 'empty-array':
             return $this->emptyArray($expression, $compilationContext);
         case 'array-access':
             $compilableExpression = new NativeArrayAccess();
             $compilableExpression->setNoisy($this->isNoisy());
             break;
         case 'property-access':
             $compilableExpression = new PropertyAccess();
             $compilableExpression->setNoisy($this->isNoisy());
             break;
         case 'property-string-access':
         case 'property-dynamic-access':
             $compilableExpression = new PropertyDynamicAccess();
             $compilableExpression->setNoisy($this->isNoisy());
             break;
         case 'static-constant-access':
             $compilableExpression = new StaticConstantAccess();
             break;
         case 'static-property-access':
             $compilableExpression = new StaticPropertyAccess();
             break;
         case 'fcall':
             $functionCall = new FunctionCall();
             return $functionCall->compile($this, $compilationContext);
         case 'mcall':
             $methodCall = new MethodCall();
             return $methodCall->compile($this, $compilationContext);
         case 'scall':
             $staticCall = new StaticCall();
             return $staticCall->compile($this, $compilationContext);
         case 'isset':
             $compilableExpression = new IssetOperator();
             break;
         case 'fetch':
             $compilableExpression = new FetchOperator();
             break;
         case 'empty':
             $compilableExpression = new EmptyOperator();
             break;
         case 'array':
             $compilableExpression = new NativeArray();
             break;
         case 'new':
             $compilableExpression = new NewInstanceOperator();
             break;
         case 'new-type':
             $compilableExpression = new NewInstanceTypeOperator();
             break;
         case 'not':
             $compilableExpression = new NotOperator();
             break;
         case 'bitwise_not':
             $compilableExpression = new BitwiseNotOperator();
             break;
         case 'equals':
             $compilableExpression = new EqualsOperator();
             break;
         case 'not-equals':
             $compilableExpression = new NotEqualsOperator();
             break;
         case 'identical':
             $compilableExpression = new IdenticalOperator();
             break;
         case 'not-identical':
             $compilableExpression = new NotIdenticalOperator();
             break;
         case 'greater':
             $compilableExpression = new GreaterOperator();
             break;
         case 'less':
             $compilableExpression = new LessOperator();
             break;
         case 'less-equal':
             $compilableExpression = new LessEqualOperator();
             break;
         case 'greater-equal':
             $compilableExpression = new GreaterEqualOperator();
             break;
         case 'add':
             $compilableExpression = new AddOperator();
             break;
         case 'minus':
             $compilableExpression = new MinusOperator();
             break;
         case 'sub':
             $compilableExpression = new SubOperator();
             break;
         case 'mul':
             $compilableExpression = new MulOperator();
             break;
         case 'div':
             $compilableExpression = new DivOperator();
             break;
         case 'mod':
             $compilableExpression = new ModOperator();
             break;
         case 'and':
             $compilableExpression = new AndOperator();
             break;
         case 'or':
             $compilableExpression = new OrOperator();
             break;
         case 'bitwise_and':
             $compilableExpression = new BitwiseAndOperator();
             break;
         case 'bitwise_or':
             $compilableExpression = new BitwiseOrOperator();
             break;
         case 'bitwise_xor':
             $compilableExpression = new BitwiseXorOperator();
             break;
         case 'bitwise_shiftleft':
             $compilableExpression = new ShiftLeftOperator();
             break;
         case 'bitwise_shiftright':
             $compilableExpression = new ShiftRightOperator();
             break;
         case 'concat':
             $expr = new ConcatOperator();
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'irange':
             $compilableExpression = new RangeInclusiveOperator();
             break;
         case 'erange':
             $compilableExpression = new RangeExclusiveOperator();
             break;
         case 'list':
             if ($expression['left']['type'] == 'list') {
                 $compilationContext->logger->warning("Unnecessary extra parentheses", "extra-parentheses", $expression);
             }
             $numberPrints = $compilationContext->codePrinter->getNumberPrints();
             $expr = new Expression($expression['left']);
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             $resolved = $expr->compile($compilationContext);
             if ($compilationContext->codePrinter->getNumberPrints() - $numberPrints <= 1) {
                 if (strpos($resolved->getCode(), ' ') !== false) {
                     return new CompiledExpression($resolved->getType(), '(' . $resolved->getCode() . ')', $expression);
                 }
             }
             return $resolved;
         case 'cast':
             $compilableExpression = new CastOperator();
             break;
         case 'type-hint':
             return $this->compileTypeHint($expression, $compilationContext);
         case 'instanceof':
             $compilableExpression = new InstanceOfOperator();
             break;
         case 'clone':
             $compilableExpression = new CloneOperator();
             break;
         case 'ternary':
             $compilableExpression = new TernaryOperator();
             break;
         case 'short-ternary':
             $expr = new ShortTernaryOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'likely':
             if (!$this->_evalMode) {
                 throw new CompilerException("'likely' operator can only be used in evaluation expressions", $expression);
             }
             $expr = new LikelyOperator();
             $expr->setReadOnly($this->isReadOnly());
             return $expr->compile($expression, $compilationContext);
         case 'unlikely':
             if (!$this->_evalMode) {
                 throw new CompilerException("'unlikely' operator can only be used in evaluation expressions", $expression);
             }
             $expr = new UnlikelyOperator();
             $expr->setReadOnly($this->isReadOnly());
             return $expr->compile($expression, $compilationContext);
         case 'typeof':
             $compilableExpression = new TypeOfOperator();
             break;
         case 'require':
             $compilableExpression = new RequireOperator();
             break;
         case 'closure':
             $compilableExpression = new Closure();
             break;
         case 'closure-arrow':
             $compilableExpression = new ClosureArrow();
             break;
         case 'reference':
             $compilableExpression = new Reference();
             break;
         default:
             throw new CompilerException("Unknown expression: " . $type, $expression);
     }
     if (!$compilableExpression) {
         throw new CompilerException("Unknown expression passed as compilableExpression", $expression);
     }
     $compilableExpression->setReadOnly($this->isReadOnly());
     $compilableExpression->setExpectReturn($this->_expecting, $this->_expectingVariable);
     return $compilableExpression->compile($expression, $compilationContext);
 }
Beispiel #30
0
 /**
  * Optimizes expressions
  *
  * @param $exprRaw
  * @param CompilationContext $compilationContext
  * @return bool|string
  * @throws CompilerException
  */
 public function optimize($exprRaw, CompilationContext $compilationContext)
 {
     $conditions = $this->optimizeNot($exprRaw, $compilationContext);
     if ($conditions !== false) {
         return $conditions;
     }
     /**
      * Discard first level parentheses
      */
     if ($exprRaw['type'] == 'list') {
         $expr = new Expression($exprRaw['left']);
     } else {
         $expr = new Expression($exprRaw);
     }
     $expr->setReadOnly(true);
     $expr->setEvalMode(true);
     $compiledExpression = $expr->compile($compilationContext);
     /**
      * Possible corrupted expression?
      */
     if (!is_object($compiledExpression)) {
         throw new CompilerException('Corrupted expression: ' . $exprRaw['type'], $exprRaw);
     }
     /**
      * Generate the condition according to the value returned by the evaluated expression
      */
     switch ($compiledExpression->getType()) {
         case 'null':
             $this->_unreachable = true;
             return '0';
         case 'int':
         case 'uint':
         case 'long':
         case 'ulong':
         case 'double':
             $code = $compiledExpression->getCode();
             if (is_numeric($code)) {
                 if ($code == '1') {
                     $this->_unreachableElse = true;
                 } else {
                     $this->_unreachable = true;
                 }
             }
             return $code;
         case 'char':
         case 'uchar':
             return $compiledExpression->getCode();
         case 'bool':
             $code = $compiledExpression->getBooleanCode();
             if ($code == '1') {
                 $this->_unreachableElse = true;
             } else {
                 if ($code == '0') {
                     $this->_unreachable = true;
                 }
             }
             return $code;
         case 'variable':
             $variableRight = $compilationContext->symbolTable->getVariableForRead($compiledExpression->getCode(), $compilationContext, $exprRaw);
             $possibleValue = $variableRight->getPossibleValue();
             if (is_object($possibleValue)) {
                 $possibleValueBranch = $variableRight->getPossibleValueBranch();
                 if ($possibleValueBranch instanceof Branch) {
                     /**
                      * Check if the possible value was assigned in the root branch
                      */
                     if ($possibleValueBranch->getType() == Branch::TYPE_ROOT) {
                         if ($possibleValue instanceof LiteralCompiledExpression) {
                             switch ($possibleValue->getType()) {
                                 case 'null':
                                     $this->_unreachable = true;
                                     break;
                                 case 'bool':
                                     if ($possibleValue->getBooleanCode() == '0') {
                                         $this->_unreachable = true;
                                     } else {
                                         $this->_unreachableElse = true;
                                     }
                                     break;
                                 case 'int':
                                     if (!intval($possibleValue->getCode())) {
                                         $this->_unreachable = true;
                                     } else {
                                         $this->_unreachableElse = true;
                                     }
                                     break;
                                 case 'double':
                                     if (!floatval($possibleValue->getCode())) {
                                         $this->_unreachable = true;
                                     } else {
                                         $this->_unreachableElse = true;
                                     }
                                     break;
                                 default:
                                     //echo $possibleValue->getType();
                             }
                         }
                     }
                 }
             }
             $this->_usedVariables[] = $variableRight->getName();
             /**
              * Evaluate the variable
              */
             switch ($variableRight->getType()) {
                 case 'int':
                 case 'uint':
                 case 'char':
                 case 'uchar':
                 case 'long':
                 case 'ulong':
                     return $variableRight->getName();
                 case 'string':
                     return $variableRight->getName() . ' && Z_STRLEN_P(' . $variableRight->getName() . ')';
                 case 'bool':
                     return $variableRight->getName();
                 case 'double':
                     return $variableRight->getName();
                 case 'variable':
                     $compilationContext->headersManager->add('kernel/operators');
                     if ($variableRight->isLocalOnly()) {
                         return 'zephir_is_true(&' . $variableRight->getName() . ')';
                     } else {
                         return 'zephir_is_true(' . $variableRight->getName() . ')';
                     }
                     break;
                 default:
                     throw new CompilerException("Variable can't be evaluated " . $variableRight->getType(), $exprRaw);
             }
             break;
         default:
             throw new CompilerException("Expression " . $compiledExpression->getType() . " can't be evaluated", $exprRaw);
     }
 }