Compiles x->y[] = foo.

@param string             $variable
@param ZephirVariable     $symbolVariable
@param CompiledExpression $resolvedExpr
@param CompilationContext $compilationContext
@param array              $statement

@throws CompilerException
502522
public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, array $statement)
    {
        if (!$symbolVariable->isInitialized()) {
            throw new CompilerException("Cannot mutate variable '".$variable."' because it is not initialized", $statement);
        }

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

        $codePrinter = $compilationContext->codePrinter;

        $property = $statement['property'];

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

        /*
         * Check if the variable to update is defined
         */
        if ('this' == $symbolVariable->getRealName()) {
            $classDefinition = $compilationContext->classDefinition;
            if (!$classDefinition->hasProperty($property)) {
                throw new CompilerException("Class '".$classDefinition->getCompleteName()."' does not have a property called: '".$property."'", $statement);
            }
        } else {
            /*
             * If we know the class related to a variable we could check if the property
             * is defined on that class
             */
            if ($symbolVariable->hasAnyDynamicType('object')) {
                $classType = current($symbolVariable->getClassTypes());
                $compiler = $compilationContext->compiler;

                if ($compiler->isClass($classType)) {
                    $classDefinition = $compiler->getClassDefinition($classType);
                    if (!$classDefinition) {
                        throw new CompilerException('Cannot locate class definition for class: '.$classType, $statement);
                    }

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

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

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

            case 'char':
                $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                $compilationContext->backend->assignLong($tempVariable, '\''.$resolvedExpr->getCode().'\'', $compilationContext);
                $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $tempVariable, $compilationContext);
                if ($tempVariable->isTemporal()) {
                    $tempVariable->setIdle(true);
                }
                break;

            case 'int':
            case 'long':
            case 'uint':
                $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                $compilationContext->backend->assignLong($tempVariable, $resolvedExpr->getCode(), $compilationContext);
                $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $tempVariable, $compilationContext);
                if ($tempVariable->isTemporal()) {
                    $tempVariable->setIdle(true);
                }
                break;

            case 'double':
                $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                $compilationContext->backend->assignDouble($tempVariable, $resolvedExpr->getCode(), $compilationContext);
                $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $tempVariable, $compilationContext);
                if ($tempVariable->isTemporal()) {
                    $tempVariable->setIdle(true);
                }
                break;

            case 'string':
                $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                $compilationContext->backend->assignString($tempVariable, $resolvedExpr->getCode(), $compilationContext);
                $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $tempVariable, $compilationContext);
                if ($tempVariable->isTemporal()) {
                    $tempVariable->setIdle(true);
                }
                break;

            case 'array':
                $variableExpr = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
                $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $variableExpr, $compilationContext);
                break;

            case 'variable':
                $variableExpr = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement);
                switch ($variableExpr->getType()) {
                    case 'int':
                    case 'long':
                    case 'uint':
                    case 'char':
                        $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                        $compilationContext->backend->assignLong($tempVariable, $variableExpr, $compilationContext);
                        $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $tempVariable, $compilationContext);
                        if ($tempVariable->isTemporal()) {
                            $tempVariable->setIdle(true);
                        }
                        break;

                    case 'double':
                        $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                        $compilationContext->backend->assignDouble($tempVariable, $variableExpr, $compilationContext);
                        $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $tempVariable, $compilationContext);
                        if ($tempVariable->isTemporal()) {
                            $tempVariable->setIdle(true);
                        }
                        break;

                    case 'bool':
                        $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true);
                        $compilationContext->backend->assignBool($tempVariable, $variableExpr, $compilationContext);
                        $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $tempVariable, $compilationContext);
                        if ($tempVariable->isTemporal()) {
                            $tempVariable->setIdle(true);
                        }
                        break;

                    case 'variable':
                    case 'string':
                    case 'array':
                    case 'resource':
                    case 'object':
                        $compilationContext->backend->assignArrayProperty($symbolVariable, $property, null, $variableExpr, $compilationContext);
                        if ($variableExpr->isTemporal()) {
                            $variableExpr->setIdle(true);
                        }
                        break;

                    default:
                        throw new CompilerException('Variable: '.$variableExpr->getType().' cannot be appended to array property', $statement);
                }
                break;

            default:
                throw new CompilerException('Expression: '.$resolvedExpr->getType().' cannot be appended to array property', $statement);
        }
    }
534043
public function compile(array $expression, CompilationContext $compilationContext)
    {
        $compilationContext->headersManager->add('kernel/operators');

        if (!isset($expression['left'])) {
            throw new CompilerException("Invalid 'left' operand for 'empty' expression", $expression['left']);
        }

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

        if ('variable' != $left->getType() && 'array' != $left->getType()) {
            throw new CompilerException("'empty' operand only can be a variable", $expression['left']);
        }

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

        return new CompiledExpression('bool', 'ZEPHIR_IS_EMPTY('.$compilationContext->backend->getVariableCode($variableLeft).')', $expression);
    }
1049481
public function compile(array $expression, CompilationContext $compilationContext)
    {
        if (!isset($expression['left'])) {
            throw new CompilerException("Invalid 'left' operand for 'irange' expression", $expression['left']);
        }

        if (!isset($expression['right'])) {
            throw new CompilerException("Invalid 'right' operand for 'irange' expression", $expression['right']);
        }

        $exprBuilder = Expression\Builder\BuilderFactory::getInstance();

        /**
         * Implicit type coercing.
         */
        $castBuilder = $exprBuilder->operators()->cast(Types::T_ARRAY, $exprBuilder->statements()
            ->functionCall('range', [$expression['left'], $expression['right']]));

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

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

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

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

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

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

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

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

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

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

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

            return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
        } catch (Exception $e) {
            throw new CompilerException($e->getMessage(), $expression, $e->getCode(), $e);
        }
    }
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);
    }
1215433
public function compile($expression, CompilationContext $compilationContext)
    {
        if (!isset($expression['left'])) {
            throw new CompilerException('Missing left part of the expression', $expression);
        }

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

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

        /**
         * Try to optimize the concatenation.
         */
        $optimized = $this->_getOptimizedConcat($expression, $compilationContext, $isFullString);
        if (\is_array($optimized)) {
            if (!$isFullString) {
                $expected = $this->getExpectedComplexLiteral($compilationContext, $expression);
            } else {
                $expected = $this->getExpectedComplexLiteral($compilationContext, $expression, 'string');
            }

            $expected->setDynamicTypes('string');
            $expectedCode = $compilationContext->backend->getVariableCode($expected);
            $compilationContext->codePrinter->output('ZEPHIR_CONCAT_'.strtoupper($optimized[0]).'('.$expectedCode.', '.$optimized[1].');');

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

        /**
         * If the expression cannot be optimized, fall back to the standard compilation.
         */
        $leftExpr = new Expression($expression['left']);
        switch ($expression['left']['type']) {
            case 'array-access':
            case 'property-access':
                $leftExpr->setReadOnly(true);
                break;

            default:
                $leftExpr->setReadOnly($this->readOnly);
                break;
        }
        $left = $leftExpr->compile($compilationContext);

        if ('variable' == $left->getType()) {
            $variableLeft = $compilationContext->symbolTable->getVariableForRead($left->getCode(), $compilationContext, $expression['right']);
            $variableLeft = $compilationContext->backend->getVariableCode($variableLeft);
        }

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

            default:
                $rightExpr->setReadOnly($this->readOnly);
                break;
        }
        $right = $rightExpr->compile($compilationContext);

        if ('variable' == $right->getType()) {
            $variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['right']);
            $variableRight = $compilationContext->backend->getVariableCode($variableRight);
        }

        $expected = $this->getExpectedComplexLiteral($compilationContext, $expression);
        $expectedCode = $compilationContext->backend->getVariableCode($expected);

        if ('string' == $left->getType() && 'variable' == $right->getType()) {
            $compilationContext->codePrinter->output('ZEPHIR_CONCAT_SV('.$expectedCode.', "'.$left->getCode().'", '.$variableRight.');');
        }

        if ('variable' == $left->getType() && 'string' == $right->getType()) {
            $compilationContext->codePrinter->output('ZEPHIR_CONCAT_VS('.$expectedCode.', '.$variableLeft.', "'.$right->getCode().'");');
        }

        if ('variable' == $left->getType() && 'variable' == $right->getType()) {
            $compilationContext->codePrinter->output('zephir_concat_function('.$expectedCode.', '.$variableLeft.', '.$variableRight.');');
        }

        $expected->setDynamicTypes('string');

        return new CompiledExpression('variable', $expected->getName(), $expression);
    }
839566
public function compile(array $expression, CompilationContext $compilationContext)
    {
        $expr = new Expression($expression['right']);
        $expr->setReadOnly(true);
        $resolved = $expr->compile($compilationContext);

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

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

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

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

        return $resolved;
    }
1317923
public function compile($expression, CompilationContext $compilationContext)
    {
        $propertyAccess = $expression;

        $expr = new Expression($propertyAccess['left']);
        $exprVariable = $expr->compile($compilationContext);

        switch ($exprVariable->getType()) {
            case 'variable':
                $variableVariable = $compilationContext->symbolTable->getVariableForRead($exprVariable->getCode(), $compilationContext, $expression);
                switch ($variableVariable->getType()) {
                    case 'variable':
                        break;
                    default:
                        throw new CompilerException('Variable type: '.$variableVariable->getType().' cannot be used as object', $propertyAccess['left']);
                }
                break;
            default:
                throw new CompilerException('Cannot use expression: '.$exprVariable->getType().' as an object', $propertyAccess['left']);
        }

        switch ($propertyAccess['right']['type']) {
            case 'variable':
                $propertyVariable = $compilationContext->symbolTable->getVariableForRead($propertyAccess['right']['value'], $compilationContext, $expression);
                break;
            case 'string':
                $propertyVariable = null;
                break;
            default:
                throw new CompilerException('Variable type: '.$propertyAccess['right']['type'].' cannot be used as object', $propertyAccess['left']);
        }

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

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

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

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

        $property = $propertyVariable ? $propertyVariable : add_slashes($expression['right']['value']);
        $compilationContext->backend->fetchProperty($symbolVariable, $variableVariable, $property, false, $compilationContext, false);

        return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
    }
864802
public function compile($expression, CompilationContext $compilationContext)
    {
        if (!isset($expression['left'])) {
            throw new CompilerException('Missing left part of the expression');
        }

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

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

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

                    case 'variable':
                        $compilationContext->headersManager->add('kernel/operators');
                        $compilationContext->codePrinter->output('zephir_negate('.$compilationContext->backend->getVariableCode($variable).' TSRMLS_CC);');

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

                    default:
                        throw new CompilerException("Cannot operate minus with variable of '".$left->getType()."' type");
                }
                break;

            default:
                throw new CompilerException("Cannot operate minus with '".$left->getType()."' type");
        }
    }
628548
public function optimize(array $expression, Call $call, CompilationContext $context)
    {
        if (isset($expression['parameters'])) {
            if (0 != \count($expression['parameters'])) {
                throw new CompilerException("This function doesn't require parameters", $expression);
            }
        }

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

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

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

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

        $context->codePrinter->output('zephir_create_symbol_table(TSRMLS_C);');
        $context->codePrinter->output('');

        return new CompiledExpression('null', null, $expression);
    }
817244
StatementDMQL compileCallStatement(RangeVariable[] outerRanges,
                                       boolean isStrictlyProcedure) {

        read();

        if (isIdentifier()) {
            checkValidCatalogName(token.namePrePrefix);

            RoutineSchema routineSchema =
                (RoutineSchema) database.schemaManager.findSchemaObject(
                    token.tokenString,
                    session.getSchemaName(token.namePrefix),
                    SchemaObject.PROCEDURE);

            if (routineSchema != null) {
                read();

                HsqlArrayList list = new HsqlArrayList();

                readThis(Tokens.OPENBRACKET);

                if (token.tokenType == Tokens.CLOSEBRACKET) {
                    read();
                } else {
                    while (true) {
                        Expression e = XreadValueExpression();

                        list.add(e);

                        if (token.tokenType == Tokens.COMMA) {
                            read();
                        } else {
                            readThis(Tokens.CLOSEBRACKET);

                            break;
                        }
                    }
                }

                Expression[] arguments = new Expression[list.size()];

                list.toArray(arguments);

                Routine routine =
                    routineSchema.getSpecificRoutine(arguments.length);
                HsqlList unresolved = null;

                for (int i = 0; i < arguments.length; i++) {
                    Expression e = arguments[i];

                    if (e.isParam()) {
                        e.setAttributesAsColumn(
                            routine.getParameter(i),
                            routine.getParameter(i).isWriteable());
                    } else {
                        int paramMode =
                            routine.getParameter(i).getParameterMode();

                        unresolved =
                            arguments[i].resolveColumnReferences(outerRanges,
                                unresolved);

                        if (paramMode
                                != SchemaObject.ParameterModes.PARAM_IN) {
                            if (e.getType() != OpTypes.VARIABLE) {
                                throw Error.error(ErrorCode.X_42603);
                            }
                        }
                    }
                }

                ExpressionColumn.checkColumnsResolved(unresolved);

                for (int i = 0; i < arguments.length; i++) {
                    arguments[i].resolveTypes(session, null);
                }

                StatementDMQL cs = new StatementProcedure(session, routine,
                    arguments, compileContext);

                return cs;
            }
        }

        if (isStrictlyProcedure) {
            throw Error.error(ErrorCode.X_42501, token.tokenString);
        }

        Expression expression = this.XreadValueExpression();
        HsqlList unresolved = expression.resolveColumnReferences(outerRanges,
            null);

        ExpressionColumn.checkColumnsResolved(unresolved);
        expression.resolveTypes(session, null);

//        expression.paramMode = PARAM_OUT;
        StatementDMQL cs = new StatementProcedure(session, expression,
            compileContext);

        return cs;
    }
990303
public function compile($expression, CompilationContext $context)
    {
        $left = new Expression($expression['left']);
        $resolved = $left->compile($context);

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

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

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

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

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

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

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

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

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

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

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

        return new CompiledExpression('bool', 'zephir_instance_of_ev('.$symbol.', '.$classEntry.' TSRMLS_CC)', $expression);
    }
221508
public function get(CompilationContext $compilationContext, $methodName, Variable $caller)
    {
        $compiler = $compilationContext->compiler;

        $numberPoly = 0;

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

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

                    if (!$classDefinition) {
                        continue;
                    }

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

        if (!$numberPoly) {
            // Try to generate a cache based on the fact the variable is not modified within the loop block
            if ($compilationContext->insideCycle && !$caller->isTemporal()) {
                if (\count($compilationContext->cycleBlocks) && 'variable' == $caller->getType()) {
                    $currentBlock = $compilationContext->cycleBlocks[\count($compilationContext->cycleBlocks) - 1];

                    if (0 == $currentBlock->getMutateGatherer(true)->getNumberOfMutations($caller->getName())) {
                        $functionCache = $compilationContext->symbolTable->getTempVariableForWrite('zephir_fcall_cache_entry', $compilationContext);
                        $functionCache->setMustInitNull(true);
                        $functionCache->setReusable(false);

                        return '&'.$functionCache->getName().', 0';
                    }
                }
            }

            return 'NULL, 0';
        }

        if (!($method instanceof \ReflectionMethod)) {
            if ($method->getClassDefinition()->isExternal()) {
                return 'NULL, 0';
            }

            $completeName = $method->getClassDefinition()->getCompleteName();
            if (isset($this->cache[$completeName][$method->getName()])) {
                return $this->cache[$completeName][$method->getName()].', '.SlotsCache::getExistingMethodSlot($method);
            }

            $gatherer = $this->gatherer;
            if (\is_object($gatherer)) {
                $number = $gatherer->getNumberOfMethodCalls($method->getClassDefinition()->getCompleteName(), $method->getName());
            } else {
                $number = 0;
            }

            $staticCacheable = !$method->getClassDefinition()->isInterface() && ($compilationContext->currentMethod == $method || $method->getClassDefinition()->isFinal() || $method->isFinal() || $method->isPrivate());
            if ($number > 1 || $compilationContext->insideCycle) {
                $cacheable = true;
            } else {
                $cacheable = false;
            }
        } else {
            $staticCacheable = false;
            $cacheable = false;
        }

        // Recursive methods require warm-up
        if ($compilationContext->currentMethod == $method) {
            if (!$compilationContext->methodWarmUp) {
                $compilationContext->methodWarmUp = new MethodCallWarmUp();
            }
        }

        if ('this_ptr' != $caller->getName()) {
            $associatedClass = $caller->getAssociatedClass();
            if ($this->isClassCacheable($associatedClass)) {
                $staticCacheable = true;
            }
        }

        if ($staticCacheable) {
            $cacheSlot = SlotsCache::getMethodSlot($method);
        } else {
            $cacheSlot = '0';
        }

        if ($cacheable) {
            $functionCacheVar = $compilationContext->symbolTable->getTempVariableForWrite('zephir_fcall_cache_entry', $compilationContext);
            $functionCacheVar->setMustInitNull(true);
            $functionCacheVar->setReusable(false);
            $functionCache = '&'.$functionCacheVar->getName();
        } else {
            $functionCache = 'NULL';
        }

        if (!($method instanceof \ReflectionMethod)) {
            $this->cache[$completeName][$method->getName()] = $functionCache;
        }

        return $functionCache.', '.$cacheSlot;
    }
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;
    }
661163
public function compile($expression, CompilationContext $compilationContext)
    {
        /*
         * This variable is used to check if the compound and expression is evaluated as true or false:
         * Ensure that newly allocated variables are local-only (setReadOnly)
         */
        $this->setReadOnly(false);
        $returnVariable = $this->getExpected($compilationContext, $expression, false);
        /* Make sure that passed variables (passed symbol variables) are promoted */
        $returnVariable->setLocalOnly(false);

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

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

        $compilationContext->codePrinter->increaseLevel();

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

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

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

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

        return new CompiledExpression('variable', $returnVariable->getName(), $expression);
    }
1346367
protected void addExportVariableIfPresent(String variable, String typeName) {
        String expVar = findPropertyValue(variable).getLatestValue();
        if(expVar != null && !expVar.isEmpty()) {
            addVariable(new CodeVariableBuilder().exportOnly().variableType(typeName).variableName(expVar));
        }
    }