Separates variables before being updated.

@param CompilationContext $compilationContext
557380
public function separate(CompilationContext $compilationContext)
    {
        if ('this_ptr' != $this->getName() && 'return_value' != $this->getName()) {
            $compilationContext->codePrinter->output('ZEPHIR_SEPARATE('.$compilationContext->backend->getVariableCode($this).');');
        }
    }
567389
protected function _beforeUpdate(KDatabaseContextInterface $context)
    {
        if(isset($this->order) && $this->hasProperty('ordering')) {
            $this->order($this->order);
        }
    }
612598
public function optimize($exprRaw, CompilationContext $compilationContext)
    {
        $conditions = $this->optimizeNot($exprRaw, $compilationContext);

        if (false !== $conditions) {
            return $conditions;
        }

        /*
         * Discard first level parentheses
         */
        if ('list' == $exprRaw['type']) {
            $expr = new Expression($exprRaw['left']);
        } else {
            $expr = new Expression($exprRaw);
        }

        $expr->setReadOnly(true);
        $expr->setEvalMode(true);
        $compiledExpression = $expr->compile($compilationContext);

        /*
         * Possible corrupted expression?
         */
        if (!\is_object($compiledExpression)) {
            throw new CompilerException('Corrupted expression: '.$exprRaw['type'], $exprRaw);
        }

        /*
         * Generate the condition according to the value returned by the evaluated expression
         */
        switch ($compiledExpression->getType()) {
            case 'null':
                $this->unreachable = true;

                return '0';

            case 'int':
            case 'uint':
            case 'long':
            case 'ulong':
            case 'double':
                $code = $compiledExpression->getCode();
                if (is_numeric($code)) {
                    if ('1' == $code) {
                        $this->unreachableElse = true;
                    } else {
                        $this->unreachable = true;
                    }
                }

                return $code;

            case 'char':
            case 'uchar':
                return $compiledExpression->getCode();

            case 'bool':
                $code = $compiledExpression->getBooleanCode();
                if ('1' == $code) {
                    $this->unreachableElse = true;
                } else {
                    if ('0' == $code) {
                        $this->unreachable = true;
                    }
                }

                return $code;

            case 'variable':
                $variableRight = $compilationContext->symbolTable->getVariableForRead($compiledExpression->getCode(), $compilationContext, $exprRaw);
                $possibleValue = $variableRight->getPossibleValue();
                if (\is_object($possibleValue)) {
                    $possibleValueBranch = $variableRight->getPossibleValueBranch();
                    if ($possibleValueBranch instanceof Branch) {
                        /*
                         * Check if the possible value was assigned in the root branch
                         */
                        if (Branch::TYPE_ROOT == $possibleValueBranch->getType()) {
                            if ($possibleValue instanceof LiteralCompiledExpression) {
                                switch ($possibleValue->getType()) {
                                    case 'null':
                                        $this->unreachable = true;
                                        break;

                                    case 'bool':
                                        if ('0' == $possibleValue->getBooleanCode()) {
                                            $this->unreachable = true;
                                        } else {
                                            $this->unreachableElse = true;
                                        }
                                        break;

                                    case 'int':
                                        if (!(int) ($possibleValue->getCode())) {
                                            $this->unreachable = true;
                                        } else {
                                            $this->unreachableElse = true;
                                        }
                                        break;

                                    case 'double':
                                        if (!(float) ($possibleValue->getCode())) {
                                            $this->unreachable = true;
                                        } else {
                                            $this->unreachableElse = true;
                                        }
                                        break;

                                    default:
                                        //echo $possibleValue->getType();
                                }
                            }
                        }
                    }
                }

                $this->usedVariables[] = $variableRight->getName();

                /*
                 * Evaluate the variable
                 */
                switch ($variableRight->getType()) {
                    case 'int':
                    case 'uint':
                    case 'char':
                    case 'uchar':
                    case 'long':
                    case 'ulong':
                        return $variableRight->getName();

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

                        return '!('.$compilationContext->backend->ifVariableValueUndefined($variableRight, $compilationContext, true, false).') && Z_STRLEN_P('.$variableRightCode.')';

                    case 'bool':
                        return $variableRight->getName();

                    case 'double':
                        return $variableRight->getName();

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

                        return 'zephir_is_true('.$variableRightCode.')';

                    default:
                        throw new CompilerException("Variable can't be evaluated ".$variableRight->getType(), $exprRaw);
                }
                break;

            default:
                throw new CompilerException('Expression '.$compiledExpression->getType()." can't be evaluated", $exprRaw);
        }
    }
910170
public function addCallStatusFlag(CompilationContext $compilationContext)
    {
        if (!$compilationContext->symbolTable->hasVariable('ZEPHIR_LAST_CALL_STATUS')) {
            $callStatus = new Variable('int', 'ZEPHIR_LAST_CALL_STATUS', $compilationContext->branchManager->getCurrentBranch());
            $callStatus->setIsInitialized(true, $compilationContext);
            $callStatus->increaseUses();
            $callStatus->setReadOnly(true);
            $compilationContext->symbolTable->addRawVariable($callStatus);
        }
    }
924039
public function observeVariant(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);
            $symbol = $compilationContext->backend->getVariableCode($this);

            if ($this->variantInits > 0 || $compilationContext->insideCycle) {
                $this->mustInitNull = true;
                $compilationContext->codePrinter->output('ZEPHIR_OBS_NVAR('.$symbol.');');
            } else {
                $compilationContext->codePrinter->output('ZEPHIR_OBS_VAR('.$symbol.');');
            }

            ++$this->variantInits;
        }
    }
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
        );
    }
958242
public function compile(array $expression, CompilationContext $compilationContext)
    {
        $codePrinter = $compilationContext->codePrinter;

        /*
         * Resolves the symbol that expects the value
         */
        $this->literalOnly = false;
        $symbolVariable = $this->getExpectedNonLiteral($compilationContext, $expression);
        if (!$symbolVariable->isVariable()) {
            throw new CompilerException('Objects can only be instantiated into dynamic variables', $expression);
        }

        if ($symbolVariable->isLocalOnly()) {
            throw new CompilerException('Cannot use non-heap variable to store new instance', $expression);
        }

        if ('return_value' != $symbolVariable->getName()) {
            if ($symbolVariable->hasDifferentDynamicType(['unknown', 'undefined', 'object', 'null'])) {
                $compilationContext->logger->warning(
                    'Possible attempt to use non-object in "new" operator',
                    ['non-valid-new', $expression]
                );
            }
        }

        /*
         * Mark variables as dynamic objects
         */
        $symbolVariable->setDynamicTypes('object');

        $dynamic = false;
        if ('self' == $expression['class'] || 'static' == $expression['class']) {
            $className = $compilationContext->classDefinition->getCompleteName();
        } else {
            $className = $expression['class'];
            $dynamic = $expression['dynamic'];
            if (!$dynamic) {
                $className = $compilationContext->getFullName($expression['class']);
            }
        }

        if (!$className) {
            throw new CompilerException('A class name is required to instantiate the object', $expression);
        }

        /**
         * stdclass doesn't have constructors.
         */
        $lowerClassName = strtolower($className);
        $isStdClass = 'stdclass' === $lowerClassName || '\stdclass' === $lowerClassName;

        if ($isStdClass) {
            if (isset($expression['parameters']) && \count($expression['parameters']) > 0) {
                throw new CompilerException('stdclass does not receive parameters in its constructor', $expression);
            }

            $compilationContext->backend->initObject($symbolVariable, null, $compilationContext);
            $symbolVariable->setClassTypes('stdclass');
        } else {
            $classDefinition = false;
            if ($compilationContext->compiler->isClass($className)) {
                $classDefinition = $compilationContext->compiler->getClassDefinition($className);
            }

            /*
             * Classes inside the same extension
             */
            if ($classDefinition) {
                $compilationContext->backend->initObject($symbolVariable, $classDefinition->getClassEntry($compilationContext), $compilationContext);
                $symbolVariable->setClassTypes($className);
                $symbolVariable->setAssociatedClass($classDefinition);
            } else {
                /*
                 * Classes outside the extension
                 */
                if ($dynamic) {
                    $classNameVariable = $compilationContext->symbolTable->getVariableForRead($className, $compilationContext, $expression);
                    if ($classNameVariable->isNotVariableAndString()) {
                        throw new CompilerException('Only dynamic/string variables can be used in new operator. '.$classNameVariable->getName(), $expression);
                    }

                    /*
                     * Use a safe string version of the variable to avoid segfaults
                     */
                    $compilationContext->headersManager->add('kernel/object');
                    $safeSymbolVariable = $compilationContext->symbolTable->getTempVariable('variable', $compilationContext);
                    $safeSymbolVariable->setMustInitNull(true);
                    $safeSymbolVariable->setIsInitialized(true, $compilationContext);
                    $safeSymbolVariable->increaseUses();
                    $safeSymbol = $compilationContext->backend->getVariableCode($safeSymbolVariable);
                    $classNameSymbol = $compilationContext->backend->getVariableCode($classNameVariable);

                    $compilationContext->codePrinter->output('zephir_fetch_safe_class('.$safeSymbol.', '.$classNameSymbol.');');
                    $classNameToFetch = 'Z_STRVAL_P('.$safeSymbol.'), Z_STRLEN_P('.$safeSymbol.')';
                    $zendClassEntry = $compilationContext->cacheManager->getClassEntryCache()->get($classNameToFetch, true, $compilationContext);
                    $classEntry = $zendClassEntry->getName();
                } else {
                    if (!class_exists($className, false)) {
                        $compilationContext->logger->warning(
                            'Class "'.$className.'" does not exist at compile time',
                            ['nonexistent-class', $expression]
                        );
                        $classNameToFetch = 'SL("'.escape_class($className).'")';

                        $zendClassEntry = $compilationContext->cacheManager->getClassEntryCache()->get($classNameToFetch, false, $compilationContext);
                        $classEntry = $zendClassEntry->getName();
                    } else {
                        $reflectionClass = new \ReflectionClass($className);
                        if ($reflectionClass->isInterface()) {
                            throw new CompilerException('Interfaces cannot be instantiated', $expression);
                        } else {
                            if (method_exists($reflectionClass, 'isTrait')) {
                                if ($reflectionClass->isTrait()) {
                                    throw new CompilerException('Traits cannot be instantiated', $expression);
                                }
                            }
                        }

                        $classEntry = $compilationContext->classDefinition->getClassEntryByClassName($className, $compilationContext, true);
                        if (!$classEntry) {
                            $classNameToFetch = 'SL("'.escape_class($className).'")';
                            $zendClassEntry = $compilationContext->cacheManager->getClassEntryCache()->get($classNameToFetch, false, $compilationContext);
                            $classEntry = $zendClassEntry->getName();
                        } else {
                            $symbolVariable->setAssociatedClass($reflectionClass);
                        }
                    }

                    $symbolVariable->setClassTypes($className);
                }
                $compilationContext->backend->initObject($symbolVariable, $classEntry, $compilationContext);
            }
        }

        /*
         * Mark variable initialized
         */
        $symbolVariable->setIsInitialized(true, $compilationContext);

        /*
         * Don't check the constructor for stdclass instances
         */
        if ($isStdClass) {
            return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
        }

        /**
         * Call the constructor
         * For classes in the same extension we check if the class does implement a constructor
         * For external classes we always assume the class does implement a constructor.
         */
        $callConstructor = false;
        if ($compilationContext->compiler->isClass($className)) {
            $classDefinition = $compilationContext->compiler->getClassDefinition($className);

            if ('class' != $classDefinition->getType()) {
                throw new CompilerException('Only classes can be instantiated', $expression);
            }

            $callConstructor = $classDefinition->hasMethod('__construct');
        } else {
            if ($compilationContext->compiler->isBundledClass($className)) {
                $classDefinition = $compilationContext->compiler->getInternalClassDefinition($className);
                $callConstructor = $classDefinition->hasMethod('__construct');
            }
        }

        /* @TODO use the MethodBuilder here */
        if (isset($expression['parameters'])) {
            $callExpr = new Expression([
                'variable' => ['type' => 'variable', 'value' => $symbolVariable->getRealName()],
                'name' => '__construct',
                'parameters' => $expression['parameters'],
                'call-type' => MethodCall::CALL_NORMAL,
                'file' => $expression['file'],
                'line' => $expression['line'],
                'char' => $expression['char'],
                'check' => $callConstructor,
            ]);
        } else {
            $callExpr = new Expression([
                'variable' => ['type' => 'variable', 'value' => $symbolVariable->getRealName()],
                'name' => '__construct',
                'call-type' => MethodCall::CALL_NORMAL,
                'file' => $expression['file'],
                'line' => $expression['line'],
                'char' => $expression['char'],
                'check' => $callConstructor,
            ]);
        }

        /*
         * If we are certain that there is a constructor we call it, otherwise we checked it at runtime.
         */
        if ($callConstructor) {
            $methodCall = new MethodCall();
            $callExpr->setExpectReturn(false);
            $methodCall->compile($callExpr, $compilationContext);
        } else {
            $compilationContext->headersManager->add('kernel/fcall');

            /* @todo, generate the code using builders */
            $compilationContext->backend->checkConstructor($symbolVariable, $compilationContext);
            $codePrinter->increaseLevel();

            $methodCall = new MethodCall();
            $callExpr->setExpectReturn(false);
            $methodCall->compile($callExpr, $compilationContext);

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

        return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
    }
1099999
protected function registerTempVariable($type, $location, Variable $variable, CompilationContext $compilationContext = null)
    {
        $compilationContext = $compilationContext ?: $this->compilationContext;
        $branchId = $compilationContext->branchManager->getCurrentBranchId();

        if (!isset($this->branchTempVariables[$branchId][$location][$type])) {
            $this->branchTempVariables[$branchId][$location][$type] = [];
        }
        $this->branchTempVariables[$branchId][$location][$type][] = $variable;
    }
145169
public function compile($expression, CompilationContext $compilationContext)
    {
        if (!isset($expression['left'])) {
            throw new CompilerException("Invalid 'left' operand for 'typeof' expression", $expression['left']);
        }

        $functionCall = BuilderFactory::getInstance()->statements()->functionCall('gettype', [$expression['left']]);
        $expression = new Expression($functionCall->build());

        return $expression->compile($compilationContext);
    }
511195
public function compileFunction(CompilationContext $compilationContext, FunctionDefinition $functionDefinition)
    {
        /** Make sure we do not produce calls like ZEPHIR_CALL_SELF */
        $bakClassDefinition = $compilationContext->classDefinition;
        $compilationContext->classDefinition = null;
        $compilationContext->currentMethod = $functionDefinition;

        $codePrinter = $compilationContext->codePrinter;
        $codePrinter->output('PHP_FUNCTION('.$functionDefinition->getInternalName().') {');
        $functionDefinition->compile($compilationContext);
        $codePrinter->output('}');
        $codePrinter->outputBlankLine();

        /* Restore */
        $compilationContext->classDefinition = $bakClassDefinition;
        $compilationContext->currentMethod = null;
    }
695375
public function compile($expression, CompilationContext $compilationContext)
    {
        $conditions = $this->optimizeTypeOf($expression, $compilationContext);
        if (false !== $conditions) {
            return $conditions;
        }

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

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

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

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

        switch ($left->getType()) {
            case 'null':
                switch ($right->getType()) {
                    case 'null':
                        return new CompiledExpression('bool', '(0 '.$this->operator.' 0)', $expression);

                    case 'int':
                    case 'uint':
                    case 'long':
                    case 'ulong':
                        return new CompiledExpression('bool', '(0 '.$this->operator.' '.$right->getCode().')', $expression);

                    case 'char':
                    case 'uchar':
                        return new CompiledExpression('bool', '(\'\\0\' '.$this->operator.' \''.$right->getCode().'\')', $expression);

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

                    case 'variable':
                        $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                        switch ($variableRight->getType()) {
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                            case 'double':
                                $compilationContext->headersManager->add('kernel/operators');

                                return new CompiledExpression('bool', '0 '.$this->operator.' '.$variableRight->getName(), $expression);

                            case 'variable':
                                $compilationContext->headersManager->add('kernel/operators');
                                $condition = $compilationContext->backend->getTypeofCondition($variableRight, $this->operator, 'null', $compilationContext);

                                return new CompiledExpression('bool', $condition, $expression);

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

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

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

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

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

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

                    case 'variable':
                        $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                        switch ($variableRight->getType()) {
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                            case 'double':
                                $compilationContext->headersManager->add('kernel/operators');

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

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

                                return new CompiledExpression('bool', $this->zvalLongNegOperator.'('.$variableCode.', '.$left->getCode().')', $expression);

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

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

            case 'bool':
                switch ($right->getType()) {
                    case 'null':
                        return new CompiledExpression('bool', $left->getBooleanCode().' '.$this->operator.' 0', $expression);

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

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

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

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

                    case 'variable':
                        $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                        switch ($variableRight->getType()) {
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                            case 'double':
                                $compilationContext->headersManager->add('kernel/operators');

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

                            case 'variable':
                                $compilationContext->headersManager->add('kernel/operators');
                                $boolOperator = '1' == $left->getBooleanCode() ? $this->zvalBoolTrueOperator : $this->zvalBoolFalseOperator;
                                $variableRight = $compilationContext->backend->getVariableCode($variableRight);

                                return new CompiledExpression('bool', $boolOperator.'('.$variableRight.')', $expression);
                            default:
                                throw new CompilerException('Unknown type: '.$variableRight->getType(), $expression['right']);
                        }
                        break;

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

            case 'string':
                $variableLeft = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $expression);
                $variableLeftCode = $compilationContext->backend->getVariableCode($variableLeft);
                $compilationContext->backend->assignString($variableLeft, $left->getCode(), $compilationContext, true, false);
                switch ($right->getType()) {
                    case 'string':
                    case 'null':
                        $rightStr = 'null' == $right->getType() ? '' : $right->getCode();
                        $compilationContext->headersManager->add('kernel/operators');

                        return new CompiledExpression('bool', $this->zvalStringOperator.'('.$variableLeftCode.', "'.$rightStr.'")', $expression['left']);
                        break;

                    case 'variable':
                        $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                        switch ($variableRight->getType()) {
                            case 'string':
                            case 'variable':
                                $compilationContext->headersManager->add('kernel/operators');
                                $variableRight = $compilationContext->backend->getVariableCode($variableRight);

                                return new CompiledExpression('bool', $this->zvalOperator.'('.$variableLeftCode.', '.$variableRight.')', $expression);
                                break;

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

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

            case 'variable':
                $variable = $compilationContext->symbolTable->getVariableForRead($left->getCode(), $compilationContext, $expression['left']);
                $variableCode = $compilationContext->backend->getVariableCode($variable);
                switch ($variable->getType()) {
                    case 'int':
                    case 'uint':
                    case 'long':
                    case 'ulong':
                    case 'char':
                    case 'uchar':
                        switch ($right->getType()) {
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                            case 'double':
                                return new CompiledExpression('bool', $left->getCode().' '.$this->operator.' '.$right->getCode(), $expression);

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

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

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

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

                                        return new CompiledExpression('bool', $this->zvalLongNegOperator.'('.$variableRightCode.', '.$variableCode.')', $expression);
                                        break;

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

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

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

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

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

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

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

                                        return new CompiledExpression('bool', $this->zvalDoubleNegOperator.'('.$variableRightCode.', '.$variableCode.')', $expression);

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

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

                    case 'bool':
                        switch ($right->getType()) {
                            case 'int':
                                return new CompiledExpression('bool', $left->getCode().' '.$this->operator.' '.$right->getCode(), $expression['left']);

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

                            case 'null':
                                return new CompiledExpression('bool', $left->getCode().' '.$this->operator.' 0', $expression['left']);

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

                                switch ($variableRight->getType()) {
                                    case 'int':
                                    case 'uint':
                                    case 'long':
                                    case 'ulong':
                                    case 'bool':
                                    case 'double':
                                        return new CompiledExpression('bool', $variable->getName().' '.$this->operator.' '.$variableRight->getName(), $expression);

                                    case 'variable':
                                        $compilationContext->headersManager->add('kernel/operators');
                                        $boolOperator = '1' == $left->getBooleanCode() ? $this->zvalBoolTrueOperator : $this->zvalBoolFalseOperator;
                                        $variableRightCode = $compilationContext->backend->getVariableCode($variableRight);

                                        return new CompiledExpression('bool', $boolOperator.'('.$variableRightCode.')', $expression);

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

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

                    case 'array':
                        switch ($right->getType()) {
                            case 'null':
                                $compilationContext->headersManager->add('kernel/operators');

                                return new CompiledExpression('bool', $this->zvalStringOperator.'('.$variableCode.', "")', $expression['left']);

                            case 'variable':
                                $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                                switch ($variableRight->getType()) {
                                    case 'string':
                                    case 'variable':
                                    case 'array':
                                        $compilationContext->headersManager->add('kernel/operators');
                                        $variableRight = $compilationContext->backend->getVariableCode($variableRight);

                                        return new CompiledExpression('bool', $this->zvalOperator.'('.$variableCode.', '.$variableRight.')', $expression);

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

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

                    case 'string':
                        switch ($right->getType()) {
                            case 'null':
                                $compilationContext->headersManager->add('kernel/operators');

                                return new CompiledExpression('bool', $this->zvalStringOperator.'('.$variableCode.', "")', $expression['left']);

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

                                return new CompiledExpression('bool', $this->zvalStringOperator.'('.$variableCode.', "'.$right->getCode().'")', $expression['left']);

                            case 'variable':
                                $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                                switch ($variableRight->getType()) {
                                    case 'string':
                                    case 'variable':
                                        $compilationContext->headersManager->add('kernel/operators');
                                        $variableRight = $compilationContext->backend->getVariableCode($variableRight);

                                        return new CompiledExpression('bool', $this->zvalOperator.'('.$variableCode.', '.$variableRight.')', $expression);

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

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

                    case 'variable':
                        switch ($right->getType()) {
                            case 'null':
                                $compilationContext->headersManager->add('kernel/operators');
                                $condition = $compilationContext->backend->getTypeofCondition($variable, $this->operator, 'null', $compilationContext);

                                return new CompiledExpression('bool', $condition, $expression['left']);

                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                            case 'double':
                                $compilationContext->headersManager->add('kernel/operators');

                                return new CompiledExpression('bool', $this->zvalLongOperator.'('.$variableCode.', '.$right->getCode().')', $expression['left']);

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

                                return new CompiledExpression('bool', $this->zvalLongOperator.'('.$variableCode.', \''.$right->getCode().'\')', $expression['left']);

                            case 'bool':
                                $compilationContext->headersManager->add('kernel/operators');
                                $zvalBoolOperator = 'true' == $right->getCode() ? $this->zvalBoolTrueOperator : $this->zvalBoolFalseOperator;

                                return new CompiledExpression('bool', $zvalBoolOperator.'('.$variableCode.')', $expression['left']);

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

                                return new CompiledExpression('bool', $this->zvalStringOperator.'('.$variableCode.', "'.$right->getCode().'")', $expression['left']);

                            case 'variable':
                                $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['left']);
                                switch ($variableRight->getType()) {
                                    case 'int':
                                    case 'uint':
                                    case 'long':
                                    case 'ulong':
                                        $compilationContext->headersManager->add('kernel/operators');

                                        return new CompiledExpression('bool', $this->zvalLongOperator.'('.$variableCode.', '.$variableRight->getName().')', $expression);

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

                                        return new CompiledExpression('bool', $this->zvalDoubleOperator.'('.$variableCode.', '.$variableRight->getName().')', $expression);

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

                                        return new CompiledExpression('bool', $this->zvalBoolOperator.'('.$variableCode.', '.$variableRight->getName().')', $expression);

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

                                        return new CompiledExpression('bool', $this->zvalOperator.'('.$variableCode.', '.$variableRight.')', $expression);

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

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

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

            default:
                throw new CompilerException('Unknown type: '.$left->getType(), $expression);
        }
    }
60436
public function compile($expression, CompilationContext $compilationContext)
    {
        /**
         * Resolve the left part of the expression.
         */
        $expr = new Expression($expression['left']);
        $expr->setReadOnly(true);
        $exprVariable = $expr->compile($compilationContext);

        /*
         * Only dynamic variables can be used as arrays
         */
        switch ($exprVariable->getType()) {
            case 'variable':
                $variableVariable = $compilationContext->symbolTable->getVariableForRead($exprVariable->getCode(), $compilationContext, $expression);
                switch ($variableVariable->getType()) {
                    case 'variable':
                    case 'array':
                    case 'string':
                        break;

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

            default:
                throw new CompilerException('Cannot use expression: '.$exprVariable->getType().' as an array', $expression['left']);
        }

        /*
         * Resolve the dimension according to variable's type
         */
        switch ($variableVariable->getType()) {
            case 'variable':
                return $this->_accessDimensionArray($expression, $variableVariable, $compilationContext);

            case 'array':
                return $this->_accessDimensionArray($expression, $variableVariable, $compilationContext);

            case 'string':
                return $this->_accessStringOffset($expression, $variableVariable, $compilationContext);
        }
    }
134678
public function compile($expression, CompilationContext $compilationContext)
    {
        /*
         * Resolves the symbol that expects the value
         */
        if ($this->expecting) {
            if ($this->expectingVariable) {
                $symbolVariable = $this->expectingVariable;
                if ('variable' != $symbolVariable->getType() && 'array' != $symbolVariable->getType()) {
                    throw new CompilerException('Cannot use variable type: '.$symbolVariable->getType().' as an array', $expression);
                }
            } else {
                $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('array', $compilationContext, $expression);
            }
        } else {
            $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('array', $compilationContext, $expression);
        }

        if (!isset($expression['left'])) {
            if ($this->expectingVariable) {
                $symbolVariable->initVariant($compilationContext);
            }
            /*+
             * Mark the variable as an array
             */
            $symbolVariable->setDynamicTypes('array');

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

        $codePrinter = $compilationContext->codePrinter;

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

        /**
         * This calculates a prime number bigger than the current array size to possibly
         * reduce hash collisions when adding new members to the array.
         */
        $arrayLength = \count($expression['left']);
        if ($arrayLength >= 33 && \function_exists('gmp_nextprime')) {
            $arrayLength = gmp_strval(gmp_nextprime($arrayLength - 1));
        }
        $oldSymbolVariable = $symbolVariable;
        if ($this->expectingVariable && $symbolVariable->geVariantInits() >= 1) {
            $symbolVariable = $compilationContext->symbolTable->addTemp('variable', $compilationContext);
            $symbolVariable->initVariant($compilationContext);
            $compilationContext->backend->initArray($symbolVariable, $compilationContext, $arrayLength > 0 ? $arrayLength : null);
            $symbolVariable->setDynamicTypes('array');
        } else {
            if ($this->expectingVariable) {
                $symbolVariable->initVariant($compilationContext);
            }
            /*+
             * Mark the variable as an array
             */
            $symbolVariable->setDynamicTypes('array');
            $compilationContext->backend->initArray($symbolVariable, $compilationContext, $arrayLength > 0 ? $arrayLength : null);
        }
        foreach ($expression['left'] as $item) {
            if (isset($item['key'])) {
                $key = null;
                $exprKey = new Expression($item['key']);
                $resolvedExprKey = $exprKey->compile($compilationContext);

                switch ($resolvedExprKey->getType()) {
                    case 'string':
                        $expr = new Expression($item['value']);
                        $resolvedExpr = $expr->compile($compilationContext);
                        switch ($resolvedExpr->getType()) {
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                            case 'double':
                                $compilationContext->backend->addArrayEntry($symbolVariable, $resolvedExprKey, $resolvedExpr, $compilationContext);
                                break;

                            case 'bool':
                                $compilationContext->headersManager->add('kernel/array');
                                if ('true' == $resolvedExpr->getCode()) {
                                    $compilationContext->backend->updateArray($symbolVariable, $resolvedExprKey, 'true', $compilationContext, 'PH_COPY | PH_SEPARATE');
                                } else {
                                    $compilationContext->backend->updateArray($symbolVariable, $resolvedExprKey, 'false', $compilationContext, 'PH_COPY | PH_SEPARATE');
                                }
                                break;

                            case 'string':
                                $compilationContext->backend->addArrayEntry($symbolVariable, $resolvedExprKey, $resolvedExpr, $compilationContext);
                                break;

                            case 'null':
                                $compilationContext->backend->updateArray($symbolVariable, $resolvedExprKey, 'null', $compilationContext, 'PH_COPY | PH_SEPARATE');
                                break;

                            case 'array':
                            case 'variable':
                                $valueVariable = $this->getArrayValue($resolvedExpr, $compilationContext);
                                $compilationContext->backend->updateArray($symbolVariable, $resolvedExprKey, $valueVariable, $compilationContext, 'PH_COPY | PH_SEPARATE');
                                if ($valueVariable->isTemporal()) {
                                    $valueVariable->setIdle(true);
                                }
                                break;

                            default:
                                throw new CompilerException('Invalid value type: '.$resolvedExpr->getType(), $item['value']);
                        }
                        break;

                    case 'int':
                    case 'uint':
                    case 'long':
                    case 'ulong':
                        $expr = new Expression($item['value']);
                        $resolvedExpr = $expr->compile($compilationContext);
                        switch ($resolvedExpr->getType()) {
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                            case 'double':
                            case 'string':
                                $compilationContext->backend->addArrayEntry($symbolVariable, $resolvedExprKey, $resolvedExpr, $compilationContext);
                                break;

                            case 'bool':
                                if ('true' == $resolvedExpr->getCode()) {
                                    $compilationContext->backend->updateArray($symbolVariable, $resolvedExprKey, 'true', $compilationContext, 'PH_COPY');
                                } else {
                                    $compilationContext->backend->updateArray($symbolVariable, $resolvedExprKey, 'false', $compilationContext, 'PH_COPY');
                                }
                                break;

                            case 'null':
                                $compilationContext->backend->updateArray($symbolVariable, $resolvedExprKey, 'null', $compilationContext, 'PH_COPY');
                                break;

                            case 'array':
                            case 'variable':
                                $valueVariable = $this->getArrayValue($resolvedExpr, $compilationContext);
                                $compilationContext->backend->updateArray($symbolVariable, $resolvedExprKey, $valueVariable, $compilationContext, 'PH_COPY');
                                if ($valueVariable->isTemporal()) {
                                    $valueVariable->setIdle(true);
                                }
                                break;

                            default:
                                throw new CompilerException('Invalid value type: '.$item['value']['type'], $item['value']);
                        }
                        break;

                    case 'variable':
                        $variableVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExprKey->getCode(), $compilationContext, $item['key']);
                        switch ($variableVariable->getType()) {
                            case 'int':
                            case 'uint':
                            case 'long':
                            case 'ulong':
                                $expr = new Expression($item['value']);
                                $resolvedExpr = $expr->compile($compilationContext);
                                switch ($resolvedExpr->getType()) {
                                    case 'int':
                                    case 'uint':
                                    case 'long':
                                    case 'ulong':
                                    case 'bool':
                                    case 'double':
                                    case 'null':
                                    case 'string':
                                        $compilationContext->backend->addArrayEntry($symbolVariable, $resolvedExprKey, $resolvedExpr, $compilationContext);
                                        break;

                                    case 'variable':
                                        $valueVariable = $this->getArrayValue($resolvedExpr, $compilationContext);
                                        $compilationContext->backend->updateArray($symbolVariable, $resolvedExprKey, $valueVariable, $compilationContext, 'PH_COPY');
                                        if ($valueVariable->isTemporal()) {
                                            $valueVariable->setIdle(true);
                                        }
                                        break;

                                    default:
                                        throw new CompilerException('Invalid value type: '.$item['value']['type'], $item['value']);
                                }
                                break;

                            case 'string':
                                $expr = new Expression($item['value']);
                                $resolvedExpr = $expr->compile($compilationContext);
                                switch ($resolvedExpr->getType()) {
                                    case 'int':
                                    case 'uint':
                                    case 'long':
                                    case 'ulong':
                                        $codePrinter->output('add_assoc_long_ex('.$symbolVariable->getName().', Z_STRVAL_P('.$resolvedExprKey->getCode().'), Z_STRLEN_P('.$item['key']['value'].'), '.$resolvedExpr->getCode().');');
                                        break;

                                    case 'double':
                                        $codePrinter->output('add_assoc_double_ex('.$symbolVariable->getName().', Z_STRVAL_P('.$resolvedExprKey->getCode().'), Z_STRLEN_P('.$item['key']['value'].'), '.$resolvedExpr->getCode().');');
                                        break;

                                    case 'bool':
                                        $codePrinter->output('add_assoc_bool_ex('.$symbolVariable->getName().', Z_STRVAL_P('.$resolvedExprKey->getCode().'), Z_STRLEN_P('.$item['key']['value'].'), '.$resolvedExpr->getBooleanCode().');');
                                        break;

                                    case 'string':
                                        $compilationContext->backend->addArrayEntry($symbolVariable, $resolvedExprKey, $resolvedExpr, $compilationContext);
                                        break;

                                    case 'null':
                                        $codePrinter->output('add_assoc_null_ex('.$symbolVariable->getName().', Z_STRVAL_P('.$resolvedExprKey->getCode().'), Z_STRLEN_P('.$item['key']['value'].') + 1);');
                                        break;

                                    case 'variable':
                                        $valueVariable = $this->getArrayValue($resolvedExpr, $compilationContext);
                                        $compilationContext->backend->updateArray($symbolVariable, $resolvedExprKey, $resolvedExpr, $compilationContext);
                                        if ($valueVariable->isTemporal()) {
                                            $valueVariable->setIdle(true);
                                        }
                                        break;

                                    default:
                                        throw new CompilerException('Invalid value type: '.$resolvedExpr->getType(), $item['value']);
                                }
                                break;

                            case 'variable':
                                $expr = new Expression($item['value']);
                                $resolvedExpr = $expr->compile($compilationContext);
                                switch ($resolvedExpr->getType()) {
                                    case 'null':
                                    case 'bool':
                                        $valueVariable = $this->getArrayValue($resolvedExpr, $compilationContext);
                                        $compilationContext->backend->updateArray($symbolVariable, $variableVariable, $valueVariable, $compilationContext);

                                        if ($valueVariable->isTemporal()) {
                                            $valueVariable->setIdle(true);
                                        }
                                        break;

                                    case 'variable':
                                        $valueVariable = $this->getArrayValue($resolvedExpr, $compilationContext);
                                        $compilationContext->backend->updateArray($symbolVariable, $variableVariable, $valueVariable, $compilationContext);

                                        if ($valueVariable->isTemporal()) {
                                            $valueVariable->setIdle(true);
                                        }
                                        break;

                                    default:
                                        throw new CompilerException('Invalid value type: '.$item['value']['type'], $item['value']);
                                }
                                break;

                            default:
                                throw new CompilerException('Cannot use variable type: '.$variableVariable->getType().' as array index', $item['key']);
                        }
                        break;

                    default:
                        throw new CompilerException('Invalid key type: '.$resolvedExprKey->getType(), $item['key']);
                }
            } else {
                $expr = new Expression($item['value']);
                $resolvedExpr = $expr->compile($compilationContext);
                $itemVariable = $this->getArrayValue($resolvedExpr, $compilationContext);
                $symbol = $compilationContext->backend->getVariableCode($symbolVariable);
                $item = $compilationContext->backend->resolveValue($itemVariable, $compilationContext);
                $codePrinter->output('zephir_array_fast_append('.$symbol.', '.$item.');');
                if ($itemVariable->isTemporal()) {
                    $itemVariable->setIdle(true);
                }
            }
        }

        return new CompiledExpression('array', $symbolVariable->getRealName(), $expression);
    }
1284267
public function getExpected(CompilationContext $compilationContext, $expression, $init = true)
    {
        $isExpecting = $this->expecting;
        $symbolVariable = $this->expectingVariable;

        if ($isExpecting) {
            if (\is_object($symbolVariable)) {
                if ('variable' == $symbolVariable->getType()) {
                    if (!$init) {
                        return $symbolVariable;
                    }
                    $symbolVariable->initVariant($compilationContext);
                } else {
                    if (!$this->readOnly) {
                        if (!$this->literalOnly) {
                            $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $expression);
                        } else {
                            $symbolVariable = $compilationContext->symbolTable->getTempComplexLiteralVariableForWrite('variable', $compilationContext, $expression);
                        }
                    } else {
                        $symbolVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $expression);
                    }
                }
            } else {
                if (!$this->readOnly) {
                    if (!$this->literalOnly) {
                        $symbolVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $expression);
                    } else {
                        $symbolVariable = $compilationContext->symbolTable->getTempComplexLiteralVariableForWrite('variable', $compilationContext, $expression);
                    }
                } else {
                    $symbolVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $expression);
                }
            }
        }

        return $symbolVariable;
    }
167701
protected function _beforeRender(ControllerContext $context)
    {
        $controller = $context->getSubject();

        if (!$controller->isDispatched()) {
            $controller->loadLanguage();
        }
    }
181499
public function compile(Expression $expr, CompilationContext $compilationContext)
    {
        $expression = $expr->getExpression();

        $exprVariable = new Expression($expression['variable']);
        $exprVariable->setReadOnly(true);
        $exprCompiledVariable = $exprVariable->compile($compilationContext);

        $builtInType = false;
        switch ($exprCompiledVariable->getType()) {
            case 'variable':
                $variableVariable = $compilationContext->symbolTable->getVariableForRead(
                    $exprCompiledVariable->getCode(),
                    $compilationContext,
                    $expression
                );
                switch ($variableVariable->getType()) {
                    case 'variable':
                        $caller = $variableVariable;
                        break;
                    default:
                        /* Check if there is a built-in type optimizer available */
                        $builtInTypeClass = 'Zephir\Types\\'.ucfirst($variableVariable->getType()).'Type';
                        if (class_exists($builtInTypeClass)) {
                            /**
                             * @var \Zephir\Types\AbstractType
                             */
                            $builtInType = new $builtInTypeClass();
                            $caller = $exprCompiledVariable;
                        } else {
                            throw new CompilerException(
                                'Methods cannot be called on variable type: '.$variableVariable->getType(),
                                $expression
                            );
                        }
                }
                break;
            default:
                /* Check if there is a built-in type optimizer available */
                $builtInTypeClass = 'Zephir\Types\\'.ucfirst($exprCompiledVariable->getType()).'Type';
                if (class_exists($builtInTypeClass)) {
                    $builtInType = new $builtInTypeClass();
                    $caller = $exprCompiledVariable;
                } else {
                    throw new CompilerException(
                        'Cannot use expression: '.$exprCompiledVariable->getType().' as method caller',
                        $expression['variable']
                    );
                }
        }

        $codePrinter = $compilationContext->codePrinter;

        $type = $expression['call-type'];

        /*
         * In normal method calls and dynamic string method calls we just use the name given by the user
         */
        if (self::CALL_NORMAL == $type || self::CALL_DYNAMIC_STRING == $type) {
            $methodName = strtolower($expression['name']);
        } else {
            $variableMethod = $compilationContext->symbolTable->getVariableForRead(
                $expression['name'],
                $compilationContext,
                $expression
            );

            if (\is_object($builtInType)) {
                throw new CompilerException(
                    'Dynamic method invocation for type: '.$variableMethod->getType().' is not supported',
                    $expression
                );
            }

            if ($variableMethod->isNotVariableAndString()) {
                throw new CompilerException(
                    'Cannot use variable type: '.$variableMethod->getType().' as dynamic method name',
                    $expression
                );
            }
        }

        $symbolVariable = null;

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

        /*
         * Method calls only return zvals so we need to validate the target variable is also a zval
         */
        if (!$builtInType) {
            if ($isExpecting) {
                if (!$symbolVariable->isVariable()) {
                    throw new CompilerException(
                        'Returned values by functions can only be assigned to variant variables',
                        $expression
                    );
                }

                /*
                 * At this point, we don't know the exact dynamic type returned by the method call
                 */
                $symbolVariable->setDynamicTypes('undefined');
            }
        } else {
            return $builtInType->invokeMethod($methodName, $caller, $compilationContext, $this, $expression);
        }

        $check = true;
        if (isset($expression['check'])) {
            $check = $expression['check'];
        }

        /*
         * Try to check if the method exist in the callee, only when method call is self::CALL_NORMAL
         */
        if (self::CALL_NORMAL == $type) {
            if ('this' == $variableVariable->getRealName()) {
                $classDefinition = $compilationContext->classDefinition;
                if (!$classDefinition->hasMethod($methodName)) {
                    if ($check) {
                        $found = false;

                        if ($classDefinition->isAbstract()) {
                            $interfaces = $classDefinition->getImplementedInterfaces();
                        } else {
                            $interfaces = null;
                        }

                        if (\is_array($interfaces)) {
                            $compiler = $compilationContext->compiler;
                            foreach ($interfaces as $interface) {
                                $classInterfaceDefinition = $compiler->getClassDefinition($interface);

                                if (!$classInterfaceDefinition) {
                                    $classInterfaceDefinition = $compiler->getInternalClassDefinition($interface);
                                    if (!$classInterfaceDefinition) {
                                        throw new CompilerException(
                                            "Couldn't locate internal or external interface: ".$interface,
                                            $expression
                                        );
                                    }
                                }

                                if ($classInterfaceDefinition->hasMethod($methodName)) {
                                    $found = true;
                                    $classMethod = $classInterfaceDefinition->getMethod($methodName);
                                    break;
                                }
                            }
                        }

                        if (!$found) {
                            $possibleMethod = $classDefinition->getPossibleMethodName($expression['name']);
                            if ($possibleMethod && $expression['name'] != $possibleMethod) {
                                throw new CompilerException(
                                    sprintf(
                                        "Class '%s' does not implement method: '%s'. Did you mean '%s'?",
                                        $classDefinition->getCompleteName(),
                                        $expression['name'],
                                        $possibleMethod
                                    ),
                                    $expression
                                );
                            }

                            throw new CompilerException(
                                sprintf(
                                    "Class '%s' does not implement method: '%s'",
                                    $classDefinition->getCompleteName(),
                                    $expression['name']
                                ),
                                $expression
                            );
                        }
                    }
                } else {
                    if ($check) {
                        $classMethod = $classDefinition->getMethod($methodName);
                    }
                }

                if ($check) {
                    /*
                     * Private methods must be called in their declaration scope
                     */
                    if ($classMethod->isPrivate()) {
                        if ($classMethod->getClassDefinition() !== $classDefinition) {
                            throw new CompilerException(
                                "Cannot call private method '".$expression['name']."' out of its scope",
                                $expression
                            );
                        }
                    }

                    /*
                     * Try to produce an exception if method is called with a wrong number of parameters
                     */
                    if (isset($expression['parameters'])) {
                        $callNumberParameters = \count($expression['parameters']);
                    } else {
                        $callNumberParameters = 0;
                    }

                    $expectedNumberParameters = $classMethod->getNumberOfRequiredParameters();
                    if (!$expectedNumberParameters && $callNumberParameters > 0) {
                        $numberParameters = $classMethod->getNumberOfParameters();
                        if ($callNumberParameters > $numberParameters) {
                            throw new CompilerException(
                                sprintf(
                                    "Method '%s::%s' called with a wrong number of parameters, ".
                                    'the method has: %d, passed: %d',
                                    $classDefinition->getCompleteName(),
                                    $expression['name'],
                                    $expectedNumberParameters,
                                    $callNumberParameters
                                ),
                                $expression
                            );
                        }
                    }

                    if ($callNumberParameters < $expectedNumberParameters) {
                        throw new CompilerException(
                            sprintf(
                                "Method '%s::%s' called with a wrong number of parameters, ".
                                'the method has: %d, passed: %d',
                                $classDefinition->getCompleteName(),
                                $expression['name'],
                                $expectedNumberParameters,
                                $callNumberParameters
                            ),
                            $expression
                        );
                    }

                    $method = $classMethod;
                }
            } else {
                /*
                 * Variables whose dynamic type is 'object' can be used
                 * to determine method existence in compile time
                 */
                if ($check && $variableVariable->hasAnyDynamicType('object')) {
                    $classTypes = $variableVariable->getClassTypes();

                    if (\count($classTypes)) {
                        $numberImplemented = 0;
                        $compiler = $compilationContext->compiler;
                        foreach ($classTypes as $classType) {
                            if ($compiler->isClass($classType) ||
                                $compiler->isInterface($classType) ||
                                $compiler->isBundledClass($classType) ||
                                $compiler->isBundledInterface($classType)
                            ) {
                                if ($compiler->isClass($classType) || $compiler->isInterface($classType)) {
                                    $classDefinition = $compiler->getClassDefinition($classType);
                                } else {
                                    $classDefinition = $compiler->getInternalClassDefinition($classType);
                                }

                                if (!$classDefinition) {
                                    throw new CompilerException(
                                        'Cannot locate class definition for class '.$classType,
                                        $expression
                                    );
                                }

                                if (!$classDefinition->hasMethod($methodName)) {
                                    if (!$classDefinition->isInterface()) {
                                        if (1 == \count($classTypes)) {
                                            throw new CompilerException(
                                                sprintf(
                                                    "Class '%s' does not implement method: '%s'",
                                                    $classType,
                                                    $expression['name']
                                                ),
                                                $expression
                                            );
                                        }
                                    }
                                    continue;
                                }

                                $method = $classDefinition->getMethod($methodName);

                                /*
                                 * Private methods must be called in their declaration scope
                                 */
                                if ($method->isPrivate()) {
                                    if ($method->getClassDefinition() != $classDefinition) {
                                        throw new CompilerException(
                                            sprintf(
                                                "Cannot call private method '%s' out of its scope",
                                                $expression['name']
                                            ),
                                            $expression
                                        );
                                    }
                                }

                                /*
                                 * Check visibility for protected methods
                                 */
                                if ($method->isProtected() &&
                                    $method->getClassDefinition() != $classDefinition &&
                                    $method->getClassDefinition() != $classDefinition->getExtendsClass()
                                ) {
                                    throw new CompilerException(
                                        sprintf(
                                            "Cannot call protected method '%s' out of its scope",
                                            $expression['name']
                                        ),
                                        $expression
                                    );
                                }

                                /*
                                 * Try to produce an exception if a method is called with a wrong number of parameters
                                 * We only check extension parameters if methods are extension methods
                                 * Internal methods may have invalid Reflection information
                                 */
                                if ($method instanceof ClassMethod && !$method->isBundled()) {
                                    if (isset($expression['parameters'])) {
                                        $callNumberParameters = \count($expression['parameters']);
                                    } else {
                                        $callNumberParameters = 0;
                                    }

                                    $classMethod = $classDefinition->getMethod($methodName);
                                    $expectedNumberParameters = $classMethod->getNumberOfRequiredParameters();

                                    if (!$expectedNumberParameters && $callNumberParameters > 0) {
                                        $numberParameters = $classMethod->getNumberOfParameters();
                                        if ($callNumberParameters > $numberParameters) {
                                            $className = $classDefinition->getCompleteName();
                                            throw new CompilerException(
                                                sprintf(
                                                    "Method '%s::%s' called with a wrong number of parameters, ".
                                                    'the method has: %d, passed: %s',
                                                    $className,
                                                    $expression['name'],
                                                    $expectedNumberParameters,
                                                    $callNumberParameters
                                                ),
                                                $expression
                                            );
                                        }
                                    }

                                    if ($callNumberParameters < $expectedNumberParameters) {
                                        throw new CompilerException(
                                            sprintf(
                                                "Method '%s::%s' called with a wrong number of parameters, ".
                                                'the method has: %d, passed: %d',
                                                $classDefinition->getCompleteName(),
                                                $expression['name'],
                                                $expectedNumberParameters,
                                                $callNumberParameters
                                            ),
                                            $expression
                                        );
                                    }
                                }

                                /*
                                 * The method is checked in the first class that implements the method
                                 * We could probably have collisions here
                                 */
                                ++$numberImplemented;
                                break;
                            } else {
                                ++$numberImplemented;
                                $compilationContext->logger->warning(
                                    'Class "'.$classType.'" does not exist at compile time',
                                    ['nonexistent-class', $expression]
                                );
                            }
                        }

                        if (0 == $numberImplemented) {
                            if (!$classDefinition->isInterface()) {
                                if (\count($classTypes) > 1) {
                                    throw new CompilerException(
                                        sprintf(
                                            "None of classes: '%s' implement method: '%s'",
                                            implode(' or ', $classTypes),
                                            $expression['name']
                                        ),
                                        $expression
                                    );
                                } else {
                                    throw new CompilerException(
                                        sprintf(
                                            "Class '%s' does not implement method: '%s'",
                                            $classTypes[0],
                                            $expression['name']
                                        ),
                                        $expression
                                    );
                                }
                            } else {
                                // @TODO, raise an exception here?
                            }
                        }
                    }
                }
            }
        }

        if (isset($method)) {
            $this->reflection = $method;
        }

        /*
         * Transfer the return type-hint to the returned variable
         */
        if ($isExpecting) {
            if (isset($method)) {
                if ($method instanceof ClassMethod) {
                    if ($method->isVoid()) {
                        throw new CompilerException(
                            sprintf(
                                "Method '%s::%s' is marked as '%s' and it does not return anything",
                                $classDefinition->getCompleteName(),
                                $expression['name'],
                                Types::T_VOID
                            ),
                            $expression
                        );
                    }

                    $returnClassTypes = $method->getReturnClassTypes();

                    if (null !== $returnClassTypes) {
                        $symbolVariable->setDynamicTypes('object');
                        foreach ($returnClassTypes as &$returnClassType) {
                            $returnClassType = $compilationContext->getFullName($returnClassType);
                        }
                        $symbolVariable->setClassTypes($returnClassTypes);
                    }

                    $returnTypes = $method->getReturnTypes();
                    if (null !== $returnTypes) {
                        foreach ($returnTypes as $dataType => $returnType) {
                            $symbolVariable->setDynamicTypes($dataType);
                        }
                    }
                }
            }
        }

        /*
         * Some parameters in internal methods receive parameters as references
         */
        if (isset($expression['parameters'])) {
            $references = [];
            if (self::CALL_NORMAL == $type || self::CALL_DYNAMIC_STRING == $type) {
                if (isset($method)) {
                    if ($method instanceof \ReflectionMethod) {
                        $position = 0;
                        foreach ($method->getParameters() as $parameter) {
                            if ($parameter->isPassedByReference()) {
                                $references[$position] = true;
                            }
                            ++$position;
                        }
                    }
                }
            }
        }

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

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

        /*
         * Mark references
         */
        $params = [];
        if (isset($expression['parameters'])) {
            $params = $this->getResolvedParams(
                $expression['parameters'],
                $compilationContext,
                $expression,
                isset($method) ? $method : null
            );

            if (\count($references)) {
                foreach ($params as $position => $param) {
                    if (isset($references[$position])) {
                        $compilationContext->codePrinter->output('Z_SET_ISREF_P('.$param.');');
                    }
                }
            }

            // We check here if a correct parameter type is passed to the called method
            if (self::CALL_NORMAL == $type) {
                if (isset($method) && $method instanceof ClassMethod && isset($expression['parameters'])) {
                    $resolvedTypes = $this->getResolvedTypes();
                    $resolvedDynamicTypes = $this->getResolvedDynamicTypes();

                    foreach ($method->getParameters() as $n => $parameter) {
                        if (isset($parameter['data-type'])) {
                            if (!isset($resolvedTypes[$n])) {
                                continue;
                            }

                            /*
                             * If the passed parameter is different to the expected type we show a warning
                             */
                            if ($resolvedTypes[$n] != $parameter['data-type']) {
                                $template = sprintf(
                                    'Passing possible incorrect type for parameter: %s::%s(%s), '.
                                    'passing: %s, expecting: %s',
                                    $classDefinition->getCompleteName(),
                                    $method->getName(),
                                    $parameter['name'],
                                    $resolvedTypes[$n],
                                    $parameter['data-type']
                                );

                                switch ($resolvedTypes[$n]) {
                                    case 'bool':
                                    case 'boolean':
                                        switch ($parameter['data-type']) {
                                            /* compatible types */
                                            case 'bool':
                                            case 'boolean':
                                            case 'variable':
                                                break;

                                            default:
                                                $compilationContext->logger->warning(
                                                    $template,
                                                    ['possible-wrong-parameter', $expression]
                                                );
                                                break;
                                        }
                                        break;

                                    case 'array':
                                        switch ($parameter['data-type']) {
                                            /* compatible types */
                                            case 'array':
                                            case 'variable':
                                                break;

                                            case 'callable':
                                                /*
                                                 * Array can be a callable type, example: [$this, "method"]
                                                 *
                                                 * @todo we need to check this array if can...
                                                 */
                                                break;

                                            default:
                                                $compilationContext->logger->warning(
                                                    $template,
                                                    ['possible-wrong-parameter', $expression]
                                                );
                                                break;
                                        }
                                        break;

                                    case 'callable':
                                        switch ($parameter['data-type']) {
                                            /* compatible types */
                                            case 'callable':
                                            case 'variable':
                                                break;

                                            default:
                                                $compilationContext->logger->warning(
                                                    $template,
                                                    ['possible-wrong-parameter', $expression]
                                                );
                                                break;
                                        }
                                        break;

                                    case 'string':
                                        switch ($parameter['data-type']) {
                                            /* compatible types */
                                            case 'string':
                                            case 'variable':
                                                break;

                                            default:
                                                $compilationContext->logger->warning(
                                                    $template,
                                                    ['possible-wrong-parameter', $expression]
                                                );
                                                break;
                                        }
                                        break;

                                    /*
                                     * Passing polymorphic variables to static typed parameters
                                     * could lead to potential unexpected type coercions
                                     */
                                    case 'variable':
                                        if ($resolvedDynamicTypes[$n] != $parameter['data-type']) {
                                            if ('undefined' == $resolvedDynamicTypes[$n]) {
                                                $compilationContext->logger->warning(
                                                    sprintf(
                                                        'Passing possible incorrect type for parameter: %s::%s(%s), '.
                                                        'passing: undefined, expecting: %s',
                                                        $classDefinition->getCompleteName(),
                                                        $method->getName(),
                                                        $parameter['name'],
                                                        $parameter['data-type']
                                                    ),
                                                    ['possible-wrong-parameter-undefined', $expression]
                                                );
                                            }
                                        }
                                        break;
                                }
                            }
                        }
                    }
                }
            }
        }

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

        // Initialize non-temporary variables
        if ($mustInit) {
            $symbolVariable->setMustInitNull(true);
            $symbolVariable->trackVariant($compilationContext);
        }

        // Generate the code according to the call type
        if (self::CALL_NORMAL == $type || self::CALL_DYNAMIC_STRING == $type) {
            $realMethod = $this->getRealCalledMethod($compilationContext, $variableVariable, $methodName);

            $isInternal = false;
            if (\is_object($realMethod[1])) {
                $realMethod[1] = $realMethod[1]->getOptimizedMethod();
                $method = $realMethod[1];
                $isInternal = $realMethod[1]->isInternal();
                if ($isInternal && $realMethod[0] > 1) {
                    throw new CompilerException(
                        "Cannot resolve method: '".$expression['name']."' in polymorphic variable",
                        $expression
                    );
                }
            }

            if (!$isInternal) {
                // Check if the method call can have an inline cache
                $methodCache = $compilationContext->cacheManager->getMethodCache();

                $cachePointer = $methodCache->get(
                    $compilationContext,
                    $methodName,
                    $variableVariable
                );

                $compilationContext->backend->callMethod(
                    $isExpecting ? $symbolVariable : null,
                    $variableVariable,
                    $methodName,
                    $cachePointer,
                    \count($params) ? $params : null,
                    $compilationContext
                );
            } else {
                //TODO: also move to backend
                if ($isExpecting) {
                    $symbolCode = $compilationContext->backend->getVariableCodePointer($symbolVariable);
                }
                $variableCode = $compilationContext->backend->getVariableCode($variableVariable);
                $paramCount = \count($params);
                $paramsStr = $paramCount ? ', '.implode(', ', $params) : '';

                if ($isExpecting) {
                    if ('return_value' == $symbolVariable->getName()) {
                        $macro = $compilationContext->backend->getFcallManager()->getMacro(false, true, $paramCount);
                        $codePrinter->output($macro.'('.$variableCode.', '.$method->getInternalName().$paramsStr.');');
                    } else {
                        $macro = $compilationContext->backend->getFcallManager()->getMacro(false, 2, $paramCount);
                        $codePrinter->output(
                            $macro.'('.$symbolCode.', '.$variableCode.', '.$method->getInternalName().$paramsStr.');'
                        );
                    }
                } else {
                    $macro = $compilationContext->backend->getFcallManager()->getMacro(false, false, $paramCount);
                    $codePrinter->output($macro.'('.$variableCode.', '.$method->getInternalName().$paramsStr.');');
                }
            }
        } else {
            if (self::CALL_DYNAMIC == $type) {
                switch ($variableMethod->getType()) {
                    case 'string':
                    case 'variable':
                        break;
                    default:
                        throw new Exception(
                            sprintf('Cannot use variable type: %s as method caller', $variableMethod->getType())
                        );
                }

                $cachePointer = 'NULL, 0';

                $compilationContext->backend->callMethod(
                    $isExpecting ? $symbolVariable : null,
                    $variableVariable,
                    $variableMethod,
                    $cachePointer,
                    \count($params) ? $params : null,
                    $compilationContext
                );
            }
        }

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

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

        // Release parameters marked as references
        if (isset($expression['parameters'])) {
            if (\count($references)) {
                foreach ($params as $position => $param) {
                    if (isset($references[$position])) {
                        $compilationContext->codePrinter->output('Z_UNSET_ISREF_P('.$param.');');
                    }
                }
            }
        }

        $this->addCallStatusOrJump($compilationContext);

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

        return new CompiledExpression('null', null, $expression);
    }
1231185
public function compile(Compiler $compiler): void
    {
        if ($this->module->hasAttribute('is_embedded')) {
            return;
        }

        $presentationModel = $this->findPresentationModel->for($this->getSourceContext());

        $compiler
            ->write("\$presentationModel = new $presentationModel(\$context);\n")
            ->write("\$originalContext = \$context;\n\n")
            ->write("\$callback = function (array \$context) use (\$blocks, \$originalContext) {\n")
            ->indent()
            ->write("\$suppressedException = null;\n\n");
    }