// 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)); }
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)); }
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)); }
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)); }