Compiles the arithmetical division operation.

@param array              $expression
@param CompilationContext $compilationContext
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);
        }
    }
839566
public function compile(array $expression, CompilationContext $compilationContext)
    {
        $expr = new Expression($expression['right']);
        $expr->setReadOnly(true);
        $resolved = $expr->compile($compilationContext);

        if ('variable' != $resolved->getType()) {
            throw new CompilerException('Type-Hints only can be applied to dynamic variables.', $expression);
        }

        $symbolVariable = $compilationContext->symbolTable->getVariableForRead(
            $resolved->getCode(),
            $compilationContext,
            $expression
        );

        if (!$symbolVariable->isVariable()) {
            throw new CompilerException('Type-Hints only can be applied to dynamic variables.', $expression);
        }

        $symbolVariable->setDynamicTypes('object');
        $symbolVariable->setClassTypes($compilationContext->getFullName($expression['left']['value']));

        return $resolved;
    }
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;
    }
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);
    }
992875
public function optimize(array $expression, Call $call, CompilationContext $context)
    {
        if (!isset($expression['parameters']) || 1 != \count($expression['parameters'])) {
            throw new CompilerException(
                sprintf(
                    'func_get_arg() expects at exactly 1 parameter, %d given',
                    isset($expression['parameters']) ? \count($expression['parameters']) : 0
                ),
                $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
            );
        }

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

        $symbol = $context->backend->getVariableCode($symbolVariable);

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

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

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

            if ($context->backend->isZE3()) {
                $template = 'zephir_get_arg(%s, zephir_get_intval(%s));';
            } else {
                $template = 'zephir_get_arg(%s, zephir_get_intval(%s) TSRMLS_CC);';
            }

            $context->codePrinter->output(sprintf($template, $symbol, $resolvedParams[0]));

            return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
        } catch (Exception $e) {
            throw new CompilerException($e->getMessage(), $expression, $e->getCode(), $e);
        }
    }
1004803
public function optimize(array $expression, Call $call, CompilationContext $context)
    {
        if (!isset($expression['parameters'])) {
            return false;
        }

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

        if (1 == \count($expression['parameters'])) {
            return new CompiledExpression('bool', 'false', $expression);
        }

        return false;
    }
466183
public function compile(CompilationContext $compilationContext)
    {
        foreach ($this->statement['expressions'] as $echoExpr) {
            $expr = new Expression($echoExpr);
            $expr->setReadOnly(true);
            $resolvedExpr = $expr->compile($compilationContext);

            switch ($resolvedExpr->getType()) {
                case 'int':
                    $compilationContext->codePrinter->output('php_printf("%d", '.$resolvedExpr->getCode().');');
                    break;

                case 'bool':
                    $compilationContext->codePrinter->output('php_printf("%s", '.$resolvedExpr->getBooleanCode().' ? "1": "");');
                    break;

                case 'double':
                    $compilationContext->codePrinter->output('php_printf("%f", '.$resolvedExpr->getCode().');');
                    break;

                case 'char':
                case 'uchar':
                    $compilationContext->codePrinter->output('php_printf("%c", \''.$resolvedExpr->getCode().'\');');
                    break;

                case 'long':
                    $compilationContext->codePrinter->output('php_printf("%ld", '.$resolvedExpr->getCode().');');
                    break;

                case 'string':
                    $compilationContext->codePrinter->output(
                        'php_printf("%s", "'.add_slashes($resolvedExpr->getCode()).'");'
                    );
                    break;

                case 'null':
                    break;

                case 'variable':
                    $variable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $echoExpr);
                    switch ($variable->getType()) {
                        case 'int':
                            $compilationContext->codePrinter->output('php_printf("%d", '.$variable->getName().');');
                            break;

                        case 'long':
                            $compilationContext->codePrinter->output('php_printf("%ld", '.$variable->getName().');');
                            break;

                        case 'double':
                            $compilationContext->codePrinter->output('php_printf("%f", '.$variable->getName().');');
                            break;

                        case 'uchar':
                        case 'char':
                            $compilationContext->codePrinter->output('php_printf("%c", '.$variable->getName().');');
                            break;

                        case 'bool':
                            $compilationContext->codePrinter->output('php_printf("%s", '.$variable->getName().' ? "1": "");');
                            break;

                        case 'string':
                        case 'variable':
                            $compilationContext->codePrinter->output('zend_print_zval('.$compilationContext->backend->getVariableCode($variable).', 0);');
                            break;

                        case 'null':
                            break;

                        default:
                            throw new CompilerException('Unknown type: '.$variable->getType(), $echoExpr);
                    }
                    break;

                default:
                    throw new CompilerException('Unknown type: '.$resolvedExpr->getType(), $echoExpr);
            }
        }
    }
387352
protected function compileEchoStack($expression)
    {
        foreach (['RawEcho', 'Echo'] as $token) {
            $out = $this->{'compile'.$token}($expression);

            if (strlen($out) !== 0) {
                $expression = $out;
            }
        }

        return $expression;
    }
459055
public function compile(array $expression, CompilationContext $compilationContext)
    {
        if ('list' == $expression['left']['type']) {
            $left = $expression['left']['left'];
        } else {
            $left = $expression['left'];
        }

        switch ($left['type']) {
            case 'array-access':
                $compilationContext->headersManager->add('kernel/array');

                $exprVariable = new Expression($left['left']);
                $exprVariable->setReadOnly(true);
                $exprVariable->setNoisy(false);

                $exprCompiledVariable = $exprVariable->compile($compilationContext);
                if ('variable' != $exprCompiledVariable->getType() && 'array' != $exprCompiledVariable->getType()) {
                    throw new CompilerException('Expression type: '.$exprCompiledVariable->getType().' cannot be used as array', $left['left']);
                }

                $variable = $compilationContext->symbolTable->getVariableForRead($exprCompiledVariable->getCode(), $compilationContext, $left['left']);
                switch ($variable->getType()) {
                    case 'array':
                    case 'variable':
                        break;

                    default:
                        throw new CompilerException('Variable type: '.$variable->getType().' cannot be used as array', $left['left']);
                        break;
                }

                if ('variable' == $variable->getType()) {
                    if ($variable->hasDifferentDynamicType(['undefined', 'array', 'null'])) {
                        $compilationContext->logger->warning(
                            'Possible attempt to use non array in isset operator',
                            ['non-valid-isset', $expression]
                        );
                    }
                }

                $expr = new Expression($left['right']);
                $expr->setReadOnly(true);
                $expr->setNoisy(false);
                $resolvedExpr = $expr->compile($compilationContext);

                switch ($resolvedExpr->getType()) {
                    case 'int':
                    case 'long':
                    case 'string':
                        return $compilationContext->backend->arrayIsset($variable, $resolvedExpr, $left['right'], $compilationContext);

                    case 'variable':
                        $indexVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $left['right']);

                        return $compilationContext->backend->arrayIsset($variable, $indexVariable, $left['right'], $compilationContext);
                        break;

                    default:
                        throw new CompilerException('['.$left['right']['type'].']', $expression);
                }
                break;

            case 'property-access':
            case 'property-dynamic-access':
                $compilationContext->headersManager->add('kernel/object');

                $exprVariable = new Expression($left['left']);
                $exprVariable->setReadOnly(true);

                $exprCompiledVariable = $exprVariable->compile($compilationContext);
                if ('variable' != $exprCompiledVariable->getType()) {
                    throw new CompilerException('Expression type: '.$exprCompiledVariable->getType().' cannot be used as object', $left['left']);
                }

                $variable = $compilationContext->symbolTable->getVariableForRead($exprCompiledVariable->getCode(), $compilationContext, $left['left']);
                if ('variable' != $variable->getType()) {
                    throw new CompilerException('Variable type: '.$variable->getType().' cannot be used as object', $left['left']);
                }

                if ($variable->hasDifferentDynamicType(['undefined', 'object', 'null'])) {
                    $compilationContext->logger->warning(
                        'Possible attempt to use non object in isset operator',
                        ['non-valid-isset', $expression]
                    );
                }
                $variableCode = $compilationContext->backend->getVariableCode($variable);

                if ('property-access' == $left['type']) {
                    return $compilationContext->backend->propertyIsset($variable, $left['right']['value'], $compilationContext);
                }

                $expr = new Expression($left['right']);
                $expr->setReadOnly(true);
                $expr->setNoisy(false);
                $resolvedExpr = $expr->compile($compilationContext);

                switch ($resolvedExpr->getType()) {
                    case 'variable':
                        $indexVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $left['right']);
                        switch ($indexVariable->getType()) {
                            case 'variable':
                            case 'string':
                                $indexVariableCode = $compilationContext->backend->getVariableCode($indexVariable);

                                return new CompiledExpression('bool', 'zephir_isset_property_zval('.$variableCode.', '.$indexVariableCode.' TSRMLS_CC)', $left['right']);

                            default:
                                throw new CompilerException('['.$indexVariable->getType().']', $expression);
                        }
                        break;

                    default:
                        throw new CompilerException('['.$expression['left']['right']['type'].']', $expression);
                }
                break;

            case 'property-string-access':
                return new CompiledExpression('bool', '(0 == 0)', $left);

            case 'static-property-access':
                return new CompiledExpression('bool', '(0 == 0)', $left);

            default:
                throw new CompilerException('This expression is not valid for "isset" operator', $expression);
        }
    }
1132176
public function optimize(array $expression, Call $call, CompilationContext $context)
    {
        if (!isset($expression['parameters']) || 1 != \count($expression['parameters'])) {
            return false;
        }

        if ('string' == $expression['parameters'][0]['parameter']['type']) {
            $str = add_slashes($expression['parameters'][0]['parameter']['value']);
            unset($expression['parameters'][0]);
        }

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

        $resolvedParams = $call->getReadOnlyResolvedParams($expression['parameters'], $context, $expression);
        if (isset($str)) {
            /* TODO: Solve this macro stuff better, move to backend */
            $macro = $context->backend->isZE3() ? 'SL' : 'SS';

            return new CompiledExpression('bool', '(zephir_function_exists_ex('.$macro.'("'.strtolower($str).'") TSRMLS_CC) == SUCCESS)', $expression);
        }

        return new CompiledExpression('bool', '(zephir_function_exists('.$resolvedParams[0].' TSRMLS_CC)  == SUCCESS)', $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);
    }
146485
public function optimize(array $expression, Call $call, CompilationContext $context)
    {
        if (!isset($expression['parameters'])) {
            throw new CompilerException('This function requires parameters', $expression);
        }

        if (1 != \count($expression['parameters'])) {
            throw new CompilerException('This function only requires one parameter', $expression);
        }

        $variableType = $expression['parameters'][0]['parameter']['type'];

        if (!isset($this->allowedTypes[$variableType])) {
            throw new CompilerException("This function requires a scalar types parameter, $variableType given", $expression);
        }

        preg_match('/^(?<major>\d+)(?:\.(?<minor>!?\d+))?(?:\.(?<patch>!?\d+))?(?:[^Ee0-9.]+.*)?$/', $expression['parameters'][0]['parameter']['value'], $matches);
        if (!\count($matches)) {
            throw new CompilerException('Could not parse PHP version', $expression);
        }

        $minorVersion = 0;
        $releaseVersion = 0;

        $majorVersion = $matches['major'] * 10000;

        if (isset($matches['minor'])) {
            $minorVersion = $matches['minor'] * 100;
        }

        if (isset($matches['patch'])) {
            $releaseVersion = $matches['patch'];
        }

        $versionId = (int) ($majorVersion + $minorVersion + $releaseVersion);

        return new CompiledExpression('bool', 'zephir_is_php_version('.$versionId.')', $expression);
    }
527195
public function compile($expression, CompilationContext $compilationContext)
    {
        if (!isset($expression['left'])) {
            throw new CompilerException('Missing left part of the expression', $expression);
        }

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

        /**
         * Check for constant folding optimizations.
         */
        $optimized = $this->optimizeConstantFolding($expression, $compilationContext);
        if ($optimized) {
            return $optimized;
        }

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

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

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

                    case 'double':
                        return new CompiledExpression('int', '('.$left->getCode().' '.$this->operator.' (int) ('.$right->getCode().'))', $expression);

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

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

                            case 'bool':
                                return new CompiledExpression('int', '('.$left->getCode().' '.$this->operator.' '.$variableRight->getName().')', $expression);

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

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

                                return new CompiledExpression('int', '('.$left->getCode().' '.$this->operator.' zephir_get_numberval('.$symbol.'))', $expression);
                                break;

                            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('int', '('.$left->getBooleanCode().' '.$this->bitOperator.'(('.$right->getCode().') ? 1 : 0))', $expression);

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

                    case 'variable':
                        $variableRight = $compilationContext->symbolTable->getVariableForRead($expression['right']['value'], $compilationContext, $expression);
                        switch ($variableRight->getType()) {
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                                return new CompiledExpression('int', '((int) ('.$left->getBooleanCode().') '.$this->operator.' '.$variableRight->getName().')', $expression);

                            case 'bool':
                                return new CompiledExpression('int', '((int) ('.$left->getBooleanCode().') '.$this->operator.' '.$variableRight->getName().')', $expression);

                            case 'double':
                                return new CompiledExpression('int', '((int) ('.$left->getBooleanCode().') '.$this->operator.' (int) ('.$variableRight->getName().'))', $expression);

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

                                return new CompiledExpression('int', '((int) ('.$left->getBooleanCode().') '.$this->operator.' zephir_get_numberval('.$symbol.'))', $expression);
                                break;

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

                    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('int', '((int) ('.$left->getCode().') '.$this->operator.' '.$right->getCode().')', $expression);

                    case 'double':
                        return new CompiledExpression('int', '((int) ('.$left->getCode().') '.$this->operator.' (int) ('.$right->getCode().'))', $expression);

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

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

                            case 'bool':
                                return new CompiledExpression('int', '((int) ('.$left->getCode().') '.$this->operator.' '.$variableRight->getName().')', $expression);

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

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

                                return new CompiledExpression('int', '((int) ('.$left->getCode().') '.$this->operator.' zephir_get_numberval('.$symbol.'))', $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':
                switch ($right->getType()) {
                    default:
                        throw new CompilerException('Operation is not supported between strings', $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':
                    case 'char':
                    case 'uchar':
                        switch ($right->getType()) {
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                            case 'double':
                            case 'char':
                            case 'uchar':
                                return new CompiledExpression('int', '('.$left->getCode().' '.$this->operator.' '.$right->getCode().')', $expression);

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

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

                                    case 'double':
                                        return new CompiledExpression('int', '('.$variableLeft->getName().' '.$this->operator.' (int) ('.$variableRight->getName().'))', $expression);

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

                                        return new CompiledExpression('int', '('.$variableLeft->getName().' '.$this->operator.' (int) (zephir_get_numberval('.$symbol.')))', $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('int', '('.$left->getCode().' '.$this->operator.' '.$right->getCode().')', $expression);

                            case 'bool':
                                return new CompiledExpression('int', '('.$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('int', '('.$variableLeft->getName().' '.$this->operator.' '.$variableRight->getName().')', $expression);

                                    case 'double':
                                        return new CompiledExpression('int', '('.$variableLeft->getName().' '.$this->operator.' (int) ('.$variableRight->getName().'))', $expression);

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

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

                                        return new CompiledExpression('int', '('.$variableLeft->getName().' '.$this->operator.' zephir_get_numberval('.$symbol.'))', $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':
                                return new CompiledExpression('int', '((int) ('.$left->getCode().') '.$this->operator.' '.$right->getCode().')', $expression);

                            case 'double':
                                return new CompiledExpression('int', '((int) ('.$left->getCode().') '.$this->operator.' (int) ('.$right->getCode().'))', $expression);

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

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

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

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

                                        return new CompiledExpression('int', '((int) ('.$variableLeft->getName().') '.$this->operator.' (int) (zephir_get_numberval('.$symbol.')))', $expression);

                                        break;

                                    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 'variable':
                        switch ($right->getType()) {
                            /* a + 1 */
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                            case 'double':
                                $compilationContext->headersManager->add('kernel/operators');
                                $op = $this->operator;
                                $op1 = $compilationContext->backend->getVariableCode($variableLeft);
                                $op2 = $right->getCode();
                                if ('double' == $right->getType()) {
                                    return new CompiledExpression('int', '((int) (zephir_get_numberval('.$op1.')) '.$op.' (int) ('.$op2.'))', $expression);
                                } else {
                                    return new CompiledExpression('int', '((int) (zephir_get_numberval('.$op1.')) '.$op.' '.$op2.')', $expression);
                                }
                                break;

                            /* a(var) + a(x) */
                            case 'variable':
                                $variableRight = $compilationContext->symbolTable->getVariableForRead($right->resolve(null, $compilationContext), $compilationContext, $expression);
                                $symbol = $compilationContext->backend->getVariableCode($variableLeft);
                                switch ($variableRight->getType()) {
                                    /* a(var) + a(int) */
                                    case 'int':
                                    case 'uint':
                                    case 'long':
                                    case 'ulong':
                                        $compilationContext->headersManager->add('kernel/operators');

                                        return new CompiledExpression('int', '((int) (zephir_get_numberval('.$symbol.')) '.$this->operator.' '.$variableRight->getName().')', $expression);
                                        break;

                                    /* a(var) + a(bool) */
                                    case 'bool':
                                        $compilationContext->headersManager->add('kernel/operators');

                                        return new CompiledExpression('int', '((int) (zephir_get_numberval('.$symbol.')) '.$this->operator.' '.$variableRight->getName().')', $expression);
                                        break;

                                    /* a(var) + a(var) */
                                    case 'variable':
                                        $compilationContext->headersManager->add('kernel/operators');
                                        $op1 = $symbol;
                                        $op2 = $compilationContext->backend->getVariableCode($variableRight);

                                        $expected = $this->getExpected($compilationContext, $expression);
                                        $expectedSymbol = $compilationContext->backend->getVariableCode($expected);
                                        $compilationContext->codePrinter->output($this->zvalOperator.'('.$expectedSymbol.', '.$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;

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

            default:
                throw new CompilerException('Unsupported type: '.$left->getType(), $expression);
        }
    }
446068
@Override
    public Object visitMultiplicationOrDivisionExpression(ExcellentParser.MultiplicationOrDivisionExpressionContext ctx) {
        boolean multiplication = ctx.TIMES() != null;

        BigDecimal arg1 = Conversions.toDecimal(visit(ctx.expression(0)), m_evalContext);
        BigDecimal arg2 = Conversions.toDecimal(visit(ctx.expression(1)), m_evalContext);

        if (!multiplication && arg2.equals(BigDecimal.ZERO)) {
            throw new EvaluationError("Division by zero");
        }

        return multiplication ? arg1.multiply(arg2, ExpressionUtils.MATH) : arg1.divide(arg2, ExpressionUtils.MATH);
    }
806394
protected function _accessDimensionArray($expression, Variable $variableVariable, CompilationContext $compilationContext)
    {
        $arrayAccess = $expression;

        if ('variable' == $variableVariable->getType()) {
            if ($variableVariable->hasAnyDynamicType('unknown')) {
                throw new CompilerException('Cannot use non-initialized variable as an array', $arrayAccess['left']);
            }

            /*
             * Trying to use a non-object dynamic variable as object
             */
            if ($variableVariable->hasDifferentDynamicType(['undefined', 'array', 'null'])) {
                $compilationContext->logger->warning(
                    'Possible attempt to access array-index on a non-array dynamic variable',
                    ['non-array-access', $arrayAccess['left']]
                );
            }
        }

        /**
         * Resolves the symbol that expects the value.
         */
        $readOnly = false;
        $symbolVariable = $this->expectingVariable;

        if ($this->readOnly) {
            if ($this->expecting && $this->expectingVariable) {
                /*
                 * If a variable is assigned once in the method, we try to promote it
                 * to a read only variable
                 */
                if ('return_value' != $symbolVariable->getName()) {
                    $line = $compilationContext->symbolTable->getLastCallLine();
                    if (false === $line || ($line > 0 && $line < $expression['line'])) {
                        $numberMutations = $compilationContext->symbolTable->getExpectedMutations($symbolVariable->getName());
                        if (1 == $numberMutations) {
                            if ($symbolVariable->getNumberMutations() == $numberMutations) {
                                $symbolVariable->setMemoryTracked(false);
                                $readOnly = true;
                            }
                        }
                    }
                }

                /*
                 * Variable is not read-only or it wasn't promoted
                 */
                if (!$readOnly) {
                    if ('return_value' != $symbolVariable->getName()) {
                        $symbolVariable->observeVariant($compilationContext);
                        $this->readOnly = false;
                    } else {
                        $symbolVariable = $compilationContext->symbolTable->getTempNonTrackedUninitializedVariable('variable', $compilationContext, $expression);
                    }
                }
            } else {
                $symbolVariable = $compilationContext->symbolTable->getTempNonTrackedUninitializedVariable('variable', $compilationContext, $expression);
            }
        } else {
            if ($this->expecting && $this->expectingVariable) {
                /*
                 * If a variable is assigned once in the method, we try to promote it
                 * to a read only variable
                 */
                if ('return_value' != $symbolVariable->getName()) {
                    $line = $compilationContext->symbolTable->getLastCallLine();
                    if (false === $line || ($line > 0 && $line < $expression['line'])) {
                        $numberMutations = $compilationContext->symbolTable->getExpectedMutations($symbolVariable->getName());
                        if (1 == $numberMutations) {
                            if ($symbolVariable->getNumberMutations() == $numberMutations) {
                                $symbolVariable->setMemoryTracked(false);
                                $readOnly = true;
                            }
                        }
                    }
                }

                /*
                 * Variable is not read-only or it wasn't promoted
                 */
                if (!$readOnly) {
                    if ('return_value' != $symbolVariable->getName()) {
                        $symbolVariable->observeVariant($compilationContext);
                        $this->readOnly = false;
                    } else {
                        $symbolVariable = $compilationContext->symbolTable->getTempVariableForObserve('variable', $compilationContext, $expression);
                    }
                }
            } else {
                $symbolVariable = $compilationContext->symbolTable->getTempVariableForObserve('variable', $compilationContext, $expression);
            }
        }

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

        /*
         * At this point, we don't know the type fetched from the index
         */
        $symbolVariable->setDynamicTypes('undefined');

        if ($this->readOnly || $readOnly) {
            if ($this->noisy) {
                $flags = 'PH_NOISY | PH_READONLY';
            } else {
                $flags = 'PH_READONLY';
            }
        } else {
            if ($this->noisy) {
                $flags = 'PH_NOISY';
            } else {
                $flags = '0';
            }
        }

        /**
         * Right part of expression is the index.
         */
        $expr = new Expression($arrayAccess['right']);
        $exprIndex = $expr->compile($compilationContext);
        $compilationContext->headersManager->add('kernel/array');
        if ('variable' == $exprIndex->getType()) {
            $exprIndex = $compilationContext->symbolTable->getVariableForRead($exprIndex->getCode(), $compilationContext, $expression);
        }
        $compilationContext->backend->arrayFetch($symbolVariable, $variableVariable, $exprIndex, $flags, $arrayAccess, $compilationContext);

        return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
    }
1178847
public function optimize(array $expression, Call $call, CompilationContext $context)
    {
        if (!isset($expression['parameters']) || \count($expression['parameters']) < 2) {
            throw new CompilerException(
                sprintf(
                    'preg_match() expects at least 2 parameters, %d given',
                    isset($expression['parameters']) ? \count($expression['parameters']) : 0
                ),
                $expression
            );
        }

        if (\count($expression['parameters']) > 5) {
            throw new CompilerException(
                sprintf(
                    'preg_match() expects at most 5 parameters, %d given',
                    \count($expression['parameters'])
                ),
                $expression
            );
        }

        $matches = $this->createMatches($expression, $context);
        list($flags, $offset) = $this->processOptionals($expression, $call, $context);

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

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

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

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

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

            $symbol = $context->backend->getVariableCode($symbolVariable);
            $matchesSymbol = $context->backend->getVariableCode($matches);

            $context->codePrinter->output(
                sprintf(
                    'zephir_preg_match(%s, %s, %s, %s, %d, %s, %s TSRMLS_CC);',
                    $symbol,
                    $resolvedParams[0],
                    $resolvedParams[1],
                    $matchesSymbol,
                    static::GLOBAL_MATCH,
                    $flags,
                    $offset
                )
            );

            return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
        } catch (Exception $e) {
            throw new CompilerException($e->getMessage(), $expression, $e->getCode(), $e);
        }
    }
854941
protected function _callNormal(array $expression, CompilationContext $compilationContext)
    {
        $funcName = strtolower($expression['name']);

        if ('array' == $funcName) {
            throw new CompilerException("Cannot use 'array' as a function call", $expression);
        }

        /**
         * Try to optimize function calls using existing optimizers.
         */
        $compiledExpr = $this->optimize($funcName, $expression, $this, $compilationContext);
        if (\is_object($compiledExpr)) {
            return $compiledExpr;
        }

        $exists = $this->functionExists($funcName, $compilationContext);

        if (!$exists) {
            $compilationContext->logger->warning(
                sprintf('Function "%s" does not exist at compile time', $funcName),
                ['nonexistent-function', $expression]
            );
        }

        /*
         * Static variables can be passed using local variables saving memory if the function is read only
         */
        if ($exists) {
            $readOnly = $this->isReadOnly($funcName, $expression);
        } else {
            $readOnly = false;
        }

        /*
         * Resolve parameters
         */
        if (isset($expression['parameters'])) {
            if ($readOnly) {
                $params = $this->getReadOnlyResolvedParams($expression['parameters'], $compilationContext, $expression);
            } else {
                $params = $this->getResolvedParams($expression['parameters'], $compilationContext, $expression);
            }
        } else {
            $params = [];
        }

        /*
         * Some functions receive parameters as references
         * We mark those parameters temporary as references to properly pass them
         */
        $this->markReferences($funcName, $params, $compilationContext, $references, $expression);
        $codePrinter = $compilationContext->codePrinter;

        /*
         * Process the expected symbol to be returned
         */
        $this->processExpectedObservedReturn($compilationContext);

        /**
         * At this point the function will be called in the PHP userland.
         * PHP functions only return zvals so we need to validate the target variable is also a zval.
         */
        $symbolVariable = $this->getSymbolVariable();
        if ($symbolVariable) {
            if (!$symbolVariable->isVariable()) {
                throw new CompilerException(
                    'Returned values by functions can only be assigned to variant variables',
                    $expression
                );
            }

            /*
             * We don't know the exact dynamic type returned by the method call
             */
            $symbolVariable->setDynamicTypes('undefined');
            $symbol = $compilationContext->backend->getVariableCodePointer($symbolVariable);
        }

        /*
         * Include fcall header
         */
        $compilationContext->headersManager->add('kernel/fcall');

        /*
         * Call functions must grown the stack
         */
        $compilationContext->symbolTable->mustGrownStack(true);

        /**
         * Check if the function can have an inline cache.
         */
        $functionCache = $compilationContext->cacheManager->getFunctionCache();
        $cachePointer = $functionCache->get($funcName, $compilationContext, $this, $exists);

        /*
         * Add the last call status to the current symbol table
         */
        $this->addCallStatusFlag($compilationContext);

        if (!\count($params)) {
            if ($this->isExpectingReturn()) {
                if ('return_value' == $symbolVariable->getName()) {
                    $codePrinter->output(
                        'ZEPHIR_RETURN_CALL_FUNCTION("'.$funcName.'", '.$cachePointer.');'
                    );
                } else {
                    if ($this->mustInitSymbolVariable()) {
                        $symbolVariable->setMustInitNull(true);
                        $symbolVariable->trackVariant($compilationContext);
                    }
                    $codePrinter->output(
                        'ZEPHIR_CALL_FUNCTION('.$symbol.', "'.$funcName.'", '.$cachePointer.');'
                    );
                }
            } else {
                $codePrinter->output('ZEPHIR_CALL_FUNCTION(NULL, "'.$funcName.'", '.$cachePointer.');');
            }
        } else {
            if ($this->isExpectingReturn()) {
                if ('return_value' == $symbolVariable->getName()) {
                    $codePrinter->output(
                        strtr('ZEPHIR_RETURN_CALL_FUNCTION(":func", :pointer, :params);', [
                            ':func' => $funcName,
                            ':pointer' => $cachePointer,
                            ':params' => implode(', ', $params),
                        ])
                    );
                } else {
                    if ($this->mustInitSymbolVariable()) {
                        $symbolVariable->setMustInitNull(true);
                        $symbolVariable->trackVariant($compilationContext);
                    }

                    $codePrinter->output(
                        strtr('ZEPHIR_CALL_FUNCTION(:symbol, ":func", :pointer, :params);', [
                            ':symbol' => $symbol,
                            ':func' => $funcName,
                            ':pointer' => $cachePointer,
                            ':params' => implode(', ', $params),
                        ])
                    );
                }
            } else {
                $codePrinter->output(
                    strtr('ZEPHIR_CALL_FUNCTION(NULL, ":func", :pointer, :params);', [
                        ':func' => $funcName,
                        ':pointer' => $cachePointer,
                        ':params' => implode(', ', $params),
                    ])
                );
            }
        }

        /*
         * Temporary variables must be copied if they have more than one reference
         */
        foreach ($this->getMustCheckForCopyVariables() as $checkVariable) {
            $codePrinter->output('zephir_check_temp_parameter('.$checkVariable.');');
        }

        if (\is_array($references)) {
            foreach ($references as $reference) {
                $variable = $compilationContext->symbolTable->getVariable($reference, $compilationContext);
                $compilationContext->codePrinter->output(
                    'ZEPHIR_UNREF('.$compilationContext->backend->getVariableCode($variable).');'
                );
            }
        }

        $this->addCallStatusOrJump($compilationContext);

        /*
         * We can mark temporary variables generated as idle
         */
        foreach ($this->getTemporalVariables() as $tempVariable) {
            $tempVariable->setIdle(true);
        }

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

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