@param array              $expression
@param Call               $call
@param CompilationContext $context

@throws CompilerException

@return CompiledExpression
509507
public function optimize(array $expression, Call $call, CompilationContext $context)
    {
        if (!isset($expression['parameters'])) {
            throw new CompilerException("'globals_set' requires two parameters", $expression);
        }

        if (2 != \count($expression['parameters'])) {
            throw new CompilerException("'globals_set' only accepts two parameters", $expression);
        }

        if ('string' != $expression['parameters'][0]['parameter']['type']) {
            throw new CompilerException("A string parameter is required for 'globals_set'", $expression);
        }

        $globalName = $expression['parameters'][0]['parameter']['value'];

        if (!$context->compiler->isExtensionGlobal($globalName)) {
            throw new CompilerException(
                "Global variable '{$globalName}' cannot be written because it wasn't defined",
                $expression
            );
        }

        unset($expression['parameters'][0]);

        try {
            $globalDefinition = $context->compiler->getExtensionGlobal($globalName);
            $resolvedParams = $call->getReadOnlyResolvedParams($expression['parameters'], $context, $expression);

            if (!isset($resolvedParams[0]) || empty($resolvedParams[0]) || !\is_string($resolvedParams[0])) {
                throw new CompilerException(
                    "Unable to reslove value for '{$globalName}' global variable.",
                    $expression
                );
            }

            if (!isset($globalDefinition['type'])) {
                throw new CompilerException(
                    "Unable to determine type for '{$globalName}' global variable.",
                    $expression
                );
            }

            $internalAccessor = $this->resolveInternalAccessor($globalName);
            $internalValue = $this->resolveInternalValue($globalDefinition, $expression, $globalName, $resolvedParams[0]);

            $context->codePrinter->output("{$internalAccessor} = {$internalValue};");

            return new CompiledExpression('null', null, $expression);
        } catch (Exception $e) {
            throw new CompilerException($e->getMessage(), $expression);
        }
    }
990303
public function compile($expression, CompilationContext $context)
    {
        $left = new Expression($expression['left']);
        $resolved = $left->compile($context);

        if ('variable' != $resolved->getType()) {
            throw new CompilerException("InstanceOf requires a 'dynamic variable' in the left operand", $expression);
        }

        $symbolVariable = $context->symbolTable->getVariableForRead($resolved->getCode(), $context, $expression);
        if (!$symbolVariable->isVariable()) {
            throw new CompilerException("InstanceOf requires a 'dynamic variable' in the left operand", $expression);
        }

        $right = new Expression($expression['right']);
        $resolved = $right->compile($context);
        $resolvedVariable = $resolved->getCode();

        switch ($resolved->getType()) {
            case 'string':
                $className = fqcn($resolvedVariable, $context->classDefinition->getNamespace(), $context->aliasManager);

                if ($context->compiler->isClass($className)) {
                    $classDefinition = $context->compiler->getClassDefinition($className);
                    $classEntry = $classDefinition->getClassEntry($context);
                } else {
                    if (!class_exists($className, false)) {
                        $code = 'SL("'.$resolvedVariable.'")';
                    } else {
                        $classEntry = $context->classDefinition->getClassEntryByClassName($className, $context, true);
                        if (!$classEntry) {
                            $code = 'SL("'.$resolvedVariable.'")';
                        }
                    }
                }
                break;
            default:
                switch ($resolved->getType()) {
                    case 'variable':
                        if ('this' == $resolvedVariable) {
                            /**
                             * @todo It's an optimization variant, but maybe we need to get entry in runtime?
                             */
                            $classEntry = $context->classDefinition->getClassEntry($context);
                        } elseif (!$context->symbolTable->hasVariable($resolvedVariable)) {
                            $className = $context->getFullName($resolvedVariable);

                            if ('Traversable' == $className) {
                                $symbol = $context->backend->getVariableCode($symbolVariable);

                                return new CompiledExpression('bool', 'zephir_zval_is_traversable('.$symbol.' TSRMLS_CC)', $expression);
                            }

                            if ($context->compiler->isClass($className)) {
                                $classDefinition = $context->compiler->getClassDefinition($className);
                                $classEntry = $classDefinition->getClassEntry($context);
                            } else {
                                if ($context->compiler->isInterface($className)) {
                                    $classDefinition = $context->compiler->getClassDefinition($className);
                                    $classEntry = $classDefinition->getClassEntry($context);
                                } else {
                                    if (!class_exists($className, false)) {
                                        $code = 'SL("'.trim(escape_class($className), '\\').'")';
                                    } else {
                                        $classEntry = $context->classDefinition->getClassEntryByClassName($className, $context, true);
                                        if (!$classEntry) {
                                            $code = 'SL("'.trim(escape_class($className), '\\').'")';
                                        }
                                    }
                                }
                            }
                        } else {
                            $code = $this->prepareBackendSpecificCode($resolvedVariable, $context);
                        }
                        break;

                    case 'property-access':
                    case 'array-access':
                        $context->headersManager->add('kernel/operators');
                        $tempVariable = $context->symbolTable->getTempVariableForWrite('string', $context);
                        $tempVariable->setMustInitNull(true);
                        $tempVariableName = $tempVariable->getName();
                        $context->codePrinter->output('zephir_get_strval('.$tempVariableName.', '.$resolvedVariable.');');
                        $code = $this->prepareBackendSpecificCode($tempVariableName, $context);
                        break;

                    default:
                        throw new CompilerException("InstanceOf requires a 'variable' or a 'string' in the right operand", $expression);
                }
        }

        /* @TODO, Possible optimization is use zephir_is_instance when the const class name is an internal class or interface */
        $context->headersManager->add('kernel/object');
        $symbol = $context->backend->getVariableCode($symbolVariable);
        if (isset($code)) {
            return new CompiledExpression('bool', 'zephir_is_instance_of('.$symbol.', '.$code.' TSRMLS_CC)', $expression);
        }

        return new CompiledExpression('bool', 'zephir_instance_of_ev('.$symbol.', '.$classEntry.' TSRMLS_CC)', $expression);
    }
1158432
public void pushEnclosingMethodCall(Expression call) {
        if (call instanceof MethodCallExpression || call instanceof StaticMethodCallExpression) {
            enclosingMethodCalls.addFirst(call);
        } else {
            throw new IllegalArgumentException("Expression must be a method call or a static method call");
        }
    }
719318
public function compile($expression, CompilationContext $compilationContext)
    {
        /*
         * This variable is used to check if the compound and expression is evaluated as true or false:
         * Ensure that newly allocated variables are local-only (setReadOnly)
         */
        $this->setReadOnly(false);
        $returnVariable = $this->getExpected($compilationContext, $expression, false);
        /* Make sure that passed variables (passed symbol variables) are promoted */
        $returnVariable->setLocalOnly(false);

        if ('variable' != $returnVariable->getType() || 'return_value' == $returnVariable->getName()) {
            $returnVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
            if ($returnVariable->isTemporal()) {
                $returnVariable->skipInitVariant(2);
            }
        }

        $ifBuilder = new IfStatementBuilder(
            new UnaryOperatorBuilder(
                'not',
                $expression['left']
            ),
            new StatementsBlockBuilder([
                /*
                 * Create an implicit 'let' operation to update the evaluated right operator
                 */
                new LetStatementBuilder([
                    'assign-type' => 'variable',
                    'variable' => $returnVariable->getName(),
                    'operator' => 'assign',
                    'expr' => $expression['extra'],
                    'file' => $expression['file'],
                    'line' => $expression['line'],
                    'char' => $expression['char'],
                ], $expression['extra']),
            ]),
            new StatementsBlockBuilder([
                /*
                 * Create an implicit 'let' operation to update the evaluated right operator
                 */
                new LetStatementBuilder([
                    'assign-type' => 'variable',
                    'variable' => $returnVariable->getName(),
                    'operator' => 'assign',
                    'expr' => $expression['left'],
                    'file' => $expression['file'],
                    'line' => $expression['line'],
                    'char' => $expression['char'],
                ], $expression['extra']),
            ])
        );

        $ifStatement = new IfStatement($ifBuilder->get());
        $ifStatement->compile($compilationContext);

        return new CompiledExpression('variable', $returnVariable->getName(), $expression);
    }
1049481
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::T_ARRAY, $exprBuilder->statements()
            ->functionCall('range', [$expression['left'], $expression['right']]));

        $expression = new Expression($castBuilder->build());
        $expression->setReadOnly($this->readOnly);

        return $expression->compile($compilationContext);
    }
534043
public function compile(array $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 ('variable' != $left->getType() && 'array' != $left->getType()) {
            throw new CompilerException("'empty' operand only can be a variable", $expression['left']);
        }

        $variableLeft = $compilationContext->symbolTable->getVariableForRead($left->getCode(), $compilationContext, $expression['left']);
        if (!$variableLeft->isVariable() && !$variableLeft->isString() && !$variableLeft->isArray()) {
            throw new CompilerException("Only dynamic/string variables can be used in 'empty' operators", $expression['left']);
        }

        return new CompiledExpression('bool', 'ZEPHIR_IS_EMPTY('.$compilationContext->backend->getVariableCode($variableLeft).')', $expression);
    }
72610
public function optimize(array $expression, Call $call, CompilationContext $context)
    {
        if (!isset($expression['parameters'])) {
            return false;
        }

        if (1 != \count($expression['parameters'])) {
            return false;
        }

        $resolvedParams = $call->getReadOnlyResolvedParams($expression['parameters'], $context, $expression);

        if ($context->backend->isZE3()) {
            if ('IS_BOOL' == $this->getType()) {
                $condition = '(Z_TYPE_P('.$resolvedParams[0].') == IS_TRUE || Z_TYPE_P('.$resolvedParams[0].') == IS_FALSE)';
            } else {
                $condition = 'Z_TYPE_P('.$resolvedParams[0].') == '.$this->getType();
            }
        } else {
            $condition = 'Z_TYPE_P('.$resolvedParams[0].') == '.$this->getType();
        }

        return new CompiledExpression('bool', $condition, $expression);
    }
107948
public function optimize(array $expression, Call $call, CompilationContext $context)
    {
        if (!isset($expression['parameters'])) {
            return false;
        }

        $context->headersManager->add('kernel/variables');
        $resolvedParams = $call->getResolvedParamsAsExpr($expression['parameters'], $context, $expression);

        foreach ($resolvedParams as $resolvedParam) {
            $variable = $context->symbolTable->getVariable($resolvedParam->getCode());
            if (!$variable || !$variable->isVariable()) {
                /*
                 * Complex expressions require a temporary variable
                 */
                switch ($resolvedParam->getType()) {
                    case 'array':
                        $type = 'array';
                        break;
                    default:
                        $type = 'variable';
                        break;
                }

                $variable = $context->symbolTable->addTemp($type, $context);
                $variable->initVariant($context);

                $statement = new LetStatement([
                    'type' => 'let',
                    'assignments' => [
                        [
                            'assign-type' => $type,
                            'variable' => $variable->getName(),
                            'operator' => 'assign',
                            'expr' => [
                                'type' => $resolvedParam->getType(),
                                'value' => $resolvedParam->getCode(),
                                'file' => $expression['file'],
                                'line' => $expression['line'],
                                'char' => $expression['char'],
                            ],
                            'file' => $expression['file'],
                            'line' => $expression['line'],
                            'char' => $expression['char'],
                        ],
                    ],
                ]);
                $statement->compile($context);
            } else {
                /**
                 * This mark the variable as used.
                 */
                $variable = $context->symbolTable->getVariableForRead($resolvedParam->getCode(), $context, $expression);
            }

            $symbol = $context->backend->getVariableCodePointer($variable);
            $context->codePrinter->output('zephir_var_dump('.$symbol.' TSRMLS_CC);');
        }

        return new CompiledExpression('null', 'null', $expression);
    }
663163
public function optimize(array $expression, Call $call, CompilationContext $context)
    {
        if (!isset($expression['parameters'])) {
            return false;
        }

        /*
         * Process the expected symbol to be returned
         */
        $call->processExpectedReturn($context);

        $symbolVariable = $call->getSymbolVariable();
        if ($symbolVariable) {
            if (!$symbolVariable->isVariable()) {
                throw new CompilerException('Returned values by functions can only be assigned to variant variables', $expression);
            }
        }

        $context->headersManager->add('kernel/variables');
        $resolvedParams = $call->getResolvedParamsAsExpr($expression['parameters'], $context, $expression);
        $resolvedParam = $resolvedParams[0];

        if (!$symbolVariable || !$symbolVariable->isVariable()) {
            /*
             * Complex expressions require a temporary variable
             */
            switch ($resolvedParam->getType()) {
                case 'array':
                    $type = 'array';
                    break;
                default:
                    $type = 'variable';
                    break;
            }

            $variable = $context->symbolTable->addTemp($type, $context);
            $variable->initVariant($context);

            $statement = new LetStatement([
                'type' => 'let',
                'assignments' => [
                    [
                        'assign-type' => $type,
                        'variable' => $variable->getName(),
                        'operator' => 'assign',
                        'expr' => [
                            'type' => $resolvedParam->getType(),
                            'value' => $resolvedParam->getCode(),
                            'file' => $expression['file'],
                            'line' => $expression['line'],
                            'char' => $expression['char'],
                        ],
                        'file' => $expression['file'],
                        'line' => $expression['line'],
                        'char' => $expression['char'],
                    ],
                ],
            ]);
            $statement->compile($context);
        } else {
            /**
             * This mark the variable as used.
             */
            $variable = $context->symbolTable->getVariableForRead($resolvedParam->getCode(), $context, $expression);
        }
        $variableSymbol = $context->backend->getVariableCodePointer($variable);

        /*
         * let a = var_export(val);
         */
        if ($symbolVariable) {
            if ('return_value' == $symbolVariable->getName()) {
                $symbolVariable = $context->symbolTable->getTempVariableForWrite('variable', $context);
            } else {
                $symbolVariable->initVariant($context);
            }
            $symbol = $context->backend->getVariableCode($symbolVariable);
            $context->codePrinter->output('zephir_var_export_ex('.$symbol.', '.$variableSymbol.' TSRMLS_CC);');

            return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
        }

        $context->codePrinter->output('zephir_var_export('.$variableSymbol.' TSRMLS_CC);');

        return new CompiledExpression('null', 'null', $expression);
    }
747597
public function compile(array $expression, CompilationContext $compilationContext)
    {
        $compiler = &$compilationContext->compiler;
        $className = $expression['left']['value'];
        $constant = $expression['right']['value'];

        /*
         * Fetch the class definition according to the class where the constant
         * is supposed to be declared
         */
        if (!\in_array($className, ['this', 'self', 'static', 'parent'])) {
            $className = $compilationContext->getFullName($className);
            if ($compiler->isClass($className) || $compiler->isInterface($className)) {
                $classDefinition = $compiler->getClassDefinition($className);
            } else {
                if ($compiler->isBundledClass($className) || $compiler->isBundledInterface($className)) {
                    $classDefinition = $compiler->getInternalClassDefinition($className);
                } else {
                    throw new CompilerException("Cannot locate class '".$className."'", $expression['left']);
                }
            }
        } else {
            if (\in_array($className, ['self', 'static', 'this'])) {
                $classDefinition = $compilationContext->classDefinition;
            } else {
                if ('parent' == $className) {
                    $classDefinition = $compilationContext->classDefinition;
                    $extendsClass = $classDefinition->getExtendsClass();
                    if (!$extendsClass) {
                        throw new CompilerException(
                            sprintf(
                                'Cannot find constant called "%s" on parent because class %s does not extend any class',
                                $constant,
                                $classDefinition->getCompleteName()
                            ),
                            $expression
                        );
                    } else {
                        $classDefinition = $classDefinition->getExtendsClassDefinition();
                    }
                }
            }
        }

        /*
         * Constants are resolved to their values at compile time
         * so we need to check that they effectively do exist
         */
        if (!$classDefinition->hasConstant($constant)) {
            throw new CompilerException(
                sprintf(
                    "Class '%s' does not have a constant called: '%s'",
                    $classDefinition->getCompleteName(),
                    $constant
                ),
                $expression
            );
        }

        /*
         * We can optimize the reading of constants by avoiding query their value every time
         */
        if (!$compilationContext->config->get('static-constant-class-folding', 'optimizations')) {
            /*
             * Resolves the symbol that expects the value
             */
            if ($this->expecting) {
                if ($this->expectingVariable) {
                    $symbolVariable = $this->expectingVariable;
                    $symbolVariable->initVariant($compilationContext);
                } else {
                    $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite(
                        'variable',
                        $compilationContext,
                        $expression
                    );
                }
            } else {
                $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite(
                    'variable',
                    $compilationContext,
                    $expression
                );
            }

            /*
             * Variable that receives property accesses must be polymorphic
             */
            if (!$symbolVariable->isVariable()) {
                throw new CompilerException(
                    'Cannot use variable: '.$symbolVariable->getType().' to assign class constants',
                    $expression
                );
            }

            $symbolVariable->setDynamicTypes('undefined');

            $compilationContext->headersManager->add('kernel/object');

            $compilationContext->codePrinter->output(
                sprintf(
                    'zephir_get_class_constant(%s, %s, SS("%s") TSRMLS_CC);',
                    $symbolVariable->getName(),
                    $classDefinition->getClassEntry($compilationContext),
                    $constant
                )
            );

            return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
        }

        $constantDefinition = $classDefinition->getConstant($constant);

        if ($constantDefinition instanceof ClassConstant) {
            $constantDefinition->processValue($compilationContext);
            $value = $constantDefinition->getValueValue();
            $type = $constantDefinition->getValueType();
        } else {
            $value = $constantDefinition;
            $type = \gettype($value);
            if ('integer' == $type) {
                $type = 'int';
            }
        }

        switch ($type) {
            case 'string':
            case 'int':
            case 'double':
            case 'float':
            case 'bool':
            case 'null':
                break;
            default:
                $compilationContext->logger->warning(
                    "Constant '".$constantDefinition->getName()."' does not exist at compile time",
                    ['nonexistent-constant', $expression]
                );

                return new CompiledExpression('null', null, $expression);
        }

        /*
         * Return the value as a literal expression
         */
        return new CompiledExpression($type, $value, $expression);
    }
956602
function create(context) {
    return {
        CallExpression(node) {
            if (isRequireCall(node) && ancestor(isConditional, node)) {
                context.report(node, message);
            }
        }
    };
}
599009
public function evaluate(array $values, Context $context, Token $token)
    {
        if (count($values) !== $this->getOperands()) {
            throw new ExpressionException('Invalid number of operands for operator.',
              $this, $values);
        }
        $evaluator = $this->evaluator;
        return (string)$evaluator($values, $context, $token);
    }
746992
public function optimize(array $expression, Call $call, CompilationContext $context)
    {
        if (!isset($expression['parameters']) || 2 != \count($expression['parameters'])) {
            throw new CompilerException("'hash_equals' requires two parameters", $expression);
        }

        /*
         * Process the expected symbol to be returned
         */
        $call->processExpectedReturn($context);

        $symbolVariable = $call->getSymbolVariable(true, $context);
        if ($symbolVariable->isNotVariableAndString()) {
            throw new CompilerException('Returned values by functions can only be assigned to variant variables', $expression);
        }

        $context->headersManager->add('kernel/string');

        /**
         * Process parameters.
         */
        $resolvedParams = $call->getReadOnlyResolvedParams($expression['parameters'], $context, $expression);

        if ($call->mustInitSymbolVariable()) {
            $symbolVariable->initVariant($context);
        }

        return new CompiledExpression('bool', 'zephir_hash_equals('.$resolvedParams[0].', '.$resolvedParams[1].')', $expression);
    }
420159
public function optimize(array $expression, Call $call, CompilationContext $context)
    {
        if (isset($expression['parameters']) && \count($expression['parameters']) > 1) {
            return false;
        }

        $context->headersManager->add('kernel/exit');
        if (isset($expression['parameters'])) {
            //TODO: protect resolvedParams[0] from restore
        }
        if (!isset($expression['parameters'])) {
            $context->codePrinter->output('ZEPHIR_MM_RESTORE();');
            $context->codePrinter->output('zephir_exit_empty();');
        } else {
            $resolvedParams = $call->getReadOnlyResolvedParams($expression['parameters'], $context, $expression);
            $context->codePrinter->output('ZEPHIR_MM_RESTORE();');
            $context->codePrinter->output('zephir_exit('.$resolvedParams[0].');');
        }

        return new CompiledExpression('void ', '', $expression);
    }
1198764
public function optimizeNot($expr, CompilationContext $compilationContext)
    {
        /*
         * Compile the expression negating the evaluated expression
         */
        if ('not' == $expr['type']) {
            $conditions = $this->optimize($expr['left'], $compilationContext);
            if (false !== $conditions) {
                if (null !== $this->unreachable) {
                    $this->unreachable = !$this->unreachable;
                }
                if (null !== $this->unreachableElse) {
                    $this->unreachableElse = !$this->unreachableElse;
                }

                return '!('.$conditions.')';
            }
        }

        return false;
    }
1109979
public function compile(array $expression, CompilationContext $compilationContext)
    {
        $expr = new Expression($expression['left']);
        $expr->setReadOnly(true);
        $expr->setExpectReturn(true);

        $exprPath = $expr->compile($compilationContext);
        if ('variable' == $exprPath->getType()) {
            $exprVariable = $compilationContext->symbolTable->getVariableForRead($exprPath->getCode(), $compilationContext, $expression);
            $exprVar = $compilationContext->backend->getVariableCode($exprVariable);
            if ('variable' == $exprVariable->getType()) {
                if ($exprVariable->hasDifferentDynamicType(['undefined', 'string'])) {
                    $compilationContext->logger->warning(
                        'Possible attempt to use invalid type as path in "require" operator',
                        ['non-valid-require', $expression]
                    );
                }
            }
        } else {
            $exprVar = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $expression);
            $compilationContext->backend->assignString($exprVar, $exprPath->getCode(), $compilationContext);
            $exprVar = $compilationContext->backend->getVariableCode($exprVar);
        }

        $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().');');
            $symbol = $compilationContext->backend->getVariableCodePointer($symbolVariable);
            $codePrinter->output('if (zephir_require_zval_ret('.$symbol.', '.$exprVar.' TSRMLS_CC) == FAILURE) {');
        } else {
            $codePrinter->output('if (zephir_require_zval('.$exprVar.' 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);
    }
354597
public function compile($expression, CompilationContext $compilationContext)
    {
        if (!isset($expression['left'])) {
            throw new \Exception('Missing left part of the expression');
        }

        if (!isset($expression['right'])) {
            throw new \Exception('Missing right part of the expression');
        }

        $leftExpr = new Expression($expression['left']);
        $leftExpr->setReadOnly(true);
        $left = $leftExpr->compile($compilationContext);

        $rightExpr = new Expression($expression['right']);
        $rightExpr->setReadOnly(true);
        $right = $rightExpr->compile($compilationContext);

        $compilationContext->headersManager->add('kernel/operators');

        switch ($left->getType()) {
            case 'int':
            case 'uint':
            case 'long':
            case 'ulong':
                switch ($right->getType()) {
                    case 'int':
                    case 'uint':
                    case 'long':
                    case 'ulong':
                        return new CompiledExpression('double', 'zephir_safe_div_long_long('.$left->getCode().', '.$right->getCode().' TSRMLS_CC)', $expression);

                    case 'double':
                        return new CompiledExpression('double', 'zephir_safe_div_long_double((double) '.$left->getCode().', '.$right->getCode().' TSRMLS_CC)', $expression);

                    case 'bool':
                        return new CompiledExpression('bool', '('.$left->getCode().' - '.$right->getBooleanCode().')', $expression);

                    case 'variable':
                        $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression);
                        switch ($variableRight->getType()) {
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                            case 'bool':
                                return new CompiledExpression('double', 'zephir_safe_div_long_long('.$left->getCode().', '.$variableRight->getName().' TSRMLS_CC)', $expression);

                            case 'double':
                                return new CompiledExpression('double', 'zephir_safe_div_long_double('.$left->getCode().', '.$variableRight->getName().' TSRMLS_CC)', $expression);

                            case 'variable':
                                $variableRightCode = $compilationContext->backend->getVariableCode($variableRight);

                                return new CompiledExpression('double', 'zephir_safe_div_long_zval('.$left->getCode().', '.$variableRightCode.' TSRMLS_CC)', $expression);

                            default:
                                throw new CompilerException("Cannot operate variable('int') with variable('".$variableRight->getType()."')", $expression);
                        }
                        break;

                    default:
                        throw new CompilerException("Cannot operate 'int' with '".$right->getType()."'", $expression);
                }
                break;

            case 'bool':
                switch ($right->getType()) {
                    case 'int':
                    case 'uint':
                    case 'long':
                    case 'ulong':
                    case 'double':
                        return new CompiledExpression('long', '('.$left->getBooleanCode().' - '.$right->getCode().')', $expression);

                    case 'bool':
                        return new CompiledExpression('bool', '('.$left->getBooleanCode().' '.$this->bitOperator.' '.$right->getBooleanCode().')', $expression);

                    default:
                        throw new CompilerException("Cannot operate 'bool' with '".$right->getType()."'", $expression);
                }
                break;

            case 'double':
                switch ($right->getType()) {
                    case 'int':
                    case 'uint':
                    case 'long':
                    case 'ulong':
                        return new CompiledExpression('double', 'zephir_safe_div_double_long('.$left->getCode().', (double) ('.$right->getCode().') TSRMLS_CC)', $expression);

                    case 'double':
                        return new CompiledExpression('double', 'zephir_safe_div_double_long('.$left->getCode().', '.$right->getCode().' TSRMLS_CC)', $expression);

                    case 'bool':
                        return new CompiledExpression('double', 'zephir_safe_div_double_long('.$left->getCode().', '.$right->getBooleanCode().' TSRMLS_CC)', $expression);

                    case 'variable':
                        $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression);
                        switch ($variableRight->getType()) {
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                            case 'bool':
                                return new CompiledExpression('double', 'zephir_safe_div_double_long('.$left->getCode().', '.$variableRight->getName().' TSRMLS_CC)', $expression);

                            case 'double':
                                return new CompiledExpression('double', 'zephir_safe_div_double_double('.$left->getCode().', '.$variableRight->getName().' TSRMLS_CC)', $expression);

                            case 'variable':
                                $symbolRight = $compilationContext->backend->getVariableCode($variableRight);

                                return new CompiledExpression('double', 'zephir_safe_div_double_zval('.$left->getCode().', '.$symbolRight.' TSRMLS_CC)', $expression);
                                break;

                            default:
                                throw new CompilerException("Cannot operate variable('double') with variable('".$variableRight->getType()."')", $expression);
                        }
                        break;

                    default:
                        throw new CompilerException("Cannot operate 'double' with '".$right->getType()."'", $expression);
                }
                break;

            case 'string':
            case 'array':
                switch ($right->getType()) {
                    default:
                        throw new CompilerException('Operation is not supported between '.$right->getType(), $expression);
                }
                break;

            case 'variable':
                $variableLeft = $compilationContext->symbolTable->getVariableForRead($left->resolve(null, $compilationContext), $compilationContext, $expression);
                switch ($variableLeft->getType()) {
                    case 'int':
                    case 'uint':
                    case 'long':
                    case 'ulong':
                        switch ($right->getType()) {
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                                return new CompiledExpression('double', 'zephir_safe_div_long_long('.$left->getCode().', '.$right->getCode().' TSRMLS_CC)', $expression);

                            case 'double':
                                return new CompiledExpression('double', 'zephir_safe_div_long_double('.$left->getCode().', '.$right->getCode().' TSRMLS_CC)', $expression);

                            case 'variable':
                                $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['right']);
                                switch ($variableRight->getType()) {
                                    case 'int':
                                    case 'uint':
                                    case 'long':
                                    case 'ulong':
                                    case 'bool':
                                        return new CompiledExpression('double', 'zephir_safe_div_long_long('.$variableLeft->getName().', '.$variableRight->getName().' TSRMLS_CC)', $expression);

                                    case 'double':
                                        return new CompiledExpression('double', 'zephir_safe_div_long_double('.$variableLeft->getName().', '.$variableRight->getName().' TSRMLS_CC)', $expression);

                                    case 'variable':
                                        $compilationContext->headersManager->add('kernel/operators');
                                        if ($variableRight->isLocalOnly()) {
                                            return new CompiledExpression('double', 'zephir_safe_div_long_zval('.$variableLeft->getName().', &'.$variableRight->getName().' TSRMLS_CC)', $expression);
                                        } else {
                                            $variableRightCode = $compilationContext->backend->getVariableCode($variableRight);

                                            return new CompiledExpression('double', 'zephir_safe_div_long_zval('.$variableLeft->getName().', '.$variableRightCode.' TSRMLS_CC)', $expression);
                                        }
                                        break;

                                    default:
                                        throw new CompilerException("Cannot operate variable('int') with variable('".$variableRight->getType()."')", $expression);
                                }
                                break;

                            default:
                                throw new CompilerException("Cannot operate variable('int') with '".$right->getType()."'", $expression);
                        }
                        break;

                    case 'bool':
                        switch ($right->getType()) {
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                                return new CompiledExpression('bool', '('.$left->getCode().', '.$right->getCode().')', $expression);

                            case 'bool':
                                return new CompiledExpression('bool', '('.$left->getCode().' '.$this->bitOperator.' '.$right->getBooleanCode().')', $expression);

                            case 'variable':
                                $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['right']);
                                switch ($variableRight->getType()) {
                                    case 'int':
                                    case 'uint':
                                    case 'long':
                                    case 'ulong':
                                        return new CompiledExpression('double', 'zephir_safe_div_long_long('.$variableLeft->getName().', '.$variableRight->getName().' TSRMLS_CC)', $expression);

                                    case 'double':
                                        return new CompiledExpression('double', 'zephir_safe_div_long_double('.$variableLeft->getName().', '.$variableRight->getName().' TSRMLS_CC)', $expression);

                                    case 'bool':
                                        return new CompiledExpression('double', 'zephir_safe_div_long_long('.$variableLeft->getName().' '.$this->bitOperator.' '.$variableRight->getName().' TSRMLS_CC)', $expression);

                                    case 'variable':
                                        $compilationContext->headersManager->add('kernel/operators');
                                        if ($variableRight->isLocalOnly()) {
                                            return new CompiledExpression('double', 'zephir_safe_div_long_zval('.$variableLeft->getName().', &'.$variableRight->getName().' TSRMLS_CC)', $expression);
                                        } else {
                                            $variableRightCode = $compilationContext->backend->getVariableCode($variableRight);

                                            return new CompiledExpression('double', 'zephir_safe_div_long_zval('.$variableLeft->getName().', '.$variableRightCode.' TSRMLS_CC)', $expression);
                                        }
                                        break;

                                    default:
                                        throw new CompilerException("Cannot operate variable('int') with variable('".$variableRight->getType()."')", $expression);
                                }
                                break;

                            default:
                                throw new CompilerException("Cannot operate variable('int') with '".$right->getType()."'", $expression);
                        }
                        break;

                    case 'double':
                        switch ($right->getType()) {
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                            case 'double':
                                return new CompiledExpression('double', 'zephir_safe_div_double_long('.$left->getCode().', '.$right->getCode().' TSRMLS_CC)', $expression);

                            case 'bool':
                                return new CompiledExpression('bool', '('.$left->getCode().' '.$this->bitOperator.' '.$right->getBooleanCode().')', $expression);

                            case 'variable':
                                $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['right']);
                                switch ($variableRight->getType()) {
                                    case 'int':
                                    case 'uint':
                                    case 'long':
                                    case 'ulong':
                                        return new CompiledExpression('double', 'zephir_safe_div_double_long('.$variableLeft->getName().',  (double) '.$variableRight->getName().' TSRMLS_CC)', $expression);

                                    case 'double':
                                        return new CompiledExpression('double', 'zephir_safe_div_double_long('.$variableLeft->getName().', '.$variableRight->getName().' TSRMLS_CC)', $expression);

                                    case 'bool':
                                        return new CompiledExpression('bool', '('.$variableLeft->getName().' '.$this->bitOperator.' '.$variableRight->getName().')', $expression);

                                    case 'variable':
                                        $compilationContext->headersManager->add('kernel/operators');
                                        $symbolRight = $compilationContext->backend->getVariableCode($variableRight);

                                        return new CompiledExpression('double', 'zephir_safe_div_double_zval('.$variableLeft->getName().', '.$symbolRight.' TSRMLS_CC)', $expression);

                                    default:
                                        throw new CompilerException("Cannot operate variable('double') with variable('".$variableRight->getType()."')", $expression);
                                }
                                break;

                            default:
                                throw new CompilerException("Cannot operate variable('int') with '".$right->getType()."'", $expression);
                        }
                        break;

                    case 'string':
                        throw new CompilerException("Cannot operate string variables'", $expression);
                    case 'array':
                        throw new CompilerException("Cannot operate array variables'", $expression);
                    case 'variable':
                        $op1 = $compilationContext->backend->getVariableCode($variableLeft);
                        switch ($right->getType()) {
                            /* a + 1 */
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                                $op2 = $right->getCode();

                                return new CompiledExpression('double', 'zephir_safe_div_zval_long('.$op1.', '.$op2.' TSRMLS_CC)', $expression);

                            case 'double':
                                $op2 = $right->getCode();

                                return new CompiledExpression('double', 'zephir_safe_div_zval_double('.$op1.', '.$op2.' TSRMLS_CC)', $expression);

                            /* a(var) + a(x) */
                            case 'variable':
                                $variableRight = $compilationContext->symbolTable->getVariableForRead($right->resolve(null, $compilationContext), $compilationContext, $expression);
                                switch ($variableRight->getType()) {
                                    /* a(var) + a(int) */
                                    case 'int':
                                    case 'uint':
                                    case 'long':
                                    case 'ulong':
                                        return new CompiledExpression('double', 'zephir_safe_div_zval_long('.$op1.', '.$variableRight->getName().' TSRMLS_CC)', $expression);

                                    case 'double':
                                        return new CompiledExpression('double', 'zephir_safe_div_zval_double('.$op1.', '.$variableRight->getName().' TSRMLS_CC)', $expression);

                                    /* a(var) + a(bool) */
                                    case 'bool':
                                        return new CompiledExpression('int', 'zephir_safe_div_zval_long('.$op1.', '.$variableRight->getName().' TSRMLS_CC)', $expression);

                                    /* a(var) + a(var) */
                                    case 'variable':
                                        $op2 = $compilationContext->backend->getVariableCode($variableRight);

                                        $expected = $this->getExpected($compilationContext, $expression);
                                        $expectedCode = $compilationContext->backend->getVariableCode($expected);
                                        $compilationContext->codePrinter->output($this->zvalOperator.'('.$expectedCode.', '.$op1.', '.$op2.' TSRMLS_CC);');

                                        if ($variableLeft->isTemporal()) {
                                            $variableLeft->setIdle(true);
                                        }
                                        if ($variableRight->isTemporal()) {
                                            $variableRight->setIdle(true);
                                        }

                                        return new CompiledExpression('variable', $expected->getName(), $expression);

                                    default:
                                        throw new CompilerException("Cannot operate 'variable' with variable ('".$variableRight->getType()."')", $expression);
                                }
                                break;

                            default:
                                throw new CompilerException("Cannot operate 'variable' with '".$right->getType()."'", $expression);
                        }
                        break;

                    case 'variable':
                        $op1 = $compilationContext->backend->getVariableCode($variableLeft);
                        switch ($right->getType()) {
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                                $op2 = $right->getCode();

                                return new CompiledExpression('double', 'zephir_safe_div_zval_long('.$op1.', '.$op2.' TSRMLS_CC)', $expression);

                            case 'double':
                                $op2 = $right->getCode();

                                return new CompiledExpression('double', 'zephir_safe_div_zval_double('.$op1.', '.$op2.' TSRMLS_CC)', $expression);

                            case 'variable':
                                $variableRight = $compilationContext->symbolTable->getVariableForRead($right->resolve(null, $compilationContext), $compilationContext, $expression);
                                switch ($variableRight->getType()) {
                                    case 'int':
                                    case 'uint':
                                    case 'long':
                                    case 'ulong':
                                    case 'bool':
                                        return new CompiledExpression('double', 'zephir_safe_div_zval_long('.$op1.', '.$variableRight->getName().' TSRMLS_CC)', $expression);

                                    case 'double':
                                        return new CompiledExpression('double', 'zephir_safe_div_zval_double('.$op1.', '.$variableRight->getName().' TSRMLS_CC)', $expression);

                                    case 'variable':
                                        $variableRight = $compilationContext->symbolTable->getVariableForRead($variableRight->getCode(), $compilationContext, $expression);
                                        $op2 = $compilationContext->backend->getVariableCode($variableRight);
                                        switch ($variableRight->getType()) {
                                            case 'int':
                                                return new CompiledExpression('double', 'zephir_safe_div_zval_long('.$variableLeft->getName().', '.$variableRight->getName().' TSRMLS_CC)', $expression);

                                            case 'double':
                                                return new CompiledExpression('double', 'zephir_safe_div_zval_double('.$variableLeft->getName().', '.$variableRight->getName().' TSRMLS_CC)', $expression);

                                            case 'bool':
                                                return new CompiledExpression('bool', $variableLeft->getName().' '.$this->bitOperator.' '.$variableRight->getName(), $expression);

                                            case 'variable':
                                                $expected = $this->getExpected($compilationContext, $expression);
                                                $expectedCode = $compilationContext->backend->getVariableCode($expected);
                                                $compilationContext->codePrinter->output($this->zvalOperator.'('.$expectedCode.', '.$op1.', '.$op2.');');

                                                return new CompiledExpression('variable', $expected->getName(), $expression);

                                            default:
                                                throw new CompilerException("Cannot operate variable('double') with variable('".$variableRight->getType()."')", $expression);
                                        }
                                        break;

                                    default:
                                        throw new CompilerException("Cannot operate 'variable' with variable ('".$variableRight->getType()."')", $expression);
                                }
                                break;

                            default:
                                throw new CompilerException("Cannot operate 'variable' with '".$right->getType()."'", $expression);
                        }
                        break;

                    default:
                        throw new CompilerException("Unknown '".$variableLeft->getType()."'", $expression);
                }
                break;

            default:
                throw new CompilerException('Unsupported type: '.$left->getType(), $expression);
        }
    }