protected function buildString(array $parts, array $mergedParams, array $defaults)
    {
        $stack   = [];
        $current = [
            'is_optional' => false,
            'skip'        => true,
            'skippable'   => false,
            'path'        => '',
        ];

        foreach ($parts as $part) {
            switch ($part[static::TYPE]) {
                case 'literal':
                    $current['path'] .= $part[static::LITERAL];
                    break;

                case 'parameter':
                    $current['skippable'] = true;

                    if (!isset($mergedParams[$part[static::NAME]])) {
                        if (!$current['is_optional']) {
                            throw new Exception\InvalidArgumentException(sprintf(
                                'Missing parameter "%s"',
                                $part[static::NAME]
                            ));
                        }

                        continue;
                    } elseif (!$current['is_optional']
                        || !isset($defaults[$part[static::NAME]])
                        || $defaults[$part[static::NAME]] !== $mergedParams[$part[static::NAME]]
                    ) {
                        $current['skip'] = false;
                    }

                    $current['path'] .= $mergedParams[$part[static::NAME]];
                    break;

                case 'optional-start':
                    $stack[] = $current;
                    $current = [
                        'is_optional' => true,
                        'skip'        => true,
                        'skippable'   => false,
                        'path'        => '',
                    ];
                    break;

                case 'optional-end':
                    $parent = array_pop($stack);

                    if (!($current['path'] !== ''
                        && $current['is_optional']
                        && $current['skippable']
                        && $current['skip'])
                    ) {
                        $parent['path'] .= $current['path'];
                        $parent['skip'] = false;
                    }

                    $current = $parent;
                    break;
            }
        }

        return $current['path'];
    }