protected function parseSegment($currentPosition)
    {
        $nextStartPosition = $this->calculateNextTokenPosition($currentPosition, ContentCache::CACHE_SEGMENT_START_TOKEN);
        if ($nextStartPosition !== $currentPosition) {
            throw new Exception(sprintf('The current position (%d) is not the start of a segment, next start position %d', $currentPosition, $nextStartPosition), 1472464124);
        }

        $segmentData = [
            'identifier' => '',
            'type' => '',
            'context' => '',
            'metadata' => '',
            'content' => '',
            'cleanContent' => '',
            'embed' => ''
        ];

        $nextEndPosition = $this->calculateNextTokenPosition($currentPosition, ContentCache::CACHE_SEGMENT_END_TOKEN);
        $currentPosition = $this->calculateCurrentPosition($nextStartPosition);
        $nextStartPosition = $this->calculateNextTokenPosition($currentPosition, ContentCache::CACHE_SEGMENT_START_TOKEN);

        $nextIdentifierSeparatorPosition = $this->calculateNextTokenPosition($currentPosition, ContentCache::CACHE_SEGMENT_SEPARATOR_TOKEN);
        $nextSecondIdentifierSeparatorPosition = $this->calculateNextTokenPosition($nextIdentifierSeparatorPosition + 1, ContentCache::CACHE_SEGMENT_SEPARATOR_TOKEN);

        if ($nextIdentifierSeparatorPosition === false || $nextSecondIdentifierSeparatorPosition === false
            || $nextStartPosition !== false && $nextStartPosition < $nextSecondIdentifierSeparatorPosition
            || $nextEndPosition !== false && $nextEndPosition < $nextSecondIdentifierSeparatorPosition
        ) {
            throw new Exception(sprintf('Missing segment separator token after position %d', $currentPosition), 1391855139);
        }

        $identifier = $this->extractContent($currentPosition, $nextIdentifierSeparatorPosition);
        $contextOrMetadata = $this->extractContent($this->calculateCurrentPosition($nextIdentifierSeparatorPosition), $nextSecondIdentifierSeparatorPosition);

        $segmentData['identifier'] = $identifier;
        $segmentData['type'] = ContentCache::SEGMENT_TYPE_CACHED;
        $segmentData['metadata'] = $contextOrMetadata;
        $segmentData['context'] = $contextOrMetadata;

        if (strpos($identifier, 'eval=') === 0) {
            $segmentData['type'] = ContentCache::SEGMENT_TYPE_UNCACHED;
            unset($segmentData['metadata']);
            $this->uncachedPartCount++;
        }

        if (strpos($identifier, 'evalCached=') === 0) {
            $segmentData['type'] = ContentCache::SEGMENT_TYPE_DYNAMICCACHED;
            $segmentData['identifier'] = substr($identifier, 11);
            $additionalData = json_decode($contextOrMetadata, true);
            $segmentData['metadata'] = $additionalData['metadata'];
            $this->uncachedPartCount++;
        }

        $currentPosition = $this->calculateCurrentPosition($nextSecondIdentifierSeparatorPosition);
        $segmentData = $this->extractContentAndSubSegments($currentPosition, $segmentData);

        if ($segmentData['type'] === ContentCache::SEGMENT_TYPE_CACHED || $segmentData['type'] === ContentCache::SEGMENT_TYPE_DYNAMICCACHED) {
            $this->cacheSegments[$identifier] = $this->reduceSegmentDataToCacheRelevantInformation($segmentData);
        }

        return $segmentData;
    }