Compiles a function.

@param CompilationContext $compilationContext
@param FunctionDefinition $functionDefinition
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;
    }
253775
public function processValue(CompilationContext $compilationContext)
    {
        if ('constant' == $this->value['type']) {
            $constant = new Constants();
            $compiledExpression = $constant->compile($this->value, $compilationContext);

            $this->value = [
                'type' => $compiledExpression->getType(),
                'value' => $compiledExpression->getCode(),
            ];

            return;
        }

        if ('static-constant-access' == $this->value['type']) {
            $staticConstantAccess = new StaticConstantAccess();
            $compiledExpression = $staticConstantAccess->compile($this->value, $compilationContext);

            $this->value = [
                'type' => $compiledExpression->getType(),
                'value' => $compiledExpression->getCode(),
            ];

            return;
        }
    }
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;
    }
1062255
public function compile(CompilationContext $compilationContext)
    {
        $expression = [
            'type' => 'require',
            'left' => $this->statement['expr'],
            'file' => $this->statement['file'],
            'line' => $this->statement['line'],
            'char' => $this->statement['char'],
        ];

        $expr = new Expression($expression);
        $expr->setExpectReturn(false, null);
        $expr->compile($compilationContext);
    }
922642
private function isClassCacheable($classDefinition)
    {
        if ($classDefinition instanceof ClassDefinition) {
            return true;
        }
        if ($classDefinition instanceof \ReflectionClass) {
            if ($classDefinition->isInternal() && $classDefinition->isInstantiable()) {
                $extension = $classDefinition->getExtension();
                switch ($extension->getName()) {
                    case 'Reflection':
                    case 'Core':
                    case 'SPL':
                        return true;
                }
            }
        }

        return false;
    }
1188945
public function addClassDefinition(CompilerFileAnonymous $file, ClassDefinition $classDefinition)
    {
        $this->definitions[$classDefinition->getCompleteName()] = $classDefinition;
        $this->anonymousFiles[$classDefinition->getCompleteName()] = $file;
    }
1297600
public void loadFunctions(CatalogContext catalogContext) {
        final CatalogMap<Function> catalogFunctions = catalogContext.database.getFunctions();
        // Remove obsolete tokens
        for (UserDefinedFunctionRunner runner : m_udfs.values()) {
            // The function that the current UserDefinedFunctionRunner is referring to
            // does not exist in the catalog anymore, we need to remove its token.
            if (catalogFunctions.get(runner.m_functionName) == null) {
                FunctionForVoltDB.deregisterUserDefinedFunction(runner.m_functionName);
            }
        }
        // Build new UDF runners
        ImmutableMap.Builder<Integer, UserDefinedFunctionRunner> builder =
                            ImmutableMap.<Integer, UserDefinedFunctionRunner>builder();
        for (final Function catalogFunction : catalogFunctions) {
            final String className = catalogFunction.getClassname();
            Class<?> funcClass = null;
            try {
                funcClass = catalogContext.classForProcedureOrUDF(className);
            }
            catch (final ClassNotFoundException e) {
                if (className.startsWith("org.voltdb.")) {
                    String msg = String.format(ORGVOLTDB_FUNCCNAME_ERROR_FMT, className);
                    VoltDB.crashLocalVoltDB(msg, false, null);
                }
                else {
                    String msg = String.format(UNABLETOLOAD_ERROR_FMT, className);
                    VoltDB.crashLocalVoltDB(msg, false, null);
                }
            }
            Object funcInstance = null;
            try {
                funcInstance = funcClass.newInstance();
            }
            catch (InstantiationException | IllegalAccessException e) {
                throw new RuntimeException(String.format("Error instantiating function \"%s\"", className), e);
            }
            assert(funcInstance != null);
            builder.put(catalogFunction.getFunctionid(), new UserDefinedFunctionRunner(catalogFunction, funcInstance));
        }

        loadBuiltInJavaFunctions(builder);
        m_udfs = builder.build();
    }
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;
    }
928306
public function setCodeDefinition(CodeDefinition $codeDef)
    {
        $this->codeDefinition = $codeDef;
        $this->setTagName($codeDef->getTagName());
    }
44347
public function optimize(array $expression, Call $call, CompilationContext $context)
    {
        if (!isset($expression['parameters']) || 2 != \count($expression['parameters'])) {
            throw new CompilerException(sprintf("'%s' requires two parameters", $this->getFunctionName()), $expression);
        }

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

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

        return new CompiledExpression(
            'double',
            'zephir_'.$this->getFunctionName().'('.$resolvedParams[0].', '.$resolvedParams[1].' TSRMLS_CC)',
            $expression
        );
    }
183095
public function addCallStatusOrJump(CompilationContext $compilationContext)
    {
        $compilationContext->headersManager->add('kernel/fcall');
        if ($compilationContext->insideTryCatch) {
            $compilationContext->codePrinter->output(
                'zephir_check_call_status_or_jump(try_end_'.$compilationContext->currentTryCatch.');'
            );

            return;
        }

        $compilationContext->codePrinter->output('zephir_check_call_status();');
    }
137608
public function compile(CompilationContext $compilationContext)
    {
        $exprRaw = $this->statement['expr'];

        /*
         * @TODO implement optimizers here
         */
        if ('fcall' == $exprRaw['type']) {
            if ('range' == $exprRaw['name']) {
                $status = $this->compileRange($exprRaw, $compilationContext);
                if (false !== $status) {
                    return;
                }
            }

            if ('iterator' == $exprRaw['name']) {
                $status = $this->compileIterator($exprRaw, $compilationContext);
                if (false !== $status) {
                    return;
                }
            }
        }

        $expr = new Expression($exprRaw);
        $expr->setReadOnly(true);
        $expression = $expr->compile($compilationContext);

        /*
         * Check for traversing a constant string
         */
        if ('string' == $expression->getType()) {
            $this->compileStringTraverse($expression, $compilationContext, null);

            return;
        }

        if ('variable' != $expression->getType() && 'array' != $expression->getType()) {
            throw new CompilerException('Unknown type: '.$expression->getType(), $exprRaw);
        }

        $exprVariable = $compilationContext->symbolTable->getVariableForRead($expression->getCode(), $compilationContext, $this->statement['expr']);
        switch ($exprVariable->getType()) {
            case 'variable':
            case 'array':
                $this->compileHashTraverse($expression, $compilationContext, $exprVariable);
                break;

            case 'string':
                $this->compileStringTraverse($expression, $compilationContext, $exprVariable);
                break;

            default:
                throw new CompilerException('Cannot traverse value type: '.$exprVariable->getType(), $exprRaw);
        }
    }
619682
public function compile(CompilationContext $compilationContext)
    {
        if ($compilationContext->insideCycle) {
            $compilationContext->codePrinter->output('continue;');
        } else {
            throw new CompilerException("Cannot use 'continue' outside of a loop", $this->statement);
        }
    }
579467
private function compileContextNode(Compiler $compiler): void
    {
        $contextNode = null;
        if ($this->hasNode('context')) {
            $contextNode = $this->getNode('context');
        }

        if ($contextNode instanceof Node) {
            $compiler
                ->write('$ngbmContext = ')
                    ->subcompile($this->getNode('context'))
                ->write(';' . PHP_EOL);

            return;
        }

        $compiler->write('$ngbmContext = ' . ViewInterface::class . '::CONTEXT_DEFAULT;' . PHP_EOL);
    }
175365
public function functionExists($functionName, CompilationContext $context)
    {
        if (\function_exists($functionName)) {
            return true;
        }
        if ($this->isBuiltInFunction($functionName)) {
            return true;
        }

        $internalName = ['f__'.$functionName];
        if (isset($context->classDefinition)) {
            $lowerNamespace = strtolower($context->classDefinition->getNamespace());
            $prefix = 'f_'.str_replace('\\', '_', $lowerNamespace);

            $internalName[] = $prefix.'_'.$functionName;
        }

        foreach ($internalName as $name) {
            if (isset($context->compiler->functionDefinitions[$name])) {
                return true;
            }
        }

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

        $expr = new Expression($propertyAccess['left']);
        $expr->setReadOnly(true);
        $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']);
        }

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

        $propertyDefinition = null;
        $classDefinition = null;
        $currentClassDefinition = $compilationContext->classDefinition;

        /*
         * If the property is accessed on 'this', we check if the method does exist
         */
        if ('this' == $variableVariable->getRealName()) {
            $classDefinition = $currentClassDefinition;
            if (!$classDefinition->hasProperty($property)) {
                throw new CompilerException("Class '".$classDefinition->getCompleteName()."' does not have a property called: '".$property."'", $expression);
            }

            $propertyDefinition = $classDefinition->getProperty($property);
        } else {
            /*
             * If we know the class related to a variable we could check if the property
             * is defined on that class
             */
            if ($variableVariable->hasAnyDynamicType('object')) {
                $classType = current($variableVariable->getClassTypes());
                $compiler = $compilationContext->compiler;

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

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

                    $propertyDefinition = $classDefinition->getProperty($property);
                }
            }
        }

        /*
         * Having a proper propertyDefinition we can check if the property is readable
         * according to its modifiers
         */
        if ($propertyDefinition) {
            if ($propertyDefinition->isStatic()) {
                throw new CompilerException("Attempt to access static property '".$property."' as non static", $expression);
            }

            if (!$propertyDefinition->isPublic()) {
                /*
                 * Protected variables only can be read in the class context
                 * where they were declared
                 */
                if ($classDefinition == $currentClassDefinition) {
                    if ($propertyDefinition->isPrivate()) {
                        $declarationDefinition = $propertyDefinition->getClassDefinition();
                        if ($declarationDefinition !== $currentClassDefinition) {
                            throw new CompilerException("Attempt to access private property '".$property."' outside of its declared class context: '".$declarationDefinition->getCompleteName()."'", $expression);
                        }
                    }
                } else {
                    if ($propertyDefinition->isProtected()) {
                    } else {
                        if ($propertyDefinition->isPrivate()) {
                            $declarationDefinition = $propertyDefinition->getClassDefinition();
                            if ($declarationDefinition !== $currentClassDefinition) {
                                throw new CompilerException("Attempt to access private property '".$property."' outside of its declared class context: '".$declarationDefinition->getCompleteName()."'", $expression);
                            }
                        }
                    }
                }
            }
        }

        /**
         * Resolves the symbol that expects the value.
         */
        $readOnly = false;
        $makeSymbolVariable = false;
        if ($this->expecting) {
            if ($this->expectingVariable) {
                $symbolVariable = $this->expectingVariable;

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

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

                $this->readOnly = false;
            } else {
                $makeSymbolVariable = true;
            }
        } else {
            $makeSymbolVariable = true;
        }

        $readOnly = $this->readOnly || $readOnly;
        $useOptimized = $classDefinition == $currentClassDefinition;
        if (!$compilationContext->backend->isZE3()) {
            $readOnly = $useOptimized && $readOnly;
        }
        if ($makeSymbolVariable) {
            if ($readOnly) {
                $symbolVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext);
            } else {
                $symbolVariable = $compilationContext->symbolTable->getTempVariableForObserve('variable', $compilationContext, $expression);
            }
        }

        /*
         * Variable that receives a property value must be polymorphic
         */
        if (!$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');

        $compilationContext->backend->fetchProperty($symbolVariable, $variableVariable, $property, $readOnly, $compilationContext, $useOptimized);

        return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
    }
338084
public function compileClass(CompilationContext $compilationContext, $namespace, $classStatement)
    {
        $classDefinition = $this->classDefinition;

        /*
         * Do the compilation
         */
        $classDefinition->compile($compilationContext);
    }