public MatchContext(GlobMatcherOptions options, string str, PatternCase patternCase)
 {
     _myOptions                 = options;
     _myStr                     = str;
     _myPatternCase             = patternCase;
     _myStartOffset             = 0;
     _myEndOffset               = _myStr.Length;
     _myStartItem               = 0;
     _myEndItem                 = _myPatternCase.Count - 1;
     _myLastAsteriskItem        = -1;
     _myNextPositionForAsterisk = -1;
 }
        // parse a component of the expanded set.
        // ReSharper disable once FunctionComplexityOverflow
        private static PatternCase Parse(GlobMatcherOptions options, string?pattern)
        {
            if (pattern?.Length == 0)
            {
                return(new PatternCase());
            }

            var result = new PatternCase();
            var sb     = new StringBuilder();

            bool escaping = false, inClass = false, negate = false, range = false;
            int  classStart = -1;

            void FinishLiteral()
            {
                Debug.Assert(!escaping && !inClass, "!escaping && !inClass");
                if (sb.Length <= 0)
                {
                    return;
                }

                result.Add(new Literal(sb.ToString()));
                sb.Clear();
            }

            void AppendChar(char c1)
            {
                if (inClass && range)
                {
                    char firstChar = sb[sb.Length - 1];
                    firstChar++;

                    for (char c2 = firstChar; c2 <= c1; c2++)
                    {
                        sb.Append(c2);
                    }

                    range = false;
                }
                else
                {
                    sb.Append(c1);
                }
            }

            if (pattern == null)
            {
                throw new InvalidOperationException();
            }

            for (var i = 0; i < pattern.Length; i++)
            {
                var c = pattern[i];

                // skip over any that are escaped.
                if (escaping && c != '/')
                {
                    AppendChar(c);
                    escaping = false;
                }
                else
                {
                    switch (c)
                    {
                    case '/':
                        if (inClass)
                        {
                            // Class is left open
                            HandleOpenClass();
                            continue;
                        }
                        else
                        {
                            if (escaping)
                            {
                                sb.Append('\\');
                                escaping = false;
                            }

                            FinishLiteral();

                            if (!(result.LastOrDefault() is PathSeparator))
                            {
                                result.Add(PathSeparator.Instance);
                            }
                        }

                        break;

                    case '\\':
                        escaping = true;
                        break;

                    case '!':
                    case '^':
                        if (inClass && i == classStart + 1)
                        {
                            // the glob [!a] means negation
                            negate = true;
                        }
                        else
                        {
                            AppendChar(c);
                        }

                        break;

                    case '?':
                        if (inClass)
                        {
                            AppendChar(c);
                        }
                        else
                        {
                            FinishLiteral();
                            result.Add(OneChar.EmptyInstance);
                        }

                        break;

                    case '*':
                        if (inClass)
                        {
                            AppendChar(c);
                        }
                        else
                        {
                            FinishLiteral();
                            if (result.LastOrDefault() is Asterisk && !options.NoGlobStar)
                            {
                                result.RemoveAt(result.Count - 1);
                                result.Add(new DoubleAsterisk());
                            }
                            else if (!(result.LastOrDefault() is SimpleAsterisk))
                            {
                                result.Add(new SimpleAsterisk());
                            }
                        }

                        break;

                    // these are mostly the same in regexp and glob
                    case '[':

                        if (inClass)
                        {
                            AppendChar(c);
                        }
                        else
                        {
                            FinishLiteral();
                            inClass    = true;
                            negate     = false;
                            range      = false;
                            classStart = i;
                        }

                        break;

                    case ']':
                        //  a right bracket shall lose its special
                        //  meaning and represent itself in
                        //  a bracket expression if it occurs
                        //  first in the list.  -- POSIX.2 2.8.3.2
                        if (i == classStart + 1 || (negate && i == classStart + 2) || !inClass)
                        {
                            AppendChar(c);
                        }
                        else
                        {
                            if (range)
                            {
                                sb.Append('-');
                            }

                            // finish up the class.
                            inClass = false;
                            result.Add(new OneChar(sb.ToString(), negate));
                            sb.Clear();
                        }

                        break;

                    case '-':
                        if (i == classStart + 1 || (negate && i == classStart + 2) || !inClass || range)
                        {
                            AppendChar(c);
                        }
                        else
                        {
                            range = true;
                        }

                        break;

                    default:
                        AppendChar(c);
                        break;
                    } // switch
                }     // if

                if (i == pattern.Length - 1)
                {
                    if (inClass)
                    {
                        HandleOpenClass();

                        // Do not continue, because next check could be relevant
                    }
                }

                if (i == pattern.Length - 1)
                {
                    if (escaping)
                    {
                        sb.Append('\\');
                        escaping = false;
                        FinishLiteral();
                    }
                    else
                    {
                        FinishLiteral();
                    }
                }

                void HandleOpenClass()
                {
                    // handle the case where we left a class open.
                    // "[abc" is valid, equivalent to "\[abc"

                    // split where the last [ was, and escape it
                    // this is a huge pita.  We now have to re-walk
                    // the contents of the would-be class to re-translate
                    // any characters that were passed through as-is

                    sb.Clear();
                    if (result.LastOrDefault() is Literal literal)
                    {
                        sb.Append(literal.Source);
                        result.RemoveAt(result.Count - 1);
                    }

                    sb.Append('[');

                    escaping = false;
                    i        = classStart;
                    inClass  = false;
                } // Handle open class
            }     // for

            result.Build();
            return(result);
        }