Read() public method

Read a single character from the stream.
public Read ( ) : char
return char
Ejemplo n.º 1
0
        private static Value ParseImportant(ParserStream stream)
        {
            var buffer = new StringBuilder();

            while (stream.HasMore() && (char.IsLetterOrDigit(stream.Peek()) || stream.Peek().In('!', '-', '_')))
            {
                buffer.Append(stream.Read());
            }

            var ret = buffer.ToString();

            if (ret.Equals("!important", StringComparison.InvariantCultureIgnoreCase))
            {
                return(ImportantValue.Singleton);
            }

            return(new StringValue(ret));
        }
Ejemplo n.º 2
0
        internal static SpriteRule ParseSpriteRule(ParserStream stream)
        {
            var start = stream.Position;

            if (stream.Peek() != '@')
            {
                Current.RecordError(ErrorType.Parser, Position.Create(start, stream.Position, Current.CurrentFilePath), "Expected '@'");
                throw new StoppedParsingException();
            }

            stream.Advance(); // Advance past @

            var name = new StringBuilder();

            while (stream.HasMore() && stream.Peek() != '=')
            {
                name.Append(stream.Read());
            }

            stream.AdvancePast("="); // Advance past =

            var ignored = new StringBuilder();
            var quote   = stream.ScanUntil(ignored, '\'', '"');

            if (quote == null)
            {
                Current.RecordError(ErrorType.Parser, Position.Create(start, stream.Position, Current.CurrentFilePath), "Expected quotation mark");
                throw new StoppedParsingException();
            }

            var valueStart = stream.Position;
            var valueStr   = new StringBuilder();

            valueStr.Append(quote.Value);
            stream.ScanUntil(valueStr, quote.Value);
            valueStr.Append(quote.Value);

            stream.AdvancePast(";");

            var value = (QuotedStringValue)Value.Parse(valueStr.ToString(), valueStart, stream.Position, Current.CurrentFilePath);

            return(new SpriteRule(name.ToString().Trim(), value, start, stream.Position, Current.CurrentFilePath));
        }
Ejemplo n.º 3
0
        internal static ColorValue ParseHashColor(ParserStream stream, IPosition forPosition)
        {
            stream.Advance(); // skip #
            var buffer = new StringBuilder();

            while (buffer.Length < 6 && stream.HasMore() && char.ToLower(stream.Peek()).In('a', 'b', 'c', 'd', 'e', 'f', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'))
            {
                buffer.Append(stream.Read());
            }

            if (buffer.Length != 3 && buffer.Length != 6)
            {
                Current.RecordError(ErrorType.Parser, forPosition, "Expected 3 or 6 hexidecimal characters");
                throw new StoppedParsingException();
            }

            if (buffer.Length == 3)
            {
                return(HexTripleColorValue.Parse(buffer.ToString()));
            }

            return(HexSextupleColorValue.Parse(buffer.ToString()));
        }
Ejemplo n.º 4
0
        internal static Property ParseMixinOrVariableRule(ParserStream stream)
        {
            var start = stream.Position;

            var name = new StringBuilder();

            stream.Advance(); // Skip @

            bool trimmingWhiteSpace = false;

            while (stream.HasMore() && !stream.Peek().In('(', '='))
            {
                // Check for nested media block syntax
                if (name.ToString().Equals("media", StringComparison.InvariantCultureIgnoreCase))
                {
                    return(ParseInnerMediaDirective(stream));
                }

                var c = stream.Read();

                if (char.IsWhiteSpace(c))
                {
                    trimmingWhiteSpace = true;
                    continue;
                }

                if (trimmingWhiteSpace || (!char.IsLetterOrDigit(c) && !c.In('-', '_')))
                {
                    Current.RecordError(ErrorType.Parser, Position.Create(start, stream.Position, Current.CurrentFilePath), "Unexpected character '" + c + "'");
                    throw new StoppedParsingException();
                }
                name.Append(c);
            }

            if (!stream.Peek().In('(', '='))
            {
                Current.RecordError(ErrorType.Parser, Position.Create(start, stream.Position, Current.CurrentFilePath), "Expected '(' or '='");
                throw new StoppedParsingException();
            }

            if (stream.Peek() == '=')
            {
                stream.Advance();

                var localValue = ParseMoreValue(stream);
                var varName    = name.ToString().Trim();

                if (varName.ToLower().In(ReservedWords))
                {
                    Current.RecordError(ErrorType.Parser, Position.Create(start, stream.Position, Current.CurrentFilePath), "'" + varName + "' cannot be a variable name.");
                }

                return(new VariableProperty(varName, localValue, start, stream.Position, Current.CurrentFilePath));
            }

            stream.Advance();

            var startParams = stream.Position;

            var paramStart = stream.Position;
            var @params    = new StringBuilder();

            stream.ScanUntilWithNesting(@params, ')');
            var paramStop = stream.Position;

            var options      = new StringBuilder();
            var optionsStart = stream.Position;

            stream.ScanUntil(options, ';');

            var nameStr    = name.ToString().Trim();
            var paramsStr  = @params.ToString().Trim();
            var optionsStr = options.ToString().Trim();

            var optional  = optionsStr.Contains('?');
            var overrides = optionsStr.Contains('!');

            var unexpected = optionsStr.Where(c => !char.IsWhiteSpace(c) && c != '?' && c != '!');

            if (unexpected.Count() != 0)
            {
                if (unexpected.Count() == 0)
                {
                    Current.RecordError(ErrorType.Parser, Position.Create(start, optionsStart + options.Length, Current.CurrentFilePath), "Unexpected character '" + unexpected.ElementAt(0) + "'");
                }
                else
                {
                    Current.RecordError(
                        ErrorType.Parser,
                        Position.Create(
                            start,
                            optionsStart + options.Length,
                            Current.CurrentFilePath
                            ),
                        "Unexpected characters " +
                        string.Join(", ", unexpected.Select(c => "'" + c + "'"))
                        );
                }

                throw new StoppedParsingException();
            }

            if (name.Length == 0)
            {
                if (optional)
                {
                    Current.RecordWarning(ErrorType.Parser, Position.Create(start, optionsStart + options.Length, Current.CurrentFilePath), "Include directives are always optional, no trailing '?' is needed.");
                }
                return(new IncludeSelectorProperty(Selector.Parse(paramsStr, paramStart, paramStop, Current.CurrentFilePath), overrides, start, stream.Position, Current.CurrentFilePath));
            }

            if (name.ToString().Trim().Equals("reset", StringComparison.InvariantCultureIgnoreCase))
            {
                if (paramsStr.Trim().Length != 0)
                {
                    return(new ResetProperty(Selector.Parse(paramsStr, paramStart, paramStop, Current.CurrentFilePath), start, stream.Position, Current.CurrentFilePath));
                }

                return(new ResetSelfProperty(InvalidSelector.Singleton, start, stream.Position, Current.CurrentFilePath));
            }

            return(new MixinApplicationProperty(nameStr, ParseApplicationParameters(paramsStr, startParams), optional: optional, overrides: overrides, start: start, stop: stream.Position, filePath: Current.CurrentFilePath));
        }
Ejemplo n.º 5
0
        internal static Property ParseMixinOrVariableRule(ParserStream stream)
        {
            var start = stream.Position;

            var name = new StringBuilder();
            stream.Advance(); // Skip @

            bool trimmingWhiteSpace = false;

            while (stream.HasMore() && !stream.Peek().In('(', '='))
            {
                // Check for nested media block syntax
                if (name.ToString().Equals("media", StringComparison.InvariantCultureIgnoreCase))
                {
                    return ParseInnerMediaDirective(stream);
                }

                var c = stream.Read();

                if (char.IsWhiteSpace(c))
                {
                    trimmingWhiteSpace = true;
                    continue;
                }

                if (trimmingWhiteSpace || (!char.IsLetterOrDigit(c) && !c.In('-', '_')))
                {
                    Current.RecordError(ErrorType.Parser, Position.Create(start, stream.Position, Current.CurrentFilePath), "Unexpected character '" + c + "'");
                    throw new StoppedParsingException();
                }
                name.Append(c);
            }

            if (!stream.Peek().In('(', '='))
            {
                Current.RecordError(ErrorType.Parser, Position.Create(start, stream.Position, Current.CurrentFilePath), "Expected '(' or '='");
                throw new StoppedParsingException();
            }

            if (stream.Peek() == '=')
            {
                stream.Advance();

                var localValue = ParseMoreValue(stream);
                var varName = name.ToString().Trim();

                if (varName.ToLower().In(ReservedWords))
                {
                    Current.RecordError(ErrorType.Parser, Position.Create(start, stream.Position, Current.CurrentFilePath), "'" + varName + "' cannot be a variable name.");
                }

                return new VariableProperty(varName, localValue, start, stream.Position, Current.CurrentFilePath);
            }

            stream.Advance();

            var startParams = stream.Position;

            var paramStart = stream.Position;
            var @params = new StringBuilder();
            stream.ScanUntilWithNesting(@params, ')');
            var paramStop = stream.Position;

            var options = new StringBuilder();
            var optionsStart = stream.Position;
            stream.ScanUntil(options, ';');

            var nameStr = name.ToString().Trim();
            var paramsStr = @params.ToString().Trim();
            var optionsStr = options.ToString().Trim();

            var optional = optionsStr.Contains('?');
            var overrides = optionsStr.Contains('!');

            var unexpected = optionsStr.Where(c => !char.IsWhiteSpace(c) && c != '?' && c != '!');

            if (unexpected.Count() != 0)
            {
                if (unexpected.Count() == 0)
                {
                    Current.RecordError(ErrorType.Parser, Position.Create(start, optionsStart + options.Length, Current.CurrentFilePath), "Unexpected character '" + unexpected.ElementAt(0) + "'");
                }
                else
                {
                    Current.RecordError(
                        ErrorType.Parser,
                        Position.Create(
                            start,
                            optionsStart + options.Length,
                            Current.CurrentFilePath
                        ),
                        "Unexpected characters "+
                            string.Join(", ", unexpected.Select(c => "'"+c+"'"))
                    );
                }

                throw new StoppedParsingException();
            }

            if (name.Length == 0)
            {
                if (optional)
                {
                    Current.RecordWarning(ErrorType.Parser, Position.Create(start, optionsStart + options.Length, Current.CurrentFilePath), "Include directives are always optional, no trailing '?' is needed.");
                }
                return new IncludeSelectorProperty(Selector.Parse(paramsStr, paramStart, paramStop, Current.CurrentFilePath), overrides, start, stream.Position, Current.CurrentFilePath);
            }

            if (name.ToString().Trim().Equals("reset", StringComparison.InvariantCultureIgnoreCase))
            {
                if (paramsStr.Trim().Length != 0)
                {
                    return new ResetProperty(Selector.Parse(paramsStr, paramStart, paramStop, Current.CurrentFilePath), start, stream.Position, Current.CurrentFilePath);
                }

                return new ResetSelfProperty(InvalidSelector.Singleton, start, stream.Position, Current.CurrentFilePath);
            }

            return new MixinApplicationProperty(nameStr, ParseApplicationParameters(paramsStr, startParams), optional: optional, overrides: overrides, start: start, stop: stream.Position, filePath: Current.CurrentFilePath);
        }
Ejemplo n.º 6
0
        internal static SpriteRule ParseSpriteRule(ParserStream stream)
        {
            var start = stream.Position;

            if (stream.Peek() != '@')
            {
                Current.RecordError(ErrorType.Parser, Position.Create(start, stream.Position, Current.CurrentFilePath), "Expected '@'");
                throw new StoppedParsingException();
            }

            stream.Advance(); // Advance past @

            var name = new StringBuilder();

            while (stream.HasMore() && stream.Peek() != '=')
            {
                name.Append(stream.Read());
            }

            stream.AdvancePast("="); // Advance past =

            var ignored = new StringBuilder();
            var quote = stream.ScanUntil(ignored, '\'', '"');

            if (quote == null)
            {
                Current.RecordError(ErrorType.Parser, Position.Create(start, stream.Position, Current.CurrentFilePath), "Expected quotation mark");
                throw new StoppedParsingException();
            }

            var valueStart = stream.Position;
            var valueStr = new StringBuilder();
            valueStr.Append(quote.Value);
            stream.ScanUntil(valueStr, quote.Value);
            valueStr.Append(quote.Value);

            stream.AdvancePast(";");

            var value = (QuotedStringValue)Value.Parse(valueStr.ToString(), valueStart, stream.Position, Current.CurrentFilePath);

            return new SpriteRule(name.ToString().Trim(), value, start, stream.Position, Current.CurrentFilePath);
        }
Ejemplo n.º 7
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);
        }
Ejemplo n.º 8
0
        private static Value ParseString(ParserStream stream, IPosition forPosition)
        {
            var c = stream.Peek();

            if (c == '!')
            {
                return ParseImportant(stream);
            }

            var buffer = new StringBuilder();
            while (stream.HasMore() && !char.IsWhiteSpace(stream.Peek()))
            {
                buffer.Append(stream.Read());

                if (buffer.Length == 3 && (stream.HasMore() && stream.Peek() == '('))
                {
                    var toDate = buffer.ToString();
                    if (toDate.Equals("rgb", StringComparison.InvariantCultureIgnoreCase) || toDate.Equals("hsl", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var group = ParseGroup(stream, forPosition);
                        var @params = group.Value as CommaDelimittedValue;
                        if (@params == null || @params.Values.Count() != 3)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "Expected 3 parameters to '" + toDate + "'");
                            throw new StoppedParsingException();
                        }

                        if(toDate == "rgb")
                        {
                            return
                                new RGBColorValue(
                                    @params.Values.ElementAt(0),
                                    @params.Values.ElementAt(1),
                                    @params.Values.ElementAt(2)
                                );
                        }

                        if (toDate == "hsl")
                        {
                            return
                                new HSLColorValue
                                (
                                    @params.Values.ElementAt(0),
                                    @params.Values.ElementAt(1),
                                    @params.Values.ElementAt(2)
                                );
                        }
                    }

                    if (toDate.Equals("url", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var value = ParseGroup(stream, forPosition).Value;

                        if(value is StringValue || value is QuotedStringValue)
                        {
                            return new UrlValue(value);
                        }

                        Current.RecordError(ErrorType.Parser, forPosition, "Expected string or quoted string");
                        throw new StoppedParsingException();
                    }
                }

                if (buffer.Length == 4 && (stream.HasMore() && stream.Peek() == '('))
                {
                    var toDate = buffer.ToString();
                    if (toDate.Equals("rgba", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var @params = ParseGroup(stream, forPosition).Value as CommaDelimittedValue;
                        if (@params == null || @params.Values.Count() != 4)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "Expected 4 parameters to '" + toDate + "'");
                            throw new StoppedParsingException();
                        }

                        return
                            new RGBAColorValue(
                                @params.Values.ElementAt(0),
                                @params.Values.ElementAt(1),
                                @params.Values.ElementAt(2),
                                @params.Values.ElementAt(3)
                            );
                    }
                }

                if (buffer.Length == 5 && (stream.HasMore() && stream.Peek() == '('))
                {
                    var toDate = buffer.ToString();
                    if (toDate.Equals("local", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var val = ParseGroup(stream, forPosition).Value;
                        var comma = val as CommaDelimittedValue;
                        if (comma != null)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "Expected 1 parameter to local() value, found "+comma.Values.Count());
                            throw new StoppedParsingException();
                        }

                        return new LocalValue(val);
                    }
                }

                if (buffer.Length == 6 && (stream.HasMore() && stream.Peek() == '('))
                {
                    var toDate = buffer.ToString();
                    if (toDate.Equals("format", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var val = ParseGroup(stream, forPosition).Value;
                        var comma = val as CommaDelimittedValue;
                        if (comma != null)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "Expected 1 parameter to format() value, found " + comma.Values.Count());
                            throw new StoppedParsingException();
                        }

                        return new FormatValue(val);
                    }
                }
            }

            NamedColor color;
            if (Enum.TryParse<NamedColor>(buffer.ToString(), ignoreCase: true, result: out color))
            {
                return new NamedColorValue(color);
            }

            var str = buffer.ToString();

            if (str.Contains("!"))
            {
                var i = str.IndexOf('!');
                var left = str.Substring(0, i);
                var right = str.Substring(i);

                var ret = new List<Value>();
                var lhs = Parse(left, forPosition);
                var rhs = Parse(right, forPosition);

                if (lhs is CompoundValue)
                {
                    ret.AddRange(((CompoundValue)lhs).Values);
                }
                else
                {
                    ret.Add(lhs);
                }

                if (rhs is CompoundValue)
                {
                    ret.AddRange(((CompoundValue)rhs).Values);
                }
                else
                {
                    ret.Add(rhs);
                }

                return new CompoundValue(ret);
            }

            return new StringValue(buffer.ToString());
        }
Ejemplo n.º 9
0
        private static Value ParseNumber(ParserStream stream, IPosition forPosition)
        {
            var pushbackBuffer = new StringBuilder();

            var buffer = new StringBuilder();

            bool negate = false;

            if (stream.Peek() == '-')
            {
                negate = true;
                stream.Advance();
                pushbackBuffer.Append('-');
            }

            bool decimalPassed = false;

            while (stream.HasMore() && (char.IsDigit(stream.Peek()) || (stream.Peek() == '.' && !decimalPassed)))
            {
                var c = stream.Read();
                buffer.Append(c);
                pushbackBuffer.Append(c);

                if (c == '.') decimalPassed = true;
            }

            Unit? unit = null;
            decimal digit;
            if (!decimal.TryParse(buffer.ToString(), out digit))
            {
                // Looked like a number, but wasn't!
                stream.PushBack(pushbackBuffer.ToString());
                return ParseString(stream, forPosition);
            }

            if (negate) digit *= -1m;

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

            var nextFour = new StringBuilder();
            for (int i = 0; i < 4; i++)
            {
                if (stream.HasMore())
                {
                    nextFour.Append(stream.Read());
                }
            }

            var possibleUnit = nextFour.ToString();
            List<char> pushBack;

            unit = ParsePossibleUnit(possibleUnit, out pushBack);

            if (unit == null)
            {
                stream.PushBack(nextFour.ToString());
                stream.PushBack(buffer.ToString());
            }
            else
            {
                stream.PushBack(pushBack);
                return new NumberWithUnitValue(digit, unit.Value);
            }

            return new NumberValue(digit);
        }
Ejemplo n.º 10
0
        private static Value ParseImportant(ParserStream stream)
        {
            var buffer = new StringBuilder();

            while (stream.HasMore() && (char.IsLetterOrDigit(stream.Peek()) || stream.Peek().In('!', '-', '_')))
            {
                buffer.Append(stream.Read());
            }

            var ret = buffer.ToString();

            if (ret.Equals("!important", StringComparison.InvariantCultureIgnoreCase)) return ImportantValue.Singleton;

            return new StringValue(ret);
        }
Ejemplo n.º 11
0
        internal static ColorValue ParseHashColor(ParserStream stream, IPosition forPosition)
        {
            stream.Advance(); // skip #
            var buffer = new StringBuilder();

            while (buffer.Length < 6 && stream.HasMore() && char.ToLower(stream.Peek()).In('a', 'b', 'c', 'd', 'e', 'f', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'))
            {
                buffer.Append(stream.Read());
            }

            if (buffer.Length != 3 && buffer.Length != 6)
            {
                Current.RecordError(ErrorType.Parser, forPosition, "Expected 3 or 6 hexidecimal characters");
                throw new StoppedParsingException();
            }

            if (buffer.Length == 3)
            {
                return HexTripleColorValue.Parse(buffer.ToString());
            }

            return HexSextupleColorValue.Parse(buffer.ToString());
        }
Ejemplo n.º 12
0
        private static Value ParseNumber(ParserStream stream, IPosition forPosition)
        {
            var pushbackBuffer = new StringBuilder();

            var buffer = new StringBuilder();

            bool negate = false;

            if (stream.Peek() == '-')
            {
                negate = true;
                stream.Advance();
                pushbackBuffer.Append('-');
            }

            bool decimalPassed = false;

            while (stream.HasMore() && (char.IsDigit(stream.Peek()) || (stream.Peek() == '.' && !decimalPassed)))
            {
                var c = stream.Read();
                buffer.Append(c);
                pushbackBuffer.Append(c);

                if (c == '.')
                {
                    decimalPassed = true;
                }
            }

            Unit?   unit = null;
            decimal digit;

            if (!decimal.TryParse(buffer.ToString(), out digit))
            {
                // Looked like a number, but wasn't!
                stream.PushBack(pushbackBuffer.ToString());
                return(ParseString(stream, forPosition));
            }

            if (negate)
            {
                digit *= -1m;
            }

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

            var nextFour = new StringBuilder();

            for (int i = 0; i < 4; i++)
            {
                if (stream.HasMore())
                {
                    nextFour.Append(stream.Read());
                }
            }

            var         possibleUnit = nextFour.ToString();
            List <char> pushBack;

            unit = ParsePossibleUnit(possibleUnit, out pushBack);

            if (unit == null)
            {
                stream.PushBack(nextFour.ToString());
                stream.PushBack(buffer.ToString());
            }
            else
            {
                stream.PushBack(pushBack);
                return(new NumberWithUnitValue(digit, unit.Value));
            }

            return(new NumberValue(digit));
        }
Ejemplo n.º 13
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));
        }
Ejemplo n.º 14
0
        private static Value ParseString(ParserStream stream, IPosition forPosition)
        {
            var c = stream.Peek();

            if (c == '!')
            {
                return(ParseImportant(stream));
            }

            var buffer = new StringBuilder();

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

                if (buffer.Length == 3 && (stream.HasMore() && stream.Peek() == '('))
                {
                    var toDate = buffer.ToString();
                    if (toDate.Equals("rgb", StringComparison.InvariantCultureIgnoreCase) || toDate.Equals("hsl", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var group   = ParseGroup(stream, forPosition);
                        var @params = group.Value as CommaDelimittedValue;
                        if (@params == null || @params.Values.Count() != 3)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "Expected 3 parameters to '" + toDate + "'");
                            throw new StoppedParsingException();
                        }

                        if (toDate == "rgb")
                        {
                            return
                                (new RGBColorValue(
                                     @params.Values.ElementAt(0),
                                     @params.Values.ElementAt(1),
                                     @params.Values.ElementAt(2)
                                     ));
                        }

                        if (toDate == "hsl")
                        {
                            return
                                (new HSLColorValue
                                 (
                                     @params.Values.ElementAt(0),
                                     @params.Values.ElementAt(1),
                                     @params.Values.ElementAt(2)
                                 ));
                        }
                    }

                    if (toDate.Equals("url", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var value = ParseGroup(stream, forPosition).Value;

                        if (value is StringValue || value is QuotedStringValue)
                        {
                            return(new UrlValue(value));
                        }

                        Current.RecordError(ErrorType.Parser, forPosition, "Expected string or quoted string");
                        throw new StoppedParsingException();
                    }
                }

                if (buffer.Length == 4 && (stream.HasMore() && stream.Peek() == '('))
                {
                    var toDate = buffer.ToString();
                    if (toDate.Equals("rgba", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var @params = ParseGroup(stream, forPosition).Value as CommaDelimittedValue;
                        if (@params == null || @params.Values.Count() != 4)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "Expected 4 parameters to '" + toDate + "'");
                            throw new StoppedParsingException();
                        }

                        return
                            (new RGBAColorValue(
                                 @params.Values.ElementAt(0),
                                 @params.Values.ElementAt(1),
                                 @params.Values.ElementAt(2),
                                 @params.Values.ElementAt(3)
                                 ));
                    }

                    if (toDate.Equals("attr", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var @params = ParseGroup(stream, forPosition).Value;

                        Value attrAndType, attr, type, fallback;

                        var comma = @params as CommaDelimittedValue;
                        if (comma != null)
                        {
                            if (comma.Values.Count() > 2)
                            {
                                Current.RecordError(ErrorType.Parser, forPosition, "attr expects 1 or 2 parameters, found " + comma);
                                throw new StoppedParsingException();
                            }

                            attrAndType = comma.Values.ElementAt(0);

                            fallback = comma.Values.Count() == 2 ? comma.Values.ElementAt(1) : null;
                        }
                        else
                        {
                            attrAndType = @params;
                            fallback    = null;
                        }

                        var compound = attrAndType as CompoundValue;
                        if (compound != null)
                        {
                            if (compound.Values.Count() > 2)
                            {
                                Current.RecordError(ErrorType.Parser, forPosition, "attr expects an attribute name and optionally a type, found " + compound);
                                throw new StoppedParsingException();
                            }

                            attr = compound.Values.ElementAt(0);
                            type = compound.Values.Count() == 2 ? compound.Values.ElementAt(1) : null;
                        }
                        else
                        {
                            attr = attrAndType;
                            type = null;
                        }

                        return(new AttributeValue(attr, type, fallback));
                    }

                    if (toDate.Equals("calc", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var @params = ParseGroup(stream, forPosition).Value;

                        if (@params is CommaDelimittedValue)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "calc expects an expression, found " + @params);
                        }

                        string strVersion;
                        using (var writer = new StringWriter())
                        {
                            @params.Write(writer);
                            strVersion = writer.ToString();
                        }

                        // Things passed to calc are opting out of More magic, they don't get anything but in string replacements
                        return(new CalcValue(new StringValue(strVersion)));
                    }
                }

                if (buffer.Length == 5 && (stream.HasMore() && stream.Peek() == '('))
                {
                    var toDate = buffer.ToString();
                    if (toDate.Equals("local", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var val   = ParseGroup(stream, forPosition).Value;
                        var comma = val as CommaDelimittedValue;
                        if (comma != null)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "Expected 1 parameter to local() value, found " + comma.Values.Count());
                            throw new StoppedParsingException();
                        }

                        return(new LocalValue(val));
                    }

                    if (toDate.Equals("cycle", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var val   = ParseGroup(stream, forPosition).Value;
                        var param = new List <Value>();

                        var comma = val as CommaDelimittedValue;
                        if (comma != null)
                        {
                            param.AddRange(comma.Values);
                        }
                        else
                        {
                            param.Add(val);
                        }

                        return(new CycleValue(param));
                    }

                    if (toDate.Equals("steps", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var val   = ParseGroup(stream, forPosition).Value;
                        var comma = val as CommaDelimittedValue;
                        if (comma != null && comma.Values.Count() > 2)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "Expected at most 2 parameters to steps() value, found " + comma.Values.Count());
                            throw new StoppedParsingException();
                        }

                        var steps = comma != null?comma.Values.ElementAt(0) : val;

                        var dir = comma != null?comma.Values.ElementAt(1) : null;

                        return(new StepsValue(steps, dir));
                    }
                }

                if (buffer.Length == 6 && (stream.HasMore() && stream.Peek() == '('))
                {
                    var toDate = buffer.ToString();
                    if (toDate.Equals("format", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var val   = ParseGroup(stream, forPosition).Value;
                        var comma = val as CommaDelimittedValue;
                        if (comma != null)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "Expected 1 parameter to format() value, found " + comma.Values.Count());
                            throw new StoppedParsingException();
                        }

                        return(new FormatValue(val));
                    }
                }

                if (buffer.Length == 7 && (stream.HasMore() && stream.Peek() == '('))
                {
                    var toDate = buffer.ToString();
                    if (toDate.Equals("counter", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var val   = ParseGroup(stream, forPosition).Value;
                        var comma = val as CommaDelimittedValue;
                        if (comma != null && comma.Values.Count() > 2)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "Expected at most 2 parameters to counter() value, found " + comma.Values.Count());
                            throw new StoppedParsingException();
                        }

                        var counter = comma != null?comma.Values.ElementAt(0) : val;

                        var style = comma != null?comma.Values.ElementAt(1) : null;

                        return(new CounterValue(counter, style));
                    }
                }

                if (buffer.Length == 8 && (stream.HasMore() && stream.Peek() == '('))
                {
                    var toDate = buffer.ToString();
                    if (toDate.Equals("counters", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var val   = ParseGroup(stream, forPosition).Value;
                        var comma = val as CommaDelimittedValue;
                        if (comma != null && comma.Values.Count() > 2)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "Expected at most 2 parameters to counters() value, found " + comma.Values.Count());
                            throw new StoppedParsingException();
                        }

                        var counter = comma != null?comma.Values.ElementAt(0) : val;

                        var style = comma != null?comma.Values.ElementAt(1) : null;

                        return(new CountersValue(counter, style));
                    }
                }

                if (buffer.Length == 12 && (stream.HasMore() && stream.Peek() == '('))
                {
                    var toDate = buffer.ToString();
                    if (toDate.Equals("cubic-bezier", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var val   = ParseGroup(stream, forPosition).Value;
                        var comma = val as CommaDelimittedValue;
                        if (comma == null || comma.Values.Count() != 4)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "Excepted 4 parameters to cubic-bezier()");
                            throw new StoppedParsingException();
                        }

                        return
                            (new CubicBezierValue(
                                 comma.Values.ElementAt(0),
                                 comma.Values.ElementAt(1),
                                 comma.Values.ElementAt(2),
                                 comma.Values.ElementAt(3)
                                 ));
                    }
                }

                if (buffer.Length == 15 && (stream.HasMore() && stream.Peek() == '('))
                {
                    var toDate = buffer.ToString();
                    if (toDate.Equals("linear-gradient", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var val   = ParseGroup(stream, forPosition).Value;
                        var comma = val as CommaDelimittedValue;

                        if (comma == null || comma.Values.Count() < 2)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "linear-gradient expects at least two parameters");
                            throw new StoppedParsingException();
                        }

                        return(new LinearGradientValue(comma.Values));
                    }

                    if (toDate.Equals("radial-gradient", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var val   = ParseGroup(stream, forPosition).Value;
                        var comma = val as CommaDelimittedValue;

                        if (comma == null || comma.Values.Count() < 2)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "radial-gradient expects at least two parameters");
                            throw new StoppedParsingException();
                        }

                        return(new RadialGradientValue(comma.Values));
                    }
                }
            }

            NamedColor color;

            if (Enum.TryParse <NamedColor>(buffer.ToString(), ignoreCase: true, result: out color))
            {
                return(new NamedColorValue(color));
            }

            var str = buffer.ToString();

            if (str.Contains("!"))
            {
                var i     = str.IndexOf('!');
                var left  = str.Substring(0, i);
                var right = str.Substring(i);

                var ret = new List <Value>();
                var lhs = Parse(left, forPosition);
                var rhs = Parse(right, forPosition);

                if (lhs is CompoundValue)
                {
                    ret.AddRange(((CompoundValue)lhs).Values);
                }
                else
                {
                    ret.Add(lhs);
                }

                if (rhs is CompoundValue)
                {
                    ret.AddRange(((CompoundValue)rhs).Values);
                }
                else
                {
                    ret.Add(rhs);
                }

                return(new CompoundValue(ret));
            }

            return(new StringValue(buffer.ToString()));
        }
Ejemplo n.º 15
0
        private static Value ParseString(ParserStream stream, IPosition forPosition)
        {
            var c = stream.Peek();

            if (c == '!')
            {
                return ParseImportant(stream);
            }

            var buffer = new StringBuilder();
            while (stream.HasMore() && !char.IsWhiteSpace(stream.Peek()))
            {
                buffer.Append(stream.Read());

                if (buffer.Length == 3 && (stream.HasMore() && stream.Peek() == '('))
                {
                    var toDate = buffer.ToString();
                    if (toDate.Equals("rgb", StringComparison.InvariantCultureIgnoreCase) || toDate.Equals("hsl", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var group = ParseGroup(stream, forPosition);
                        var @params = group.Value as CommaDelimittedValue;
                        if (@params == null || @params.Values.Count() != 3)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "Expected 3 parameters to '" + toDate + "'");
                            throw new StoppedParsingException();
                        }

                        if(toDate == "rgb")
                        {
                            return
                                new RGBColorValue(
                                    @params.Values.ElementAt(0),
                                    @params.Values.ElementAt(1),
                                    @params.Values.ElementAt(2)
                                );
                        }

                        if (toDate == "hsl")
                        {
                            return
                                new HSLColorValue
                                (
                                    @params.Values.ElementAt(0),
                                    @params.Values.ElementAt(1),
                                    @params.Values.ElementAt(2)
                                );
                        }
                    }

                    if (toDate.Equals("url", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var value = ParseGroup(stream, forPosition).Value;

                        if(value is StringValue || value is QuotedStringValue)
                        {
                            return new UrlValue(value);
                        }

                        Current.RecordError(ErrorType.Parser, forPosition, "Expected string or quoted string");
                        throw new StoppedParsingException();
                    }
                }

                if (buffer.Length == 4 && (stream.HasMore() && stream.Peek() == '('))
                {
                    var toDate = buffer.ToString();
                    if (toDate.Equals("rgba", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var @params = ParseGroup(stream, forPosition).Value as CommaDelimittedValue;
                        if (@params == null || @params.Values.Count() != 4)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "Expected 4 parameters to '" + toDate + "'");
                            throw new StoppedParsingException();
                        }

                        return
                            new RGBAColorValue(
                                @params.Values.ElementAt(0),
                                @params.Values.ElementAt(1),
                                @params.Values.ElementAt(2),
                                @params.Values.ElementAt(3)
                            );
                    }

                    if (toDate.Equals("attr", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var @params = ParseGroup(stream, forPosition).Value;

                        Value attrAndType, attr, type, fallback;

                        var comma = @params as CommaDelimittedValue;
                        if (comma != null)
                        {
                            if (comma.Values.Count() > 2)
                            {
                                Current.RecordError(ErrorType.Parser, forPosition, "attr expects 1 or 2 parameters, found " + comma);
                                throw new StoppedParsingException();
                            }

                            attrAndType = comma.Values.ElementAt(0);

                            fallback = comma.Values.Count() == 2 ? comma.Values.ElementAt(1) : null;
                        }
                        else
                        {
                            attrAndType = @params;
                            fallback = null;
                        }

                        var compound = attrAndType as CompoundValue;
                        if (compound != null)
                        {
                            if (compound.Values.Count() > 2)
                            {
                                Current.RecordError(ErrorType.Parser, forPosition, "attr expects an attribute name and optionally a type, found " + compound);
                                throw new StoppedParsingException();
                            }

                            attr = compound.Values.ElementAt(0);
                            type = compound.Values.Count() == 2 ? compound.Values.ElementAt(1) : null;
                        }
                        else
                        {
                            attr = attrAndType;
                            type = null;
                        }

                        return new AttributeValue(attr, type, fallback);
                    }

                    if (toDate.Equals("calc", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var @params = ParseGroup(stream, forPosition).Value;

                        if (@params is CommaDelimittedValue)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "calc expects an expression, found " + @params);
                        }

                        string strVersion;
                        using(var writer = new StringWriter())
                        {
                            @params.Write(writer);
                            strVersion = writer.ToString();
                        }

                        // Things passed to calc are opting out of More magic, they don't get anything but in string replacements
                        return new CalcValue(new StringValue(strVersion));
                    }
                }

                if (buffer.Length == 5 && (stream.HasMore() && stream.Peek() == '('))
                {
                    var toDate = buffer.ToString();
                    if (toDate.Equals("local", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var val = ParseGroup(stream, forPosition).Value;
                        var comma = val as CommaDelimittedValue;
                        if (comma != null)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "Expected 1 parameter to local() value, found " + comma.Values.Count());
                            throw new StoppedParsingException();
                        }

                        return new LocalValue(val);
                    }

                    if (toDate.Equals("cycle", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var val = ParseGroup(stream, forPosition).Value;
                        var param = new List<Value>();

                        var comma = val as CommaDelimittedValue;
                        if (comma != null)
                        {
                            param.AddRange(comma.Values);
                        }
                        else
                        {
                            param.Add(val);
                        }

                        return new CycleValue(param);
                    }

                    if (toDate.Equals("steps", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var val = ParseGroup(stream, forPosition).Value;
                        var comma = val as CommaDelimittedValue;
                        if (comma != null && comma.Values.Count() > 2)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "Expected at most 2 parameters to steps() value, found " + comma.Values.Count());
                            throw new StoppedParsingException();
                        }

                        var steps = comma != null ? comma.Values.ElementAt(0) : val;
                        var dir = comma != null ? comma.Values.ElementAt(1) : null;

                        return new StepsValue(steps, dir);
                    }
                }

                if (buffer.Length == 6 && (stream.HasMore() && stream.Peek() == '('))
                {
                    var toDate = buffer.ToString();
                    if (toDate.Equals("format", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var val = ParseGroup(stream, forPosition).Value;
                        var comma = val as CommaDelimittedValue;
                        if (comma != null)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "Expected 1 parameter to format() value, found " + comma.Values.Count());
                            throw new StoppedParsingException();
                        }

                        return new FormatValue(val);
                    }
                }

                if (buffer.Length == 7 && (stream.HasMore() && stream.Peek() == '('))
                {
                    var toDate = buffer.ToString();
                    if (toDate.Equals("counter", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var val = ParseGroup(stream, forPosition).Value;
                        var comma = val as CommaDelimittedValue;
                        if (comma != null && comma.Values.Count() > 2)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "Expected at most 2 parameters to counter() value, found " + comma.Values.Count());
                            throw new StoppedParsingException();
                        }

                        var counter = comma != null ? comma.Values.ElementAt(0) : val;
                        var style = comma != null ? comma.Values.ElementAt(1) : null;

                        return new CounterValue(counter, style);
                    }
                }

                if (buffer.Length == 8 && (stream.HasMore() && stream.Peek() == '('))
                {
                    var toDate = buffer.ToString();
                    if (toDate.Equals("counters", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var val = ParseGroup(stream, forPosition).Value;
                        var comma = val as CommaDelimittedValue;
                        if (comma != null && comma.Values.Count() > 2)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "Expected at most 2 parameters to counters() value, found " + comma.Values.Count());
                            throw new StoppedParsingException();
                        }

                        var counter = comma != null ? comma.Values.ElementAt(0) : val;
                        var style = comma != null ? comma.Values.ElementAt(1) : null;

                        return new CountersValue(counter, style);
                    }
                }

                if (buffer.Length == 12 && (stream.HasMore() && stream.Peek() == '('))
                {
                    var toDate = buffer.ToString();
                    if (toDate.Equals("cubic-bezier", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var val = ParseGroup(stream, forPosition).Value;
                        var comma = val as CommaDelimittedValue;
                        if (comma == null || comma.Values.Count() != 4)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "Excepted 4 parameters to cubic-bezier()");
                            throw new StoppedParsingException();
                        }

                        return
                            new CubicBezierValue(
                                comma.Values.ElementAt(0),
                                comma.Values.ElementAt(1),
                                comma.Values.ElementAt(2),
                                comma.Values.ElementAt(3)
                            );
                    }
                }

                if (buffer.Length == 15 && (stream.HasMore() && stream.Peek() == '('))
                {
                    var toDate = buffer.ToString();
                    if (toDate.Equals("linear-gradient", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var val = ParseGroup(stream, forPosition).Value;
                        var comma = val as CommaDelimittedValue;

                        if (comma == null || comma.Values.Count() < 2)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "linear-gradient expects at least two parameters");
                            throw new StoppedParsingException();
                        }

                        return new LinearGradientValue(comma.Values);
                    }

                    if (toDate.Equals("radial-gradient", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var val = ParseGroup(stream, forPosition).Value;
                        var comma = val as CommaDelimittedValue;

                        if (comma == null || comma.Values.Count() < 2)
                        {
                            Current.RecordError(ErrorType.Parser, forPosition, "radial-gradient expects at least two parameters");
                            throw new StoppedParsingException();
                        }

                        return new RadialGradientValue(comma.Values);
                    }
                }
            }

            NamedColor color;
            if (Enum.TryParse<NamedColor>(buffer.ToString(), ignoreCase: true, result: out color))
            {
                return new NamedColorValue(color);
            }

            var str = buffer.ToString();

            if (str.Contains("!"))
            {
                var i = str.IndexOf('!');
                var left = str.Substring(0, i);
                var right = str.Substring(i);

                var ret = new List<Value>();
                var lhs = Parse(left, forPosition);
                var rhs = Parse(right, forPosition);

                if (lhs is CompoundValue)
                {
                    ret.AddRange(((CompoundValue)lhs).Values);
                }
                else
                {
                    ret.Add(lhs);
                }

                if (rhs is CompoundValue)
                {
                    ret.AddRange(((CompoundValue)rhs).Values);
                }
                else
                {
                    ret.Add(rhs);
                }

                return new CompoundValue(ret);
            }

            return new StringValue(buffer.ToString());
        }