protected function createSegments(array $tokens) : array
    {
        // Stack of opened tags.
        $active = new TagStack();

        return array_reduce($tokens, function (array $segments, $token) use ($active) {
            if ($token instanceof TagToken) {
                /** @var TagToken $token */
                if ($token->isOpening()) {
                    // If tag token is opening, add tag to the stack.
                    $active->push(Tag::createFromToken($token));
                } else {
                    // If tag token is closing, find matching tag in the stack.
                    $tagName = $token->getTagName();
                    $isFound = $active->removeLast($tagName);
                    if (!$isFound) {
                        // If not found, return tag token as a text.
                        $text = $token->getRawText();
                        $tags = $active->asArray();
                        $segments[] = new TextSegment($text, $tags);
                    }
                }
            } else {
                // Return text segment with currently active tags.
                /** @var TextToken $token */
                $text = $token->getRawText();
                $tags = $active->asArray();
                $segments[] = new TextSegment($text, $tags);
            }

            return $segments;
        }, []);
    }