Пример #1
0
        /// <summary>
        /// Reads a tag or object variable until the end sequence, <tt>%}</tt> or <tt>}}</tt> respectively and advances the enumerator position
        /// </summary>
        /// <param name="sb">The StringBuilder to write to</param>
        /// <param name="markupEnumerator">The string enumerator</param>
        /// <param name="searchChars">The character set to search for</param>
        /// <returns>True if reaches end sequence, otherwise false</returns>
        private static bool ReadToEndOfTag(StringBuilder sb, CharEnumerator markupEnumerator, HashSet <char> searchChars, SyntaxCompatibility syntaxCompatibilityLevel)
        {
            while (markupEnumerator.AppendNext(sb))
            {
                char nextChar = markupEnumerator.Current;
                if (searchChars.Contains(nextChar))
                {
                    switch (nextChar)
                    {
                    case '\'':
                    case '"':
                        ReadToChar(sb, markupEnumerator, nextChar);
                        break;

                    case '}':
                    case '%':
                        if (markupEnumerator.Remaining > 0 && markupEnumerator.Next == '}')
                        {
                            var previousCharIsWhitespaceControl = syntaxCompatibilityLevel >= SyntaxCompatibility.DotLiquid22 && markupEnumerator.Previous == '-';
                            markupEnumerator.AppendNext(sb);
                            if (previousCharIsWhitespaceControl)
                            {
                                // Remove hyphen from token
                                sb.Remove(sb.Length - 3, 1);

                                // Trim trailing whitespace by skipping ahead beyond the tag end
                                while (markupEnumerator.Remaining > 0)
                                {
                                    if (((uint)markupEnumerator.Next - '\t') <= 5 || markupEnumerator.Next == ' ')
                                    {
                                        markupEnumerator.MoveNext();
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }
                            }
                            return(true);
                        }
                        break;
                    }
                }
            }
            ;

            // Somehow we reached the end without finding the end character(s)
            return(false);
        }
Пример #2
0
        /// <summary>
        /// Reads a fixed number of characters and advances the enumerator position
        /// </summary>
        /// <param name="markupEnumerator">The string enumerator</param>
        /// <param name="markupLength">The number of characters to read</param>
        private static string ReadChars(CharEnumerator markupEnumerator, int markupLength)
        {
            var sb = new StringBuilder(markupLength);

            for (var i = 0; i < markupLength; i++)
            {
                markupEnumerator.AppendNext(sb);
            }
            return(sb.ToString());
        }
Пример #3
0
        /// <summary>
        /// Reads a token until, and inclusive of, the end character and advances the enumerator position
        /// </summary>
        /// <param name="sb">The StringBuilder to write to</param>
        /// <param name="markupEnumerator">The string enumerator</param>
        /// <param name="endChar">The character that indicates end of token</param>
        /// <returns><see langword="true"/> if reaches <paramref name="endChar"/>, otherwise <see langword="false"/></returns>
        private static bool ReadToChar(StringBuilder sb, CharEnumerator markupEnumerator, char endChar)
        {
            while (markupEnumerator.AppendNext(sb))
            {
                if (markupEnumerator.Current == endChar)
                {
                    return(true);
                }
            }
            ;

            return(false);
        }
Пример #4
0
        /// <summary>
        /// Reads a single word-character and advances the enumerator position
        /// </summary>
        /// <param name="sb">The StringBuilder to write to</param>
        /// <param name="markupEnumerator">The string enumerator</param>
        /// <returns>True if upcoming character is a word character, otherwise false</returns>
        private static bool ReadWordChar(StringBuilder sb, CharEnumerator markupEnumerator)
        {
            var nextChar = markupEnumerator.Next;

            if (nextChar < 128) // For better performance, avoid regex for standard ascii
            {
                if (!((uint)nextChar - '0' < 10 || (uint)nextChar - 'A' < 26 || (uint)nextChar - 'a' < 26 || nextChar == '_' || nextChar == '-'))
                {
                    return(false);
                }
            }
            else if (!VariableSegmentRegex.IsMatch(nextChar.ToString()))
            {
                return(false);
            }

            markupEnumerator.AppendNext(sb);
            return(true);
        }
Пример #5
0
        /// <summary>
        /// Enumerates over a variable sequence in dotted or bracket notation
        /// </summary>
        /// <param name="source">The Liquid Variable string</param>
        /// <exception cref="SyntaxException"></exception>
        internal static IEnumerator <string> GetVariableEnumerator(string source)
        {
            if (string.IsNullOrEmpty(source))
            {
                yield break;
            }

            using (var markupEnumerator = new CharEnumerator(source))
            {
                while (markupEnumerator.HasNext())
                {
                    var isComplete   = false;
                    var nextVariable = new StringBuilder();

                    switch (markupEnumerator.Next)
                    {
                    case '[':     // Example Syntax: [var] or ["literal"]
                        markupEnumerator.AppendNext(nextVariable);
                        if (!markupEnumerator.HasNext())
                        {
                            break;
                        }

                        switch (markupEnumerator.Next)
                        {
                        case '"':
                        case '\'':
                            markupEnumerator.AppendNext(nextVariable);
                            isComplete = ReadToChar(nextVariable, markupEnumerator, markupEnumerator.Next) && ReadToChar(nextVariable, markupEnumerator, BracketEnd);
                            break;

                        default:
                            isComplete = ReadToChar(nextVariable, markupEnumerator, BracketEnd);
                            break;
                        }

                        break;

                    default:
                        isComplete = ReadWordChar(nextVariable, markupEnumerator) && ReadToEndOfVariable(nextVariable, markupEnumerator);
                        break;
                    }

                    if (!isComplete) // Somehow we reached the end without finding the end character(s)
                    {
                        throw new SyntaxException(Liquid.ResourceManager.GetString("VariableNotTerminatedException"), source, Liquid.VariableEnd);
                    }

                    if (markupEnumerator.HasNext() && markupEnumerator.Next == '.' && markupEnumerator.Remaining > 1)  // Don't include dot in tokens as it is a separator
                    {
                        markupEnumerator.MoveNext();
                    }

                    if (nextVariable.Length > 0)
                    {
                        yield return(nextVariable.ToString());
                    }
                }
                ;
            }
        }