internal FormatChunk Append([NotNull] string value, [CanBeNull] IResolvable resolver = null) { if (value == null) { throw new ArgumentNullException("value"); } string tag = null; string alignment = null; string format = null; Stack <FormatChunk> chunks = new Stack <FormatChunk>(); FormatChunk chunk = this; StringBuilder builder = new StringBuilder(value.Length); ParserState state = ParserState.Value; int i = 0; while (i < value.Length) { char c = value[i++]; // Un-escape if (c == '\\' && (i < value.Length)) { builder.Append(value[i++]); continue; } bool gotFillPoint = false; switch (state) { case ParserState.Tag: switch (c) { case FormatBuilder.AlignmentChar: state = ParserState.Alignment; break; case FormatBuilder.FormatChar: state = ParserState.Format; break; case FormatBuilder.CloseChar: state = ParserState.Value; gotFillPoint = true; break; default: builder.Append(c); break; } if (state != ParserState.Tag) { // We've got a tag tag = builder.ToString(); builder.Clear(); } break; case ParserState.Alignment: switch (c) { case FormatBuilder.FormatChar: state = ParserState.Format; break; case FormatBuilder.CloseChar: state = ParserState.Value; gotFillPoint = true; break; default: builder.Append(c); break; } if (state != ParserState.Alignment) { // We've got an alignment alignment = builder.ToString(); builder.Clear(); } break; case ParserState.Format: switch (c) { case FormatBuilder.OpenChar: if (i >= value.Length || value[i] == FormatBuilder.OpenChar) { builder.Append(FormatBuilder.OpenChar); i++; break; } // We have a nested format! Debug.Assert(tag != null); FormatChunk newChunk = new FormatChunk( chunks.Count < 1 ? resolver : null, tag, alignment, null); tag = null; alignment = null; if (builder.Length > 0) { Debug.Assert(newChunk.ChildrenInternal == null); newChunk.AppendChunk(new FormatChunk(builder.ToString())); builder.Clear(); } chunk.AppendChunk(newChunk); chunks.Push(chunk); chunk = newChunk; state = ParserState.Tag; break; case FormatBuilder.CloseChar: state = ParserState.Value; gotFillPoint = true; format = builder.ToString(); builder.Clear(); break; default: builder.Append(c); break; } break; default: switch (c) { case FormatBuilder.OpenChar: if (i >= value.Length || value[i] == FormatBuilder.OpenChar) { builder.Append(FormatBuilder.OpenChar); i++; break; } state = ParserState.Tag; // We've got a value if (builder.Length > 0) { chunk.AppendChunk(new FormatChunk(builder.ToString())); builder.Clear(); } break; case FormatBuilder.CloseChar: state = ParserState.Value; if (chunks.Count > 0) { // Closing a nest fill point. if (builder.Length > 0) { chunk.AppendChunk(new FormatChunk(builder.ToString())); builder.Clear(); } chunk = chunks.Pop(); Debug.Assert(chunk != null); } else { builder.Append(c); } break; default: builder.Append(c); break; } break; } if (gotFillPoint) { Debug.Assert(tag != null); FormatChunk newChunk = new FormatChunk( chunks.Count < 1 ? resolver : null, tag, alignment, format); chunk.AppendChunk(newChunk); tag = null; alignment = null; format = null; } } if (builder.Length <= 0) { return(this); } // We have some left overs string v = builder.ToString(); builder.Clear(); if (tag != null) { builder.Append(FormatBuilder.OpenChar).Append(tag); } if (alignment != null) { builder.Append(FormatBuilder.AlignmentChar).Append(alignment); } if (builder.Length < 1) { chunk.AppendChunk(new FormatChunk(v)); } else { builder.Append(FormatBuilder.FormatChar).Append(v); chunk.AppendChunk(new FormatChunk(builder.ToString())); } return(this); }
internal FormatChunk Append([NotNull] string value, [CanBeNull] IResolvable resolver = null) { if (value == null) throw new ArgumentNullException("value"); string tag = null; string alignment = null; string format = null; Stack<FormatChunk> chunks = new Stack<FormatChunk>(); FormatChunk chunk = this; StringBuilder builder = new StringBuilder(value.Length); ParserState state = ParserState.Value; int i = 0; while (i < value.Length) { char c = value[i++]; // Un-escape if (c == '\\' && (i < value.Length)) { builder.Append(value[i++]); continue; } bool gotFillPoint = false; switch (state) { case ParserState.Tag: switch (c) { case FormatBuilder.AlignmentChar: state = ParserState.Alignment; break; case FormatBuilder.FormatChar: state = ParserState.Format; break; case FormatBuilder.CloseChar: state = ParserState.Value; gotFillPoint = true; break; default: builder.Append(c); break; } if (state != ParserState.Tag) { // We've got a tag tag = builder.ToString(); builder.Clear(); } break; case ParserState.Alignment: switch (c) { case FormatBuilder.FormatChar: state = ParserState.Format; break; case FormatBuilder.CloseChar: state = ParserState.Value; gotFillPoint = true; break; default: builder.Append(c); break; } if (state != ParserState.Alignment) { // We've got an alignment alignment = builder.ToString(); builder.Clear(); } break; case ParserState.Format: switch (c) { case FormatBuilder.OpenChar: // We have a nested format! Debug.Assert(tag != null); FormatChunk newChunk = new FormatChunk( chunks.Count < 1 ? resolver : null, tag, alignment, null); tag = null; alignment = null; if (builder.Length > 0) { Debug.Assert(newChunk.ChildrenInternal == null); newChunk.AppendChunk(new FormatChunk(builder.ToString())); builder.Clear(); } chunk.AppendChunk(newChunk); chunks.Push(chunk); chunk = newChunk; state = ParserState.Tag; break; case FormatBuilder.CloseChar: state = ParserState.Value; gotFillPoint = true; format = builder.ToString(); builder.Clear(); break; default: builder.Append(c); break; } break; default: switch (c) { case FormatBuilder.OpenChar: state = ParserState.Tag; // We've got a value if (builder.Length > 0) { chunk.AppendChunk(new FormatChunk(builder.ToString())); builder.Clear(); } break; case FormatBuilder.CloseChar: state = ParserState.Value; if (chunks.Count > 0) { // Closing a nest fill point. if (builder.Length > 0) { chunk.AppendChunk(new FormatChunk(builder.ToString())); builder.Clear(); } chunk = chunks.Pop(); Debug.Assert(chunk != null); } else builder.Append(c); break; default: builder.Append(c); break; } break; } if (gotFillPoint) { Debug.Assert(tag != null); FormatChunk newChunk = new FormatChunk( chunks.Count < 1 ? resolver : null, tag, alignment, format); chunk.AppendChunk(newChunk); tag = null; alignment = null; format = null; } } if (builder.Length <= 0) return this; // We have some left overs string v = builder.ToString(); builder.Clear(); if (tag != null) builder.Append(FormatBuilder.OpenChar).Append(tag); if (alignment != null) builder.Append(FormatBuilder.AlignmentChar).Append(alignment); if (builder.Length < 1) chunk.AppendChunk(new FormatChunk(v)); else { builder.Append(FormatBuilder.FormatChar).Append(v); chunk.AppendChunk(new FormatChunk(builder.ToString())); } return this; }