7 internal class BlockParseState
10 private string[] rows;
11 private int[] positions;
12 private string currentRow;
14 private int blockIndex;
15 private readonly
int endBlock;
20 private bool lineBreakAfter;
21 private readonly
bool preserveCrLf;
22 private char lastChar = (char)0;
24 public BlockParseState(
string[] Rows,
int[] Positions,
int Start,
int End,
bool PreserveCrLf,
ChunkedList<Block> Blocks,
int BlockIndex,
28 this.blockIndex = BlockIndex;
29 this.endBlock = EndBlock;
31 this.positions = Positions;
32 this.current = this.start = Start;
34 this.currentRow = this.rows[this.current];
35 this.lineBreakAfter = this.currentRow.EndsWith(
" ");
37 this.len = this.currentRow.Length;
38 this.preserveCrLf = PreserveCrLf;
40 if (this.lineBreakAfter)
42 this.currentRow = this.currentRow.Substring(0, this.len - 2);
48 public string[] Rows => this.rows;
49 public int[] Positions => this.positions;
50 public int Start => this.start;
51 public int End => this.end;
52 public int Current => this.current;
53 public int BlockIndex => this.blockIndex;
54 public int EndBlock => this.endBlock;
55 public bool PreserveCrLf => this.preserveCrLf;
57 public char NextNonWhitespaceChar()
59 char ch = this.NextChar();
61 while (ch > (
char)0 && (ch <=
' ' || ch == 160))
67 public char NextNonWhitespaceCharSameRow()
69 char ch = this.NextCharSameRow();
71 while (ch > (
char)0 && (ch <=
' ' || ch == 160))
72 ch = this.NextCharSameRow();
77 public char NextCharSameRow()
79 if (this.pos >= this.len)
80 return this.lastChar = (char)0;
82 return this.lastChar = this.currentRow[this.pos++];
85 public char PeekNextNonWhitespaceCharSameRow(
bool SkipWhitespace)
87 char ch = this.PeekNextCharSameRow();
89 if (ch > 0 && (ch <=
' ' || ch == 160))
95 this.NextCharSameRow();
96 ch = this.PeekNextCharSameRow();
98 while (ch > 0 && (ch <=
' ' || ch == 160));
102 int PosBak = this.pos;
103 int LenBak = this.len;
104 int CurrentBak = this.current;
105 string CurrentRowBak = this.currentRow;
106 bool LineBreakAfterBak = this.lineBreakAfter;
110 this.NextCharSameRow();
111 ch = this.PeekNextCharSameRow();
113 while (ch > 0 && (ch <=
' ' || ch == 160));
117 this.current = CurrentBak;
118 this.currentRow = CurrentRowBak;
119 this.lineBreakAfter = LineBreakAfterBak;
126 public char PeekNextNonWhitespaceChar(
bool SkipWhitespace)
128 char ch = this.PeekNextChar();
130 if (ch > 0 && (ch <=
' ' || ch == 160))
137 ch = this.PeekNextChar();
139 while (ch > 0 && (ch <=
' ' || ch == 160));
143 int PosBak = this.pos;
144 int LenBak = this.len;
145 int CurrentBak = this.current;
146 string CurrentRowBak = this.currentRow;
147 bool LineBreakAfterBak = this.lineBreakAfter;
152 ch = this.PeekNextChar();
154 while (ch > 0 && (ch <=
' ' || ch == 160));
158 this.current = CurrentBak;
159 this.currentRow = CurrentRowBak;
160 this.lineBreakAfter = LineBreakAfterBak;
167 public char PeekNextCharSameRow()
169 if (this.pos >= this.len)
172 return this.currentRow[this.pos];
175 public char PeekNextChar()
177 int PosBak = this.pos;
178 int LenBak = this.len;
179 int CurrentBak = this.current;
180 string CurrentRowBak = this.currentRow;
181 bool LineBreakAfterBak = this.lineBreakAfter;
183 char ch = this.NextChar();
187 this.current = CurrentBak;
188 this.currentRow = CurrentRowBak;
189 this.lineBreakAfter = LineBreakAfterBak;
194 public char[] PeekNextChars(
int Len)
196 int PosBak = this.pos;
197 int LenBak = this.len;
198 int CurrentBak = this.current;
199 string CurrentRowBak = this.currentRow;
200 bool LineBreakAfterBak = this.lineBreakAfter;
201 char[] Result =
new char[Len];
204 for (i = 0; i < Len; i++)
205 Result[i] = this.NextChar();
209 this.current = CurrentBak;
210 this.currentRow = CurrentRowBak;
211 this.lineBreakAfter = LineBreakAfterBak;
216 private class StateBackup
221 public char LastChar;
222 public string CurrentRow;
223 public bool LineBreakAfter;
228 public void BackupState()
230 StateBackup Backup =
new StateBackup()
234 Current = this.current,
235 CurrentRow = this.currentRow,
236 LineBreakAfter = this.lineBreakAfter,
237 LastChar = this.lastChar
240 if (this.backup is
null)
246 public void RestoreState()
249 throw new Exception(
"No state backup to restore.");
253 this.pos = Backup.Pos;
254 this.len = Backup.Len;
255 this.current = Backup.Current;
256 this.currentRow = Backup.CurrentRow;
257 this.lineBreakAfter = Backup.LineBreakAfter;
258 this.lastChar = Backup.LastChar;
261 public void DiscardBackup()
264 throw new Exception(
"No state backup to discard.");
269 public void SkipWhitespaceSameRow(
int MaxSpaces)
273 while ((((ch = this.PeekNextCharSameRow()) <=
' ' && ch > 0) || ch == 160) && MaxSpaces > 0)
275 this.NextCharSameRow();
277 if (ch ==
' ' || ch == 160)
284 public char NextChar()
288 if (this.pos >= this.len)
291 if (this.current > this.end)
300 if (this.lineBreakAfter)
302 else if (this.preserveCrLf)
307 this.currentRow = this.rows[this.current];
309 this.len = this.currentRow.Length;
310 this.lineBreakAfter = this.currentRow.EndsWith(
" ");
312 if (this.lineBreakAfter)
314 this.currentRow = this.currentRow.Substring(0, this.len - 2);
320 ch = this.currentRow[this.pos++];
322 return this.lastChar = ch;
325 public char NextCharRaw()
329 if (this.pos >= this.len)
332 if (this.current > this.end)
341 this.currentRow = this.rows[this.current];
343 this.len = this.currentRow.Length;
344 this.lineBreakAfter = this.currentRow.EndsWith(
" ");
346 if (this.lineBreakAfter)
348 this.currentRow = this.currentRow.Substring(0, this.len - 2);
357 ch = this.currentRow[this.pos++];
359 return this.lastChar = ch;
362 public bool CheckRestOfTermination(
char ch,
int Count)
364 if (this.pos + Count > this.len)
369 for (i = 0; i < Count; i++)
371 if (this.currentRow[this.pos + i] != ch)
380 public int CurrentPosition
384 if (this.current <= this.end)
385 return this.positions[this.current] + this.pos;
387 return this.positions[this.end] + this.rows[this.end].Length;
391 public string RestOfRow()
395 if (this.pos >= this.len)
396 Result =
string.Empty;
398 Result = this.currentRow.Substring(this.pos);
401 if (this.current > this.end)
408 this.currentRow = this.rows[this.current];
410 this.len = this.currentRow.Length;
411 this.lineBreakAfter = this.currentRow.EndsWith(
" ");
413 if (this.lineBreakAfter)
415 this.currentRow = this.currentRow.Substring(0, this.len - 2);
423 public bool IsFirstCharOnLine
427 int i = this.pos - 2;
433 if (i < 0 || i >= this.len)
436 while (i >= 0 && ((ch = this.currentRow[i]) <=
' ' || ch == 160))
447 return (this.pos >= this.len && this.current > this.end);
451 public string CurrentRow => this.currentRow;
453 public char LastCharacter => this.lastChar;
455 public string UntilToken(
string Token)
457 StringBuilder sb =
new StringBuilder();
459 int c = Token.Length;
464 ch = this.NextCharRaw();
468 if (!(this.blocks is
null) && this.blockIndex < this.endBlock)
470 Block Next = this.blocks[++this.blockIndex];
472 this.rows = Next.Rows;
473 this.positions = Next.Positions;
474 this.current = this.start = Next.Start;
476 this.currentRow = this.rows[this.current];
477 this.lineBreakAfter = this.currentRow.EndsWith(
" ");
479 this.len = this.currentRow.Length;
481 if (this.lineBreakAfter)
483 this.currentRow = this.currentRow.Substring(0, this.len - 2);
493 sb.Append(Token.Substring(0, i));
495 return sb.ToString();
502 sb.Append(Token.Substring(0, i));
512 sb.Append(Token.Substring(0, i));
518 else if (
char.ToUpper(ch) == Token[i])
522 return sb.ToString();
528 sb.Append(Token.Substring(0, i));
A chunked list is a linked list of chunks of objects of type T .
void AddFirstItem(T Value)
Adds a new item first in the collection.
bool HasFirstItem
If there is a first item in the collection
T RemoveFirst()
Removes the first item in the collection.