Example #1
0
        public static StyleDeclaration ParseStyleDeclaration(ITokenStream tokens, bool nested)
        {
            var selector = ParseOrSelector(tokens, nested);
            var current  = tokens.DrainConsume();

            if (!(current is LCurlyToken))
            {
                throw new FormatException($"Unexpected symbol at {tokens.FormatPosition(current)}, '{{' expected.");
            }

            var statements = new List <StylesheetStatement>();

            while (true)
            {
                current = tokens.DrainPeek();
                if (current is RCurlyToken)
                {
                    tokens.DrainConsume();
                    break;
                }

                statements.Add(ParseStatement(tokens));
            }

            return(new StyleDeclaration(selector, statements));
        }
Example #2
0
        public static Stylesheet ParseStylesheet(ITokenStream tokens)
        {
            var statements = new List <StylesheetDeclaration>();

            while (tokens.DrainPeek() != null)
            {
                statements.Add(ParseStylesheetDeclaration(tokens));
            }

            return(new Stylesheet(statements));
        }
Example #3
0
        public static StylesheetDeclaration ParseStylesheetDeclaration(ITokenStream tokens)
        {
            var current = tokens.DrainPeek();

            switch (current)
            {
            case ScriptToken _:
                return(ParseScriptDeclaration(tokens));

            default:
                return(ParseStyleDeclaration(tokens, false));
            }
        }
Example #4
0
        public static OrSelector ParseOrSelector(ITokenStream tokens, bool isNested)
        {
            var selectors = new List <ContainmentSelector>
            {
                ParseContainmentSelector(tokens, isNested)
            };

            while (true)
            {
                var current = tokens.DrainPeek();
                if (current is CommaToken)
                {
                    tokens.Consume();
                    tokens.DrainPeek();
                    selectors.Add(ParseContainmentSelector(tokens, isNested));
                }
                else
                {
                    break;
                }
            }

            return(new OrSelector(selectors));
        }
Example #5
0
        public static ContainmentSelector ParseContainmentSelector(ITokenStream tokens, bool isNested)
        {
            var selectors = new List <AndSelector>
            {
                ParseAndSelector(tokens)
            };

            while (true)
            {
                var zero = tokens.Peek();
                if (!(zero is WhitespaceToken))
                {
                    break;
                }

                var one = tokens.DrainPeek();
                switch (one)
                {
                case CommaToken _:
                case LCurlyToken _:
                    goto exit;

                default:
                    selectors.Add(ParseAndSelector(tokens));
                    continue;
                }
            }

exit:

            for (var i = 1; i < selectors.Count; i++)
            {
                if (selectors[i].HasContextSelector)
                {
                    throw new FormatException("Unexpected context selector in rule.");
                }
            }

            if (isNested && !selectors[0].HasContextSelector)
            {
                selectors.Insert(0, new AndSelector(new[] { new ContextSelector() }));
            }

            return(new ContainmentSelector(selectors));
        }
Example #6
0
 private static Token DrainConsume(this ITokenStream tokens)
 {
     tokens.DrainPeek();
     return(tokens.Consume());
 }
Example #7
0
        public static StylesheetStatement ParseStatement(ITokenStream tokens)
        {
            var zero = tokens.DrainPeek();

            if (zero is ScriptToken scriptToken)
            {
                return(ParseScriptDeclaration(tokens));
            }

            var one = tokens.PeekOnly(t => !(t is WhitespaceToken), 1);

            if (one is ColonToken)
            {
                tokens.Consume();
                tokens.DrainConsume();

                string key;
                switch (zero)
                {
                case IdentifierToken id:
                    key = id.Value;
                    break;

                case StringToken str:
                    key = str.Value;
                    break;

                default:
                    throw new FormatException($"Expected an identifier or string at {tokens.FormatPosition(zero)}.");
                }

                var stringBuilder = new StringBuilder();
                var ws            = false;
                var counter       = 0;
                foreach (var t in tokens
                         .ConsumeUntil(t => t is SemiColonToken))
                {
                    switch (t)
                    {
                    case IdentifierToken id:
                        stringBuilder.Append(id.Value);
                        counter++;
                        ws = false;
                        continue;

                    case StringToken str:
                        stringBuilder.Append(str.Value);
                        counter++;
                        ws = false;
                        continue;

                    case WhitespaceToken _:
                        if (counter > 0 && !ws)
                        {
                            stringBuilder.Append(" ");
                        }

                        ws = true;
                        continue;

                    default:
                        throw new FormatException($"Invalid value at {tokens.FormatPosition(t)}.");
                    }
                }

                if (counter == 0)
                {
                    throw new FormatException($"Expected an assigned value to {tokens.FormatPosition(zero)}.");
                }

                tokens.Consume();
                if (ws)
                {
                    stringBuilder.Remove(stringBuilder.Length - 1, 1);
                }

                return(new AssignmentStatement(key, stringBuilder.ToString()));
            }

            return(ParseStyleDeclaration(tokens, true));
        }