public function format($sql)
    {
        $this->reset();
        $tab = "\t";

        $originalTokens = $this->tokenizer->tokenize((string) $sql);
        $tokens = WhiteSpace::removeTokenWhitespace($originalTokens);

        foreach ($tokens as $i => $token) {
            $queryValue = $token[Tokenizer::TOKEN_VALUE];
            $this->indentation->increaseSpecialIndent()->increaseBlockIndent();
            $addedNewline = $this->newLine->addNewLineBreak($tab);

            if ($this->comment->stringHasCommentToken($token)) {
                $this->formattedSql = $this->comment->writeCommentBlock($token, $tab, $queryValue);
                continue;
            }

            if ($this->parentheses->getInlineParentheses()) {
                if ($this->parentheses->stringIsClosingParentheses($token)) {
                    $this->parentheses->writeInlineParenthesesBlock($tab, $queryValue);
                    continue;
                }
                $this->newLine->writeNewLineForLongCommaInlineValues($token);
                $this->inlineCount += \strlen($token[Tokenizer::TOKEN_VALUE]);
            }

            switch ($token) {
                case $this->parentheses->stringIsOpeningParentheses($token):
                    $tokens = $this->formatOpeningParenthesis($token, $i, $tokens, $originalTokens);
                    break;

                case $this->parentheses->stringIsClosingParentheses($token):
                    $this->indentation->decreaseIndentLevelUntilIndentTypeIsSpecial($this);
                    $this->newLine->addNewLineBeforeToken($addedNewline, $tab);
                    break;

                case $this->stringIsEndOfLimitClause($token):
                    $this->clauseLimit = false;
                    break;

                case $token[Tokenizer::TOKEN_VALUE] === ',' && false === $this->parentheses->getInlineParentheses():
                    $this->newLine->writeNewLineBecauseOfComma();
                    break;

                case Token::isTokenTypeReservedTopLevel($token):
                    $queryValue = $this->formatTokenTypeReservedTopLevel($addedNewline, $tab, $token, $queryValue);
                    break;

                case $this->newLine->isTokenTypeReservedNewLine($token):
                    $this->newLine->addNewLineBeforeToken($addedNewline, $tab);

                    if (WhiteSpace::tokenHasExtraWhiteSpaces($token)) {
                        $queryValue = \preg_replace('/\s+/', ' ', $queryValue);
                    }
                    break;
            }

            $this->formatBoundaryCharacterToken($token, $i, $tokens, $originalTokens);
            $this->formatWhiteSpaceToken($token, $queryValue);
            $this->formatDashToken($token, $i, $tokens);
        }

        return \trim(\str_replace(["\t", " \n"], [$this->tab, "\n"], $this->formattedSql))."\n";
    }