protected function compile()
    {
        $this->parts = $parts = preg_split(
            '#\/#', $this->path, -1, PREG_SPLIT_NO_EMPTY
        );
        $regex = '';

        foreach ($parts as &$part) {
            $control = substr($part, 0, 2);
            if (false !== strpos($control, ':')) {
                if (! preg_match('#\A(~)?(:){1}[a-zA-Z0-9]+\Z#', $part)) {
                    throw new InvalidArgumentException(sprintf(
                        'Invalid placeholder name "%s" provided; must contain '
                        . 'only english alphanumeric characters.',
                        $part
                    ));
                }
            } elseif (preg_match('/[\#\?]+/', $part)) {
                throw new InvalidArgumentException(sprintf(
                    'The segment "%s" of path "%s" contains illegal characters.',
                    $part,
                    $this->path
                ));
            }
            if ('~:' === substr($part, 0, 2)) {
                $part = ltrim($part, '~:');
                $regex .= '\/?(?P<' . $part . '>';

                if (isset($this->constraints[$part])) {
                    $regex .= $this->constraints[$part] . ')';
                } else {
                    $regex .= '[^\/]*)';
                }
            } elseif (':' === substr($part, 0, 1)) {
                $part = ltrim($part, ':');
                $regex .= '\/(?P<' . $part . '>';

                if (isset($this->constraints[$part])) {
                    $regex .= $this->constraints[$part] . ')';
                } else {
                    $regex .= '[^\/]+)';
                }
            } elseif ('~' === substr($part, 0, 1)) {
                $part = ltrim($part, '~');
                $regex .= '\/?(' . preg_quote(Uri::encode($part)) . ')?';
            } else {
                $part = $part;
                $regex .= '\/' . preg_quote(Uri::encode($part));
            }
        }
        $this->compiled = '#\A' . $regex . '\Z#';
    }