MoreInternals.Model.Selector.ParseRawCompoundSelector C# (CSharp) Method

ParseRawCompoundSelector() private static method

private static ParseRawCompoundSelector ( string raw, int start, int stop, string filePath ) : Selector
raw string
start int
stop int
filePath string
return Selector
        private static Selector ParseRawCompoundSelector(string raw, int start, int stop, string filePath)
        {
            if (raw[0] == '&')
            {
                return new ConcatWithParentSelector(ParseRawCompoundSelector(raw.Substring(1), start, stop, filePath), start, stop, filePath);
            }

            var ret = new List<Selector>();

            bool skippedColon = false;
            for (int i = 0; i < raw.Length; i++)
            {
                var c = raw[i];

                if (c != ':')
                {
                    skippedColon = false;
                }

                if (c == '*')
                {
                    ret.Add(WildcardSelector.Singleton);
                    continue;
                }

                var j = _NextIndexOf(raw, i + 1, '#', ':', '.', '[', ']');
                if (j == -1) j = raw.Length;

                var name = raw.Substring(i, j - i);

                if (name.StartsWith(":not(") && name[name.Length - 1] != ')')
                {
                    j = raw.IndexOf(')', j);
                    if (j == -1) throw new InvalidOperationException("Expected to find closing )");
                    j++;
                    name = raw.Substring(i, j - i);
                }

                i = j - 1;

                if (c == '#')
                {
                    var id = name.Substring(1);

                    if (!Validation.IsIdentifier(id))
                    {
                        Current.RecordError(ErrorType.Parser, Position.Create(start, stop, filePath), "[" + id + "] is not a valid identifier");
                        throw new StoppedParsingException();
                    }

                    ret.Add(new IdSelector(id, start, stop, filePath));
                    continue;
                }

                if (c == '.')
                {
                    var @class = name.Substring(1);

                    ret.Add(new ClassSelector(@class, start, stop, filePath));
                    continue;
                }

                if (c == ':')
                {
                    // :: syntax, which is *technically different... but in practice every browser just
                    //   treats the same because they have to
                    if (i + 1 < raw.Length && raw[i + 1] == ':' && !skippedColon)
                    {
                        // act like that colon isn't there, but just once,
                        //   if we want to make a distinction in the AST later, we can do it here
                        skippedColon = true;
                        continue;
                    }

                    var pseudo = (PseudoClassSelector)PseudoClassSelector.Parse(name, start, stop, filePath);

                    if (pseudo.IsElement && !skippedColon)
                    {
                        Current.RecordWarning(ErrorType.Parser, pseudo, pseudo.Name + " was used as a class, but is an element.  Use :: instead.");
                    }

                    if (!pseudo.IsElement && skippedColon)
                    {
                        // Because nothing is ever easy, :before and :after are legal to refer to either way despite being elements
                        if (!pseudo.Name.In("before", "after"))
                        {
                            Current.RecordWarning(ErrorType.Parser, pseudo, pseudo.Name + " was used as an element, but is a class.  Use : instead.");
                        }
                    }

                    ret.Add(pseudo);

                    continue;
                }

                if (c == '[')
                {
                    ret.Add(AttributeSelector.Parse(name, start, stop, filePath));
                    i++;
                    continue;
                }

                if (!Validation.IsIdentifier(name))
                {
                    Current.RecordError(ErrorType.Parser, Position.Create(start, stop, filePath), "[" + name + "] is not a valid identifier");
                    throw new StoppedParsingException();
                }

                ret.Add(new ElementSelector(name, start, stop, filePath));
            }

            if (ret.Count == 1) return ret[0];

            return new ConcatSelector(ret, start, stop, filePath);
        }