BadScript 2
Loading...
Searching...
No Matches
BadSourceReaderExtensions.cs
Go to the documentation of this file.
1using System.Text;
2using System.Text.RegularExpressions;
3
7
8namespace BadScript2.Reader;
9
13public static class BadSourceReaderExtensions
14{
21 public static bool IsWordStart(this BadSourceReader reader, int offset = 0)
22 {
23 return char.IsLetter(reader.GetCurrentChar(offset)) ||
24 reader.GetCurrentChar(offset) == '_';
25 }
26
33 public static bool IsWordChar(this BadSourceReader reader, int offset = 0)
34 {
35 return char.IsLetterOrDigit(reader.GetCurrentChar(offset)) ||
36 reader.GetCurrentChar(offset) == '_';
37 }
38
39 public static bool IsKey(this BadSourceReader reader, char c, int offset = 0)
40 {
41 return reader.Is(c, offset) && !reader.IsWordChar(offset + 1);
42 }
43
44 public static bool IsKey(this BadSourceReader reader, string s, int offset = 0)
45 {
46 return reader.Is(s, offset) && !reader.IsWordChar(offset + s.Length);
47 }
48
56 public static bool IsStringQuote(this BadSourceReader reader, int offset = 0, bool singleQuote = false)
57 {
58 if (singleQuote)
59 {
60 return reader.GetCurrentChar(offset) == BadStaticKeys.SINGLE_QUOTE;
61 }
62
63 return reader.GetCurrentChar(offset) == BadStaticKeys.QUOTE;
64 }
65
72 public static bool IsNumberStart(this BadSourceReader reader, int offset = 0)
73 {
74 return reader.IsDigit(offset) ||
76 }
77
84 public static bool IsDigit(this BadSourceReader reader, int offset = 0)
85 {
86 return char.IsDigit(reader.GetCurrentChar(offset));
87 }
88
95 public static bool IsNewLine(this BadSourceReader reader, int offset = 0)
96 {
97 return reader.Is(offset, BadStaticKeys.NewLine);
98 }
99
104 public static void SkipWhiteSpace(this BadSourceReader reader)
105 {
107 }
108
109
114 public static void SkipNewLine(this BadSourceReader reader)
115 {
116 reader.Skip(BadStaticKeys.NewLine);
117 }
118
123 public static void SkipToEndOfLine(this BadSourceReader reader)
124 {
125 reader.Seek(BadStaticKeys.NewLine);
126 }
127
132 public static void SkipWhiteSpaceAndNewLine(this BadSourceReader reader)
133 {
135 .ToArray()
136 );
137 }
138
143 public static void SkipComment(this BadSourceReader reader)
144 {
146 {
148 reader.SkipToEndOfLine();
149 reader.SkipNewLine();
150 }
152 {
156 }
157 }
158
163 public static void SkipNonToken(this BadSourceReader reader)
164 {
165 int current;
166
167 do
168 {
169 current = reader.CurrentIndex;
170 reader.SkipComment();
171 reader.SkipWhiteSpaceAndNewLine();
172 }
173 while (current != reader.CurrentIndex);
174 }
175
176
186 public static BadWordToken ParseWord(this BadSourceReader reader)
187 {
188 if (!reader.IsWordStart())
189 {
190 throw new
191 BadSourceReaderException($"Expected word start character but got '{(reader.IsEof() ? "EOF" : reader.GetCurrentChar())}'",
192 reader.MakeSourcePosition(1)
193 );
194 }
195
196 int start = reader.CurrentIndex;
197 reader.MoveNext();
198
199 while (reader.IsWordChar())
200 {
201 reader.MoveNext();
202 }
203
204 return new BadWordToken(reader.MakeSourcePosition(start, reader.CurrentIndex - start));
205 }
206
213 public static BadNumberToken ParseNumber(this BadSourceReader reader)
214 {
215 if (!reader.IsNumberStart())
216 {
217 throw new
218 BadSourceReaderException($"Expected number start character but got '{(reader.IsEof() ? "EOF" : reader.GetCurrentChar())}'",
219 reader.MakeSourcePosition(1)
220 );
221 }
222
223 int start = reader.CurrentIndex;
224 reader.MoveNext();
225 bool hasDecimal = false;
226
227 while (reader.IsDigit() || (!hasDecimal && reader.Is(BadStaticKeys.DECIMAL_SEPARATOR)))
228 {
230 {
231 hasDecimal = true;
232 }
233
234 reader.MoveNext();
235 }
236
237 if (reader.Last(BadStaticKeys.DECIMAL_SEPARATOR))
238 {
239 reader.SetPosition(reader.CurrentIndex - 1);
240 }
241
242 return new BadNumberToken(reader.MakeSourcePosition(start, reader.CurrentIndex - start));
243 }
244
255 {
256 if (reader.Is(BadStaticKeys.TRUE))
257 {
258 return new BadBooleanToken(reader.Eat(BadStaticKeys.TRUE));
259 }
260
261 if (reader.Is(BadStaticKeys.FALSE))
262 {
263 return new BadBooleanToken(reader.Eat(BadStaticKeys.FALSE));
264 }
265
266 throw new
267 BadSourceReaderException($"Expected boolean but got '{(reader.IsEof() ? "EOF" : reader.GetCurrentChar())}'",
268 reader.MakeSourcePosition(1)
269 );
270 }
271
277 public static BadNullToken ParseNull(this BadSourceReader reader)
278 {
279 return new BadNullToken(reader.Eat(BadStaticKeys.NULL));
280 }
281
288 public static BadSymbolToken? TryParseSymbols(this BadSourceReader reader, string symbols)
289 {
290 return reader.Is(symbols) ? new BadSymbolToken(reader.Eat(symbols)) : null;
291 }
292
299 public static BadSymbolToken? TryParseSymbols(this BadSourceReader reader, IEnumerable<string> symbols)
300 {
301 string? symbol =
302 symbols.FirstOrDefault(x => x.All(c => char.IsLetter(c) || c == '_') ? reader.IsKey(x) : reader.Is(x));
303
304 return symbol == null ? null : reader.TryParseSymbols(symbol);
305 }
306
316 public static BadStringToken ParseString(this BadSourceReader reader)
317 {
318 if (!reader.IsStringQuote() && !reader.IsStringQuote(0, true))
319 {
320 throw new
321 BadSourceReaderException($"Expected string start character but got '{(reader.IsEof() ? "EOF" : reader.GetCurrentChar())}'",
322 reader.MakeSourcePosition(1)
323 );
324 }
325
326 bool singleQuote = reader.Is(BadStaticKeys.SINGLE_QUOTE);
327 int start = reader.CurrentIndex;
328 reader.MoveNext();
329 bool isEscaped = false;
330 StringBuilder sb = new StringBuilder("\"");
331
332 while (!reader.IsStringQuote(0, singleQuote))
333 {
334 if (reader.IsNewLine() || reader.IsEof())
335 {
336 throw new BadSourceReaderException("String not terminated",
337 reader.MakeSourcePosition(start, reader.CurrentIndex - start)
338 );
339 }
340
342 {
343 isEscaped = true;
344 reader.MoveNext();
345 }
346
347 if (isEscaped)
348 {
349 isEscaped = false;
350 sb.Append(Regex.Unescape($"\\{reader.GetCurrentChar()}"));
351 }
352 else
353 {
354 sb.Append(reader.GetCurrentChar());
355 }
356
357 reader.MoveNext();
358 }
359
360 reader.Eat(singleQuote ? BadStaticKeys.SINGLE_QUOTE : BadStaticKeys.QUOTE);
361
362 sb.Append("\"");
363
364 return new BadStringToken(sb.ToString(), reader.MakeSourcePosition(start, reader.CurrentIndex - start));
365 }
366
374 {
375 int start = reader.CurrentIndex;
377
378 StringBuilder sb = new StringBuilder("\"");
379
380 while (!reader.IsStringQuote())
381 {
382 if (reader.IsEof())
383 {
384 throw new BadSourceReaderException("String not terminated",
385 reader.MakeSourcePosition(start, reader.CurrentIndex - start)
386 );
387 }
388
389 sb.Append(reader.GetCurrentChar());
390
391 reader.MoveNext();
392 }
393
394 reader.Eat(BadStaticKeys.QUOTE);
395
396 sb.Append("\"");
397
398 return new BadStringToken(sb.ToString(), reader.MakeSourcePosition(start, reader.CurrentIndex - start));
399 }
400
407 public static bool IsWhiteSpace(this BadSourceReader reader, int offset = 0)
408 {
409 return reader.Is(offset, BadStaticKeys.Whitespace) ||
410 reader.Is(offset, BadStaticKeys.NewLine);
411 }
412
419 public static bool Last(this BadSourceReader reader, char c)
420 {
421 int index = -1;
422
423 while (reader.IsWhiteSpace(index))
424 {
425 index--;
426 }
427
428 return reader.GetCurrentChar(index) == c;
429 }
430}
Contains Static Data for the BadScript Language.
static readonly char[] Whitespace
static readonly char[] NewLine
Gets Raised if the Reader encounters an Error.
static bool IsDigit(this BadSourceReader reader, int offset=0)
Returns true if the Current Character is a Digit.
static bool Last(this BadSourceReader reader, char c)
Returns true if the last non-whitespace character is the specified character.
static void SkipWhiteSpaceAndNewLine(this BadSourceReader reader)
Skips all whitespace and newline characters.
static BadBooleanToken ParseBoolean(this BadSourceReader reader)
Parses a BadBoolean Token.
static BadStringToken ParseString(this BadSourceReader reader)
Parses a BadStringToken.
static bool IsNewLine(this BadSourceReader reader, int offset=0)
Returns true if the Current Character is a Newline Character.
static ? BadSymbolToken TryParseSymbols(this BadSourceReader reader, IEnumerable< string > symbols)
Tries to parse a list of symbols.
static bool IsKey(this BadSourceReader reader, string s, int offset=0)
static bool IsWordStart(this BadSourceReader reader, int offset=0)
Returns true if the Current Character of the Reader is a valid Word Start Character.
static void SkipNewLine(this BadSourceReader reader)
Skips all newline characters.
static void SkipWhiteSpace(this BadSourceReader reader)
Skips all whitespace characters.
static BadNumberToken ParseNumber(this BadSourceReader reader)
Parses a BadNumberToken.
static BadNullToken ParseNull(this BadSourceReader reader)
Parses a BadNullToken.
static bool IsWordChar(this BadSourceReader reader, int offset=0)
Returns true if the Current Character of the Reader is a valid Word Character.
static void SkipComment(this BadSourceReader reader)
Skips a comment.
static bool IsNumberStart(this BadSourceReader reader, int offset=0)
Returns true if the Current Character is a valid Number Character.
static void SkipToEndOfLine(this BadSourceReader reader)
Skips all characters untile a newline is found.
static BadStringToken ParseMultiLineString(this BadSourceReader reader)
Parses a Multi Line String.
static void SkipNonToken(this BadSourceReader reader)
Skips all whitespace, newline characters and comments.
static ? BadSymbolToken TryParseSymbols(this BadSourceReader reader, string symbols)
Tries to parse symbols.
static BadWordToken ParseWord(this BadSourceReader reader)
Parses a Word Token.
static bool IsWhiteSpace(this BadSourceReader reader, int offset=0)
Returns true if the Current Character is any whitespace or newline characters.
static bool IsStringQuote(this BadSourceReader reader, int offset=0, bool singleQuote=false)
Returns true if the Current Character is a String Quote Character.
static bool IsKey(this BadSourceReader reader, char c, int offset=0)
Implements the Source Code Reader.
void MoveNext()
Moves the Reader to the next character in the source code.
void SetPosition(int index)
Sets the Current Index of the Reader.
void Skip(char c)
If the current character is equal to the specified character, it will be skipped.
char GetCurrentChar(int offset=0)
Returns the Current Character.
BadSourcePosition MakeSourcePosition(int length)
Creates a source position with the specified length and the current index of the reader.
void Seek(char c)
Skips over any character that is not equal to the specified character.
int CurrentIndex
The Current Index of the Reader.
bool IsEof(int offset=0)
Returns true if the reader is at the end of the source code.
BadSourcePosition Eat(char c)
Asserts that the current character matches the specified character.
bool Is(char c, int offset=0)
Returns true if the current character matches the specified character.
Implements a Token that represents a Boolean.
Implements a Token that represents a Number.
Implements a Token that represents a String.
Contains Shared Data Structures and Functionality.
Contains the Primitive Tokens for the BadScript2 Language.
Contains the Reader Tokens for the BadScript2 Language.
Contains the Source Reader for the BadScript2 Language.