Beispiel #1
0
        public override Node Evaluate(Env env)
        {
            var closures = env.FindRulesets(Selector);

            if (closures == null)
            {
                throw new ParsingException(Selector.ToCSS(env).Trim() + " is undefined", Location);
            }

            env.Rule = this;

            var rules = new NodeList();

            if (PreComments)
            {
                rules.AddRange(PreComments);
            }

            var rulesetList = closures.ToList();

            // To address bug https://github.com/dotless/dotless/issues/136, where a mixin and ruleset selector may have the same name, we
            // need to favour matching a MixinDefinition with the required Selector and only fall back to considering other Ruleset types
            // if no match is found.
            // However, in order to support having a regular ruleset with the same name as a parameterized
            // mixin (see https://github.com/dotless/dotless/issues/387), we need to take argument counts into account, so we make the
            // decision after evaluating for argument match.

            var mixins = rulesetList.Where(c => c.Ruleset is MixinDefinition).ToList();

            var defaults = new List <Closure>();

            bool foundMatches = false, foundExactMatches = false, foundDefaultMatches = false;

            foreach (var closure in mixins)
            {
                var ruleset   = (MixinDefinition)closure.Ruleset;
                var matchType = ruleset.MatchArguments(Arguments, env);
                if (matchType == MixinMatch.ArgumentMismatch)
                {
                    continue;
                }

                if (matchType == MixinMatch.Default)
                {
                    defaults.Add(closure);
                    foundDefaultMatches = true;

                    continue;
                }

                foundMatches = true;

                if (matchType == MixinMatch.GuardFail)
                {
                    continue;
                }

                foundExactMatches = true;

                try
                {
                    var closureEnvironment = env.CreateChildEnvWithClosure(closure);
                    rules.AddRange(ruleset.Evaluate(Arguments, closureEnvironment).Rules);
                }
                catch (ParsingException e)
                {
                    throw new ParsingException(e.Message, e.Location, Location);
                }
            }

            if (!foundExactMatches && foundDefaultMatches)
            {
                foreach (var closure in defaults)
                {
                    try {
                        var closureEnvironment = env.CreateChildEnvWithClosure(closure);
                        var ruleset            = (MixinDefinition)closure.Ruleset;
                        rules.AddRange(ruleset.Evaluate(Arguments, closureEnvironment).Rules);
                    } catch (ParsingException e) {
                        throw new ParsingException(e.Message, e.Location, Location);
                    }
                }
                foundMatches = true;
            }

            if (!foundMatches)
            {
                var regularRulesets = rulesetList.Except(mixins);

                foreach (var closure in regularRulesets)
                {
                    if (closure.Ruleset.Rules != null)
                    {
                        var nodes = (NodeList)closure.Ruleset.Rules.Clone();
                        NodeHelper.ExpandNodes <MixinCall>(env, nodes);

                        rules.AddRange(nodes);
                    }

                    foundMatches = true;
                }
            }

            if (PostComments)
            {
                rules.AddRange(PostComments);
            }

            env.Rule = null;

            if (!foundMatches)
            {
                var message = String.Format("No matching definition was found for `{0}({1})`",
                                            Selector.ToCSS(env).Trim(),
                                            Arguments.Select(a => a.Value.ToCSS(env)).JoinStrings(env.Compress ? "," : ", "));
                throw new ParsingException(message, Location);
            }

            rules.Accept(new ReferenceVisitor(IsReference));

            if (Important)
            {
                return(MakeRulesImportant(rules));
            }

            return(rules);
        }
Beispiel #2
0
        public override Node Evaluate(Env env)
        {
            var closures = env.FindRulesets(Selector);
            if (closures == null)
                throw new ParsingException(Selector.ToCSS(env).Trim() + " is undefined", Location);

            env.Rule = this;

            var rules = new NodeList();

            if (PreComments)
                rules.AddRange(PreComments);

            var rulesetList = closures.ToList();

            // To address bug https://github.com/dotless/dotless/issues/136, where a mixin and ruleset selector may have the same name, we
            // need to favour matching a MixinDefinition with the required Selector and only fall back to considering other Ruleset types
            // if no match is found.
            // However, in order to support having a regular ruleset with the same name as a parameterized
            // mixin (see https://github.com/dotless/dotless/issues/387), we need to take argument counts into account, so we make the
            // decision after evaluating for argument match.

            var mixins = rulesetList.Where(c => c.Ruleset is MixinDefinition).ToList();

            var defaults = new List<Closure>();

            bool foundMatches = false, foundExactMatches = false, foundDefaultMatches = false;
            foreach (var closure in mixins)
            {
                var ruleset = (MixinDefinition)closure.Ruleset;
                var matchType = ruleset.MatchArguments(Arguments, env);
                if (matchType == MixinMatch.ArgumentMismatch)
                {
                    continue;
                }

                if (matchType == MixinMatch.Default) {
                    defaults.Add(closure);
                    foundDefaultMatches = true;

                    continue;
                }

                foundMatches = true;

                if (matchType == MixinMatch.GuardFail)
                {
                    continue;
                }

                foundExactMatches = true;

                try
                {
                    var closureEnvironment = env.CreateChildEnvWithClosure(closure);
                    rules.AddRange(ruleset.Evaluate(Arguments, closureEnvironment).Rules);
                }
                catch (ParsingException e)
                {
                    throw new ParsingException(e.Message, e.Location, Location);
                }
            }

            if (!foundExactMatches && foundDefaultMatches) {
                foreach (var closure in defaults) {
                    try {
                        var closureEnvironment = env.CreateChildEnvWithClosure(closure);
                        var ruleset = (MixinDefinition) closure.Ruleset;
                        rules.AddRange(ruleset.Evaluate(Arguments, closureEnvironment).Rules);
                    } catch (ParsingException e) {
                        throw new ParsingException(e.Message, e.Location, Location);
                    }
                }
                foundMatches = true;
            }

            if (!foundMatches)
            {
                var regularRulesets = rulesetList.Except(mixins);

                foreach (var closure in regularRulesets)
                {
                    if (closure.Ruleset.Rules != null) {
                        var nodes = (NodeList)closure.Ruleset.Rules.Clone();
                        NodeHelper.ExpandNodes<MixinCall>(env, nodes);

                        rules.AddRange(nodes);
                    }

                    foundMatches = true;
                }
            }

            if (PostComments)
                rules.AddRange(PostComments);

            env.Rule = null;

            if (!foundMatches)
            {
                var message = String.Format("No matching definition was found for `{0}({1})`",
                                            Selector.ToCSS(env).Trim(),
                                            Arguments.Select(a => a.Value.ToCSS(env)).JoinStrings(env.Compress ? "," : ", "));
                throw new ParsingException(message, Location);
            }

            rules.Accept(new ReferenceVisitor(IsReference));

            if (Important)
            {
                return MakeRulesImportant(rules);
            }

            return rules;
        }