ScanUntilWithNesting() public method

Advances until c is found, placing everything before needle into buffer. Advances past needle as well. Differs from ScanUtil in that needles between quotes and ()'s are not counted as terminating. needles appear immediately after \ (the escape char) will not be considered matching.
public ScanUntilWithNesting ( StringBuilder buffer, char needle, bool requireFound = true ) : void
buffer StringBuilder
needle char
requireFound bool
return void
Example #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));
        }
Example #2
0
        internal static Import ParseImportDirective(ParserStream stream)
        {
            var start = stream.Position;

            var buffer = new StringBuilder();

            stream.ScanUntilWithNesting(buffer, ';');

            var toParse = buffer.ToString().Trim();

            Value      val;
            MediaQuery media;
            string     mediaStr;

            if (Regex.IsMatch(toParse, @"url\s*?\(", RegexOptions.IgnoreCase))
            {
                var i = toParse.IndexOf(')');

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

                val = Value.Parse(toParse.Substring(0, i + 1), start, start + i + 1, Current.CurrentFilePath);

                mediaStr = toParse.Substring(i + 1);
            }
            else
            {
                if (!(toParse.StartsWith("\"") || toParse.StartsWith("'")))
                {
                    Current.RecordError(ErrorType.Parser, Position.Create(start, stream.Position, Current.CurrentFilePath), "Expected quote");
                    throw new StoppedParsingException();
                }

                var i = toParse.LastIndexOf(toParse[0]);

                if (i == -1)
                {
                    Current.RecordError(ErrorType.Parser, Position.Create(start, stream.Position, Current.CurrentFilePath), "Expected '" + toParse[0] + "'");
                    throw new StoppedParsingException();
                }

                val      = Value.Parse(toParse.Substring(0, i + 1), start, start + i + 1, Current.CurrentFilePath);
                mediaStr = toParse.Substring(i + 1);
            }

            mediaStr = mediaStr.Trim();
            if (mediaStr.Length > 0)
            {
                media = MediaQueryParser.Parse(mediaStr, Position.Create(start, stream.Position, Current.CurrentFilePath));
            }
            else
            {
                media = new MediaType(Media.all, Position.Create(start, stream.Position, Current.CurrentFilePath));
            }

            return(new Import(val, media, start, stream.Position, Current.CurrentFilePath));
        }
Example #3
0
        internal static Value ParseMoreValue(ParserStream stream)
        {
            var start    = stream.Position;
            var valueStr = new StringBuilder();

            stream.ScanUntilWithNesting(valueStr, ';');

            var value = valueStr.ToString();

            return(Value.Parse(value, start, stream.Position, Current.CurrentFilePath));
        }
Example #4
0
        internal static GroupedValue ParseGroup(ParserStream stream, IPosition forPosition)
        {
            var toParse = new StringBuilder();

            stream.Advance(); // skip (
            stream.ScanUntilWithNesting(toParse, ')');

            var group = toParse.ToString().Trim();
            var ret   = Parse(group, forPosition);

            return(new GroupedValue(ret));
        }
Example #5
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));
        }
Example #6
0
        internal static MoreVariable ParseMoreVariable(string name, ParserStream stream, int start)
        {
            name = name.Trim();

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

            stream.ScanUntilWithNesting(valueStr, ';');

            var value = Value.Parse(valueStr.ToString().Trim(), valueStart, stream.Position, Current.CurrentFilePath, allowSelectorIncludes: true);

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

            return(new MoreVariable(name, value, start, stream.Position, Current.CurrentFilePath));
        }
Example #7
0
        public static Value Parse(string value, IPosition forPosition, bool allowSelectorIncludes = false)
        {
            var ret = new List<Value>();

            using (var stream = new ParserStream(new StringReader(value)))
            {
                while (stream.HasMore())
                {
                    var buffer = new StringBuilder();
                    stream.ScanUntilWithNesting(buffer, ',', requireFound: false);
                    using (var subStream = new ParserStream(new StringReader(buffer.ToString())))
                    {
                        ret.Add(ParseImpl(subStream, forPosition, allowSelectorIncludes));
                    }
                }
            }

            if (ret.Count == 1) return ret[0];

            return new CommaDelimittedValue(ret);
        }
Example #8
0
        public static Value Parse(string value, IPosition forPosition, bool allowSelectorIncludes = false)
        {
            var ret = new List <Value>();

            using (var stream = new ParserStream(new StringReader(value)))
            {
                while (stream.HasMore())
                {
                    var buffer = new StringBuilder();
                    stream.ScanUntilWithNesting(buffer, ',', requireFound: false);
                    using (var subStream = new ParserStream(new StringReader(buffer.ToString())))
                    {
                        ret.Add(ParseImpl(subStream, forPosition, allowSelectorIncludes));
                    }
                }
            }

            if (ret.Count == 1)
            {
                return(ret[0]);
            }

            return(new CommaDelimittedValue(ret));
        }
Example #9
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);
        }
Example #10
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));
        }
Example #11
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));
        }
Example #12
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);
        }
Example #13
0
        internal static GroupedValue ParseGroup(ParserStream stream, IPosition forPosition)
        {
            var toParse = new StringBuilder();

            stream.Advance(); // skip (
            stream.ScanUntilWithNesting(toParse, ')');

            var group = toParse.ToString().Trim();
            var ret = Parse(group, forPosition);

            return new GroupedValue(ret);
        }
Example #14
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);
        }
Example #15
0
        internal static MoreVariable ParseMoreVariable(string name, ParserStream stream, int start)
        {
            name = name.Trim();

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

            var value = Value.Parse(valueStr.ToString().Trim(), valueStart, stream.Position, Current.CurrentFilePath, allowSelectorIncludes: true);

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

            return new MoreVariable(name, value, start, stream.Position, Current.CurrentFilePath);
        }
Example #16
0
        internal static Value ParseMoreValue(ParserStream stream)
        {
            var start = stream.Position;
            var valueStr = new StringBuilder();
            stream.ScanUntilWithNesting(valueStr, ';');

            var value = valueStr.ToString();

            return Value.Parse(value, start, stream.Position, Current.CurrentFilePath);
        }
Example #17
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);
        }
Example #18
0
        internal static Import ParseImportDirective(ParserStream stream)
        {
            var start = stream.Position;

            var buffer = new StringBuilder();
            stream.ScanUntilWithNesting(buffer, ';');

            var toParse = buffer.ToString().Trim();

            Value val;
            MediaQuery media;
            string mediaStr;

            if (Regex.IsMatch(toParse, @"url\s*?\(", RegexOptions.IgnoreCase))
            {
                var i = toParse.IndexOf(')');

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

                val = Value.Parse(toParse.Substring(0, i + 1), start, start + i + 1, Current.CurrentFilePath);

                mediaStr = toParse.Substring(i + 1);
            }
            else
            {
                if (!(toParse.StartsWith("\"") || toParse.StartsWith("'")))
                {
                    Current.RecordError(ErrorType.Parser, Position.Create(start, stream.Position, Current.CurrentFilePath), "Expected quote");
                    throw new StoppedParsingException();
                }

                var i = toParse.LastIndexOf(toParse[0]);

                if (i == -1)
                {
                    Current.RecordError(ErrorType.Parser, Position.Create(start, stream.Position, Current.CurrentFilePath), "Expected '" + toParse[0] + "'");
                    throw new StoppedParsingException();
                }

                val = Value.Parse(toParse.Substring(0, i + 1), start, start + i + 1, Current.CurrentFilePath);
                mediaStr = toParse.Substring(i + 1);
            }

            mediaStr = mediaStr.Trim();
            if (mediaStr.Length > 0)
            {
                media = MediaQueryParser.Parse(mediaStr, Position.Create(start, stream.Position, Current.CurrentFilePath));
            }
            else
            {
                media = new MediaType(Media.all, Position.Create(start, stream.Position, Current.CurrentFilePath));
            }

            return new Import(val, media, start, stream.Position, Current.CurrentFilePath);
        }