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 {
134 reader.Skip(BadStaticKeys.Whitespace.Concat(BadStaticKeys.NewLine).ToArray());
135 }
136
141 public static void SkipComment(this BadSourceReader reader)
142 {
144 {
146 reader.SkipToEndOfLine();
147 reader.SkipNewLine();
148 }
150 {
154 }
155 }
156
161 public static void SkipNonToken(this BadSourceReader reader)
162 {
163 int current;
164
165 do
166 {
167 current = reader.CurrentIndex;
168 reader.SkipComment();
169 reader.SkipWhiteSpaceAndNewLine();
170 }
171 while (current != reader.CurrentIndex);
172 }
173
174
184 public static BadWordToken ParseWord(this BadSourceReader reader)
185 {
186 if (!reader.IsWordStart())
187 {
188 throw new BadSourceReaderException(
189 $"Expected word start character but got '{(reader.IsEof() ? "EOF" : reader.GetCurrentChar())}'",
190 reader.MakeSourcePosition(1)
191 );
192 }
193
194 int start = reader.CurrentIndex;
195 reader.MoveNext();
196
197 while (reader.IsWordChar())
198 {
199 reader.MoveNext();
200 }
201
202 return new BadWordToken(reader.MakeSourcePosition(start, reader.CurrentIndex - start));
203 }
204
211 public static BadNumberToken ParseNumber(this BadSourceReader reader)
212 {
213 if (!reader.IsNumberStart())
214 {
215 throw new BadSourceReaderException(
216 $"Expected number start character but got '{(reader.IsEof() ? "EOF" : reader.GetCurrentChar())}'",
217 reader.MakeSourcePosition(1)
218 );
219 }
220
221 int start = reader.CurrentIndex;
222 reader.MoveNext();
223 bool hasDecimal = false;
224
225 while (reader.IsDigit() || !hasDecimal && reader.Is(BadStaticKeys.DECIMAL_SEPARATOR))
226 {
228 {
229 hasDecimal = true;
230 }
231
232 reader.MoveNext();
233 }
234
235 if (reader.Last(BadStaticKeys.DECIMAL_SEPARATOR))
236 {
237 reader.SetPosition(reader.CurrentIndex - 1);
238 }
239
240 return new BadNumberToken(reader.MakeSourcePosition(start, reader.CurrentIndex - start));
241 }
242
253 {
254 if (reader.Is(BadStaticKeys.TRUE))
255 {
256 return new BadBooleanToken(reader.Eat(BadStaticKeys.TRUE));
257 }
258
259 if (reader.Is(BadStaticKeys.FALSE))
260 {
261 return new BadBooleanToken(reader.Eat(BadStaticKeys.FALSE));
262 }
263
264 throw new BadSourceReaderException(
265 $"Expected boolean but got '{(reader.IsEof() ? "EOF" : reader.GetCurrentChar())}'",
266 reader.MakeSourcePosition(1)
267 );
268 }
269
275 public static BadNullToken ParseNull(this BadSourceReader reader)
276 {
277 return new BadNullToken(reader.Eat(BadStaticKeys.NULL));
278 }
279
286 public static BadSymbolToken? TryParseSymbols(this BadSourceReader reader, string symbols)
287 {
288 return reader.Is(symbols) ? new BadSymbolToken(reader.Eat(symbols)) : null;
289 }
290
297 public static BadSymbolToken? TryParseSymbols(this BadSourceReader reader, IEnumerable<string> symbols)
298 {
299 string? symbol =
300 symbols.FirstOrDefault(x => x.All(c => char.IsLetter(c) || c == '_') ? reader.IsKey(x) : reader.Is(x));
301
302 return symbol == null ? null : reader.TryParseSymbols(symbol);
303 }
304
314 public static BadStringToken ParseString(this BadSourceReader reader)
315 {
316 if (!reader.IsStringQuote() && !reader.IsStringQuote(0, true))
317 {
318 throw new BadSourceReaderException(
319 $"Expected string start character but got '{(reader.IsEof() ? "EOF" : reader.GetCurrentChar())}'",
320 reader.MakeSourcePosition(1)
321 );
322 }
323
324 bool singleQuote = reader.Is(BadStaticKeys.SINGLE_QUOTE);
325 int start = reader.CurrentIndex;
326 reader.MoveNext();
327 bool isEscaped = false;
328 StringBuilder sb = new StringBuilder("\"");
329
330 while (!reader.IsStringQuote(0, singleQuote))
331 {
332 if (reader.IsNewLine() || reader.IsEof())
333 {
334 throw new BadSourceReaderException(
335 "String not terminated",
336 reader.MakeSourcePosition(start, reader.CurrentIndex - start)
337 );
338 }
339
341 {
342 isEscaped = true;
343 reader.MoveNext();
344 }
345
346 if (isEscaped)
347 {
348 isEscaped = false;
349 sb.Append(Regex.Unescape($"\\{reader.GetCurrentChar()}"));
350 }
351 else
352 {
353 sb.Append(reader.GetCurrentChar());
354 }
355
356 reader.MoveNext();
357 }
358
359 reader.Eat(singleQuote ? BadStaticKeys.SINGLE_QUOTE : BadStaticKeys.QUOTE);
360
361 sb.Append("\"");
362
363 return new BadStringToken(sb.ToString(), reader.MakeSourcePosition(start, reader.CurrentIndex - start));
364 }
365
373 {
374 int start = reader.CurrentIndex;
376
377 StringBuilder sb = new StringBuilder("\"");
378
379 while (!reader.IsStringQuote())
380 {
381 if (reader.IsEof())
382 {
383 throw new BadSourceReaderException(
384 "String not terminated",
385 reader.MakeSourcePosition(start, reader.CurrentIndex - start)
386 );
387 }
388
389
390 sb.Append(reader.GetCurrentChar());
391
392 reader.MoveNext();
393 }
394
395 reader.Eat(BadStaticKeys.QUOTE);
396
397 sb.Append("\"");
398
399 return new BadStringToken(sb.ToString(), reader.MakeSourcePosition(start, reader.CurrentIndex - start));
400 }
401
408 public static bool IsWhiteSpace(this BadSourceReader reader, int offset = 0)
409 {
410 return reader.Is(offset, BadStaticKeys.Whitespace) ||
411 reader.Is(offset, BadStaticKeys.NewLine);
412 }
413
420 public static bool Last(this BadSourceReader reader, char c)
421 {
422 int index = -1;
423
424 while (reader.IsWhiteSpace(index))
425 {
426 index--;
427 }
428
429 return reader.GetCurrentChar(index) == c;
430 }
431}
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.