@param CompilationContext $compilationContext

@throws CompilerException
498304
public function compile(CompilationContext $compilationContext)
    {
        $compilationContext->codePrinter->output('while (1) {');

        /*
         * Variables are initialized in a different way inside cycle
         */
        ++$compilationContext->insideCycle;

        /*
         * Compile statements in the 'loop' block
         */
        if (!isset($this->statement['statements'])) {
            throw new CompilerException("Infinite loop without at least a 'break' statement is not allowed", $this->statement);
        }

        $st = new StatementsBlock($this->statement['statements']);

        /**
         * Check if the block contain at least a break statement.
         */
        $loopBreakPass = new LoopBreakPass();
        $loopBreakPass->pass($st);
        if (!$loopBreakPass->hasBreak()) {
            throw new CompilerException("Infinite loop without at least a 'break' statement is not allowed", $this->statement);
        }

        $st->isLoop(true);
        $st->compile($compilationContext, false, Branch::TYPE_LOOP_INFINITE);

        --$compilationContext->insideCycle;

        $compilationContext->codePrinter->output('}');
    }
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);
        }
    }
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);
    }
522331
protected function compile(OutputBuffer $contentBuffer, BuildContext $buildContext) {
		$n2nContext = $this->getN2nContext();
		return $this->bufferContents(array('request' => $this->getHttpContext()->getRequest(), 
				'response' => $this->getHttpContext()->getResponse(), 'view' => $this,
				'httpContext' => $this->getHttpContext()));
	}
893573
public function compile(Compiler $compiler): void
    {
        $name = $this->getAttribute('name');
        $function = $compiler->getEnvironment()->getFunction($name);
        $arguments = $function->getArguments();

        if (\count($arguments) >= 2) {
            $arguments = [$arguments[0], $arguments[1], $this->getTemplateLine(), $this->getTemplateName()];
        }

        $function->setArguments($arguments);

        parent::compile($compiler);
    }
734974
public function getCompiler(ContextInterface $context): CompilerInterface
    {
        if (empty($this->compiler)) {
            throw new EngineException("No associated compiler found.");
        }

        $this->compiler->getLoader()->setContext($context);

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

            return;
        }

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

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

            ++$this->variantInits;
        }
    }
719318
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);
            }
        }

        $ifBuilder = new IfStatementBuilder(
            new UnaryOperatorBuilder(
                'not',
                $expression['left']
            ),
            new StatementsBlockBuilder([
                /*
                 * Create an implicit 'let' operation to update the evaluated right operator
                 */
                new LetStatementBuilder([
                    'assign-type' => 'variable',
                    'variable' => $returnVariable->getName(),
                    'operator' => 'assign',
                    'expr' => $expression['extra'],
                    'file' => $expression['file'],
                    'line' => $expression['line'],
                    'char' => $expression['char'],
                ], $expression['extra']),
            ]),
            new StatementsBlockBuilder([
                /*
                 * Create an implicit 'let' operation to update the evaluated right operator
                 */
                new LetStatementBuilder([
                    'assign-type' => 'variable',
                    'variable' => $returnVariable->getName(),
                    'operator' => 'assign',
                    'expr' => $expression['left'],
                    'file' => $expression['file'],
                    'line' => $expression['line'],
                    'char' => $expression['char'],
                ], $expression['extra']),
            ])
        );

        $ifStatement = new IfStatement($ifBuilder->get());
        $ifStatement->compile($compilationContext);

        return new CompiledExpression('variable', $returnVariable->getName(), $expression);
    }
94520
public function compile(Compiler $compiler, StringsManager $stringsManager)
    {
        if (!$this->ir) {
            throw new CompilerException('Unable to locate the intermediate representation of the compiled file');
        }

        /*
         * External classes should not be compiled as part of the extension
         */
        if ($this->external) {
            return;
        }

        /**
         * Compilation context stores common objects required by compilation entities.
         */
        $compilationContext = new CompilationContext();

        /*
         * Set global compiler in the compilation context
         */
        $compilationContext->compiler = $compiler;

        /*
         * Set global config in the compilation context
         */
        $compilationContext->config = $this->config;

        /*
         * Set global logger in the compilation context
         */
        $compilationContext->logger = $this->logger;

        /*
         * Set global strings manager
         */
        $compilationContext->stringsManager = $stringsManager;

        $compilationContext->backend = $compiler->backend;

        /**
         * Headers manager.
         */
        $headersManager = new HeadersManager();
        $compilationContext->headersManager = $headersManager;

        /**
         * Main code-printer for the file.
         */
        $codePrinter = new CodePrinter();
        $compilationContext->codePrinter = $codePrinter;

        /*
         * Alias manager
         */
        $compilationContext->aliasManager = $this->aliasManager;

        $codePrinter->outputBlankLine();

        $class = false;
        $interface = false;

        foreach ($this->ir as $topStatement) {
            switch ($topStatement['type']) {
                case 'class':
                    if ($interface || $class) {
                        throw new CompilerException('More than one class defined in the same file', $topStatement);
                    }
                    $class = true;
                    $this->compileClass($compilationContext, $this->namespace, $topStatement);
                    break;

                case 'interface':
                    if ($interface || $class) {
                        throw new CompilerException('More than one class defined in the same file', $topStatement);
                    }
                    $class = true;
                    $this->compileClass($compilationContext, $this->namespace, $topStatement);
                    break;

                case 'comment':
                    $this->compileComment($compilationContext, $topStatement);
                    break;
            }
        }

        /* ensure functions are handled last */
        foreach ($this->functionDefinitions as $funcDef) {
            $this->compileFunction($compilationContext, $funcDef);
        }

        /* apply headers */
        $this->applyClassHeaders($compilationContext);

        $classDefinition = $this->classDefinition;
        if (!$classDefinition) {
            $this->ir = null;

            return;
        }

        $classDefinition->setOriginalNode($this->originalNode);

        $completeName = $classDefinition->getCompleteName();

        $path = str_replace('\\', \DIRECTORY_SEPARATOR, strtolower($completeName));

        $filePath = 'ext/'.$path.'.zep.c';
        $filePathHeader = 'ext/'.$path.'.zep.h';

        if (strpos($path, \DIRECTORY_SEPARATOR)) {
            $dirname = \dirname($filePath);
            if (!is_dir($dirname)) {
                mkdir($dirname, 0755, true);
            }
        }

        if ($codePrinter) {
            /*
             * If the file does not exists we create it for the first time
             */
            if (!file_exists($filePath)) {
                file_put_contents($filePath, $codePrinter->getOutput());
                if ($compilationContext->headerPrinter) {
                    file_put_contents($filePathHeader, $compilationContext->headerPrinter->getOutput());
                }
            } else {
                /**
                 * Use md5 hash to avoid rewrite the file again and again when it hasn't changed
                 * thus avoiding unnecessary recompilations.
                 */
                $output = $codePrinter->getOutput();
                $hash = $this->filesystem->getHashFile('md5', $filePath, true);
                if (md5($output) != $hash) {
                    file_put_contents($filePath, $output);
                }

                if ($compilationContext->headerPrinter) {
                    $output = $compilationContext->headerPrinter->getOutput();
                    $hash = $this->filesystem->getHashFile('md5', $filePathHeader, true);
                    if (md5($output) != $hash) {
                        file_put_contents($filePathHeader, $output);
                    }
                }
            }
        }

        /*
         * Add to file compiled
         */
        $this->compiledFile = $path.'.c';
        $this->ir = null;
    }
822872
public function preCompileClass(CompilationContext $compilationContext, $namespace, $topStatement, $docblock)
    {
        $classDefinition = new ClassDefinition($namespace, $topStatement['name']);
        $classDefinition->setIsExternal($this->external);

        if (isset($topStatement['extends'])) {
            $classDefinition->setExtendsClass($this->getFullName($topStatement['extends']));
        }

        if (isset($topStatement['implements'])) {
            foreach ($topStatement['implements'] as &$implement) {
                $implement['value'] = $this->getFullName($implement['value']);
            }
            $classDefinition->setImplementsInterfaces($topStatement['implements']);
        }

        if (isset($topStatement['abstract'])) {
            $classDefinition->setIsAbstract($topStatement['abstract']);
        }

        if (isset($topStatement['final'])) {
            $classDefinition->setIsFinal($topStatement['final']);
        }

        if (\is_array($docblock)) {
            $classDefinition->setDocBlock($docblock['value']);
        }

        if (isset($topStatement['definition'])) {
            $definition = $topStatement['definition'];

            if (isset($definition['properties'])) {
                foreach ($definition['properties'] as $property) {
                    /*
                     * Add property to the definition
                     */
                    $classDefinition->addProperty(new ClassProperty(
                        $classDefinition,
                        $property['visibility'],
                        $property['name'],
                        isset($property['default']) ? $property['default'] : null,
                        isset($property['docblock']) ? $property['docblock'] : null,
                        $property
                    ));

                    /*
                     * Check and process shortcuts
                     */
                    if (isset($property['shortcuts'])) {
                        $this->processShortcuts($property, $classDefinition);
                    }
                }
            }

            /*
             * Register constants
             */
            if (isset($definition['constants'])) {
                foreach ($definition['constants'] as $constant) {
                    $classDefinition->addConstant(new ClassConstant(
                        $constant['name'],
                        isset($constant['default']) ? $constant['default'] : null,
                        isset($constant['docblock']) ? $constant['docblock'] : null
                    ));
                }
            }

            /*
             * Register methods
             */
            if (isset($definition['methods'])) {
                foreach ($definition['methods'] as $method) {
                    $classDefinition->addMethod(new ClassMethod(
                        $classDefinition,
                        $method['visibility'],
                        $method['name'],
                        isset($method['parameters']) ? new ClassMethodParameters($method['parameters']) : null,
                        isset($method['statements']) ? new StatementsBlock($method['statements']) : null,
                        isset($method['docblock']) ? $method['docblock'] : null,
                        isset($method['return-type']) ? $method['return-type'] : null,
                        $method
                    ), $method);
                }
            }
        }

        $this->classDefinition = $classDefinition;

        /*
         * Assign current class definition to the compilation context
         */
        $compilationContext->classDefinition = $classDefinition;

        /*
         * Run pre-compilation passes
         */
        $classDefinition->preCompile($compilationContext);
    }
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);
    }
251936
public function compile(Compiler $compiler)
    {
        $compiler->addDebugInfo($this);

        $compiler
            ->write('try {')
        ;

        $compiler
            ->indent()
            ->subcompile($this->getNode('try'))
        ;

        if ($this->hasNode('catch') && null !== $this->getNode('catch')) {
            $compiler
                ->outdent()
                ->write('} catch (\Exception $e) {' . "\n")
                ->indent()
                ->write('if (isset($context[\'grav\'][\'debugger\'])) $context[\'grav\'][\'debugger\']->addException($e);' . "\n")
                ->write('$context[\'e\'] = $e;' . "\n")
                ->subcompile($this->getNode('catch'))
            ;
        }

        $compiler
            ->outdent()
            ->write("}\n");
    }
504791
public function observeOrNullifyVariant(CompilationContext $compilationContext)
    {
        if ($this->numberSkips) {
            --$this->numberSkips;

            return;
        }

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

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

            ++$this->variantInits;

            $this->setMustInitNull(true);
        }
    }
195053
public function hasVariable($name, CompilationContext $compilationContext = null)
    {
        return false !== $this->getVariable($name, $compilationContext ?: $this->compilationContext);
    }
197911
public function addCompilerPasses(CompilerPassInterface ...$compilerPasses): void
    {
        foreach ($compilerPasses as $compilerPass)
        {
            $this->compilerPasses->attach($compilerPass);
        }
    }
588368
public function compile(CompilationContext $compilationContext)
    {
        $statement = $this->statement;

        if (!isset($statement['data-type'])) {
            throw new CompilerException('Data type is required', $this->statement);
        }

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

        foreach ($statement['variables'] as $variable) {
            $varName = $variable['variable'];
            if ($symbolTable->hasVariableInBranch($varName, $compilationContext->branchManager->getCurrentBranch())) {
                throw new CompilerException("Variable '".$varName."' is already defined", $variable);
            }

            $currentType = $statement['data-type'];

            /*
             * Replace original data type by the pre-processed infered type
             */
            if ($typeInference) {
                if ('variable' == $currentType) {
                    $type = $typeInference->getInferedType($varName);
                    if (\is_string($type)) {
                        $currentType = $type;
                    }
                }
            }

            switch ($currentType) {
                case 'variable':
                case 'array-access':
                case 'property-access':
                case 'static-property-access':
                case 'fcall':
                case 'mcall':
                case 'scall':
                    $currentType = 'variable';
                    break;
            }

            /**
             * Variables are added to the symbol table.
             */
            $symbolVariable = $symbolTable->addVariable($currentType, $varName, $compilationContext);
            $varName = $symbolVariable->getName();

            /*
             * Set the node where the variable is declared
             */
            $symbolVariable->setOriginal($variable);

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

            if ('variable' == $currentType) {
                $symbolVariable->setMustInitNull(true);
                $symbolVariable->setLocalOnly(false);
            }
            //$symbolVariable->increaseVariantIfNull();

            if (isset($variable['expr'])) {
                $builder = BuilderFactory::getInstance();
                $letBuilder = $builder->statements()->let([
                    $builder->operators()
                        ->assignVariable($varName, $builder->raw($variable['expr'])),
                ]);

                $letStatement = new LetStatement($letBuilder->build());
                $letStatement->compile($compilationContext);
            } else {
                $symbolVariable->enableDefaultAutoInitValue();
            }
        }
    }
226317
public function compile(CompilationContext $compilationContext, $unreachable = false, $branchType = Branch::TYPE_UNKNOWN)
    {
        $compilationContext->codePrinter->increaseLevel();
        ++$compilationContext->currentBranch;

        /**
         * Create a new branch.
         */
        $currentBranch = new Branch();
        $currentBranch->setType($branchType);
        $currentBranch->setUnreachable($unreachable);

        /*
         * Activate branch in the branch manager
         */
        $compilationContext->branchManager->addBranch($currentBranch);

        $this->unreachable = $unreachable;

        $statements = $this->statements;

        /*
         * Reference the block if it belongs to a loop
         */
        if ($this->loop) {
            array_push($compilationContext->cycleBlocks, $this);
        }

        $where = '';
        if ($compilationContext->classDefinition) {
            $where = sprintf(
                'in %s',
                $compilationContext->classDefinition->getCompleteName()
            );

            if ($compilationContext->currentMethod) {
                $where .= sprintf('::%s', $compilationContext->currentMethod->getName());
            }
        }

        foreach ($statements as $statement) {
            /*
             * Generate GDB hints
             * @todo
             */
            if ($this->debug) {
                if (isset($statement['file'])) {
                    if ('declare' != $statement['type'] && 'comment' != $statement['type']) {
                        $compilationContext->codePrinter->outputNoIndent('#line '.$statement['line'].' "'.$statement['file'].'"');
                    }
                }
            }

            /*
             * Show warnings if code is generated when the 'unreachable state' is 'on'
             */
            if (true === $this->unreachable) {
                switch ($statement['type']) {
                    case 'echo':
                        $compilationContext->logger->warning(
                            sprintf('Unreachable code %s', $where),
                            ['unreachable-code', $statement['expressions'][0]]
                        );
                        break;

                    case 'let':
                        $compilationContext->logger->warning(
                            sprintf('Unreachable code %s', $where),
                            ['unreachable-code', $statement['assignments'][0]]
                        );
                        break;

                    case 'fetch':
                    case 'fcall':
                    case 'mcall':
                    case 'scall':
                    case 'if':
                    case 'while':
                    case 'do-while':
                    case 'switch':
                    case 'for':
                    case 'return':
                    case 'c-block':
                        if (isset($statement['expr'])) {
                            $compilationContext->logger->warning(
                                sprintf('Unreachable code %s', $where),
                                ['unreachable-code', $statement['expr']]
                            );
                        } else {
                            $compilationContext->logger->warning(
                                sprintf('Unreachable code %s', $where),
                                ['unreachable-code', $statement]
                            );
                        }
                        break;

                    default:
                        $compilationContext->logger->warning(
                            sprintf('Unreachable code %s', $where),
                            ['unreachable-code', $statement]
                        );
                }
            }

            switch ($statement['type']) {
                case 'let':
                    $letStatement = new LetStatement($statement);
                    $letStatement->compile($compilationContext);
                    break;

                case 'echo':
                    $echoStatement = new EchoStatement($statement);
                    $echoStatement->compile($compilationContext);
                    break;

                case 'declare':
                    $declareStatement = new DeclareStatement($statement);
                    $declareStatement->compile($compilationContext);
                    break;

                case 'if':
                    $ifStatement = new IfStatement($statement);
                    $ifStatement->compile($compilationContext);
                    break;

                case 'while':
                    $whileStatement = new WhileStatement($statement);
                    $whileStatement->compile($compilationContext);
                    break;

                case 'do-while':
                    $doWhileStatement = new DoWhileStatement($statement);
                    $doWhileStatement->compile($compilationContext);
                    break;

                case 'switch':
                    $switchStatement = new SwitchStatement($statement);
                    $switchStatement->compile($compilationContext);
                    break;

                case 'for':
                    $forStatement = new ForStatement($statement);
                    $forStatement->compile($compilationContext);
                    break;

                case 'return':
                    $returnStatement = new ReturnStatement($statement);
                    $returnStatement->compile($compilationContext);
                    $this->unreachable = true;
                    break;

                case 'require':
                    $requireStatement = new RequireStatement($statement);
                    $requireStatement->compile($compilationContext);
                    break;

                case 'loop':
                    $loopStatement = new LoopStatement($statement);
                    $loopStatement->compile($compilationContext);
                    break;

                case 'break':
                    $breakStatement = new BreakStatement($statement);
                    $breakStatement->compile($compilationContext);
                    $this->unreachable = true;
                    break;

                case 'continue':
                    $continueStatement = new ContinueStatement($statement);
                    $continueStatement->compile($compilationContext);
                    $this->unreachable = true;
                    break;

                case 'unset':
                    $unsetStatement = new UnsetStatement($statement);
                    $unsetStatement->compile($compilationContext);
                    break;

                case 'throw':
                    $throwStatement = new ThrowStatement($statement);
                    $throwStatement->compile($compilationContext);
                    $this->unreachable = true;
                    break;

                case 'try-catch':
                    $throwStatement = new TryCatchStatement($statement);
                    $throwStatement->compile($compilationContext);
                    $this->unreachable = false;
                    break;

                case 'fetch':
                    $expr = new Expression($statement['expr']);
                    $expr->setExpectReturn(false);
                    $compiledExpression = $expr->compile($compilationContext);
                    $compilationContext->codePrinter->output($compiledExpression->getCode().';');
                    break;

                case 'mcall':
                    $methodCall = new MethodCall();
                    $expr = new Expression($statement['expr']);
                    $expr->setExpectReturn(false);
                    $methodCall->compile($expr, $compilationContext);
                    break;

                case 'fcall':
                    $functionCall = new FunctionCall();
                    $expr = new Expression($statement['expr']);
                    $expr->setExpectReturn(false);
                    $compiledExpression = $functionCall->compile($expr, $compilationContext);
                    switch ($compiledExpression->getType()) {
                        case 'int':
                        case 'double':
                        case 'uint':
                        case 'long':
                        case 'ulong':
                        case 'char':
                        case 'uchar':
                        case 'bool':
                            $compilationContext->codePrinter->output($compiledExpression->getCode().';');
                            break;
                    }
                    break;

                case 'scall':
                    $methodCall = new StaticCall();
                    $expr = new Expression($statement['expr']);
                    $expr->setExpectReturn(false);
                    $methodCall->compile($expr, $compilationContext);
                    break;

                case 'cblock':
                    $compilationContext->codePrinter->output($statement['value']);
                    break;

                case 'comment':
                case 'empty':
                    break;

                default:
                    throw new Exception('Unsupported statement: '.$statement['type']);
            }

            if ('comment' != $statement['type']) {
                $this->lastStatement = $statement;
            }
        }

        /*
         * Reference the block if it belongs to a loop
         */
        if ($this->loop) {
            array_pop($compilationContext->cycleBlocks);
        }

        /*
         * Traverses temporal variables created in a specific branch
         * marking them as idle
         */
        $compilationContext->symbolTable->markTemporalVariablesIdle($compilationContext);

        $compilationContext->branchManager->removeBranch($currentBranch);

        --$compilationContext->currentBranch;
        $compilationContext->codePrinter->decreaseLevel();

        return $currentBranch;
    }