Processes the symbol variable that will be used to return
the result of the symbol call.

@param CompilationContext $compilationContext
426291
public function processExpectedReturn(CompilationContext $compilationContext)
    {
        $expr = $this->expression;
        $expression = $expr->getExpression();

        /**
         * Create temporary variable if needed.
         */
        $mustInit = false;
        $symbolVariable = null;
        $isExpecting = $expr->isExpectingReturn();
        if ($isExpecting) {
            $symbolVariable = $expr->getExpectingVariable();
            if (\is_object($symbolVariable)) {
                $readDetector = new ReadDetector();
                if ($readDetector->detect($symbolVariable->getName(), $expression)) {
                    $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite(
                        'variable',
                        $compilationContext,
                        $expression
                    );
                } else {
                    $mustInit = true;
                }
            } else {
                $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $expression);
            }
        }

        $this->mustInit = $mustInit;
        $this->symbolVariable = $symbolVariable;
        $this->isExpecting = $isExpecting;
    }
925885
public function compile(array $expression, CompilationContext $compilationContext)
    {
        $compilationContext->headersManager->add('kernel/array');

        $variable = $compilationContext->symbolTable->getVariableForWrite($expression['left']['value'], $compilationContext, $expression['left']);
        if ('variable' != $variable->getType()) {
            throw new CompilerException('Cannot use variable type: '.$variable->gettype().' in "fetch" operator', $expression);
        }

        /*
         * return_value must not be observed
         */
        if ('return_value' != $variable->getName()) {
            /*
             * @todo use a read detector here
             */
            $readOnly = false;
            $line = max($compilationContext->symbolTable->getLastCallLine(), $compilationContext->symbolTable->getLastUnsetLine());
            if (false === $line || ($line > 0 && $line < $expression['line'])) {
                $numberMutations = $compilationContext->symbolTable->getExpectedMutations($variable->getName());
                if (1 == $numberMutations) {
                    if (1 == $variable->getNumberMutations()) {
                        $variable->setIsInitialized(true, $compilationContext);
                        $variable->setMemoryTracked(false);
                        $variable->setDynamicTypes('undefined');
                        $readOnly = true;
                    }
                }
            }

            if (!$readOnly || 'array-access' != $expression['right']['type']) {
                $variable->setIsInitialized(true, $compilationContext);
                $variable->observeVariant($compilationContext);
                $variable->setDynamicTypes('undefined');
                $variable->setPossibleValue(new CompiledExpression('undefined', '', $expression), $compilationContext);
            }
        } else {
            $variable = $compilationContext->symbolTable->getTempVariableForObserve('variable', $compilationContext);
        }

        if ($readOnly) {
            $flags = '1';
        } else {
            $flags = '0';
        }

        switch ($expression['right']['type']) {
            case 'array-access':
                $exprVariable = new Expression($expression['right']['left']);
                $exprVariable->setReadOnly(true);
                $exprVariable->setNoisy(false);

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

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

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

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

                return $compilationContext->backend->arrayIssetFetch($variable, $evalVariable, $resolvedExpr, $flags, $expression, $compilationContext);
                break;

            case 'property-access':
                $exprVariable = new Expression($expression['right']['left']);
                $exprVariable->setReadOnly(true);
                $exprVariable->setNoisy(false);

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

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

                if ($evalVariable->hasDifferentDynamicType(['undefined', 'object', 'null'])) {
                    $compilationContext->logger->warning(
                        'Possible attempt to use non object in fetch operator',
                        ['non-valid-fetch', $expression['right']]
                    );
                }

                $property = $expression['right']['right']['value'];

                $compilationContext->headersManager->add('kernel/object');
                $symbol = $compilationContext->backend->getVariableCodePointer($variable);
                $evalSymbol = $compilationContext->backend->getVariableCode($evalVariable);

                return new CompiledExpression('bool', 'zephir_fetch_property('.$symbol.', '.$evalSymbol.', SL("'.$property.'"), PH_SILENT_CC)', $expression);

            case 'property-dynamic-access':
                $exprVariable = new Expression($expression['right']['left']);
                $exprVariable->setReadOnly(true);
                $exprVariable->setNoisy(false);

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

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

                if ($evalVariable->hasDifferentDynamicType(['undefined', 'object', 'null'])) {
                    $compilationContext->logger->warning(
                        'Possible attempt to use non object in fetch operator',
                        ['non-valid-fetch', $expression['right']]
                    );
                }

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

                $exprCompiledVariableProperty = $exprVariableProperty->compile($compilationContext);
                if ('variable' != $exprCompiledVariableProperty->getType()) {
                    throw new CompilerException('Expression type: '.$exprCompiledVariableProperty->getType().' cannot be used in property-dynamic-access', $expression['right']['right']);
                }

                $evalVariableProperty = $compilationContext->symbolTable->getVariableForRead($exprCompiledVariableProperty->getCode(), $compilationContext, $expression['right']['right']);
                if ('variable' != $evalVariableProperty->getType() && 'string' != $evalVariableProperty->getType()) {
                    throw new CompilerException('Variable type: '.$evalVariableProperty->getType().' cannot be used in property-dynamic-access', $expression['right']['right']);
                }

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

                $symbol = $compilationContext->backend->getVariableCodePointer($variable);
                $evalSymbol = $compilationContext->backend->getVariableCode($evalVariable);
                $evalPropertySymbol = $compilationContext->backend->getVariableCode($evalVariableProperty);

                return new CompiledExpression('bool', 'zephir_fetch_property_zval('.$symbol.', '.$evalSymbol.', '.$evalPropertySymbol.', PH_SILENT_CC)', $expression);

            default:
                throw new CompilerException('Cannot use this expression for "fetch" operators: '.$expression['right']['type'], $expression);
        }
    }
504791
public function observeOrNullifyVariant(CompilationContext $compilationContext)
    {
        if ($this->numberSkips) {
            --$this->numberSkips;

            return;
        }

        $name = $this->getName();
        if ('this_ptr' != $name && 'return_value' != $name) {
            if (false === $this->initBranch) {
                $this->initBranch = $compilationContext->currentBranch;
            }

            $compilationContext->headersManager->add('kernel/memory');
            $compilationContext->symbolTable->mustGrownStack(true);
            /**
             * TODO: Do we need this?
             * $compilationContext->codePrinter->output('ZEPHIR_OBS_NVAR(' . $this->getName() . ');');.
             *
             * TODO: What about else?
             * $compilationContext->codePrinter->output('ZEPHIR_OBS_VAR(' . $this->getName() . ');');
             */
            if ($this->variantInits > 0 || $compilationContext->insideCycle) {
                $this->mustInitNull = true;
            }

            ++$this->variantInits;

            $this->setMustInitNull(true);
        }
    }
875043
public function compile(CompilationContext $compilationContext)
    {
        $compilationContext->headersManager->add('kernel/exception');

        $codePrinter = $compilationContext->codePrinter;
        $statement = $this->statement;
        $expr = $statement['expr'];

        /*
         * This optimizes throw new Exception("hello")
         */
        if (!$compilationContext->insideTryCatch) {
            if (isset($expr['class']) &&
                isset($expr['parameters']) &&
                1 == \count($expr['parameters']) &&
                'string' == $expr['parameters'][0]['parameter']['type']
            ) {
                $className = fqcn(
                    $expr['class'],
                    $compilationContext->classDefinition->getNamespace(),
                    $compilationContext->aliasManager
                );

                if ($compilationContext->compiler->isClass($className)) {
                    $classDefinition = $compilationContext->compiler->getClassDefinition($className);
                    $message = $expr['parameters'][0]['parameter']['value'];
                    try {
                        $class = $classDefinition->getClassEntry($compilationContext);
                        $this->throwStringException($codePrinter, $class, $message, $expr);

                        return;
                    } catch (Exception $e) {
                        throw new CompilerException($e->getMessage(), $expr, $e->getCode(), $e);
                    }
                } else {
                    if ($compilationContext->compiler->isBundledClass($className)) {
                        $classEntry = $compilationContext->classDefinition->getClassEntryByClassName(
                            $className,
                            $compilationContext,
                            true
                        );
                        if ($classEntry) {
                            $message = $expr['parameters'][0]['parameter']['value'];
                            $this->throwStringException($codePrinter, $classEntry, $message, $expr);

                            return;
                        }
                    }
                }
            } else {
                if (\in_array($expr['type'], ['string', 'char', 'int', 'double'])) {
                    $class = $compilationContext->classDefinition->getClassEntryByClassName(
                        'Exception',
                        $compilationContext
                    );

                    $this->throwStringException($codePrinter, $class, $expr['value'], $expr);

                    return;
                }
            }
        }

        try {
            $throwExpr = new Expression($expr);
            $resolvedExpr = $throwExpr->compile($compilationContext);
        } catch (Exception $e) {
            throw new CompilerException($e->getMessage(), $expr, $e->getCode(), $e);
        }

        if (!\in_array($resolvedExpr->getType(), ['variable', 'string'])) {
            throw new CompilerException(
                "Expression '".$resolvedExpr->getType().'" cannot be used as exception',
                $expr
            );
        }

        $variableVariable = $compilationContext->symbolTable->getVariableForRead(
            $resolvedExpr->getCode(),
            $compilationContext,
            $expr
        );

        if (!\in_array($variableVariable->getType(), ['variable', 'string'])) {
            throw new CompilerException(
                "Variable '".$variableVariable->getType()."' cannot be used as exception",
                $expr
            );
        }

        $variableCode = $compilationContext->backend->getVariableCode($variableVariable);
        $file = Compiler::getShortUserPath($statement['expr']['file']);
        $line = $statement['expr']['line'];

        $codePrinter->output(
            'zephir_throw_exception_debug('.$variableCode.', "'.$file.'", '.$line.' TSRMLS_CC);'
        );

        if (!$compilationContext->insideTryCatch) {
            $codePrinter->output('ZEPHIR_MM_RESTORE();');
            $codePrinter->output('return;');
        } else {
            $codePrinter->output('goto try_end_'.$compilationContext->currentTryCatch.';');
            $codePrinter->outputBlankLine();
        }

        if ($variableVariable->isTemporal()) {
            $variableVariable->setIdle(true);
        }
    }
512949
public function assign($variable, ZephirVariable $symbolVariable, CompilationContext $compilationContext, $statement)
    {
        if (!$symbolVariable->isInitialized()) {
            throw new CompilerException("Cannot mutate variable '".$variable."' because it is not initialized", $statement);
        }

        if ($symbolVariable->isReadOnly()) {
            throw new CompilerException("Cannot mutate variable '".$variable."' because it is read only", $statement);
        }

        $codePrinter = $compilationContext->codePrinter;

        switch ($symbolVariable->getType()) {
            case 'int':
            case 'uint':
            case 'long':
            case 'ulong':
            case 'double':
            case 'char':
            case 'uchar':
                $codePrinter->output($variable.'--;');
                break;

            case 'variable':
                /*
                 * Variable is probably not initialized here
                 */
                if ($symbolVariable->hasAnyDynamicType('unknown')) {
                    throw new CompilerException('Attempt to decrement uninitialized variable', $statement);
                }

                /*
                 * Decrement non-numeric variables could be expensive
                 */
                if (!$symbolVariable->hasAnyDynamicType(['undefined', 'int', 'long', 'double', 'uint'])) {
                    $compilationContext->logger->warning(
                        'Possible attempt to decrement non-numeric dynamic variable',
                        ['non-valid-decrement', $statement]
                    );
                }

                $compilationContext->headersManager->add('kernel/operators');
                if (!$symbolVariable->isLocalOnly()) {
                    $symbolVariable->separate($compilationContext);
                }
                $codePrinter->output('zephir_decrement('.$compilationContext->backend->getVariableCode($symbolVariable).');');
                break;

            default:
                throw new CompilerException('Cannot decrement variable: '.$symbolVariable->getType(), $statement);
        }
    }
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);
    }
1351007
public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement)
    {
        if (!$symbolVariable->isInitialized()) {
            throw new CompilerException("Cannot mutate variable '".$variable."' because it is not initialized", $statement);
        }

        if (!$symbolVariable->isVariable()) {
            throw new CompilerException("Variable type '".$symbolVariable->getType()."' cannot be used as object", $statement);
        }

        $propertyName = $statement['property'];
        $className = $compilationContext->classDefinition->getCompleteName();

        if (!$symbolVariable->isInitialized()) {
            throw new CompilerException("Cannot mutate static property '".$className.'::'.$propertyName."' because it is not initialized", $statement);
        }

        if (!$symbolVariable->isVariable()) {
            throw new CompilerException('Cannot use variable type: '.$symbolVariable->getType().' as an object', $statement);
        }

        if ($symbolVariable->hasAnyDynamicType('unknown')) {
            throw new CompilerException('Cannot use non-initialized variable as an object', $statement);
        }

        /*
         * Trying to use a non-object dynamic variable as object
         */
        if ($symbolVariable->hasDifferentDynamicType(['undefined', 'object'])) {
            $compilationContext->logger->warning(
                'Possible attempt to update property on non-object dynamic property',
                ['non-valid-objectupdate', $statement]
            );
        }

        /*
         * Try to check if property is implemented on related object
         */
        if ('this' == $variable) {
            if (!$compilationContext->classDefinition->hasProperty($propertyName)) {
                throw new CompilerException("Property '".$propertyName."' is not defined on class '".$className."'", $statement);
            }
        }

        $codePrinter = $compilationContext->codePrinter;

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

        switch ($resolvedExpr->getType()) {
            case 'null':
                $compilationContext->backend->updateProperty($symbolVariable, $propertyName, 'null', $compilationContext);
                break;

            case 'int':
            case 'long':
            case 'uint':
                $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
                switch ($statement['operator']) {
                    case 'mul-assign':
                    case 'sub-assign':
                    case 'add-assign':
                        switch ($statement['operator']) {
                            case 'mul-assign':
                                $functionName = 'ZEPHIR_MUL_ASSIGN';
                                break;
                            case 'sub-assign':
                                $functionName = 'ZEPHIR_SUB_ASSIGN';
                                break;
                            case 'add-assign':
                                $functionName = 'ZEPHIR_ADD_ASSIGN';
                                break;
                        }

                        $resolvedVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
                        $compilationContext->backend->assignLong($resolvedVariable, $resolvedExpr->getBooleanCode(), $compilationContext);
                        $compilationContext->backend->fetchProperty($tempVariable, $symbolVariable, $propertyName, false, $compilationContext);
                        $codePrinter->output($functionName.'('.$compilationContext->backend->getVariableCode($tempVariable).', '.$compilationContext->backend->getVariableCode($resolvedVariable).')');
                        break;

                    case 'assign':
                        $tempVariable->initNonReferenced($compilationContext);
                        $compilationContext->backend->assignLong($tempVariable, $resolvedExpr->getBooleanCode(), $compilationContext);
                        break;

                    default:
                        throw new CompilerException("Operator '".$statement['operator']."' is not supported for object property: ".$tempVariable->getType(), $statement);
                }

                $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext);
                $tempVariable->setIdle(true);
                break;

            case 'char':
                $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
                switch ($statement['operator']) {
                    case 'assign':
                        $tempVariable->initNonReferenced($compilationContext);
                        $compilationContext->backend->assignLong($tempVariable, '\''.$resolvedExpr->getBooleanCode().'\'', $compilationContext);
                        break;

                    default:
                        throw new CompilerException("Operator '".$statement['operator']."' is not supported for object property: ".$tempVariable->getType(), $statement);
                }

                $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext);
                $tempVariable->setIdle(true);
                break;

            case 'double':
                $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
                switch ($statement['operator']) {
                    case 'mul-assign':
                    case 'sub-assign':
                    case 'add-assign':
                        switch ($statement['operator']) {
                            case 'mul-assign':
                                $functionName = 'ZEPHIR_MUL_ASSIGN';
                                break;
                            case 'sub-assign':
                                $functionName = 'ZEPHIR_SUB_ASSIGN';
                                break;
                            case 'add-assign':
                                $functionName = 'ZEPHIR_ADD_ASSIGN';
                                break;
                        }

                        $resolvedVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext);
                        $compilationContext->backend->assignDouble($resolvedVariable, $resolvedExpr->getBooleanCode(), $compilationContext);
                        $compilationContext->backend->fetchProperty($tempVariable, $symbolVariable, $propertyName, false, $compilationContext);
                        $codePrinter->output($functionName.'('.$compilationContext->backend->getVariableCode($tempVariable).', '.$compilationContext->backend->getVariableCode($resolvedVariable).')');
                        break;

                    case 'assign':
                        $tempVariable->initNonReferenced($compilationContext);
                        $compilationContext->backend->assignDouble($tempVariable, $resolvedExpr->getBooleanCode(), $compilationContext);
                        break;

                    default:
                        throw new CompilerException("Operator '".$statement['operator']."' is not supported for object property: ".$tempVariable->getType(), $statement);
                }

                $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext);
                $tempVariable->setIdle(true);
                break;

            case 'string':
                if ('ZendEngine2' == $compilationContext->backend->getName()) {
                    $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
                } else {
                    $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, false);
                }

                switch ($statement['operator']) {
                    case 'concat-assign':
                        $codePrinter->output('zephir_concat_self_str(&'.$tempVariable->getName().', "'.$resolvedExpr->getCode().'", sizeof("'.$resolvedExpr->getCode().'")-1 TSRMLS_CC);');
                        break;
                    case 'assign':
                        /* We only can use nonReferenced variables for not refcounted stuff in ZE3 */
                        if ('ZendEngine2' == $compilationContext->backend->getName()) {
                            $tempVariable->initNonReferenced($compilationContext);
                        } else {
                            $tempVariable->initVariant($compilationContext);
                        }
                        $compilationContext->backend->assignString($tempVariable, $resolvedExpr->getCode(), $compilationContext);
                        break;
                }

                $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext);
                $tempVariable->setIdle(true);
                break;

            case 'array':
                $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $resolvedExpr, $compilationContext);
                break;

            case 'bool':
                $codePrinter->output('if ('.$resolvedExpr->getBooleanCode().') {');
                $codePrinter->increaseLevel();
                $compilationContext->backend->updateProperty($symbolVariable, $propertyName, 'true', $compilationContext);
                $codePrinter->decreaseLevel();
                $codePrinter->output('} else {');
                $codePrinter->increaseLevel();
                $compilationContext->backend->updateProperty($symbolVariable, $propertyName, 'false', $compilationContext);
                $codePrinter->decreaseLevel();
                $codePrinter->output('}');
                break;

            /* unreachable code */
            case 'empty-array':
                $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);

                $compilationContext->backend->initArray($tempVariable, $compilationContext);
                $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $resolvedExpr->getCode(), $compilationContext);
                $tempVariable->setIdle(true);
                break;

            case 'variable':
                $variableVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
                switch ($variableVariable->getType()) {
                    case 'int':
                    case 'uint':
                    case 'long':
                    case 'ulong':
                    case 'char':
                    case 'uchar':
                        $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                        $compilationContext->backend->assignLong($tempVariable, $variableVariable, $compilationContext);
                        $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext);
                        $tempVariable->setIdle(true);
                        break;

                    case 'double':
                        $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                        $compilationContext->backend->assignDouble($tempVariable, $variableVariable, $compilationContext);
                        $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $tempVariable, $compilationContext);
                        $tempVariable->setIdle(true);
                        break;

                    case 'bool':
                        $codePrinter->output('if ('.$variableVariable->getName().') {');
                        $codePrinter->increaseLevel();
                        $compilationContext->backend->updateProperty($symbolVariable, $propertyName, 'true', $compilationContext);
                        $codePrinter->decreaseLevel();
                        $codePrinter->output('} else {');
                        $codePrinter->increaseLevel();
                        $compilationContext->backend->updateProperty($symbolVariable, $propertyName, 'false', $compilationContext);
                        $codePrinter->decreaseLevel();
                        $codePrinter->output('}');
                        break;

                    case 'array':
                    case 'string':
                    case 'variable':
                        $compilationContext->backend->updateProperty($symbolVariable, $propertyName, $variableVariable, $compilationContext);
                        if ($symbolVariable->isTemporal()) {
                            $symbolVariable->setIdle(true);
                        }
                        break;

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

            default:
                throw new CompilerException('Unknown type '.$resolvedExpr->getType(), $statement);
        }
    }
67121
private function getRealCalledMethod(CompilationContext $compilationContext, Variable $caller, $methodName)
    {
        $compiler = $compilationContext->compiler;

        $numberPoly = 0;
        $method = null;

        if ('this' == $caller->getRealName()) {
            $classDefinition = $compilationContext->classDefinition;
            if ($classDefinition->hasMethod($methodName)) {
                ++$numberPoly;
                $method = $classDefinition->getMethod($methodName);
            }
        } else {
            $classTypes = $caller->getClassTypes();
            foreach ($classTypes as $classType) {
                if ($compiler->isInterface($classType)) {
                    continue;
                }

                if ($compiler->isClass($classType) ||
                    $compiler->isBundledClass($classType) ||
                    $compiler->isBundledInterface($classType)
                ) {
                    if ($compiler->isClass($classType)) {
                        $classDefinition = $compiler->getClassDefinition($classType);
                    } else {
                        $classDefinition = $compiler->getInternalClassDefinition($classType);
                    }

                    if (!$classDefinition) {
                        continue;
                    }

                    if ($classDefinition->hasMethod($methodName) && !$classDefinition->isInterface()) {
                        ++$numberPoly;
                        $method = $classDefinition->getMethod($methodName);
                    }
                }
            }
        }

        return [$numberPoly, $method];
    }
424005
public function compile(CompilationContext $compilationContext)
    {
        /*
         * Set the method currently being compiled
         */
        $compilationContext->currentMethod = $this;

        /*
         * Initialize the method warm-up to null
         */
        $compilationContext->methodWarmUp = null;

        /**
         * Assign pre-made compilation passes.
         */
        $localContext = $this->localContext;
        $typeInference = $this->typeInference;
        $callGathererPass = $this->callGathererPass;

        /**
         * Initialization of parameters happens in a fictitious external branch.
         */
        $branch = new Branch();
        $branch->setType(Branch::TYPE_EXTERNAL);
        /**
         * BranchManager helps to create graphs of conditional/loop/root/jump branches.
         */
        $branchManager = new BranchManager();
        $branchManager->addBranch($branch);

        $compilationContext->branchManager = $branchManager;

        /**
         * Every method has its own symbol table.
         */
        $symbolTable = new SymbolTable($compilationContext);
        if ($localContext) {
            $symbolTable->setLocalContext($localContext);
        }

        if ($this->staticVariables) {
            foreach ($this->staticVariables as $var) {
                $localVar = clone $var;
                $localVar->setIsExternal(true);
                $localVar->setLocalOnly(true);
                $localVar->setType('variable');
                $symbolTable->addRawVariable($localVar);
            }
        }

        /**
         * Parameters has an additional extra mutation.
         */
        $parameters = $this->parameters;
        if ($localContext) {
            if (\is_object($parameters)) {
                foreach ($parameters->getParameters() as $parameter) {
                    $localContext->increaseMutations($parameter['name']);
                }
            }
        }

        /**
         * Cache Manager manages function calls, method calls and class entries caches.
         */
        $cacheManager = new CacheManager();
        $cacheManager->setGatherer($callGathererPass);

        $compilationContext->cacheManager = $cacheManager;
        $compilationContext->typeInference = $typeInference;
        $compilationContext->symbolTable = $symbolTable;

        $oldCodePrinter = $compilationContext->codePrinter;

        /**
         * Change the code printer to a single method instance.
         */
        $codePrinter = new CodePrinter();
        $compilationContext->codePrinter = $codePrinter;

        /*
         * Set an empty function cache
         */
        $compilationContext->functionCache = null;

        /*
         * Reset try/catch and loop counter
         */
        $compilationContext->insideCycle = 0;
        $compilationContext->insideTryCatch = 0;
        $compilationContext->currentTryCatch = 0;

        if (\is_object($parameters)) {
            /**
             * Round 1. Create variables in parameters in the symbol table.
             */
            $classCastChecks = [];
            $substituteVars = [];
            foreach ($parameters->getParameters() as $parameter) {
                /*
                 * Change dynamic variables to low level types
                 */
                if ($typeInference) {
                    if (isset($parameter['data-type'])) {
                        if ('variable' == $parameter['data-type']) {
                            $type = $typeInference->getInferedType($parameter['name']);
                            if (\is_string($type)) {
                                /* promote polymorphic parameters to low level types */
                            }
                        }
                    } else {
                        $type = $typeInference->getInferedType($parameter['name']);
                        if (\is_string($type)) {
                            /* promote polymorphic parameters to low level types */
                        }
                    }
                }

                $symbolParam = null;

                if (isset($parameter['data-type'])) {
                    switch ($parameter['data-type']) {
                        case 'object':
                        case 'callable':
                        case 'resource':
                        case 'variable':
                            $symbol = $symbolTable->addVariable($parameter['data-type'], $parameter['name'], $compilationContext);
                            /* TODO: Move this to the respective backend, which requires refactoring how this works */
                            if ($compilationContext->backend->isZE3()) {
                                $symbol->setIsDoublePointer(true);
                                $substituteVars[$parameter['name']] = $symbolTable->addVariable('variable', $parameter['name'].'_sub', $compilationContext);
                            }
                            break;

                        default:
                            $symbol = $symbolTable->addVariable($parameter['data-type'], $parameter['name'], $compilationContext);
                            $symbolParam = $symbolTable->addVariable('variable', $parameter['name'].'_param', $compilationContext);
                            /* TODO: Move this to the respective backend, which requires refactoring how this works */
                            if ($compilationContext->backend->isZE3()) {
                                $symbolParam->setIsDoublePointer(true);
                            }
                            if ('string' == $parameter['data-type'] || 'array' == $parameter['data-type']) {
                                $symbol->setMustInitNull(true);
                            }
                            break;
                    }
                } else {
                    $symbol = $symbolTable->addVariable('variable', $parameter['name'], $compilationContext);
                }

                /* ZE3 only */
                if (isset($substituteVars[$parameter['name']])) {
                    $substituteVar = $substituteVars[$parameter['name']];
                    $substituteVar->increaseUses();
                }

                /*
                 * Some parameters can be read-only
                 */
                if (isset($parameter['const']) && $parameter['const']) {
                    $symbol->setReadOnly(true);
                    if (\is_object($symbolParam)) {
                        $symbolParam->setReadOnly(true);
                    }
                }

                if (\is_object($symbolParam)) {
                    /*
                     * Parameters are marked as 'external'
                     */
                    $symbolParam->setIsExternal(true);

                    /*
                     * Assuming they're initialized
                     */
                    $symbolParam->setIsInitialized(true, $compilationContext);

                    /*
                     * Initialize auxiliary parameter zvals to null
                     */
                    $symbolParam->setMustInitNull(true);

                    /*
                     * Increase uses
                     */
                    $symbolParam->increaseUses();
                } else {
                    if (isset($parameter['default'])) {
                        if (isset($parameter['data-type'])) {
                            if ('variable' == $parameter['data-type']) {
                                $symbol->setMustInitNull(true);
                            }
                        } else {
                            $symbol->setMustInitNull(true);
                        }
                    }
                }

                /*
                 * Original node where the variable was declared
                 */
                $symbol->setOriginal($parameter);

                /*
                 * Parameters are marked as 'external'
                 */
                $symbol->setIsExternal(true);

                /*
                 * Assuming they're initialized
                 */
                $symbol->setIsInitialized(true, $compilationContext);

                /*
                 * Variables with class/type must be objects across the execution
                 */
                if (isset($parameter['cast'])) {
                    $symbol->setDynamicTypes('object');
                    $symbol->setClassTypes($compilationContext->getFullName($parameter['cast']['value']));
                    $classCastChecks[] = [$symbol, $parameter];
                } else {
                    if (isset($parameter['data-type'])) {
                        if ('variable' == $parameter['data-type']) {
                            $symbol->setDynamicTypes('undefined');
                        }
                    } else {
                        $symbol->setDynamicTypes('undefined');
                    }
                }
            }
        }

        $compilationContext->backend->onPreCompile($this, $compilationContext);

        /*
         * Compile the block of statements if any
         */
        if (\is_object($this->statements)) {
            if ($this->hasModifier('static')) {
                $compilationContext->staticContext = true;
            } else {
                $compilationContext->staticContext = false;
            }

            /*
             * Compile the statements block as a 'root' branch
             */
            $this->statements->compile($compilationContext, false, Branch::TYPE_ROOT);
        }

        /**
         * Initialize variable default values.
         */
        $initVarCode = $compilationContext->backend->initializeVariableDefaults($symbolTable->getVariables(), $compilationContext);

        /**
         * Fetch parameters from vm-top.
         */
        $initCode = '';
        $code = '';
        if (\is_object($parameters)) {
            /**
             * Round 2. Fetch the parameters in the method.
             */
            $params = [];
            $requiredParams = [];
            $optionalParams = [];
            $numberRequiredParams = 0;
            $numberOptionalParams = 0;
            foreach ($parameters->getParameters() as $parameter) {
                if (isset($parameter['data-type'])) {
                    $dataType = $parameter['data-type'];
                } else {
                    $dataType = 'variable';
                }

                switch ($dataType) {
                    case 'object':
                    case 'callable':
                    case 'resource':
                    case 'variable':
                        if (!$this->isInternal()) {
                            $params[] = '&'.$parameter['name'];
                        } else {
                            $params[] = $parameter['name'];
                        }
                        break;

                    default:
                        if (!$this->isInternal()) {
                            $params[] = '&'.$parameter['name'].'_param';
                        } else {
                            $params[] = $parameter['name'].'_param';
                        }
                        break;
                }

                if (isset($parameter['default'])) {
                    $optionalParams[] = $parameter;
                    ++$numberOptionalParams;
                } else {
                    $requiredParams[] = $parameter;
                    ++$numberRequiredParams;
                }
            }

            /**
             * Pass the write detector to the method statement block to check if the parameter
             * variable is modified so as do the proper separation.
             */
            $parametersToSeparate = [];
            if (\is_object($this->statements)) {
                /*
                 * If local context is not available
                 */
                if (!$localContext) {
                    $writeDetector = new WriteDetector();
                }

                foreach ($parameters->getParameters() as $parameter) {
                    if (isset($parameter['data-type'])) {
                        $dataType = $parameter['data-type'];
                    } else {
                        $dataType = 'variable';
                    }

                    switch ($dataType) {
                        case 'variable':
                        case 'string':
                        case 'array':
                        case 'resource':
                        case 'object':
                        case 'callable':
                            $name = $parameter['name'];
                            if (!$localContext) {
                                if ($writeDetector->detect($name, $this->statements->getStatements())) {
                                    $parametersToSeparate[$name] = true;
                                }
                            } else {
                                if ($localContext->getNumberOfMutations($name) > 1) {
                                    $parametersToSeparate[$name] = true;
                                }
                            }
                            break;
                    }
                }
            }

            /*
             * Initialize required parameters
             */
            foreach ($requiredParams as $parameter) {
                if (isset($parameter['mandatory'])) {
                    $mandatory = $parameter['mandatory'];
                } else {
                    $mandatory = 0;
                }

                if (isset($parameter['data-type'])) {
                    $dataType = $parameter['data-type'];
                } else {
                    $dataType = 'variable';
                }

                if ('variable' != $dataType) {
                    /*
                     * Assign value from zval to low level type
                     */
                    if ($mandatory) {
                        $initCode .= $this->checkStrictType($parameter, $compilationContext);
                    } else {
                        $initCode .= $this->assignZvalValue($parameter, $compilationContext);
                    }
                }

                switch ($dataType) {
                    case 'variable':
                    case 'resource':
                    case 'object':
                    case 'callable':
                        if (isset($parametersToSeparate[$parameter['name']])) {
                            $symbolTable->mustGrownStack(true);
                            $initCode .= "\t".'ZEPHIR_SEPARATE_PARAM('.$parameter['name'].');'.PHP_EOL;
                        }
                        break;
                }
            }

            /*
             * Initialize optional parameters
             */
            foreach ($optionalParams as $parameter) {
                if (isset($parameter['mandatory'])) {
                    $mandatory = $parameter['mandatory'];
                } else {
                    $mandatory = 0;
                }

                if (isset($parameter['data-type'])) {
                    $dataType = $parameter['data-type'];
                } else {
                    $dataType = 'variable';
                }

                switch ($dataType) {
                    case 'object':
                    case 'callable':
                    case 'resource':
                    case 'variable':
                        $name = $parameter['name'];
                        break;

                    default:
                        $name = $parameter['name'].'_param';
                        break;
                }

                /**
                 * Assign the default value according to the variable's type.
                 */
                $targetVar = $compilationContext->symbolTable->getVariableForWrite($name, $compilationContext);
                $initCode .= "\t".$compilationContext->backend->ifVariableValueUndefined($targetVar, $compilationContext, false, false).PHP_EOL;

                if ($compilationContext->backend->isZE3()) {
                    if ($targetVar->isDoublePointer() && isset($substituteVars[$parameter['name']])) {
                        $substituteVar = $substituteVars[$parameter['name']];
                        $initCode .= "\t\t".$targetVar->getName().' = &'.$substituteVar->getName().';'.PHP_EOL;
                    }
                }
                $initCode .= $this->assignDefaultValue($parameter, $compilationContext);

                if (isset($parametersToSeparate[$name]) || 'variable' != $dataType) {
                    $initCode .= "\t".'} else {'.PHP_EOL;
                    if (isset($parametersToSeparate[$name])) {
                        $initCode .= "\t\t".'ZEPHIR_SEPARATE_PARAM('.$name.');'.PHP_EOL;
                    } else {
                        if ($mandatory) {
                            $initCode .= $this->checkStrictType($parameter, $compilationContext, $mandatory);
                        } else {
                            $initCode .= "\t".$this->assignZvalValue($parameter, $compilationContext);
                        }
                    }
                }

                $initCode .= "\t".'}'.PHP_EOL;
            }

            /*
             * Fetch the parameters to zval pointers
             */
            $codePrinter->preOutputBlankLine();

            if (!$this->isInternal()) {
                $compilationContext->headersManager->add('kernel/memory');
                if ($symbolTable->getMustGrownStack()) {
                    $code .= "\t".'zephir_fetch_params(1, '.$numberRequiredParams.', '.$numberOptionalParams.', '.implode(', ', $params).');'.PHP_EOL;
                } else {
                    $code .= "\t".'zephir_fetch_params(0, '.$numberRequiredParams.', '.$numberOptionalParams.', '.implode(', ', $params).');'.PHP_EOL;
                }
            } else {
                foreach ($params as $param) {
                    /* TODO: Migrate all this code to codeprinter, get rid of temp code printer */
                    $tempCodePrinter = new CodePrinter();
                    $realCodePrinter = $compilationContext->codePrinter;
                    $compilationContext->codePrinter = $tempCodePrinter;
                    $paramVar = $compilationContext->symbolTable->getVariableForRead($param, $compilationContext);
                    $compilationContext->backend->assignZval($paramVar, $param.'_ext', $compilationContext);
                    $code .= "\t".$tempCodePrinter->getOutput().PHP_EOL;
                    $compilationContext->codePrinter = $realCodePrinter;
                }
            }
            $code .= PHP_EOL;
        }

        $code .= $initCode.$initVarCode;
        $codePrinter->preOutput($code);

        $compilationContext->headersManager->add('kernel/object');
        /*
         * Fetch used superglobals
         */
        foreach ($symbolTable->getVariables() as $name => $variable) {
            if ($variable->isSuperGlobal()) {
                $globalVar = $symbolTable->getVariable($name);
                $codePrinter->preOutput("\t".$compilationContext->backend->fetchGlobal($globalVar, $compilationContext, false));
            }
            if ($variable->isLocalSatic()) {
                $staticVar = $symbolTable->getVariable($name);

                $codePrinter->preOutput(sprintf(
                    "\t".'zephir_read_static_property_ce(%s%s, %s, SL("%s"), PH_NOISY_CC%s);',
                    $staticVar->isDoublePointer() ? '' : '&',
                    $staticVar->getName(),
                    $this->classDefinition->getClassEntry(),
                    $staticVar->getName(),
                    ''
                ));
            }
        }

        /*
         * Grow the stack if needed
         */
        if ($symbolTable->getMustGrownStack()) {
            $compilationContext->headersManager->add('kernel/memory');
            $codePrinter->preOutput("\t".'ZEPHIR_MM_GROW();');
        }

        /**
         * Check if there are unused variables.
         */
        $usedVariables = [];
        $classDefinition = $this->getClassDefinition();
        if ($classDefinition) {
            $completeName = $classDefinition->getCompleteName();
        } else {
            $completeName = '[unknown]';
        }

        foreach ($symbolTable->getVariables() as $variable) {
            if ($variable->getNumberUses() <= 0) {
                if (false == $variable->isExternal()) {
                    $compilationContext->logger->warning(
                        'Variable "'.$variable->getName().'" declared but not used in '.$completeName.'::'.$this->getName(),
                        ['unused-variable', $variable->getOriginal()]
                    );
                    continue;
                }
                $compilationContext->logger->warning(
                    'Variable "'.$variable->getName().'" declared but not used in '.$completeName.'::'.$this->getName(),
                    ['unused-variable-external', $variable->getOriginal()]
                );
            }

            if ('this_ptr' != $variable->getName() && 'return_value' != $variable->getName() && 'return_value_ptr' != $variable->getName()) {
                $type = $variable->getType();
                if (!isset($usedVariables[$type])) {
                    $usedVariables[$type] = [];
                }
                $usedVariables[$type][] = $variable;
            }
        }

        /*
         * Check if there are assigned but not used variables
         * Warn whenever a variable is unused aside from its declaration.
         */
        foreach ($symbolTable->getVariables() as $variable) {
            if (true == $variable->isExternal() || $variable->isTemporal()) {
                continue;
            }

            if ('this_ptr' == $variable->getName() || 'return_value' == $variable->getName() || 'return_value_ptr' == $variable->getName() || 'ZEPHIR_LAST_CALL_STATUS' == $variable->getName()) {
                continue;
            }

            if (!$variable->isUsed()) {
                $node = $variable->getLastUsedNode();
                if (\is_array($node)) {
                    $expression = isset($node['expr']) ? $node['expr'] : $node;
                    $compilationContext->logger->warning(
                        'Variable "'.$variable->getName().'" assigned but not used in '.$completeName.'::'.$this->getName(),
                        ['unused-variable', $expression]
                    );
                } else {
                    $compilationContext->logger->warning(
                        'Variable "'.$variable->getName().'" assigned but not used in '.$completeName.'::'.$this->getName(),
                        ['unused-variable', $variable->getOriginal()]
                    );
                }
            }
        }

        if (\count($usedVariables)) {
            $codePrinter->preOutputBlankLine();
        }

        /**
         * Generate the variable definition for variables used.
         */
        $initCode = "\t".implode(PHP_EOL."\t", $compilationContext->backend->declareVariables($this, $usedVariables, $compilationContext));
        if ($initCode) {
            $codePrinter->preOutput($initCode);
        }

        /*
         * Finalize the method compilation
         */
        if (\is_object($this->statements)) {
            /**
             * If the last statement is not a 'return' or 'throw' we need to
             * restore the memory stack if needed.
             */
            $lastType = $this->statements->getLastStatementType();

            if ('return' != $lastType && 'throw' != $lastType && !$this->hasChildReturnStatementType($this->statements->getLastStatement())) {
                if ($symbolTable->getMustGrownStack()) {
                    $compilationContext->headersManager->add('kernel/memory');
                    $codePrinter->output("\t".'ZEPHIR_MM_RESTORE();');
                }

                /*
                 * If a method has return-type hints we need to ensure the last statement is a 'return' statement
                 */
                if ($this->hasReturnTypes()) {
                    throw new CompilerException(
                        'Reached end of the method without returning a valid type specified in the return-type hints',
                        $this->expression['return-type']
                    );
                }
            }
        }

        $compilationContext->backend->onPostCompile($this, $compilationContext);

        /**
         * Remove macros that grow/restore the memory frame stack if it wasn't used.
         */
        $code = $this->removeMemoryStackReferences($symbolTable, $codePrinter->getOutput());

        /*
         * Restore the compilation context
         */
        $oldCodePrinter->output($code);
        $compilationContext->codePrinter = $oldCodePrinter;

        $compilationContext->branchManager = null;
        $compilationContext->cacheManager = null;
        $compilationContext->typeInference = null;

        $codePrinter->clear();

        return null;
    }
91995
public function trackVariant(CompilationContext $compilationContext)
    {
        if ($this->numberSkips) {
            --$this->numberSkips;

            return;
        }

        /*
         * Variables are allocated for the first time using ZEPHIR_INIT_VAR
         * the second, third, etc times are allocated using ZEPHIR_INIT_NVAR
         * Variables initialized for the first time in a cycle are always initialized using ZEPHIR_INIT_NVAR
         */
        if ('this_ptr' != $this->getName() && 'return_value' != $this->getName()) {
            if (false === $this->initBranch) {
                $this->initBranch = $compilationContext->currentBranch;
            }

            if (!$this->isLocalOnly()) {
                $compilationContext->symbolTable->mustGrownStack(true);
                if ($compilationContext->insideCycle) {
                    $this->mustInitNull = true;
                } else {
                    if ($this->variantInits > 0) {
                        if (1 !== $this->initBranch) {
                            $this->mustInitNull = true;
                        }
                    }
                }
            } else {
                if ($this->variantInits > 0 || $compilationContext->insideCycle) {
                    $this->mustInitNull = true;
                }
            }

            ++$this->variantInits;
        }
    }
1209314
public function compile($expression, CompilationContext $compilationContext)
    {
        $expr = new Expression($expression['right']);
        $resolved = $expr->compile($compilationContext);

        switch ($expression['left']) {
            case 'int':
                switch ($resolved->getType()) {
                    case 'null':
                        return new CompiledExpression('int', 0, $expression);

                    case 'int':
                        return new CompiledExpression('int', $resolved->getCode(), $expression);

                    case 'double':
                        return new CompiledExpression('int', '(int) '.$resolved->getCode(), $expression);

                    case 'bool':
                        return new CompiledExpression('int', $resolved->getBooleanCode(), $expression);

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

                        /**
                         * zephir_get_intval_ex use zval variable
                         * before use with it we create a new variable and assign value of literal.
                         *
                         * @todo Optimize by creating native function for string without zval using
                         */
                        $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('string', $compilationContext);
                        $let = new LetVariable();
                        $original = $resolved->getOriginal();
                        $original['operator'] = 'assign';
                        $let->assign($symbolVariable->getName(), $symbolVariable, $resolved, new ReadDetector(), $compilationContext, $original);
                        $symbol = $compilationContext->backend->getVariableCode($symbolVariable);

                        return new CompiledExpression('int', 'zephir_get_intval_ex('.$symbol.')', $expression);

                    case 'array':
                        $compilationContext->headersManager->add('kernel/operators');
                        $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                        $symbol = $compilationContext->backend->getVariableCode($symbolVariable);

                        return new CompiledExpression('int', 'zephir_get_intval('.$symbol.')', $expression);

                    case 'variable':
                        $compilationContext->headersManager->add('kernel/operators');
                        $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                        switch ($symbolVariable->getType()) {
                            case 'int':
                                return new CompiledExpression('int', $symbolVariable->getName(), $expression);

                            case 'double':
                                return new CompiledExpression('int', '(int) ('.$symbolVariable->getName().')', $expression);

                            case 'bool':
                                return new CompiledExpression('int', '(int) ('.$symbolVariable->getName().')', $expression);

                            case 'array':
                            case 'variable':
                            case 'string':
                                $symbol = $compilationContext->backend->getVariableCode($symbolVariable);

                                return new CompiledExpression('int', 'zephir_get_intval('.$symbol.')', $expression);

                            default:
                                throw new CompilerException('Cannot cast: '.$resolved->getType().'('.$symbolVariable->getType().') to '.$expression['left'], $expression);
                        }
                        break;

                    default:
                        throw new CompilerException('Cannot cast: '.$resolved->getType().' to '.$expression['left'], $expression);
                }
                break;

            case 'long':
                switch ($resolved->getType()) {
                    case 'int':
                        return new CompiledExpression('long', $resolved->getCode(), $expression);

                    case 'double':
                        return new CompiledExpression('long', '(long) '.$resolved->getCode(), $expression);

                    case 'bool':
                        return new CompiledExpression('long', $resolved->getBooleanCode(), $expression);

                    case 'array':
                        $compilationContext->headersManager->add('kernel/operators');
                        $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);

                        return new CompiledExpression('long', 'zephir_get_intval('.$symbolVariable->getName().')', $expression);

                    case 'variable':
                        $compilationContext->headersManager->add('kernel/operators');
                        $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                        switch ($symbolVariable->getType()) {
                            case 'int':
                                return new CompiledExpression('long', $symbolVariable->getName(), $expression);
                            case 'double':
                                return new CompiledExpression('long', '(long) ('.$symbolVariable->getName().')', $expression);
                            case 'variable':
                                $symbol = $compilationContext->backend->getVariableCode($symbolVariable);

                                return new CompiledExpression('long', 'zephir_get_intval('.$symbol.')', $expression);
                            default:
                                throw new CompilerException('Cannot cast: '.$resolved->getType().'('.$symbolVariable->getType().') to '.$expression['left'], $expression);
                        }
                        break;

                    default:
                        throw new CompilerException('Cannot cast: '.$resolved->getType().' to '.$expression['left'], $expression);
                }
                break;

            case 'double':
                switch ($resolved->getType()) {
                    case 'null':
                        return new CompiledExpression('double', 0, $expression);

                    case 'bool':
                        return new CompiledExpression('double', $resolved->getBooleanCode(), $expression);

                    case 'double':
                        return new CompiledExpression('double', $resolved->getCode(), $expression);

                    case 'array':
                        $compilationContext->headersManager->add('kernel/operators');
                        $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                        $symbol = $compilationContext->backend->getVariableCode($symbolVariable);

                        return new CompiledExpression('double', 'zephir_get_doubleval('.$symbol.')', $expression);

                    case 'variable':
                        $compilationContext->headersManager->add('kernel/operators');
                        $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);

                        switch ($symbolVariable->getType()) {
                            case 'int':
                                return new CompiledExpression('double', $symbolVariable->getName(), $expression);
                            case 'double':
                                return new CompiledExpression('double', '(double) ('.$symbolVariable->getName().')', $expression);
                            case 'bool':
                                return new CompiledExpression('double', '(double) ('.$symbolVariable->getName().')', $expression);
                            case 'array':
                            case 'variable':
                                $symbol = $compilationContext->backend->getVariableCode($symbolVariable);

                                return new CompiledExpression('double', 'zephir_get_doubleval('.$symbol.')', $expression);
                            default:
                                throw new CompilerException('Cannot cast: '.$resolved->getType().'('.$symbolVariable->getType().') to '.$expression['left'], $expression);
                        }
                        break;

                    default:
                        throw new CompilerException('Cannot cast: '.$resolved->getType().' to '.$expression['left'], $expression);
                }
                break;

            case 'bool':
                switch ($resolved->getType()) {
                    case 'int':
                        return new CompiledExpression('bool', '(zend_bool) '.$resolved->getCode(), $expression);
                    case 'bool':
                        return new CompiledExpression('bool', $resolved->getCode(), $expression);

                    case 'variable':
                        $compilationContext->headersManager->add('kernel/operators');
                        $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                        $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
                        if ($symbolVariable->isTemporal()) {
                            $symbolVariable->setIdle(true);
                        }
                        switch ($symbolVariable->getType()) {
                            case 'variable':
                                return new CompiledExpression('bool', 'zephir_get_boolval('.$symbol.')', $expression);
                            default:
                                throw new CompilerException('Cannot cast: '.$resolved->getType().'('.$symbolVariable->getType().') to '.$expression['left'], $expression);
                        }
                        break;

                    default:
                        throw new CompilerException('Cannot cast: '.$resolved->getType().' to '.$expression['left'], $expression);
                }
                break;

            case 'char':
                switch ($resolved->getType()) {
                    case 'variable':
                        $compilationContext->headersManager->add('kernel/operators');
                        $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('char', $compilationContext);
                        $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                        $variableCode = $compilationContext->backend->getVariableCode($symbolVariable);
                        $compilationContext->codePrinter->output($tempVariable->getName().' = (char) zephir_get_intval('.$variableCode.');');

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

                    default:
                        throw new CompilerException('Cannot cast: '.$resolved->getType().' to '.$expression['left'], $expression);
                }
                break;

            case 'string':
                switch ($resolved->getType()) {
                    case 'variable':
                        $compilationContext->headersManager->add('kernel/operators');
                        $compilationContext->symbolTable->mustGrownStack(true);
                        $symbolVariable = $compilationContext->symbolTable->getTempVariable('string', $compilationContext);
                        $symbolVariable->setMustInitNull(true);
                        $symbolVariable->setIsInitialized(true, $compilationContext);
                        $symbolVariable->increaseUses();
                        $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
                        $resolvedVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext);
                        $resolvedCode = $compilationContext->backend->getVariableCode($resolvedVariable);
                        $compilationContext->codePrinter->output('zephir_get_strval('.$symbol.', '.$resolvedCode.');');
                        if ($symbolVariable->isTemporal()) {
                            $symbolVariable->setIdle(true);
                        }

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

                    default:
                        throw new CompilerException('Cannot cast: '.$resolved->getType().' to '.$expression['left'], $expression);
                }
                break;

            case 'array':
                switch ($resolved->getType()) {
                    case 'variable':
                        $compilationContext->headersManager->add('kernel/operators');
                        $compilationContext->symbolTable->mustGrownStack(true);
                        $symbolVariable = $compilationContext->symbolTable->getTempVariable('array', $compilationContext);
                        $symbolVariable->setMustInitNull(true);
                        $symbolVariable->setIsInitialized(true, $compilationContext);
                        $symbolVariable->increaseUses();
                        $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
                        $resolvedVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext);
                        $resolvedCode = $compilationContext->backend->getVariableCode($resolvedVariable);
                        $compilationContext->codePrinter->output('zephir_get_arrval('.$symbol.', '.$resolvedCode.');');
                        if ($symbolVariable->isTemporal()) {
                            $symbolVariable->setIdle(true);
                        }

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

                    default:
                        throw new CompilerException('Cannot cast: '.$resolved->getType().' to '.$expression['left'], $expression);
                }
                break;

            case 'object':
                switch ($resolved->getType()) {
                    case 'int':
                    case 'double':
                    case 'bool':
                    case 'null':
                    case 'string':
                    case 'array':
                        $compilationContext->headersManager->add('kernel/operators');
                        $compilationContext->symbolTable->mustGrownStack(true);
                        $symbolVariable = $compilationContext->symbolTable->getTempVariable('variable', $compilationContext);
                        $symbol = $compilationContext->backend->getVariableCode($symbolVariable);

                        /**
                         * zephir_convert_to_object use zval variable
                         * before use with it we create a new variable and assign value of literal.
                         */
                        $let = new LetVariable();
                        $original = $resolved->getOriginal();
                        $original['operator'] = 'assign';
                        $let->assign($symbolVariable->getName(), $symbolVariable, $resolved, new ReadDetector(), $compilationContext, $original);

                        $compilationContext->codePrinter->output('zephir_convert_to_object('.$symbol.');');

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

                    case 'variable':
                        $compilationContext->headersManager->add('kernel/operators');
                        $symbolVariable = $compilationContext->symbolTable->getVariableForRead($resolved->getCode(), $compilationContext, $expression);
                        $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
                        if ($symbolVariable->isTemporal()) {
                            $symbolVariable->setIdle(true);
                        }

                        $compilationContext->codePrinter->output('zephir_convert_to_object('.$symbol.');');

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

                    default:
                        throw new CompilerException('Cannot cast: '.$resolved->getType().' to '.$expression['left'], $expression);
                }
                break;

            default:
                throw new CompilerException('Cannot cast: '.$resolved->getType().' to '.$expression['left'], $expression);
        }
    }
633721
public function compile($expression, CompilationContext $compilationContext)
    {
        $className = $expression['left']['value'];
        $compiler = $compilationContext->compiler;
        $property = $expression['right']['value'];

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

        if (!$classDefinition->hasProperty($property)) {
            throw new CompilerException("Class '".$classDefinition->getCompleteName()."' does not have a property called: '".$property."'", $expression);
        }

        /** @var ClassProperty $propertyDefinition */
        $propertyDefinition = $classDefinition->getProperty($property);
        if (!$propertyDefinition->isStatic()) {
            throw new CompilerException("Cannot access non-static property '".$classDefinition->getCompleteName().'::'.$property."'", $expression);
        }

        if ($propertyDefinition->isPrivate()) {
            if ($classDefinition != $compilationContext->classDefinition) {
                throw new CompilerException("Cannot access private static property '".$classDefinition->getCompleteName().'::'.$property."' out of its declaring context", $expression);
            }
        }

        if ($propertyDefinition->isProtected()) {
            if ($classDefinition != $compilationContext->classDefinition && $classDefinition != $compilationContext->classDefinition->getExtendsClassDefinition()) {
                throw new CompilerException("Cannot access protected static property '".$classDefinition->getCompleteName().'::'.$property."' out of its declaring context", $expression);
            }
        }

        /*
         * Resolves the symbol that expects the value
         */
        if ($this->expecting) {
            if ($this->expectingVariable) {
                $symbolVariable = $this->expectingVariable;
                if ('return_value' == $symbolVariable->getName()) {
                    $symbolVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
                }
            } else {
                $symbolVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
            }
        } else {
            $symbolVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
        }

        /*
         * 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');

        $readOnly = $this->readOnly;
        if (!$readOnly) {
            if ('return_value' != $symbolVariable->getName()) {
                $symbolVariable->observeVariant($compilationContext);
            }
        }
        $compilationContext->backend->fetchStaticProperty($symbolVariable, $classDefinition, $property, $this->readOnly, $compilationContext);

        return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
    }
1019420
public function compile(CompilationContext $compilationContext)
    {
        $this->processValue($compilationContext);

        $constanValue = isset($this->value['value']) ? $this->value['value'] : null;

        $compilationContext->backend->declareConstant(
            $this->value['type'],
            $this->getName(),
            $constanValue,
            $compilationContext
        );
    }
661163
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);
            }
        }

        $expr = new EvalExpression();
        $condition = $expr->optimize($expression['left'], $compilationContext);
        $compilationContext->codePrinter->output('if ('.$condition.') {');

        $compilationContext->codePrinter->increaseLevel();

        /**
         * Create an implicit 'let' operation to update the evaluated left operator.
         */
        $statement = new LetStatement([
            'type' => 'let',
            'assignments' => [
                [
                    'assign-type' => 'variable',
                    'variable' => $returnVariable->getName(),
                    'operator' => 'assign',
                    'expr' => $expression['right'],
                    'file' => $expression['file'],
                    'line' => $expression['line'],
                    'char' => $expression['char'],
                ],
            ],
        ]);
        $statement->compile($compilationContext);

        $compilationContext->codePrinter->decreaseLevel();
        $compilationContext->codePrinter->output('} else {');
        $compilationContext->codePrinter->increaseLevel();

        /**
         * Create an implicit 'let' operation to update the evaluated left operator.
         */
        $statement = new LetStatement([
            'type' => 'let',
            'assignments' => [
                [
                    'assign-type' => 'variable',
                    'variable' => $returnVariable->getName(),
                    'operator' => 'assign',
                    'expr' => $expression['extra'],
                    'file' => $expression['file'],
                    'line' => $expression['line'],
                    'char' => $expression['char'],
                ],
            ],
        ]);
        $statement->compile($compilationContext);

        $compilationContext->codePrinter->decreaseLevel();
        $compilationContext->codePrinter->output('}');

        return new CompiledExpression('variable', $returnVariable->getName(), $expression);
    }
690985
public function optimize(array $expression, Call $call, CompilationContext $context)
    {
        if (!isset($expression['parameters'])) {
            return false;
        }

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

        /*
         * 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);
        }

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

        $symbolVariable->setDynamicTypes('array');

        $resolvedParams = $call->getReadOnlyResolvedParams($expression['parameters'], $context, $expression);
        if ($call->mustInitSymbolVariable()) {
            $symbolVariable->initVariant($context);
        }
        $symbol = $context->backend->getVariableCode($symbolVariable);
        $resolveParam = $this->createParamResolver($context);
        $context->codePrinter->output('zephir_fast_array_merge('.$symbol.', '.$resolveParam($resolvedParams[0]).', '.$resolveParam($resolvedParams[1]).' TSRMLS_CC);');

        return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
    }
168353
public function compile(array $expression, CompilationContext $compilationContext)
    {
        $compilationContext->headersManager->add('kernel/object');

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

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

        $clonedVariable = $compilationContext->symbolTable->getVariableForRead($exprCompiledVariable->getCode(), $compilationContext, $expression);
        if ('variable' != $clonedVariable->getType()) {
            throw new CompilerException('Variable type: '.$exprVariable->getType().' cannot be cloned');
        }

        if ($clonedVariable->hasDifferentDynamicType(['undefined', 'object', 'null'])) {
            $compilationContext->logger->warning(
                'Possible attempt to use non array in "clone" operator',
                ['non-valid-clone', $expression]
            );
        }

        $symbolVariable = $this->getExpected($compilationContext, $expression);
        if (!$symbolVariable->isVariable()) {
            throw new CompilerException('Objects can only be cloned into dynamic variables', $expression);
        }

        $symbolVariable->setDynamicTypes('object');

        $symbolVariable->setIsInitialized(true, $compilationContext);

        /* Inherit the dynamic type data from the cloned object */
        $symbolVariable->setDynamicTypes($clonedVariable->getDynamicTypes());
        $symbolVariable->setClassTypes($clonedVariable->getClassTypes());

        $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
        $clonedSymbol = $compilationContext->backend->getVariableCode($clonedVariable);

        $compilationContext->codePrinter->output('if (zephir_clone('.$symbol.', '.$clonedSymbol.' TSRMLS_CC) == FAILURE) {');
        $compilationContext->codePrinter->output("\t".'RETURN_MM();');
        $compilationContext->codePrinter->output('}');

        return new CompiledExpression('variable', $symbolVariable->getName(), $expression);
    }
511614
public function initVariant(CompilationContext $compilationContext)
    {
        if ($this->numberSkips) {
            --$this->numberSkips;

            return;
        }

        /*
         * Variables are allocated for the first time using ZEPHIR_INIT_VAR
         * the second, third, etc times are allocated using ZEPHIR_INIT_NVAR
         * Variables initialized for the first time in a cycle are always initialized using ZEPHIR_INIT_NVAR
         */
        if ('this_ptr' != $this->getName() && 'return_value' != $this->getName()) {
            if (false === $this->initBranch) {
                $this->initBranch = $compilationContext->currentBranch;
            }

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

            if (!$this->isLocalOnly()) {
                $compilationContext->symbolTable->mustGrownStack(true);
                if ($compilationContext->insideCycle) {
                    $this->mustInitNull = true;
                    $compilationContext->backend->initVar($this, $compilationContext, true, true);
                } else {
                    if ($this->variantInits > 0) {
                        if (0 === $this->initBranch) {
                            $compilationContext->codePrinter->output('ZEPHIR_INIT_BNVAR('.$this->getName().');');
                        } else {
                            $this->mustInitNull = true;
                            $compilationContext->backend->initVar($this, $compilationContext, true, true);
                        }
                    } else {
                        $compilationContext->backend->initVar($this, $compilationContext);
                    }
                }
            } else {
                if ($this->variantInits > 0 || $compilationContext->insideCycle) {
                    $this->mustInitNull = true;
                    $compilationContext->codePrinter->output('ZEPHIR_SINIT_NVAR('.$this->getName().');');
                } else {
                    $compilationContext->codePrinter->output('ZEPHIR_SINIT_VAR('.$this->getName().');');
                }
            }

            ++$this->variantInits;
            $this->associatedClass = null;
        }
    }