/// <summary>
		/// Parse the specified format string.
		/// </summary>
		/// <param name='format'>
		/// The format string.
		/// </param>
		public FormatStringParseResult Parse (string format)
		{
			if (format == null)
				throw new ArgumentNullException ("format");

			var result = new FormatStringParseResult();

			// Format string syntax: http://msdn.microsoft.com/en-us/library/txafckwd.aspx
			int textStart = 0;
			var length = format.Length;
			for (int i = 0; i < length; i++) {
				// Get fixed text
				GetText (format, ref i);

				if (i < format.Length && format [i] == '{') {
					int formatItemStart = i;
					int index;
					int? alignment = null;
					string argumentFormat = null;
					var textSegmentErrors = new List<IFormatStringError>(GetErrors());

					// Try to parse the parts of the format item
					++i;
					index = ParseIndex (format, ref i);
					CheckForMissingEndBrace (format, i, length);

					alignment = ParseAlignment (format, ref i, length);
					CheckForMissingEndBrace (format, i, length);

					argumentFormat = ParseSubFormatString (format, ref i, length);
					CheckForMissingEndBrace (format, i, length);

					// Check what we parsed
					if (i == formatItemStart + 1 && (i == length || (i < length && format [i] != '}'))) {
						// There were no format item after all, this was just an
						// unescaped left brace
						SetErrors(textSegmentErrors);
						AddError (new DefaultFormatStringError {
							Message = "Unescaped '{'",
							StartLocation = formatItemStart,
							EndLocation = formatItemStart + 1,
							OriginalText = "{",
							SuggestedReplacementText = "{{"
						});
						continue;
					} else if (formatItemStart - textStart > 0) {
						// We have parsed a format item, end the text segment
						var textSegment = new TextSegment (UnEscape (format.Substring (textStart, formatItemStart - textStart)));
						textSegment.Errors = textSegmentErrors;
						result.Segments.Add (textSegment);
					}
					
					// Unclosed format items in fixed text gets advances i one step too far
					if (i < length && format [i] != '}')
						--i;

					// i may actually point outside of format if there is a syntactical error
					// if that happens, we want the last position
					var endLocation = Math.Min (length, i + 1);
					result.Segments.Add (new FormatItem (index, alignment, argumentFormat) {
						StartLocation = formatItemStart,
						EndLocation = endLocation,
						Errors = GetErrors ()
					});
					ClearErrors ();

					// The next potential text segment starts after this format item
					textStart = i + 1;
				}
			}
			// Handle remaining text
			if (textStart < length) {
				var textSegment = new TextSegment (UnEscape (format.Substring (textStart)), textStart);
				textSegment.Errors = GetErrors();
				result.Segments.Add (textSegment);

			}
			return result;
		}
Example #2
0
        /// <summary>
        /// Parse the specified format string.
        /// </summary>
        /// <param name='format'>
        /// The format string.
        /// </param>
        public FormatStringParseResult Parse(string format)
        {
            if (format == null)
            {
                throw new ArgumentNullException("format");
            }

            var result = new FormatStringParseResult();

            // Format string syntax: http://msdn.microsoft.com/en-us/library/txafckwd.aspx
            int textStart = 0;
            var length    = format.Length;

            for (int i = 0; i < length; i++)
            {
                // Get fixed text
                GetText(format, ref i);

                if (i < format.Length && format [i] == '{')
                {
                    int    formatItemStart = i;
                    int    index;
                    int?   alignment         = null;
                    string argumentFormat    = null;
                    var    textSegmentErrors = new List <IFormatStringError>(GetErrors());

                    // Try to parse the parts of the format item
                    ++i;
                    index = ParseIndex(format, ref i);
                    CheckForMissingEndBrace(format, i, length);

                    alignment = ParseAlignment(format, ref i, length);
                    CheckForMissingEndBrace(format, i, length);

                    argumentFormat = ParseSubFormatString(format, ref i, length);
                    CheckForMissingEndBrace(format, i, length);

                    // Check what we parsed
                    if (i == formatItemStart + 1 && (i == length || (i < length && format [i] != '}')))
                    {
                        // There were no format item after all, this was just an
                        // unescaped left brace
                        SetErrors(textSegmentErrors);
                        AddError(new DefaultFormatStringError {
                            Message                  = "Unescaped '{'",
                            StartLocation            = formatItemStart,
                            EndLocation              = formatItemStart + 1,
                            OriginalText             = "{",
                            SuggestedReplacementText = "{{"
                        });
                        continue;
                    }
                    else if (formatItemStart - textStart > 0)
                    {
                        // We have parsed a format item, end the text segment
                        var textSegment = new TextSegment(UnEscape(format.Substring(textStart, formatItemStart - textStart)));
                        textSegment.Errors = textSegmentErrors;
                        result.Segments.Add(textSegment);
                    }

                    // Unclosed format items in fixed text gets advances i one step too far
                    if (i < length && format [i] != '}')
                    {
                        --i;
                    }

                    // i may actually point outside of format if there is a syntactical error
                    // if that happens, we want the last position
                    var endLocation = Math.Min(length, i + 1);
                    result.Segments.Add(new FormatItem(index, alignment, argumentFormat)
                    {
                        StartLocation = formatItemStart,
                        EndLocation   = endLocation,
                        Errors        = GetErrors()
                    });
                    ClearErrors();

                    // The next potential text segment starts after this format item
                    textStart = i + 1;
                }
            }
            // Handle remaining text
            if (textStart < length)
            {
                var textSegment = new TextSegment(UnEscape(format.Substring(textStart)), textStart);
                textSegment.Errors = GetErrors();
                result.Segments.Add(textSegment);
            }
            return(result);
        }