Пример #1
0
        // Basically, it's realy common for background-position to be something like "0px -20px", which shouldn't be interpretted as a math value
        //   so detect the case where two number with unit values are separated by whitespace and treat them as a compound value instead
        //   otherwise, fallback to normal parsing
        internal static Value ParseBackgroundPositionValue(ParserStream stream)
        {
            var start    = stream.Position;
            var valueStr = new StringBuilder();

            stream.ScanUntilWithNesting(valueStr, ';');

            var value = valueStr.ToString();

            var parts = value.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

            var pos = Position.Create(start, stream.Position, Current.CurrentFilePath);

            // something's up
            if (parts.Length != 2)
            {
                return(MoreValueParser.Parse(value, pos));
            }

            var p1 = parts[0];
            var p2 = parts[1];

            var v1 = MoreValueParser.Parse(p1, pos);
            var v2 = MoreValueParser.Parse(p2, pos);

            if (v1 is NumberWithUnitValue && v2 is NumberWithUnitValue)
            {
                return(new CompoundValue(v1, v2));
            }

            return(MoreValueParser.Parse(value, pos));
        }
Пример #2
0
        internal static Value ParseFontLikeValue(ParserStream stream)
        {
            var start    = stream.Position;
            var valueStr = new StringBuilder();

            stream.ScanUntilWithNesting(valueStr, ';');

            var value = valueStr.ToString();

            // The shorthand isn't in use, so we can handle this
            if (value.IndexOf('/') == -1)
            {
                return(MoreValueParser.Parse(value, Position.Create(start, stream.Position, Current.CurrentFilePath)));
            }

            return(new StringValue(value));
        }
Пример #3
0
        private static MediaQuery ParseMediaClause(string media, IPosition forPosition)
        {
            if (!media.StartsWith("(") || !media.EndsWith(")"))
            {
                Current.RecordError(ErrorType.Parser, forPosition, "Media features must be enclosed in paranthesis, found '" + media + "'");
                throw new StoppedParsingException();
            }

            // Trim leading ( and trailing )
            media = media.Substring(1, media.Length - 2).Trim();

            var i = media.IndexOf(':');

            if (i == -1)
            {
                if (!IsValidFeatureName(media))
                {
                    Current.RecordError(ErrorType.Parser, forPosition, "Media feature not recognized, found '" + media + "'");
                    throw new StoppedParsingException();
                }

                return(new FeatureMedia(media, forPosition));
            }

            var feature  = media.Substring(0, i).Trim();
            var valueStr = media.Substring(i + 1).Trim();
            var value    = MoreValueParser.Parse(valueStr, forPosition);

            var math = value as MathValue;

            if (math != null)
            {
                // Ratio check
                if (math.Operator == Operator.Div && IsRatioFeature(feature))
                {
                    var ratio = new RatioValue(math.LeftHand, math.RightHand);
                    ratio.Start    = value.Start;
                    ratio.Stop     = value.Stop;
                    ratio.FilePath = value.FilePath;

                    value = ratio;
                }
            }

            if (feature.StartsWith("min-", StringComparison.InvariantCultureIgnoreCase))
            {
                feature = feature.Substring("min-".Length);
                if (!IsValidMinMaxFeatureName(feature))
                {
                    Current.RecordError(ErrorType.Parser, forPosition, "Media feature not recognized in min clause, found '" + feature + "'");
                    throw new StoppedParsingException();
                }

                return(new MinFeatureMedia(feature, value, forPosition));
            }

            if (feature.StartsWith("max-", StringComparison.InvariantCultureIgnoreCase))
            {
                feature = feature.Substring("max-".Length);
                if (!IsValidMinMaxFeatureName(feature))
                {
                    Current.RecordError(ErrorType.Parser, forPosition, "Media feature not recognized in max clause, found '" + feature + "'");
                    throw new StoppedParsingException();
                }

                return(new MaxFeatureMedia(feature, value, forPosition));
            }

            return(new EqualFeatureMedia(feature, value, forPosition));
        }
Пример #4
0
        internal static Value ParseFuncValue(ParserStream stream, IPosition forPosition, bool allowSelectorIncludes)
        {
            stream.Advance(); // skip @
            var buffer = new StringBuilder();

            var c = stream.Peek();

            while (char.IsWhiteSpace(c))
            {
                stream.Advance();
                c = stream.Peek();
            }

            if (!char.IsLetter(c) && c != '(')
            {
                Current.RecordError(ErrorType.Parser, forPosition, "Expected letter or '(', found '" + c + "'");
                throw new StoppedParsingException();
            }

            if (c != '(')
            {
                buffer.Append(stream.Read());

                while (stream.HasMore() && char.IsLetterOrDigit(stream.Peek()))
                {
                    buffer.Append(stream.Read());
                }
            }

            var funcName = buffer.ToString();

            buffer.Clear();

            while (stream.HasMore() && char.IsWhiteSpace(stream.Peek()))
            {
                buffer.Append(stream.Read());
            }

            if (stream.HasMore() && stream.Peek() == '(')
            {
                stream.Read(); // Skip (

                buffer.Clear();
                stream.ScanUntilWithNesting(buffer, ')');

                if (funcName.Length == 0)
                {
                    if (allowSelectorIncludes)
                    {
                        var sel = Selector.Parse(buffer.ToString(), forPosition.Start, forPosition.Stop, forPosition.FilePath);
                        return(new IncludeSelectorValue(sel));
                    }

                    return(new StringValue("@(" + buffer + ")"));
                }

                var value = MoreValueParser.Parse(buffer.ToString().Trim(), forPosition, allowSelectorIncludes: true);
                if (value is NotFoundValue)
                {
                    throw new StoppedParsingException();
                }

                var @params = new List <Value>();
                if (value is CommaDelimittedValue)
                {
                    @params.AddRange(((CommaDelimittedValue)value).Values);
                }
                else
                {
                    @params.Add(value);
                }

                return(new FuncAppliationValue(funcName, @params));
            }

            return(new FuncValue(funcName));
        }