예제 #1
0
        //
        // A Selector Element
        //
        //     div
        //     + h1
        //     #socks
        //     input[type="text"]
        //
        // Elements are the building blocks for Selectors,
        // they are made out of a `Combinator` (see combinator rule),
        // and an element name, such as a tag a class, or `*`.
        //
        public Element Element(Parser parser)
        {
            var index = parser.Tokenizer.Location.Index;

            GatherComments(parser);

            Combinator c = Combinator(parser);

            PushComments();
            GatherComments(parser); // to collect, combinator must have picked up something which would require memory anyway
            var e = parser.Tokenizer.Match(@"[.#:]?[a-zA-Z0-9_-]+") || parser.Tokenizer.Match('*') || Attribute(parser) ||
                    parser.Tokenizer.MatchAny(@"\([^)@]+\)");

            bool isCombinatorAnd = !e && c.Value.StartsWith("&");

            if (e || isCombinatorAnd)
            {
                c.PostComments = PullComments();
                PopComments();
                c.PreComments = PullComments();
                return(NodeProvider.Element(c, isCombinatorAnd ? null : e.Value, index));
            }

            PopComments();
            return(null);
        }
예제 #2
0
        //
        // div, .class, body > p {...}
        //
        public Ruleset Ruleset(Parser parser)
        {
            var selectors = new NodeList <Selector>();

            var memo  = Remember(parser);
            var index = memo.TokenizerLocation.Index;

            if (parser.Tokenizer.Peek(@"([a-z.#: _-]+)[\s\n]*\{")) //simple case with no comments
            {
                var match = parser.Tokenizer.Match(@"[a-z.#: _-]+");
                selectors =
                    new NodeList <Selector>(
                        NodeProvider.Selector(new NodeList <Element>(NodeProvider.Element(null, match.Value, index)), index));
            }
            else
            {
                Selector s;
                while (s = Selector(parser))
                {
                    selectors.Add(s);
                    if (!parser.Tokenizer.Match(','))
                    {
                        break;
                    }

                    GatherComments(parser);
                }
            }

            NodeList rules;

            if (selectors.Count > 0 && (rules = Block(parser)) != null)
            {
                return(NodeProvider.Ruleset(selectors, rules, index));
            }

            Recall(parser, memo);

            return(null);
        }
예제 #3
0
        //
        // Mixins
        //

        //
        // A Mixin call, with an optional argument list
        //
        //     #mixins > .square(#fff);
        //     .rounded(4px, black);
        //     .button;
        //
        // The `while` loop is there because mixins can be
        // namespaced, but we only support the child and descendant
        // selector for now.
        //
        public MixinCall MixinCall(Parser parser)
        {
            var elements = new NodeList <Element>();
            var index    = parser.Tokenizer.Location.Index;

            RegexMatchResult e;
            Combinator       c = null;

            PushComments();

            for (var i = parser.Tokenizer.Location.Index; e = parser.Tokenizer.Match(@"[#.][a-zA-Z0-9_-]+"); i = parser.Tokenizer.Location.Index)
            {
                elements.Add(NodeProvider.Element(c, e.Value, i));

                i = parser.Tokenizer.Location.Index;
                var match = parser.Tokenizer.Match('>');
                c = match != null?NodeProvider.Combinator(match.Value, i) : null;
            }

            var args = new List <NamedArgument>();

            if (parser.Tokenizer.Match('('))
            {
                Expression arg;
                while (arg = Expression(parser))
                {
                    var    value = arg;
                    string name  = null;

                    if (arg.Value.Count == 1 && arg.Value[0] is Variable)
                    {
                        if (parser.Tokenizer.Match(':'))
                        {
                            if (value = Expression(parser))
                            {
                                name = (arg.Value[0] as Variable).Name;
                            }
                            else
                            {
                                throw new ParsingException("Expected value", parser.Tokenizer.Location.Index);
                            }
                        }
                    }

                    args.Add(new NamedArgument {
                        Name = name, Value = value
                    });

                    if (!parser.Tokenizer.Match(','))
                    {
                        break;
                    }
                }
                if (!parser.Tokenizer.Match(')'))
                {
                    throw new ParsingException("Expected ')'", parser.Tokenizer.Location.Index);
                }
            }

            if (elements.Count > 0)
            {
                // if elements then we've picked up chars so don't need to worry about remembering
                var postComments = GatherAndPullComments(parser);

                if (End(parser))
                {
                    var mixinCall = NodeProvider.MixinCall(elements, args, index);
                    mixinCall.PostComments = postComments;
                    PopComments();
                    return(mixinCall);
                }
            }

            PopComments();
            return(null);
        }