public function addPattern($pattern, $childRuleName = null) {
        preg_match_all(
            '/\\\\.|' . // match \.
            '\(\?|[()]|' . // match "(" or ")"
            '\[\^?\]?(?:\\\\.|\[:[^]]*:\]|[^]\\\\])*\]|' . // match combination of "[]"
            '[^[()\\\\]+/', // match not in list "()\"
            $pattern, $matches);

        $groupDeep = 0;
        $pattern = '(';

        foreach ($matches[0] as $match) {
            switch ($match) {
                case '(':
                    $pattern .= '\\(';
                    break;

                case ')':
                    if ($groupDeep > 0) {
                        $groupDeep--;
                    } else {
                        $pattern .= '\\';
                    }
                    $pattern .= ')';
                    break;

                case '(?':
                    $groupDeep++;
                    $pattern .= '(?';
                    break;

                default:
                    $pattern .= substr($match, 0, 1) == '\\'
                        ? $match
                        : str_replace('/', '\\/', $match);
                    break;
            }
        }

        $pattern .= ')';

        $this->patterns[] = [
            'pattern'       => $pattern,
            'childRuleName' => $childRuleName,
        ];
    }