BadScript 2
Loading...
Searching...
No Matches
BadSourceParser.cs
Go to the documentation of this file.
1using System.Globalization;
2using System.Text;
3using System.Text.RegularExpressions;
4
25
26namespace BadScript2.Parser;
27
32public class BadSourceParser
33{
37 private readonly BadOperatorTable m_Operators;
38
43
49 public BadSourceParser(BadSourceReader sourceReader, BadOperatorTable operators)
50 {
51 Reader = sourceReader;
52 m_Operators = operators;
53 }
54
58 public BadSourceReader Reader { get; }
59
66 public static BadSourceParser Create(string fileName, string source)
67 {
68 return new BadSourceParser(new BadSourceReader(fileName, source), BadOperatorTable.Instance);
69 }
70
79 public static BadSourceParser Create(string fileName, string source, int start, int end)
80 {
81 return new BadSourceParser(new BadSourceReader(fileName, source, start, end), BadOperatorTable.Instance);
82 }
83
90 public static IEnumerable<BadExpression> Parse(string fileName, string source)
91 {
92 return Create(fileName, source)
93 .Parse();
94 }
95
102 private BadExpression? ParsePrefix(int precedence)
103 {
104 // Parse Symbol
105 BadSymbolToken? symbol = Reader.TryParseSymbols(m_Operators.UnaryPrefixSymbols);
106
107 if (symbol == null)
108 {
109 return null;
110 }
111
113
114 if (op != null)
115 {
116 return op.Parse(this);
117 }
118
120
121 return null;
122 }
123
125 {
126 int start = Reader.CurrentIndex;
128 Reader.SkipNonToken();
129 Reader.Eat('(');
130 Reader.SkipNonToken();
132 Reader.SkipNonToken();
133 Reader.Eat(')');
134 Reader.SkipNonToken();
135 Reader.Eat('{');
136 Reader.SkipNonToken();
137 Dictionary<BadExpression, BadExpression[]> cases = new Dictionary<BadExpression, BadExpression[]>();
138 List<BadExpression>? defaultCase = null;
139
140 while (!Reader.IsEof() && !Reader.Is('}'))
141 {
142 Reader.SkipNonToken();
143
145 {
147 Reader.SkipNonToken();
148 Reader.Eat(':');
149 Reader.SkipNonToken();
150 defaultCase = ParseBlock(out bool _);
151 Reader.SkipNonToken();
152
153 break;
154 }
155
157 Reader.SkipNonToken();
158 BadExpression caseValue = ParseExpression();
159 Reader.SkipNonToken();
160 Reader.Eat(':');
161 Reader.SkipNonToken();
162 List<BadExpression> caseBody = new List<BadExpression>();
163
164 if (Reader.Is('{'))
165 {
166 caseBody = ParseBlock(out bool _);
167 }
168
169 Reader.SkipNonToken();
170 cases[caseValue] = caseBody.ToArray();
171 }
172
173 Reader.Eat('}');
174
176 value,
177 cases,
178 defaultCase
179 );
180 }
181
187 {
188 int start = Reader.CurrentIndex;
189
190 Dictionary<BadExpression, BadExpression[]> conditionMap = new Dictionary<BadExpression, BadExpression[]>();
191
192 bool readNext;
193 bool isElse;
194
195 do
196 {
197 readNext = false;
198 isElse = false;
200 Reader.SkipNonToken();
201 Reader.Eat('(');
202 Reader.SkipNonToken();
203 BadExpression condition = ParseExpression();
204 Reader.SkipNonToken();
205 Reader.Eat(')');
206 Reader.SkipNonToken();
207 List<BadExpression> block = ParseBlock(out bool _);
208 Reader.SkipNonToken();
209 conditionMap[condition] = block.ToArray();
210
211 if (!Reader.IsKey(BadStaticKeys.ELSE_KEY))
212 {
213 continue;
214 }
215
217 isElse = true;
218 Reader.SkipNonToken();
219 readNext = Reader.IsKey(BadStaticKeys.IF_KEY);
220 }
221 while (readNext);
222
223 BadExpression[]? elseBlock = null;
224
225 if (isElse)
226 {
227 elseBlock = ParseBlock(out bool _)
228 .ToArray();
229 }
230
231 return new BadIfExpression(conditionMap,
232 elseBlock,
234 );
235 }
236
242 {
243 int start = Reader.CurrentIndex;
245 Reader.SkipNonToken();
246 Reader.Eat('(');
247 Reader.SkipNonToken();
248 BadWordToken variableName = Reader.ParseWord();
249 Reader.SkipNonToken();
250 Reader.Eat("in");
251 Reader.SkipNonToken();
252 BadExpression collection = ParseExpression();
253 Reader.SkipNonToken();
254 Reader.Eat(')');
255 Reader.SkipNonToken();
256 List<BadExpression> block = ParseBlock(out bool _);
257 Reader.SkipNonToken();
258
259 return new BadForEachExpression(collection,
260 variableName,
261 block.ToArray(),
263 );
264 }
265
266
272 {
273 int start = Reader.CurrentIndex;
275 Reader.SkipNonToken();
276 Reader.Eat('(');
277 Reader.SkipNonToken();
278 BadExpression collection = ParseExpression();
279 Reader.SkipNonToken();
280 Reader.Eat(')');
281 Reader.SkipNonToken();
282 List<BadExpression> block = ParseBlock(out bool _);
283 Reader.SkipNonToken();
284
286 collection,
287 block.ToArray()
288 );
289 }
290
296 {
297 int start = Reader.CurrentIndex;
299 Reader.SkipNonToken();
300 Reader.Eat('(');
301 Reader.SkipNonToken();
303 Reader.SkipNonToken();
305 Reader.SkipNonToken();
306 BadExpression condition = ParseExpression();
307 Reader.SkipNonToken();
309 Reader.SkipNonToken();
311 Reader.SkipNonToken();
312 Reader.Eat(')');
313 Reader.SkipNonToken();
314 List<BadExpression> block = ParseBlock(out bool _);
315 Reader.SkipNonToken();
316
317 return new BadForExpression(vDef,
318 condition,
319 vInc,
320 block.ToArray(),
322 );
323 }
324
328 private void ParseMeta()
329 {
330 if (!Reader.Is("@|"))
331 {
332 return;
333 }
334
335 Reader.Eat("@|");
336 Reader.SkipNonToken();
337 StringBuilder rootMeta = new StringBuilder();
338 StringBuilder returnMeta = new StringBuilder();
339 string returnType = "any";
340 Dictionary<string, (string, StringBuilder)> meta = new Dictionary<string, (string, StringBuilder)>();
341
342 StringBuilder GetMeta(string name, string type)
343 {
344 if (meta.TryGetValue(name, out (string, StringBuilder) val))
345 {
346 return val.Item2;
347 }
348
349 val = (type, new StringBuilder());
350 meta[name] = val;
351
352 return val.Item2;
353 }
354
355 while (!Reader.Is("|@"))
356 {
357 if (Reader.Is("|PARAM"))
358 {
359 Reader.Eat("|PARAM");
360 Reader.SkipNonToken();
361
362 string name = Reader.ParseWord()
363 .Text;
364 Reader.SkipNonToken();
365 string type = "any";
366
367 if (!Reader.Is(':'))
368 {
369 type = "";
370
371 while (!Reader.IsEof() && (Reader.IsWordStart() || Reader.Is('.')))
372 {
373 type += Reader.ParseWord()
374 .Text;
375
376 if (!Reader.Is('.'))
377 {
378 continue;
379 }
380
381 type += '.';
383 }
384
385 Reader.SkipNonToken();
386 }
387
388 Reader.Eat(':');
389 Reader.SkipNonToken();
390 StringBuilder m = GetMeta(name, type);
391
392 while (!Reader.IsEof() && !Reader.Is("|@") && !Reader.IsNewLine())
393 {
394 m.Append(Reader.GetCurrentChar());
396 }
397
398 Reader.SkipNonToken();
399 }
400 else if (Reader.Is("|RET"))
401 {
402 Reader.Eat("|RET");
403 Reader.SkipNonToken();
404 string type = "any";
405
406 if (!Reader.Is(':'))
407 {
408 type = "";
409
410 while (!Reader.IsEof() && (Reader.IsWordStart() || Reader.Is('.')))
411 {
412 type += Reader.ParseWord()
413 .Text;
414
415 if (!Reader.Is('.'))
416 {
417 continue;
418 }
419
420 type += '.';
422 }
423
424 Reader.SkipNonToken();
425 }
426
427 Reader.Eat(':');
428 Reader.SkipNonToken();
429
430 while (!Reader.IsEof() && !Reader.Is("|@") && !Reader.IsNewLine())
431 {
432 returnMeta.Append(Reader.GetCurrentChar());
434 }
435
436 Reader.SkipNonToken();
437
438 returnType = type;
439 }
440 else
441 {
442 if (Reader.IsNewLine(-1))
443 {
444 Reader.SkipNonToken();
445
446 if (Reader.Is("|"))
447 {
448 continue;
449 }
450 }
451
452 while (!Reader.IsEof() && !Reader.IsNewLine() && !Reader.Is("|@"))
453 {
454 rootMeta.Append(Reader.GetCurrentChar());
456 }
457
458 rootMeta.AppendLine();
459 Reader.SkipNonToken();
460 }
461 }
462
463 Reader.Eat("|@");
464 Reader.SkipNonToken();
465
466 m_MetaData = new BadMetaData(rootMeta.ToString()
467 .Trim(),
468 returnMeta.ToString()
469 .Trim(),
470 returnType,
471 meta.ToDictionary(x => x.Key,
472 x => new BadParameterMetaData(x.Value.Item1,
473 x.Value.Item2.ToString()
474 .Trim()
475 )
476 )
477 );
478 }
479
487 private BadExpression ParseValue(int precedence)
488 {
489 Reader.SkipNonToken();
490
491 ParseMeta();
492
493 Reader.SkipNonToken();
494
495 BadExpression? prefixExpr = ParsePrefix(precedence);
496
497 if (prefixExpr != null)
498 {
499 return prefixExpr;
500 }
501
502 if (Reader.Is('('))
503 {
504 int start = Reader.CurrentIndex;
505
506 try
507 {
508 List<BadFunctionParameter> p = ParseParameters(start);
509
510 Reader.SkipNonToken();
511
512 if (!Reader.Is("=>"))
513 {
514 Reader.SetPosition(start);
515 }
516 else
517 {
518 return ParseFunction(start, null, null, false, false, BadFunctionCompileLevel.None, p);
519 }
520 }
521 catch (Exception)
522 {
523 Reader.SetPosition(start);
524 }
525 }
526
527 if (Reader.Is('('))
528 {
529 Reader.Eat('(');
531 Reader.Eat(')');
532
533 return expr;
534 }
535
536 if (Reader.Is('['))
537 {
538 int start = Reader.CurrentIndex;
539 Reader.Eat('[');
540 Reader.SkipNonToken();
541 List<BadExpression> initExpressions = new List<BadExpression>();
542
543 if (!Reader.Is(']'))
544 {
545 bool parseNext;
546
547 do
548 {
549 parseNext = false;
550
551 Reader.SkipNonToken();
552 initExpressions.Add(ParseExpression());
553
554 Reader.SkipNonToken();
555
556 if (Reader.Is(','))
557 {
558 Reader.Eat(',');
559 Reader.SkipNonToken();
560 parseNext = true;
561 }
562 }
563 while (parseNext);
564 }
565
566 Reader.SkipNonToken();
567 Reader.Eat(']');
568
569 return new BadArrayExpression(initExpressions.ToArray(),
571 );
572 }
573
574 if (Reader.Is('{'))
575 {
576 int start = Reader.CurrentIndex;
577 Reader.Eat('{');
578 Dictionary<BadWordToken, BadExpression> table = new Dictionary<BadWordToken, BadExpression>();
579 Reader.SkipNonToken();
580
581 if (!Reader.Is('}'))
582 {
583 bool parseNext;
584
585 do
586 {
587 parseNext = false;
588 Reader.SkipNonToken();
589 BadWordToken key = Reader.ParseWord();
590 Reader.SkipNonToken();
591 Reader.Eat(':');
592 Reader.SkipNonToken();
594 table[key] = value;
595 Reader.SkipNonToken();
596
597 if (Reader.Is(','))
598 {
599 parseNext = true;
600 Reader.Eat(',');
601 }
602 }
603 while (parseNext);
604 }
605
606 Reader.Eat('}');
607
608 return new BadTableExpression(table,
610 );
611 }
612
613 if (Reader.IsKey(BadStaticKeys.LOCK_KEY))
614 {
615 return ParseLock();
616 }
617
619 {
620 return ParseForEach();
621 }
622
623 if (Reader.IsKey(BadStaticKeys.FOR_KEY))
624 {
625 return ParseFor();
626 }
627
628 if (Reader.IsKey(BadStaticKeys.IF_KEY))
629 {
630 return ParseIf();
631 }
632
634 {
635 return ParseSwitch();
636 }
637
639 {
641
642 if (Reader.IsWordChar())
643 {
645 }
646 else
647 {
648 Reader.SkipNonToken();
649
650 return new BadContinueExpression(pos);
651 }
652 }
653
654 if (Reader.IsKey(BadStaticKeys.BREAK_KEY))
655 {
657
658 if (Reader.IsWordChar())
659 {
661 }
662 else
663 {
664 Reader.SkipNonToken();
665
666 return new BadBreakExpression(pos);
667 }
668 }
669
670 if (Reader.IsKey(BadStaticKeys.THROW_KEY))
671 {
673
674 if (Reader.IsWordChar())
675 {
677 }
678 else
679 {
680 return new BadThrowExpression(ParseExpression(), pos);
681 }
682 }
683
685 {
687
688 if (Reader.IsWordChar())
689 {
691 }
692 else
693 {
694 Reader.SkipNonToken();
695 bool isRef = false;
696
697 if (Reader.Is(';'))
698 {
699 return new BadReturnExpression(null, pos, false);
700 }
701
702 if (Reader.IsKey(BadStaticKeys.REF_KEY))
703 {
704 isRef = true;
706 Reader.SkipNonToken();
707 }
708
710
711 return new BadReturnExpression(expr, pos, isRef);
712 }
713 }
714
715 if (Reader.IsKey(BadStaticKeys.TRUE) ||
717 {
718 BadBooleanToken token = Reader.ParseBoolean();
719
720 if (Reader.IsWordChar())
721 {
723 }
724 else
725 {
726 return new BadBooleanExpression(bool.Parse(token.Text), token.SourcePosition);
727 }
728 }
729
730 bool isConstant = false;
731 bool isStatic = false;
733 int constStart = Reader.CurrentIndex;
734
736 {
737 isConstant = true;
739 Reader.SkipNonToken();
740 }
742 {
743 isStatic = true;
745 Reader.SkipNonToken();
746 }
747
748 int compiledStart = Reader.CurrentIndex;
749
751 {
752 compileLevel = BadFunctionCompileLevel.Compiled;
754 Reader.SkipNonToken();
755
757 {
758 compileLevel = BadFunctionCompileLevel.CompiledFast;
760 Reader.SkipNonToken();
761 }
762 }
763
765 {
766 return ParseFunction(isConstant, isStatic, compileLevel);
767 }
768
769 if (compileLevel != BadFunctionCompileLevel.None || isConstant)
770 {
771 Reader.SetPosition(compiledStart < constStart ? compiledStart : constStart);
772 }
773
774 if (Reader.IsKey(BadStaticKeys.CLASS_KEY))
775 {
776 return ParseClass();
777 }
778
780 {
781 return ParseInterface();
782 }
783
784 if (Reader.IsKey(BadStaticKeys.NEW_KEY))
785 {
786 return ParseNew();
787 }
788
789 if (Reader.IsKey(BadStaticKeys.TRY_KEY))
790 {
791 return ParseTry();
792 }
793
794 if (Reader.IsKey(BadStaticKeys.USING_KEY))
795 {
796 return ParseUsing();
797 }
798
799 if (Reader.IsKey(BadStaticKeys.WHILE))
800 {
801 return ParseWhile();
802 }
803
804 if (Reader.IsKey(BadStaticKeys.NULL))
805 {
806 BadNullToken token = Reader.ParseNull();
807
808 if (Reader.IsWordChar())
809 {
811 }
812 else
813 {
814 return new BadNullExpression(token.SourcePosition);
815 }
816 }
817
818 if (Reader.IsStringQuote() || Reader.IsStringQuote(0, true))
819 {
820 BadStringToken token = Reader.ParseString();
821
822 return new BadStringExpression(token.Value, token.SourcePosition);
823 }
824
826 {
827 return ParseFormatString();
828 }
829
831 {
833 }
834
836 {
837 BadStringToken token = Reader.ParseMultiLineString();
838
839 return new BadStringExpression(token.Value, token.SourcePosition);
840 }
841
842 if (Reader.IsNumberStart())
843 {
844 BadNumberToken token = Reader.ParseNumber();
845
846 return new BadNumberExpression(decimal.Parse(token.Text, NumberFormatInfo.InvariantInfo),
847 token.SourcePosition
848 );
849 }
850
851 BadValueParser? valueParser = m_Operators.GetValueParser(this);
852
853 if (valueParser != null)
854 {
855 return valueParser.ParseValue(this);
856 }
857
858 Reader.SkipNonToken();
859
860 int wordStart = Reader.CurrentIndex;
861 BadWordToken word = Reader.ParseWord();
862
865 {
866 bool isReadOnly = word.Text == BadStaticKeys.CONSTANT_DEFINITION_KEY;
867 Reader.SkipNonToken();
868 BadExpression nameExpr = ParseValue(0);
869 Reader.SkipNonToken();
870
871 while (Reader.Is("."))
872 {
873 Reader.Eat(".");
874 BadWordToken right = Reader.ParseWord();
875 List<BadExpression>? genArgs = ParseGenericArguments();
876
877 nameExpr = new BadMemberAccessExpression(nameExpr,
878 right,
879 nameExpr.Position.Combine(right.SourcePosition),
880 genArgs
881 );
882 Reader.SkipNonToken();
883 }
884
885 BadWordToken name;
886 BadExpression? type = null;
887 Reader.SkipNonToken();
888
889 if (Reader.IsWordStart())
890 {
891 type = nameExpr;
892 name = Reader.ParseWord();
893 }
894 else
895 {
896 if (nameExpr is not BadVariableExpression expr)
897 {
898 throw new BadRuntimeException("Expected variable name", nameExpr.Position);
899 }
900
901 name = expr.Name;
902 }
903
904 Reader.SkipNonToken();
905
906 if (Reader.Is('{'))
907 {
908 //Parse Property Accessors
909 // => { get => <expr> [set => <expr>] }
910 Reader.Eat('{');
911 Reader.SkipNonToken();
913 Reader.SkipNonToken();
914 Reader.Eat("=>");
915 Reader.SkipNonToken();
916 BadExpression getExpr = ParseExpression();
917 Reader.SkipNonToken();
919 Reader.SkipNonToken();
920 BadExpression? setExpr = null;
921
923 {
924 if (isReadOnly)
925 {
926 throw new BadParserException("Cannot define a set accessor for a constant",
927 Reader.MakeSourcePosition(wordStart,
928 Reader.CurrentIndex - wordStart
929 )
930 );
931 }
932
934 Reader.SkipNonToken();
935 Reader.Eat("=>");
936 Reader.SkipNonToken();
937 setExpr = ParseExpression();
938 Reader.SkipNonToken();
940 }
941
942 Reader.SkipNonToken();
943 Reader.Eat('}');
944
946 word.SourcePosition,
947 getExpr,
948 type,
949 setExpr,
950 isReadOnly
951 );
952 }
953
954 return new BadVariableDefinitionExpression(name.Text, word.SourcePosition, type, isReadOnly);
955 }
956
957 Reader.SkipNonToken();
958
959 List<BadExpression> typeArgs = ParseGenericArguments();
960
961 if (precedence <= 0 || (!Reader.Is("=>") && !Reader.Is('*') && !Reader.Is('?') && !Reader.Is('!')))
962 {
963 return new BadVariableExpression(word.Text, word.SourcePosition, typeArgs.ToArray());
964 }
965
966 {
967 int start = Reader.CurrentIndex;
968
969 while (Reader.Is('*') || Reader.Is('?') || Reader.Is('!'))
970 {
972 }
973
974 Reader.SkipNonToken();
975
976 if (!Reader.Is("=>"))
977 {
978 Reader.SetPosition(start);
979 }
980 else
981 {
982 Reader.SetPosition(start);
984
985 if (Reader.Is("=>"))
986 {
987 p = new BadFunctionParameter(word.Text, false, false, false);
988 }
989 else
990 {
991 Reader.SetPosition(wordStart);
992 p = ParseParameter();
993 }
994
995 Reader.SkipNonToken();
996
997 if (!Reader.Is("=>"))
998 {
999 Reader.SetPosition(start);
1000 }
1001 else
1002 {
1003 return ParseFunction(start,
1004 null,
1005 null,
1006 false,
1007 isStatic,
1009 new List<BadFunctionParameter> { p }
1010 );
1011 }
1012 }
1013 }
1014
1015 return new BadVariableExpression(word.Text, word.SourcePosition, typeArgs.ToArray());
1016 }
1017
1018 public List<BadExpression> ParseGenericArguments()
1019 {
1020 List<BadExpression> typeArgs = new List<BadExpression>();
1021
1022 if (Reader.Is('<'))
1023 {
1024 int genStart = Reader.CurrentIndex;
1025
1026 try
1027 {
1028 Reader.Eat('<');
1029 Reader.SkipNonToken();
1030
1031 while (true)
1032 {
1033 BadExpression? expr = ParseExpression(null, 3);
1034 typeArgs.Add(expr);
1035 Reader.SkipNonToken();
1036
1037 if (!Reader.Is(','))
1038 {
1039 break;
1040 }
1041
1042 Reader.Eat(',');
1043 Reader.SkipNonToken();
1044 }
1045
1046 Reader.Eat('>');
1047
1048 Reader.SkipNonToken();
1049 }
1050 catch (Exception)
1051 {
1052 Reader.SetPosition(genStart);
1053 typeArgs.Clear();
1054 }
1055 }
1056
1057 return typeArgs;
1058 }
1059
1066 public BadExpression ParseExpression(BadExpression? left = null, int precedence = int.MaxValue)
1067 {
1068 left ??= ParseValue(precedence);
1069
1070 while (!Reader.IsEof())
1071 {
1072 Reader.SkipNonToken();
1073
1075 {
1076 return left;
1077 }
1078
1079 if (Reader.Is('[') || Reader.Is("?["))
1080 {
1081 bool isNullChecked = Reader.Is("?[");
1082
1083 if (isNullChecked)
1084 {
1085 Reader.Eat("?[");
1086 }
1087 else
1088 {
1089 Reader.Eat('[');
1090 }
1091
1092 Reader.SkipNonToken();
1093 bool isReverse = false;
1094
1095 if (Reader.Is('^'))
1096 {
1097 Reader.Eat('^');
1098 isReverse = true;
1099 }
1100
1101 List<BadExpression> indices = new List<BadExpression>();
1102
1103 if (!Reader.Is(']'))
1104 {
1105 bool readNext;
1106
1107 do
1108 {
1109 readNext = false;
1110 Reader.SkipNonToken();
1111 indices.Add(ParseExpression());
1112
1113 Reader.SkipNonToken();
1114
1115 if (Reader.Is(','))
1116 {
1117 readNext = true;
1118 Reader.Eat(',');
1119 }
1120
1121 Reader.SkipNonToken();
1122 }
1123 while (readNext);
1124 }
1125
1126 BadSourcePosition end = Reader.Eat(']');
1127 Reader.SkipNonToken();
1128
1129 if (isReverse)
1130 {
1131 left = new BadArrayAccessReverseExpression(left,
1132 indices.ToArray(),
1133 left.Position.Combine(end),
1134 isNullChecked
1135 );
1136 }
1137 else
1138 {
1139 left = new BadArrayAccessExpression(left,
1140 indices.ToArray(),
1141 left.Position.Combine(end),
1142 isNullChecked
1143 );
1144 }
1145
1146 continue;
1147 }
1148
1149 if (Reader.Is('('))
1150 {
1151 Reader.Eat('(');
1152 Reader.SkipNonToken();
1153 List<BadExpression> args = new List<BadExpression>();
1154
1155 if (!Reader.Is(')'))
1156 {
1157 bool readNext;
1158
1159 do
1160 {
1161 readNext = false;
1162 Reader.SkipNonToken();
1163 args.Add(ParseExpression());
1164
1165 Reader.SkipNonToken();
1166
1167 if (Reader.Is(','))
1168 {
1169 readNext = true;
1170 Reader.Eat(',');
1171 }
1172
1173 Reader.SkipNonToken();
1174 }
1175 while (readNext);
1176 }
1177
1179 Reader.Eat(')');
1180 left = new BadInvocationExpression(left, args.ToArray(), left.Position.Combine(rightPos));
1181 Reader.SkipNonToken();
1182
1183 continue;
1184 }
1185
1186 // Parse Symbol
1187 BadSymbolToken? symbol = Reader.TryParseSymbols(m_Operators.BinarySymbols);
1188
1189 if (symbol == null)
1190 {
1191 return left;
1192 }
1193
1194 BadBinaryOperator? op = m_Operators.FindBinaryOperator(symbol.Text, precedence);
1195
1196 if (op == null)
1197 {
1199
1200 return left;
1201 }
1202
1203 left = op.Parse(left, this);
1204 }
1205
1206 return left;
1207 }
1208
1209
1216 {
1218 {
1219 throw new
1220 BadSourceReaderException($"Expected string start character but got '{(Reader.IsEof() ? "EOF" : Reader.GetCurrentChar())}'",
1222 );
1223 }
1224
1225 int start = Reader.CurrentIndex;
1227 StringBuilder sb = new StringBuilder();
1228 List<BadExpression> args = new List<BadExpression>();
1229
1230 while (!Reader.IsStringQuote())
1231 {
1232 if (Reader.IsEof())
1233 {
1234 throw new BadSourceReaderException("String not terminated",
1236 );
1237 }
1238
1239 if (Reader.Is('{'))
1240 {
1241 Reader.Eat('{');
1242 Reader.SkipNonToken();
1243
1244 if (!Reader.Is('{'))
1245 {
1247 Reader.SkipNonToken();
1248 Reader.Eat('}');
1249 sb.Append($"{{{args.Count}}}");
1250 args.Add(expr);
1251
1252 continue;
1253 }
1254
1255 Reader.Eat('{');
1256 sb.Append("{{");
1257
1258 continue;
1259 }
1260
1261 if (Reader.Is('}'))
1262 {
1263 int idx = Reader.CurrentIndex;
1264 Reader.Eat('}');
1265
1266 if (!Reader.Is('}'))
1267 {
1268 throw new BadSourceReaderException("Expected '}'",
1270 );
1271 }
1272
1273 Reader.Eat('}');
1274 sb.Append("}}");
1275
1276 continue;
1277 }
1278
1279 sb.Append(Reader.GetCurrentChar());
1280
1281 Reader.MoveNext();
1282 }
1283
1285
1286 if (args.Count == 0)
1287 {
1288 string str = sb.ToString()
1289 .Replace("{{", "{")
1290 .Replace("}}", "}");
1291
1292 return new BadStringExpression('"' + str + '"',
1294 );
1295 }
1296
1297 return new BadFormattedStringExpression(args.ToArray(),
1298 sb.ToString(),
1300 );
1301 }
1302
1316 {
1318 {
1319 throw new
1320 BadSourceReaderException($"Expected string start character but got '{(Reader.IsEof() ? "EOF" : Reader.GetCurrentChar())}'",
1322 );
1323 }
1324
1325 int start = Reader.CurrentIndex;
1327 bool isEscaped = false;
1328 StringBuilder sb = new StringBuilder();
1329 List<BadExpression> args = new List<BadExpression>();
1330
1331 while (!Reader.IsStringQuote())
1332 {
1333 if (Reader.IsNewLine() || Reader.IsEof())
1334 {
1335 throw new BadSourceReaderException("String not terminated",
1337 );
1338 }
1339
1340 if (Reader.Is('{'))
1341 {
1342 Reader.Eat('{');
1343 Reader.SkipNonToken();
1344
1345 if (!Reader.Is('{'))
1346 {
1348 Reader.SkipNonToken();
1349 Reader.Eat('}');
1350 sb.Append($"{{{args.Count}}}");
1351 args.Add(expr);
1352
1353 continue;
1354 }
1355
1356 Reader.Eat('{');
1357 sb.Append("{{");
1358
1359 continue;
1360 }
1361
1362 if (Reader.Is('}'))
1363 {
1364 int idx = Reader.CurrentIndex;
1365 Reader.Eat('}');
1366
1367 if (!Reader.Is('}'))
1368 {
1369 throw new BadParserException("Expected '}'",
1371 );
1372 }
1373
1374 Reader.Eat('}');
1375 sb.Append("}}");
1376
1377 continue;
1378 }
1379
1381 {
1382 isEscaped = true;
1383 Reader.MoveNext();
1384 }
1385
1386 if (isEscaped)
1387 {
1388 isEscaped = false;
1389 sb.Append(Regex.Unescape($"\\{Reader.GetCurrentChar()}"));
1390 }
1391 else
1392 {
1393 sb.Append(Reader.GetCurrentChar());
1394 }
1395
1396 Reader.MoveNext();
1397 }
1398
1400
1401 if (args.Count == 0)
1402 {
1403 string str = sb.ToString()
1404 .Replace("{{", "{")
1405 .Replace("}}", "}");
1406
1407 return new BadStringExpression('"' + str + '"',
1409 );
1410 }
1411
1412 return new BadFormattedStringExpression(args.ToArray(),
1413 sb.ToString(),
1415 );
1416 }
1417
1423 {
1424 int start = Reader.CurrentIndex;
1426 Reader.SkipNonToken();
1427 Reader.Eat('(');
1428 BadExpression condition = ParseExpression();
1429 Reader.Eat(')');
1430
1431 List<BadExpression> block = ParseBlock(out bool _);
1432
1433 return new BadWhileExpression(condition,
1434 block,
1436 );
1437 }
1438
1444 private List<BadExpression> ParseBlock(out bool isSingleLine)
1445 {
1446 Reader.SkipNonToken();
1447
1448 List<BadExpression> block = new List<BadExpression>();
1449
1450 if (Reader.Is('{'))
1451 {
1452 isSingleLine = false;
1453 Reader.Eat('{');
1454 Reader.SkipNonToken();
1455
1457 {
1458 Reader.SkipNonToken();
1460 block.Add(expr);
1461 Reader.SkipNonToken();
1462
1463 if (!RequireSemicolon(expr))
1464 {
1465 continue;
1466 }
1467
1469 Reader.SkipNonToken();
1470 }
1471
1473 }
1474 else
1475 {
1476 isSingleLine = true;
1478
1479 if (RequireSemicolon(expr))
1480 {
1482 }
1483
1484 Reader.SkipNonToken();
1485 block.Add(expr);
1486 }
1487
1488 Reader.SkipNonToken();
1489
1490 return block;
1491 }
1492
1503 private List<BadExpression> ParseFunctionBlock(int start, out bool isSingleLine)
1504 {
1505 Reader.SkipNonToken();
1506
1507 List<BadExpression> block = new List<BadExpression>();
1508
1509 if (Reader.Is("=>"))
1510 {
1511 Reader.Eat("=>");
1512 block.Add(ParseExpression());
1513 isSingleLine = true;
1514 }
1515 else if (Reader.Is('{'))
1516 {
1517 isSingleLine = false;
1518 Reader.Eat('{');
1519 Reader.SkipNonToken();
1520
1522 {
1523 Reader.SkipNonToken();
1525 block.Add(expr);
1526 Reader.SkipNonToken();
1527
1528 if (!RequireSemicolon(expr))
1529 {
1530 continue;
1531 }
1532
1534 Reader.SkipNonToken();
1535 }
1536
1538 }
1539 else
1540 {
1541 throw new BadParserException("Expected Expression Body",
1543 );
1544 }
1545
1546 Reader.SkipNonToken();
1547
1548 return block;
1549 }
1550
1558 {
1559 Reader.SkipNonToken();
1560
1562 {
1563 throw new BadParserException("Expected Constant Variable Definition",
1565 );
1566 }
1567
1568 //Parse single expression
1570
1571 if (expr is not BadAssignExpression assignExpr)
1572 {
1573 throw new BadParserException("Expected Constant Variable Definition",
1575 );
1576 }
1577
1578 if (assignExpr.Left is not BadVariableDefinitionExpression varDef)
1579 {
1580 throw new BadParserException("Expected Constant Variable Definition",
1582 );
1583 }
1584
1585 Reader.SkipNonToken();
1586
1587 //Reader.Eat(BadStaticKeys.STATEMENT_END_KEY); //Not Needed, the parser will automatically eat the statement end key
1588
1590 varDef.Name,
1591 expr
1592 );
1593 }
1594
1601 {
1602 int start = Reader.CurrentIndex;
1604 Reader.SkipNonToken();
1605
1606 if (!Reader.Is('('))
1607 {
1608 return ParseUsingStatement(start);
1609 }
1610
1611 Reader.Eat('(');
1612 Reader.SkipNonToken();
1613
1615 {
1616 throw new BadParserException("Expected Constant Variable Definition",
1618 );
1619 }
1620
1621 //Parse single expression
1623
1624 if (expr is not BadAssignExpression assignExpr)
1625 {
1626 throw new BadParserException("Expected Constant Variable Definition",
1628 );
1629 }
1630
1631 if (assignExpr.Left is not BadVariableDefinitionExpression varDef)
1632 {
1633 throw new BadParserException("Expected Constant Variable Definition",
1635 );
1636 }
1637
1638 Reader.SkipNonToken();
1639
1640 Reader.Eat(')');
1641
1642 Reader.SkipNonToken();
1643 List<BadExpression> block = ParseBlock(out bool isSingleLine);
1644 Reader.SkipNonToken();
1645
1646 if (isSingleLine)
1647 {
1649 }
1650
1651 Reader.SkipNonToken();
1652
1653 return new BadUsingExpression(varDef.Name,
1654 block.ToArray(),
1656 expr
1657 );
1658 }
1659
1665 {
1666 int start = Reader.CurrentIndex;
1668 Reader.SkipNonToken();
1669 List<BadExpression> block = ParseBlock(out bool isSingleLine);
1670 Reader.SkipNonToken();
1671
1672 if (isSingleLine)
1673 {
1675 }
1676
1677 Reader.SkipNonToken();
1679 Reader.SkipNonToken();
1680 Reader.Eat('(');
1681 Reader.SkipNonToken();
1682 BadWordToken errorName = Reader.ParseWord();
1683 Reader.SkipNonToken();
1684 Reader.Eat(')');
1685 Reader.SkipNonToken();
1686 List<BadExpression> errorBlock = ParseBlock(out isSingleLine);
1687 Reader.SkipNonToken();
1688
1689 if (isSingleLine)
1690 {
1692 }
1693
1694 Reader.SkipNonToken();
1695
1696 BadExpression[] finallyBlock = Array.Empty<BadExpression>();
1697
1699 {
1701 Reader.SkipNonToken();
1702 List<BadExpression> finallyExprs = ParseBlock(out isSingleLine);
1703 Reader.SkipNonToken();
1704
1705 if (isSingleLine)
1706 {
1708 }
1709
1710 Reader.SkipNonToken();
1711 finallyBlock = finallyExprs.ToArray();
1712 }
1713
1715 block.ToArray(),
1716 errorBlock.ToArray(),
1717 finallyBlock,
1718 errorName.Text
1719 );
1720 }
1721
1722
1729 {
1730 int start = Reader.CurrentIndex;
1732 Reader.SkipNonToken();
1734
1735 if (right is not BadInvocationExpression invoc)
1736 {
1737 throw new BadParserException("Expected Invocation Expression", right.Position);
1738 }
1739
1740 return new BadNewExpression(invoc, Reader.MakeSourcePosition(start, Reader.CurrentIndex - start));
1741 }
1742
1749 {
1750 int start = Reader.CurrentIndex;
1751 string? name = null;
1752 BadExpression? type = null;
1753
1754 if (!Reader.Is('('))
1755 {
1756 BadExpression nameExpr = ParseValue(0);
1757 Reader.SkipNonToken();
1758
1759 while (Reader.Is("."))
1760 {
1761 Reader.Eat(".");
1762 BadWordToken right = Reader.ParseWord();
1763 List<BadExpression>? genArgs = ParseGenericArguments();
1764
1765 nameExpr = new BadMemberAccessExpression(nameExpr,
1766 right,
1767 nameExpr.Position.Combine(right.SourcePosition),
1768 genArgs
1769 );
1770 Reader.SkipNonToken();
1771 }
1772
1773 Reader.SkipNonToken();
1774
1775 if (!Reader.Is('('))
1776 {
1777 type = nameExpr;
1778
1779 name = Reader.ParseWord()
1780 .Text;
1781 }
1782 else
1783 {
1784 if (nameExpr is not BadVariableExpression expr)
1785 {
1786 throw new BadParserException("Expected Variable Expression",
1787 nameExpr.Position
1788 );
1789 }
1790
1791 name = expr.Name;
1792 }
1793 }
1794
1795 if (name == null)
1796 {
1797 throw new BadParserException("Expected Name",
1799 );
1800 }
1801
1802 Reader.SkipNonToken();
1803
1804 if (Reader.Is('('))
1805 {
1806 List<BadFunctionParameter> parameters = ParseParameters(start);
1807
1808 Reader.SkipNonToken();
1809
1811
1812 return new BadInterfaceFunctionConstraint(name, type, parameters.ToArray());
1813 }
1814
1816
1817 return new BadInterfacePropertyConstraint(name, type);
1818 }
1819
1820 private List<BadWordToken> ParseGenericParameters()
1821 {
1822 List<BadWordToken> genericParameters = new List<BadWordToken>();
1823 Reader.SkipNonToken();
1824
1825 if (Reader.Is('<'))
1826 {
1827 Reader.Eat('<');
1828 Reader.SkipNonToken();
1829
1830 while (!Reader.IsEof())
1831 {
1832 genericParameters.Add(Reader.ParseWord());
1833 Reader.SkipNonToken();
1834
1835 if (Reader.Is('>'))
1836 {
1837 break;
1838 }
1839
1840 Reader.Eat(',');
1841 Reader.SkipNonToken();
1842 }
1843
1844 Reader.Eat('>');
1845 Reader.SkipNonToken();
1846 }
1847
1848 return genericParameters;
1849 }
1850
1856 {
1857 BadMetaData? meta = m_MetaData;
1858 m_MetaData = null;
1859 int start = Reader.CurrentIndex;
1861 Reader.SkipNonToken();
1862 BadWordToken name = Reader.ParseWord();
1863 List<BadWordToken> genericParameters = ParseGenericParameters();
1864 Reader.SkipNonToken();
1865 List<BadExpression> interfaces = new List<BadExpression>();
1866
1867 if (Reader.Is(':'))
1868 {
1869 Reader.Eat(':');
1870
1871 while (!Reader.IsEof())
1872 {
1873 Reader.SkipNonToken();
1874 interfaces.Add(ParseExpression());
1875 Reader.SkipNonToken();
1876
1877 if (!Reader.Is(','))
1878 {
1879 break;
1880 }
1881
1882 Reader.Eat(',');
1883 Reader.SkipNonToken();
1884 }
1885 }
1886
1887 Reader.Eat('{');
1888 Reader.SkipNonToken();
1889 List<BadInterfaceConstraint> constraints = new List<BadInterfaceConstraint>();
1890
1891 while (!Reader.Is('}'))
1892 {
1893 Reader.SkipNonToken();
1895
1896 constraints.Add(expr);
1897
1898 Reader.SkipNonToken();
1899 }
1900
1901 Reader.Eat('}');
1902 Reader.SkipNonToken();
1903
1904 return new BadInterfacePrototypeExpression(name.Text,
1905 constraints.ToArray(),
1906 interfaces.ToArray(),
1907 meta,
1909 genericParameters.ToArray()
1910 );
1911 }
1912
1918 {
1919 BadMetaData? meta = m_MetaData;
1920 m_MetaData = null;
1921 int start = Reader.CurrentIndex;
1923 Reader.SkipNonToken();
1924 BadWordToken name = Reader.ParseWord();
1925 Reader.SkipNonToken();
1926 List<BadWordToken> genericParameters = ParseGenericParameters();
1927
1928 List<BadFunctionParameter>? primaryConstructor = null;
1929 List<BadExpression>? baseInvocationParameters = null;
1930 BadSourcePosition? primaryConstructorPosition = null;
1931 BadSourcePosition? baseInvocationParametersPosition = null;
1932 List<BadExpression> members = new List<BadExpression>();
1933 List<BadExpression> staticMembers = new List<BadExpression>();
1934
1935 if (Reader.Is('('))
1936 {
1937 int ctorStart = Reader.CurrentIndex;
1938 primaryConstructor = ParseParameters(start);
1939 primaryConstructorPosition = Reader.MakeSourcePosition(ctorStart, Reader.CurrentIndex - ctorStart);
1940 Reader.SkipNonToken();
1941 }
1942
1943 List<BadExpression> baseClasses = new List<BadExpression>();
1944
1945 if (Reader.Is(':'))
1946 {
1947 Reader.Eat(':');
1948
1949 while (!Reader.IsEof())
1950 {
1951 Reader.SkipNonToken();
1952 BadExpression baseExpr = ParseExpression();
1953
1954 if (baseClasses.Count == 0)
1955 {
1956 if (baseExpr is BadInvocationExpression baseInvoc)
1957 {
1958 baseInvocationParameters = baseInvoc.Arguments.ToList();
1959 baseInvocationParametersPosition = baseInvoc.Position;
1960 baseExpr = baseInvoc.Left;
1961 }
1962 }
1963 else if (baseExpr is BadInvocationExpression)
1964 {
1965 throw new BadParserException("Base Class Invocation must be the first base class",
1966 baseExpr.Position
1967 );
1968 }
1969
1970 baseClasses.Add(baseExpr);
1971 Reader.SkipNonToken();
1972
1973 if (!Reader.Is(','))
1974 {
1975 break;
1976 }
1977
1978 Reader.Eat(',');
1979 Reader.SkipNonToken();
1980 }
1981 }
1982
1984 {
1985 Reader.Eat('{');
1986 Reader.SkipNonToken();
1987
1988 List<BadExpression> attributeExpressions = new List<BadExpression>();
1989
1990 while (!Reader.Is('}'))
1991 {
1992 Reader.SkipNonToken();
1993
1994 bool isAttribute = false;
1995
1996 if (Reader.Is('@') && !Reader.Is('|', 1))
1997 {
1998 Reader.Eat('@');
1999 isAttribute = true;
2000 }
2001
2003
2004 if (isAttribute)
2005 {
2006 attributeExpressions.Add(expr);
2007 Reader.SkipNonToken();
2008
2009 continue;
2010 }
2011
2012 if (expr is BadFunctionExpression { IsStatic: true })
2013 {
2014 staticMembers.Add(expr);
2015 }
2016 else if (expr is BadFunctionExpression fExpr && fExpr.Name?.Text == name.Text)
2017 {
2018 if (primaryConstructor != null)
2019 {
2020 throw new BadParserException("Primary Constructor already defined",
2021 expr.Position
2022 );
2023 }
2024
2025 fExpr.SetName(BadStaticKeys.CONSTRUCTOR_NAME);
2026 members.Add(expr);
2027 }
2028 else
2029 {
2030 members.Add(expr);
2031 }
2032
2033 if (attributeExpressions.Count > 0)
2034 {
2035 expr.SetAttributes(attributeExpressions.ToArray());
2036 attributeExpressions.Clear();
2037 }
2038
2039 if (expr is IBadNamedExpression nExpr && nExpr.GetName() == name.Text)
2040 {
2041 throw new BadParserException("Class Member cannot have the same name as the class",
2042 expr.Position
2043 );
2044 }
2045
2046 Reader.SkipNonToken();
2047
2048 if (RequireSemicolon(expr))
2049 {
2051 }
2052
2053 Reader.SkipNonToken();
2054 }
2055
2056 if (attributeExpressions.Count != 0)
2057 {
2058 throw new BadParserException("Attributes without target",
2060 );
2061 }
2062
2063 Reader.Eat('}');
2064 }
2065 else
2066 {
2068 }
2069
2070 Reader.SkipNonToken();
2071
2072 if (primaryConstructor != null)
2073 {
2074 List<BadExpression> block = new List<BadExpression>();
2075
2076 //2. Add the primary constructor as a function to the class
2078 primaryConstructor,
2079 block,
2080 primaryConstructorPosition!,
2081 false,
2082 null,
2083 false,
2084 false
2085 );
2086 members.Add(ctor);
2087
2088 if (baseInvocationParameters != null)
2089 {
2090 // 2.1. (call base class constructor if baseInvocationParameters is not null)
2091 BadInvocationExpression baseInvocation =
2092 new BadInvocationExpression(new BadVariableExpression("base", primaryConstructorPosition!),
2093 baseInvocationParameters,
2094 baseInvocationParametersPosition!
2095 );
2096 block.Add(baseInvocation);
2097 }
2098 else
2099 {
2100 BadVariableExpression thisExpr =
2101 new BadVariableExpression(BadStaticKeys.THIS_KEY, primaryConstructorPosition!);
2102
2103 foreach (BadFunctionParameter parameter in primaryConstructor)
2104 {
2105 // 2.2. (if baseInvocationParameters is null, assign the parameters to the class members)
2106 // this.{parameter.Name} = {parameter.Name};
2107 block.Add(new BadAssignExpression(new BadMemberAccessExpression(thisExpr,
2108 parameter.Name,
2109 primaryConstructorPosition!,
2110 new List<BadExpression>()
2111 ),
2112 new BadVariableExpression(parameter.Name,
2113 primaryConstructorPosition!
2114 ),
2115 primaryConstructorPosition!
2116 )
2117 );
2118
2119 //3. (if baseInvocationParameters is null, define the properties for the parameters)
2120 //let {type} {parameter.Name};
2121 members.Add(new BadVariableDefinitionExpression(parameter.Name,
2122 primaryConstructorPosition!,
2123 parameter.TypeExpr,
2124 true
2125 )
2126 );
2127 }
2128 }
2129 }
2130
2131 return new BadClassPrototypeExpression(name.Text,
2132 members.ToArray(),
2133 staticMembers.ToArray(),
2134 baseClasses.ToArray(),
2136 meta,
2137 genericParameters.ToArray()
2138 );
2139 }
2140
2147 {
2148 BadExpression nameExpr = ParseValue(0);
2149 Reader.SkipNonToken();
2150
2151 while (Reader.Is("."))
2152 {
2153 Reader.Eat(".");
2154 BadWordToken right = Reader.ParseWord();
2155 List<BadExpression>? genArgs = ParseGenericArguments();
2156
2157 nameExpr = new BadMemberAccessExpression(nameExpr,
2158 right,
2159 nameExpr.Position.Combine(right.SourcePosition),
2160 genArgs
2161 );
2162 Reader.SkipNonToken();
2163 }
2164
2165 Reader.SkipNonToken();
2166 string name;
2167 BadExpression? typeExpr = null;
2168 Reader.SkipNonToken();
2169
2170 if (Reader.IsWordStart())
2171 {
2172 name = Reader.ParseWord()
2173 .Text;
2174 typeExpr = nameExpr;
2175 }
2176 else
2177 {
2178 if (nameExpr is not BadVariableExpression expr)
2179 {
2180 throw new BadParserException("Expected Variable Expression",
2181 nameExpr.Position
2182 );
2183 }
2184
2185 name = expr.Name;
2186 }
2187
2188 bool isOptional = false;
2189 bool isNullChecked = false;
2190 bool isRestArgs = false;
2191
2192 if (Reader.Is('*'))
2193 {
2194 isRestArgs = true;
2195 Reader.Eat('*');
2196 Reader.SkipNonToken();
2197 }
2198 else
2199 {
2200 if (Reader.Is('?'))
2201 {
2202 isOptional = true;
2203 Reader.Eat('?');
2204 Reader.SkipNonToken();
2205
2206 if (Reader.Is('!'))
2207 {
2208 isNullChecked = true;
2209 Reader.Eat('!');
2210 Reader.SkipNonToken();
2211 }
2212 }
2213 else if (Reader.Is('!'))
2214 {
2215 isNullChecked = true;
2216 Reader.Eat('!');
2217 Reader.SkipNonToken();
2218
2219 if (Reader.Is('?'))
2220 {
2221 isOptional = true;
2222 Reader.Eat('?');
2223 Reader.SkipNonToken();
2224 }
2225 }
2226 }
2227
2228 Reader.SkipNonToken();
2229
2230 return new BadFunctionParameter(name, isOptional, isNullChecked, isRestArgs, typeExpr);
2231 }
2232
2239 private List<BadFunctionParameter> ParseParameters(int start)
2240 {
2241 List<BadFunctionParameter> parameters = new List<BadFunctionParameter>();
2242
2243 Reader.Eat('(');
2244 Reader.SkipNonToken();
2245
2246 if (!Reader.Is(')'))
2247 {
2248 bool first = true;
2249 bool hadOptional = false;
2250 bool hadRest = false;
2251
2252 while (Reader.Is(',') || first)
2253 {
2254 if (hadRest)
2255 {
2256 throw new BadParserException("Rest parameter must be last parameter",
2258 );
2259 }
2260
2261 if (!first)
2262 {
2263 Reader.Eat(',');
2264 Reader.SkipNonToken();
2265 }
2266
2267 first = false;
2268
2270
2271 if (hadOptional && param is { IsOptional: false, IsRestArgs: false })
2272 {
2273 throw new BadParserException("Non-Optional parameters must be in front of optional parameters",
2275 );
2276 }
2277
2278 Reader.SkipNonToken();
2279
2280 if (parameters.Any(p => p.Name == param.Name))
2281 {
2282 throw new BadParserException("Duplicate parameter name",
2284 );
2285 }
2286
2287 hadOptional |= param.IsOptional;
2288 hadRest |= param.IsRestArgs;
2289
2290 parameters.Add(param);
2291 }
2292 }
2293
2294 Reader.SkipNonToken();
2295 Reader.Eat(')');
2296
2297 return parameters;
2298 }
2299
2312 string? functionName,
2313 BadExpression? functionReturn,
2314 bool isConstant,
2315 bool isStatic,
2316 BadFunctionCompileLevel compileLevel,
2317 List<BadFunctionParameter> parameters)
2318 {
2319 BadMetaData? meta = m_MetaData;
2320 m_MetaData = null;
2321 List<BadExpression> block = ParseFunctionBlock(start, out bool isSingleLine);
2322
2323 if (isSingleLine)
2324 {
2325 block[0] = new BadReturnExpression(block[0], block[0].Position, false);
2326 }
2327
2328 if (functionName == null)
2329 {
2330 return new BadFunctionExpression(null,
2331 parameters,
2332 block,
2334 isConstant,
2335 meta,
2336 isSingleLine,
2337 isStatic,
2338 compileLevel,
2339 functionReturn
2340 );
2341 }
2342
2343 return new BadFunctionExpression(functionName,
2344 parameters,
2345 block,
2347 isConstant,
2348 meta,
2349 isSingleLine,
2350 isStatic,
2351 compileLevel,
2352 functionReturn
2353 );
2354 }
2355
2367 private BadFunctionExpression ParseFunction(bool isConstant, bool isStatic, BadFunctionCompileLevel compileLevel)
2368 {
2369 int start = Reader.CurrentIndex;
2371 Reader.SkipNonToken();
2372
2373 string? functionName = null;
2374 BadExpression? functionReturn = null;
2375
2376 if (!Reader.Is('('))
2377 {
2378 BadExpression functionNameExpr = ParseValue(0);
2379 Reader.SkipNonToken();
2380
2381 while (Reader.Is("."))
2382 {
2383 Reader.Eat(".");
2384 BadWordToken right = Reader.ParseWord();
2385 List<BadExpression>? genArgs = ParseGenericArguments();
2386
2387 functionNameExpr = new BadMemberAccessExpression(functionNameExpr,
2388 right,
2389 functionNameExpr.Position
2390 .Combine(right.SourcePosition),
2391 genArgs
2392 );
2393 Reader.SkipNonToken();
2394 }
2395
2396 Reader.SkipNonToken();
2397
2398 if (!Reader.Is('('))
2399 {
2400 functionReturn = functionNameExpr;
2401
2402 functionName = Reader.ParseWord()
2403 .Text;
2404 }
2405 else
2406 {
2407 if (functionNameExpr is not BadVariableExpression expr)
2408 {
2409 throw new BadParserException("Expected Variable Expression",
2410 functionNameExpr.Position
2411 );
2412 }
2413
2414 functionName = expr.Name;
2415 }
2416 }
2417
2418 List<BadFunctionParameter> parameters = ParseParameters(start);
2419
2420 return ParseFunction(start, functionName, functionReturn, isConstant, isStatic, compileLevel, parameters);
2421 }
2422
2428 private static bool RequireSemicolon(BadExpression expr)
2429 {
2430 if (expr is BadNamedExportExpression named)
2431 {
2432 return RequireSemicolon(named.Expression);
2433 }
2434
2435 if (expr is BadDefaultExportExpression def)
2436 {
2437 return RequireSemicolon(def.Expression);
2438 }
2439
2440 return expr is not (
2451 BadPropertyDefinitionExpression or BadFunctionExpression { IsSingleLine: false });
2452 }
2453
2458 public IEnumerable<BadExpression> Parse()
2459 {
2460 Reader.SkipNonToken();
2461
2462 while (!Reader.IsEof())
2463 {
2464 Reader.SkipNonToken();
2466 Reader.SkipNonToken();
2467
2468 if (!RequireSemicolon(expr))
2469 {
2470 Reader.SkipNonToken();
2471
2472 yield return expr;
2473
2474 continue;
2475 }
2476
2478 Reader.SkipNonToken();
2479
2480 yield return expr;
2481 }
2482 }
2483}
Describes a specific position inside a source file.
int Index
The Start Index of the Position.
BadSourcePosition Combine(BadSourcePosition other)
Combines two Source Positions.
Contains Static Data for the BadScript Language.
Implements a Meta Data container for an expression.
Implements a Meta Data container for a parameter.
Gets Raised when a Parser Error occurs.
The Parser of the Language. It turns Source Code into an Expression Tree.
BadStringExpression ParseFormatString()
Parses a Format Expression. Moves the reader to the next token.
BadSourceParser(BadSourceReader sourceReader, BadOperatorTable operators)
Constructor of the Parser.
BadNewExpression ParseNew()
Parses a New Expression. Moves the reader to the next token.
static BadSourceParser Create(string fileName, string source, int start, int end)
Creates a BadSourceParser Instance based on the source and filename provided.
BadExpression ParseLock()
Parses a Lock Expression. Moves the Reader to the Next Token.
IEnumerable< BadExpression > Parse()
Parses the File from start to end.
BadFunctionExpression ParseFunction(int start, string? functionName, BadExpression? functionReturn, bool isConstant, bool isStatic, BadFunctionCompileLevel compileLevel, List< BadFunctionParameter > parameters)
Parses a Function Definition. Moves the reader to the next token.
static bool RequireSemicolon(BadExpression expr)
Returns true if the given expression requires a semicolon.
static BadSourceParser Create(string fileName, string source)
Creates a BadSourceParser Instance based on the source and filename provided.
BadSourceReader Reader
The Source Reader.
List< BadExpression > ParseBlock(out bool isSingleLine)
Parses a Block Expression. Moves the reader to the next token.
BadClassPrototypeExpression ParseClass()
Parses a Class Structure. Moves the reader to the next token.
List< BadExpression > ParseGenericArguments()
BadExpression ParseUsingStatement(int start)
Parses a Using Statement Expression. Moves the reader to the next token.
BadExpression ParseValue(int precedence)
Parses a Value Expression or a Prefix Function with precedence greater than the provided precedence....
List< BadExpression > ParseFunctionBlock(int start, out bool isSingleLine)
Parses a Block. Moves the reader to the next token.
BadFunctionExpression ParseFunction(bool isConstant, bool isStatic, BadFunctionCompileLevel compileLevel)
Parses a function definition. Moves the reader to the next token.
BadExpression ParseExpression(BadExpression? left=null, int precedence=int.MaxValue)
Parses an Expression with a precedence greater than the given precedence. Moves the reader to the nex...
BadExpression? ParsePrefix(int precedence)
Parses a Prefix Expression that has precedence greater than the provided precedence....
BadInterfaceConstraint ParseInterfaceConstraint()
Parses an Interface Constraint. Moves the reader to the next token.
BadExpression ParseFor()
Parses a For Loop Expression. Moves the Reader to the Next Token.
BadInterfacePrototypeExpression ParseInterface()
Parses an Interface prototype. Moves the reader to the next token.
BadExpression ParseTry()
Parses a Try Catch Block. Moves the reader to the next token.
readonly BadOperatorTable m_Operators
The Operator Table that is used to parse the Source Code.
BadFunctionParameter ParseParameter()
Parses a Function Parameter. Moves the reader to the next token.
BadExpression ParseUsing()
Parses a Using Block or Statement. Moves the reader to the next token.
List< BadWordToken > ParseGenericParameters()
BadMetaData? m_MetaData
The Meta Data of the current expression.
BadStringExpression ParseMultiLineFormatString()
Parses a Multiline Format string expression. Moves the reader to the next token.
List< BadFunctionParameter > ParseParameters(int start)
Parses a Function Parameter List. Moves the reader to the next token.
BadWhileExpression ParseWhile()
Parses a While Loop. Moves the reader to the next token.
void ParseMeta()
Parses the MetaData of the current expression.
BadExpression ParseForEach()
Parses a For Each Expression. Moves the Reader to the Next Token.
static IEnumerable< BadExpression > Parse(string fileName, string source)
Parses a BadExpression from the Source Reader.
BadExpression ParseIf()
Parses an If Expression. Moves the Reader to the Next Token.
Implements the Array Access to set or get properties from an object. LEFT[RIGHT].
Implements the Reverse Array Access to set or get properties from an object. LEFT[^RIGHT].
Implements the Member Access to set or get properties from an object. LEFT.RIGHT.
Base Implementation for all Expressions used inside the Script.
BadSourcePosition Position
The source Position of the Expression.
void SetAttributes(IEnumerable< BadExpression > attributes)
Implements the Assign Expression LEFT = RIGHT.
Implements the If Statement Expression.
Implements the Switch Statement Expression.
Implements the Try Catch Statement Expression.
Implements the Break Expression that is used to prematurely exit a loop.
Implements the Break Expression that is used to skip a loop iteraion.
Implements the Return expression that is used to exit the current function with an Optional Return Va...
Implements the Throw Expression that is used to raise errors inside the Script.
Implements a Function Constraint for an Interface The Constraints specifies how a specific function s...
Base class for all binary operators.
BadExpression Parse(BadExpression left, BadSourceParser parser)
Parses the operator.
Implements the Operator Table used by the Parser.
IEnumerable< string > BinarySymbols
Enumeration of all Binary Operator Symbols.
BadValueParser? GetValueParser(BadSourceParser parser)
Returns a Value Parser that is able to parse the given Token.
IEnumerable< string > UnaryPrefixSymbols
Enumeration of all Unary Prefix Operator Symbols.
BadBinaryOperator? FindBinaryOperator(string symbol, int precedence)
Finds a Binary Operator by its Symbol.
BadUnaryPrefixOperator? FindUnaryPrefixOperator(string symbol, int precedence)
Finds a Unary Prefix Operator by its Symbol.
static BadOperatorTable Instance
The Operator Table Instance.
Base class for all Unary Prefix Operators.
BadExpression Parse(BadSourceParser parser)
Parses the Operator and returns the resulting Expression.
Base class for all Value Parsers.
BadExpression ParseValue(BadSourceParser parser)
Parses the Current Token.
Gets Raised if the Reader encounters an Error.
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.
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.
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.
string Text
The Text Representation of the Token.
Definition BadToken.cs:27
BadSourcePosition SourcePosition
The Source Position of the Token.
Definition BadToken.cs:22
Implements a Token that represents a Boolean.
Implements a Token that represents a Number.
Implements a Token that represents a String.
bool IsOptional
Indicates if this parameter is optional.
BadExpression? TypeExpr
The Expression that returns the type of the parameter if evaluated.
bool IsRestArgs
Indicates if this parameter is the rest parameter of the function.
Gets inherited by all Expressions that have a Name(e.g. Variable Definitions, Function Definitions,...
string? GetName()
Returns the Name of the Expression.
Contains Shared Data Structures and Functionality.
Contains the Access Expressions for the BadScript2 Language.
Contains the Binary Expressions for the BadScript2 Language.
Contains the Locking Expressions for the BadScript2 Language.
Contains the Loop Expressions for the BadScript2 Language.
Contains the Block Expressions for the BadScript2 Language.
Contains the Constant Expressions for the BadScript2 Language.
Contains the Controlflow Expressions for the BadScript2 Language.
Contains the Function Expressions for the BadScript2 Language.
BadFunctionCompileLevel
The BadFunctionCompileLevel enum defines the different levels of compilation for a function.
Contains the Type Expressions for the BadScript2 Language.
Contains the Variable Expressions for the BadScript2 Language.
Contains the Expressions for the BadScript2 Language.
Contains the Operators for the BadScript2 Language.
Contains the Parser for the BadScript2 Language.
Contains the Primitive Tokens for the BadScript2 Language.
Contains the Reader Tokens for the BadScript2 Language.
Contains the Source Reader for the BadScript2 Language.
Contains the Error Objects for the BadScript2 Language.
Contains Runtime Function Objects.
Contains Runtime Interface Objects.