Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
BlockParseState.cs
1using System;
2using System.Text;
4
6{
7 internal class BlockParseState
8 {
9 private readonly ChunkedList<Block> blocks;
10 private string[] rows;
11 private int[] positions;
12 private string currentRow;
13 private int current;
14 private int blockIndex;
15 private readonly int endBlock;
16 private int start;
17 private int end;
18 private int pos;
19 private int len;
20 private bool lineBreakAfter;
21 private readonly bool preserveCrLf;
22 private char lastChar = (char)0;
23
24 public BlockParseState(string[] Rows, int[] Positions, int Start, int End, bool PreserveCrLf, ChunkedList<Block> Blocks, int BlockIndex,
25 int EndBlock)
26 {
27 this.blocks = Blocks;
28 this.blockIndex = BlockIndex;
29 this.endBlock = EndBlock;
30 this.rows = Rows;
31 this.positions = Positions;
32 this.current = this.start = Start;
33 this.end = End;
34 this.currentRow = this.rows[this.current];
35 this.lineBreakAfter = this.currentRow.EndsWith(" ");
36 this.pos = 0;
37 this.len = this.currentRow.Length; // >= 1
38 this.preserveCrLf = PreserveCrLf;
39
40 if (this.lineBreakAfter)
41 {
42 this.currentRow = this.currentRow.Substring(0, this.len - 2);
43 this.len -= 2;
44 }
45 }
46
47 public ChunkedList<Block> Blocks => this.blocks;
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;
56
57 public char NextNonWhitespaceChar()
58 {
59 char ch = this.NextChar();
60
61 while (ch > (char)0 && (ch <= ' ' || ch == 160))
62 ch = this.NextChar();
63
64 return ch;
65 }
66
67 public char NextNonWhitespaceCharSameRow()
68 {
69 char ch = this.NextCharSameRow();
70
71 while (ch > (char)0 && (ch <= ' ' || ch == 160))
72 ch = this.NextCharSameRow();
73
74 return ch;
75 }
76
77 public char NextCharSameRow()
78 {
79 if (this.pos >= this.len)
80 return this.lastChar = (char)0;
81 else
82 return this.lastChar = this.currentRow[this.pos++];
83 }
84
85 public char PeekNextNonWhitespaceCharSameRow(bool SkipWhitespace)
86 {
87 char ch = this.PeekNextCharSameRow();
88
89 if (ch > 0 && (ch <= ' ' || ch == 160))
90 {
91 if (SkipWhitespace)
92 {
93 do
94 {
95 this.NextCharSameRow();
96 ch = this.PeekNextCharSameRow();
97 }
98 while (ch > 0 && (ch <= ' ' || ch == 160));
99 }
100 else
101 {
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;
107
108 do
109 {
110 this.NextCharSameRow();
111 ch = this.PeekNextCharSameRow();
112 }
113 while (ch > 0 && (ch <= ' ' || ch == 160));
114
115 this.pos = PosBak;
116 this.len = LenBak;
117 this.current = CurrentBak;
118 this.currentRow = CurrentRowBak;
119 this.lineBreakAfter = LineBreakAfterBak;
120 }
121 }
122
123 return ch;
124 }
125
126 public char PeekNextNonWhitespaceChar(bool SkipWhitespace)
127 {
128 char ch = this.PeekNextChar();
129
130 if (ch > 0 && (ch <= ' ' || ch == 160))
131 {
132 if (SkipWhitespace)
133 {
134 do
135 {
136 this.NextChar();
137 ch = this.PeekNextChar();
138 }
139 while (ch > 0 && (ch <= ' ' || ch == 160));
140 }
141 else
142 {
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;
148
149 do
150 {
151 this.NextChar();
152 ch = this.PeekNextChar();
153 }
154 while (ch > 0 && (ch <= ' ' || ch == 160));
155
156 this.pos = PosBak;
157 this.len = LenBak;
158 this.current = CurrentBak;
159 this.currentRow = CurrentRowBak;
160 this.lineBreakAfter = LineBreakAfterBak;
161 }
162 }
163
164 return ch;
165 }
166
167 public char PeekNextCharSameRow()
168 {
169 if (this.pos >= this.len)
170 return (char)0;
171 else
172 return this.currentRow[this.pos];
173 }
174
175 public char PeekNextChar()
176 {
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;
182
183 char ch = this.NextChar();
184
185 this.pos = PosBak;
186 this.len = LenBak;
187 this.current = CurrentBak;
188 this.currentRow = CurrentRowBak;
189 this.lineBreakAfter = LineBreakAfterBak;
190
191 return ch;
192 }
193
194 public char[] PeekNextChars(int Len)
195 {
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];
202 int i;
203
204 for (i = 0; i < Len; i++)
205 Result[i] = this.NextChar();
206
207 this.pos = PosBak;
208 this.len = LenBak;
209 this.current = CurrentBak;
210 this.currentRow = CurrentRowBak;
211 this.lineBreakAfter = LineBreakAfterBak;
212
213 return Result;
214 }
215
216 private class StateBackup
217 {
218 public int Pos;
219 public int Len;
220 public int Current;
221 public char LastChar;
222 public string CurrentRow;
223 public bool LineBreakAfter;
224 }
225
226 private ChunkedList<StateBackup> backup = null;
227
228 public void BackupState()
229 {
230 StateBackup Backup = new StateBackup()
231 {
232 Pos = this.pos,
233 Len = this.len,
234 Current = this.current,
235 CurrentRow = this.currentRow,
236 LineBreakAfter = this.lineBreakAfter,
237 LastChar = this.lastChar
238 };
239
240 if (this.backup is null)
241 this.backup = new ChunkedList<StateBackup>();
242
243 this.backup.AddFirstItem(Backup);
244 }
245
246 public void RestoreState()
247 {
248 if (this.backup is null || !this.backup.HasFirstItem)
249 throw new Exception("No state backup to restore.");
250
251 StateBackup Backup = this.backup.RemoveFirst();
252
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;
259 }
260
261 public void DiscardBackup()
262 {
263 if (this.backup is null || !this.backup.HasFirstItem)
264 throw new Exception("No state backup to discard.");
265
266 this.backup.RemoveFirst();
267 }
268
269 public void SkipWhitespaceSameRow(int MaxSpaces)
270 {
271 char ch;
272
273 while ((((ch = this.PeekNextCharSameRow()) <= ' ' && ch > 0) || ch == 160) && MaxSpaces > 0)
274 {
275 this.NextCharSameRow();
276
277 if (ch == ' ' || ch == 160)
278 MaxSpaces--;
279 else if (ch == '\t')
280 MaxSpaces -= 4;
281 }
282 }
283
284 public char NextChar()
285 {
286 char ch;
287
288 if (this.pos >= this.len)
289 {
290 this.current++;
291 if (this.current > this.end)
292 {
293 this.pos = 0;
294 this.len = 0;
295
296 ch = (char)0;
297 }
298 else
299 {
300 if (this.lineBreakAfter)
301 ch = '\n';
302 else if (this.preserveCrLf)
303 ch = '\r';
304 else
305 ch = ' ';
306
307 this.currentRow = this.rows[this.current];
308 this.pos = 0;
309 this.len = this.currentRow.Length;
310 this.lineBreakAfter = this.currentRow.EndsWith(" ");
311
312 if (this.lineBreakAfter)
313 {
314 this.currentRow = this.currentRow.Substring(0, this.len - 2);
315 this.len -= 2;
316 }
317 }
318 }
319 else
320 ch = this.currentRow[this.pos++];
321
322 return this.lastChar = ch;
323 }
324
325 public char NextCharRaw()
326 {
327 char ch;
328
329 if (this.pos >= this.len)
330 {
331 this.current++;
332 if (this.current > this.end)
333 {
334 this.pos = 0;
335 this.len = 0;
336
337 ch = (char)0;
338 }
339 else
340 {
341 this.currentRow = this.rows[this.current];
342 this.pos = 0;
343 this.len = this.currentRow.Length;
344 this.lineBreakAfter = this.currentRow.EndsWith(" ");
345
346 if (this.lineBreakAfter)
347 {
348 this.currentRow = this.currentRow.Substring(0, this.len - 2);
349 this.len -= 2;
350 ch = '\r';
351 }
352 else
353 ch = '\n';
354 }
355 }
356 else
357 ch = this.currentRow[this.pos++];
358
359 return this.lastChar = ch;
360 }
361
362 public bool CheckRestOfTermination(char ch, int Count)
363 {
364 if (this.pos + Count > this.len)
365 return false;
366
367 int i;
368
369 for (i = 0; i < Count; i++)
370 {
371 if (this.currentRow[this.pos + i] != ch)
372 return false;
373 }
374
375 this.pos += Count;
376
377 return true;
378 }
379
380 public int CurrentPosition
381 {
382 get
383 {
384 if (this.current <= this.end)
385 return this.positions[this.current] + this.pos;
386 else
387 return this.positions[this.end] + this.rows[this.end].Length;
388 }
389 }
390
391 public string RestOfRow()
392 {
393 string Result;
394
395 if (this.pos >= this.len)
396 Result = string.Empty;
397 else
398 Result = this.currentRow.Substring(this.pos);
399
400 this.current++;
401 if (this.current > this.end)
402 {
403 this.pos = 0;
404 this.len = 0;
405 }
406 else
407 {
408 this.currentRow = this.rows[this.current];
409 this.pos = 0;
410 this.len = this.currentRow.Length;
411 this.lineBreakAfter = this.currentRow.EndsWith(" ");
412
413 if (this.lineBreakAfter)
414 {
415 this.currentRow = this.currentRow.Substring(0, this.len - 2);
416 this.len -= 2;
417 }
418 }
419
420 return Result;
421 }
422
423 public bool IsFirstCharOnLine
424 {
425 get
426 {
427 int i = this.pos - 2;
428 char ch;
429
430 if (i == -1)
431 return true;
432
433 if (i < 0 || i >= this.len)
434 return false;
435
436 while (i >= 0 && ((ch = this.currentRow[i]) <= ' ' || ch == 160))
437 i--;
438
439 return i < 0;
440 }
441 }
442
443 public bool EOF
444 {
445 get
446 {
447 return (this.pos >= this.len && this.current > this.end);
448 }
449 }
450
451 public string CurrentRow => this.currentRow;
452
453 public char LastCharacter => this.lastChar;
454
455 public string UntilToken(string Token)
456 {
457 StringBuilder sb = new StringBuilder();
458 int i = 0;
459 int c = Token.Length;
460 char ch;
461
462 while (true)
463 {
464 ch = this.NextCharRaw();
465
466 if (ch == 0)
467 {
468 if (!(this.blocks is null) && this.blockIndex < this.endBlock)
469 {
470 Block Next = this.blocks[++this.blockIndex];
471
472 this.rows = Next.Rows;
473 this.positions = Next.Positions;
474 this.current = this.start = Next.Start;
475 this.end = Next.End;
476 this.currentRow = this.rows[this.current];
477 this.lineBreakAfter = this.currentRow.EndsWith(" ");
478 this.pos = 0;
479 this.len = this.currentRow.Length; // >= 1
480
481 if (this.lineBreakAfter)
482 {
483 this.currentRow = this.currentRow.Substring(0, this.len - 2);
484 this.len -= 2;
485 }
486
487 sb.AppendLine();
488 sb.AppendLine();
489 }
490 else
491 {
492 if (i > 0)
493 sb.Append(Token.Substring(0, i));
494
495 return sb.ToString();
496 }
497 }
498 else if (ch == '\n') // Next line, no trailing double-space
499 {
500 if (i > 0)
501 {
502 sb.Append(Token.Substring(0, i));
503 i = 0;
504 }
505
506 sb.AppendLine();
507 }
508 else if (ch == '\r') // Next line, with trailing double-space
509 {
510 if (i > 0)
511 {
512 sb.Append(Token.Substring(0, i));
513 i = 0;
514 }
515
516 sb.AppendLine(" ");
517 }
518 else if (char.ToUpper(ch) == Token[i])
519 {
520 i++;
521 if (i >= c)
522 return sb.ToString();
523 }
524 else
525 {
526 if (i > 0)
527 {
528 sb.Append(Token.Substring(0, i));
529 i = 0;
530 }
531
532 sb.Append(ch);
533 }
534 }
535 }
536
537 }
538}
A chunked list is a linked list of chunks of objects of type T .
Definition: ChunkedList.cs:54
void AddFirstItem(T Value)
Adds a new item first in the collection.
Definition: ChunkedList.cs:832
bool HasFirstItem
If there is a first item in the collection
Definition: ChunkedList.cs:778
T RemoveFirst()
Removes the first item in the collection.
Definition: ChunkedList.cs:876