1using System;
2using System.Collections.Generic;
3using System.Dynamic;
4using System.Linq;
5using System.Reflection;
6using System.Text;
7using System.Threading.Tasks;
8
9namespace Astrid;
10
11public enum Types
12{
13 String,
14 Int,
15 Float,
16 Bool,
17 ArrayString,
18 ArrayInt,
19 ArrayFloat,
20 ArrayBool
21}
22
23public class AST { }
24
25public class ASTVariableDefine : AST
26{
27 public string label;
28 public Types type;
29 public ASTExpression value;
30
31 public ASTVariableDefine(string label, Types type, ASTExpression value)
32 {
33 this.label = label;
34 this.type = type;
35 this.value = value;
36 }
37}
38
39public class ASTVariableReassign : AST
40{
41 public string label;
42 public ASTExpression value;
43 public AssignOp asop;
44
45 public ASTVariableReassign(string label, ASTExpression value, AssignOp asop)
46 {
47 this.label = label;
48 this.value = value;
49 this.asop = asop;
50 }
51}
52
53public class ASTFunctionDefine : AST
54{
55 public string label;
56 public List<(string, Types)> parameters;
57 public Types? returnType;
58 public List<AST> block;
59
60 public ASTFunctionDefine(string label, List<(string, Types)> parameters, Types? returnType, List<AST> block)
61 {
62 this.label = label;
63 this.parameters = parameters;
64 this.returnType = returnType;
65 this.block = block;
66 }
67}
68
69public class ASTFunctionCall : AST
70{
71 public string label;
72 public Dictionary<string, ASTExpression> value;
73
74 public ASTFunctionCall(string label, Dictionary<string, ASTExpression> value)
75 {
76 this.label = label;
77 this.value = value;
78 }
79}
80
81public class ASTExpression : AST
82{
83 public List<object> expression;
84
85 public ASTExpression(List<object> expression)
86 {
87 this.expression = expression;
88 }
89}
90
91public class ASTConditional : AST
92{
93 public ASTExpression condition;
94 public List<AST> block;
95
96 public ASTConditional(ASTExpression condition, List<AST> block)
97 {
98 this.condition = condition;
99 this.block = block;
100
101 }
102}
103
104public class ASTReturn : AST
105{
106 public ASTExpression expression;
107
108 public ASTReturn(ASTExpression expression)
109 {
110 this.expression = expression;
111 }
112}
113
114public class ASTWhile : AST
115{
116 public ASTExpression condition;
117 public List<AST> block;
118
119 public ASTWhile(ASTExpression condition, List<AST> block)
120 {
121 this.condition = condition;
122 this.block = block;
123
124 }
125}
126
127public class ASTMatch : AST
128{
129 public ASTExpression expr;
130 public Dictionary<ASTExpression, List<AST>> matches;
131
132 public ASTMatch(ASTExpression expr, Dictionary<ASTExpression, List<AST>> matches)
133 {
134 this.expr = expr;
135 this.matches = matches;
136 }
137}
138
139public enum AssignOp
140{
141 Assign,
142 Plus,
143 Minus,
144 Divide,
145 Multiply,
146 Power,
147 Modulo
148}
149
150public static class Parser
151{
152 public static (Token[], List<AST>) ParseBlock(Token[] tokens_)
153 {
154 List<Token> tokens = tokens_.ToList();
155 List<AST> ast = new();
156
157 while(tokens.Count > 0)
158 {
159 var token = tokens[0];
160
161 // Tokenizer.Print(token);
162
163 if(token.GetType() == typeof(TokenEOL))
164 {
165 tokens = tokens.Skip(1).ToList();
166 } else if(token.GetType() == typeof(TokenBlockEnd))
167 {
168 tokens = tokens.Skip(1).ToList();
169 return (tokens.ToArray(), ast);
170 } else if(token.GetType() == typeof(TokenIdentifier))
171 {
172 var identifierLabel = token.value;
173 tokens = tokens.Skip(1).ToList();
174 token = tokens[0];
175
176 if(token.GetType() == typeof(TokenDoubleColon))
177 {
178 tokens = tokens.Skip(1).ToList();
179 var (newtokens, newast) = ParseFunctionDefine(tokens.ToArray(), identifierLabel);
180 tokens = newtokens.ToList();
181 ast.Add(newast);
182 } else if(token.GetType() == typeof(TokenParenStart))
183 {
184 tokens = tokens.Skip(1).ToList();
185 var (newtokens, newast) = ParseFunctionCall(tokens.ToArray(), identifierLabel);
186 tokens = newtokens.ToList();
187 ast.Add(newast);
188 } else if(token.GetType() == typeof(TokenColon))
189 {
190 tokens = tokens.Skip(1).ToList();
191 var (newtokens, newast) = ParseVariableDefine(tokens.ToArray(), identifierLabel);
192 tokens = newtokens.ToList();
193 ast.Add(newast);
194 } else if(new [] {typeof(TokenAssign), typeof(TokenAssignDivide), typeof(TokenAssignMinus), typeof(TokenAssignMultiply), typeof(TokenAssignPlus), typeof(TokenAssignPower), typeof(TokenAssignModulo)}.Contains(token.GetType()))
195 {
196 tokens = tokens.Skip(1).ToList();
197 var (newtokens, newast) = ParseVariableReassign(tokens.ToArray(), identifierLabel, token);
198 tokens = newtokens.ToList();
199 ast.Add(newast);
200 } else
201 {
202 Error.Throw("Unexpected token after identifier", token);
203 }
204 } else if(token.GetType() == typeof(TokenKeyword))
205 {
206 if(token.value == "return")
207 {
208 tokens = tokens.Skip(1).ToList();
209 var (newtokens, newast) = ParseReturn(tokens.ToArray());
210 tokens = newtokens.ToList();
211 ast.Add(newast);
212 } else if(token.value == "if")
213 {
214 tokens = tokens.Skip(1).ToList();
215 var (newtokens, newast) = ParseConditional(tokens.ToArray());
216 tokens = newtokens.ToList();
217 ast.Add(newast);
218 } else if(token.value == "while")
219 {
220 tokens = tokens.Skip(1).ToList();
221 var (newtokens, newast) = ParseWhile(tokens.ToArray());
222 tokens = newtokens.ToList();
223 ast.Add(newast);
224 } else if(token.value == "match")
225 {
226 tokens = tokens.Skip(1).ToList();
227 var (newtokens, newast) = ParseMatch(tokens.ToArray());
228 tokens = newtokens.ToList();
229 ast.Add(newast);
230 } else
231 {
232 Error.Throw("Unimplemented keyword", token);
233 }
234 } else
235 {
236 Error.Throw("Unexpected token", token);
237 }
238 }
239
240 return (tokens.ToArray(), ast);
241 }
242
243 public static Types GetTypeFromToken(Token t, bool array=false)
244 {
245 if(!array)
246 {
247 switch(t.value)
248 {
249 case "int": return Types.Int;
250 case "float": return Types.Float;
251 case "string": return Types.String;
252 case "bool": return Types.Bool;
253 default: Error.Throw($"Invalid type", t); return Types.Int;
254 }
255 } else
256 {
257 switch(t.value)
258 {
259 case "int": return Types.ArrayInt;
260 case "float": return Types.ArrayFloat;
261 case "string": return Types.ArrayString;
262 case "bool": return Types.ArrayBool;
263 default: Error.Throw($"Invalid type", t); return Types.Int;
264 }
265 }
266 }
267
268 public static Types GetTypeFromValue(Token t)
269 {
270 if(t.GetType() == typeof(TokenInt))
271 {
272 return Types.Int;
273 } else if(t.GetType() == typeof(TokenFloat))
274 {
275 return Types.Float;
276 } else if(t.GetType() == typeof(TokenString))
277 {
278 return Types.String;
279 }
280 Error.Throw($"Invalid type", t);
281 return Types.Int;
282 }
283
284 public static (Token[], AST) ParseConditional(Token[] tokens_)
285 {
286 List<Token> tokens = tokens_.ToList();
287 AST ast = new();
288
289 var (newtokens, expr) = ParseExpression(tokens.ToArray());
290 tokens = newtokens.ToList();
291
292 (newtokens, var astblock) = ParseBlock(tokens.ToArray());
293 tokens = newtokens.ToList();
294
295 return (tokens.ToArray(), new ASTConditional(expr, astblock));
296 }
297
298 public static (Token[], AST) ParseWhile(Token[] tokens_)
299 {
300 List<Token> tokens = tokens_.ToList();
301 AST ast = new();
302
303 var (newtokens, expr) = ParseExpression(tokens.ToArray());
304 tokens = newtokens.ToList();
305
306 (newtokens, var astblock) = ParseBlock(tokens.ToArray());
307 tokens = newtokens.ToList();
308
309 return (tokens.ToArray(), new ASTWhile(expr, astblock));
310 }
311
312 public static (Token[], AST) ParseMatch(Token[] tokens_)
313 {
314 List<Token> tokens = tokens_.ToList();
315 AST ast = new();
316
317 var (newtokens, expr) = ParseExpression(tokens.ToArray());
318 tokens = newtokens.ToList();
319
320 var token = tokens[0];
321
322 Dictionary<ASTExpression, List<AST>> matches = new();
323
324 bool matchesDone = false;
325
326 while(tokens.Count > 0 && !matchesDone)
327 {
328 token = tokens[0];
329 // Tokenizer.Print(token);
330
331 (newtokens, var matchexpr) = ParseExpression(tokens.ToArray());
332 tokens = newtokens.ToList();
333 token = tokens[0];
334
335 if(token.GetType() == typeof(TokenBlockStart))
336 {
337 tokens = tokens.Skip(1).ToList();
338 token = tokens[0];
339 } else
340 {
341 Error.Throw("Expected block start after match expression", token);
342 }
343
344 (newtokens, var block) = ParseBlock(tokens.ToArray());
345 tokens = newtokens.ToList();
346
347 token = tokens[0];
348
349 // tokens = tokens.Skip(1).ToList();
350
351 matches.Add(matchexpr, block);
352
353 if(token.GetType() == typeof(TokenBlockEnd))
354 {
355 return (tokens.ToArray(), new ASTMatch(expr, matches));
356 }
357 }
358
359 return (tokens.ToArray(), new ASTMatch(expr, matches));
360 }
361
362 public static (Token[], AST) ParseFunctionDefine(Token[] tokens_, string label)
363 {
364 List<Token> tokens = tokens_.ToList();
365 AST ast = new();
366
367 var token = tokens[0];
368
369 if(token.GetType() == typeof(TokenParenStart))
370 {
371 tokens = tokens.Skip(1).ToList();
372 token = tokens[0];
373 } else
374 {
375 Error.Throw("Expected left parenthesis '(' after double colon '::'", token);
376 }
377
378 List<(string, Types)> parameters = new();
379
380 bool parametersDone = false;
381 while(tokens.Count > 0 || !parametersDone)
382 {
383 token = tokens[0];
384
385 if(token.GetType() == typeof(TokenParenEnd))
386 {
387 tokens = tokens.Skip(1).ToList();
388 token = tokens[0];
389 parametersDone = true;
390 break;
391 }
392
393 var parameterLabel = "";
394 if(token.GetType() == typeof(TokenIdentifier))
395 {
396 parameterLabel = token.value;
397 tokens = tokens.Skip(1).ToList();
398 token = tokens[0];
399 } else {
400 Error.Throw("Expected identifier as paramter label", token);
401 }
402
403 if(token.GetType() == typeof(TokenColon))
404 {
405 tokens = tokens.Skip(1).ToList();
406 token = tokens[0];
407 } else
408 {
409 Error.Throw("Expected colon after parameter label", token);
410 }
411
412 Token type = default(Token)!;
413 if(token.GetType() == typeof(TokenIdentifier))
414 {
415 type = token;
416 tokens = tokens.Skip(1).ToList();
417 token = tokens[0];
418 } else {
419 Error.Throw("Expected type", token);
420 }
421
422 // Console.WriteLine("i");
423 parameters.Add((parameterLabel, GetTypeFromToken(type)));
424
425 if(token.GetType() == typeof(TokenParenEnd))
426 {
427 parametersDone = true;
428 tokens = tokens.Skip(1).ToList();
429 token = tokens[0];
430
431 break;
432 }
433
434 if(token.GetType() == typeof(TokenComma))
435 {
436 tokens = tokens.Skip(1).ToList();
437 token = tokens[0];
438 } else
439 {
440 Error.Throw("Expected comma after parameter label", token);
441 }
442 }
443
444 Types? returnType = null;
445 if(token.GetType() == typeof(TokenIdentifier))
446 {
447 if(token.value == "void")
448 {
449 returnType = null;
450 } else
451 {
452 returnType = GetTypeFromToken(token);
453 }
454 // Console.WriteLine("2");
455 tokens = tokens.Skip(1).ToList();
456 token = tokens[0];
457 } else {
458 Error.Throw("Expected return type", token);
459 }
460
461 List<AST> block = new();
462 if(token.GetType() == typeof(TokenBlockStart))
463 {
464 tokens = tokens.Skip(1).ToList();
465 token = tokens[0];
466
467 var (newtokens, newast) = ParseBlock(tokens.ToArray());
468 block = newast;
469 tokens = newtokens.ToList();
470 } else {
471 Error.Throw("Expected block start", token);
472 }
473
474 ast = new ASTFunctionDefine(label, parameters, returnType, block);
475
476 return (tokens.ToArray(), ast);
477 }
478
479 public static (Token[], AST) ParseFunctionCall(Token[] tokens_, string function)
480 {
481 List<Token> tokens = tokens_.ToList();
482 AST ast = new();
483
484 Dictionary<string, ASTExpression> parameters = new();
485
486 bool parametersDone = false;
487 while(tokens.Count > 0 || !parametersDone)
488 {
489 var token = tokens[0];
490
491 if(token.GetType() == typeof(TokenParenEnd))
492 {
493 tokens = tokens.Skip(1).ToList();
494 token = tokens[0];
495 parametersDone = true;
496 break;
497 }
498
499 var parameterLabel = "";
500 if(token.GetType() == typeof(TokenIdentifier))
501 {
502 parameterLabel = token.value;
503 tokens = tokens.Skip(1).ToList();
504 token = tokens[0];
505 } else {
506 Error.Throw("Expected identifier as paramter label", token);
507 }
508
509 if(token.GetType() == typeof(TokenColon))
510 {
511 tokens = tokens.Skip(1).ToList();
512 token = tokens[0];
513 } else
514 {
515 Error.Throw("Expected colon after parameter label", token);
516 }
517
518 var (newtokens, newast) = ParseExpression(tokens.ToArray());
519 // Console.WriteLine(tokens[tokens.Count - newtokens.Length - 1]);
520
521 var newtok = newtokens.ToList();
522 newtok = newtok.Prepend(tokens[tokens.Count - newtokens.Length - 1]).ToList();
523 tokens = newtok.ToArray().ToList();
524 token = tokens[0];
525
526 parameters.Add(parameterLabel, newast);
527
528 if(token.GetType() == typeof(TokenParenEnd) || token.GetType() == typeof(TokenEOL))
529 {
530 tokens = tokens.Skip(1).ToList();
531 return (tokens.ToArray(), new ASTFunctionCall(function, parameters));
532 } else if(token.GetType() == typeof(TokenComma))
533 {
534 tokens = tokens.Skip(1).ToList();
535 }
536 }
537 return (tokens.ToArray(), new ASTFunctionCall(function, parameters));
538 }
539
540 public static (Token[], AST) ParseReturn(Token[] tokens)
541 {
542 var (newtokens, newast) = ParseExpression(tokens);
543
544 return (newtokens, new ASTReturn(newast));
545 }
546
547 public static (Token[], AST) ParseVariableDefine(Token[] tokens_, string label)
548 {
549 List<Token> tokens = tokens_.ToList();
550 AST ast = new();
551
552 var token = tokens[0];
553
554 Types type = Types.Int;
555 if(token.GetType() == typeof(TokenIdentifier))
556 {
557 // Console.WriteLine("3");
558 type = GetTypeFromToken(token);
559 tokens = tokens.Skip(1).ToList();
560 token = tokens[0];
561 } else if(token.GetType() == typeof(TokenArrayStart))
562 {
563 tokens = tokens.Skip(1).ToList();
564 token = tokens[0];
565 type = GetTypeFromToken(token, true);
566 tokens = tokens.Skip(1).ToList();
567 token = tokens[0];
568
569 if(token.GetType() == typeof(TokenArrayEnd))
570 {
571 tokens = tokens.Skip(1).ToList();
572 token = tokens[0];
573 } else
574 {
575 Error.Throw("Expected array end after array type definition", token);
576 }
577 } else
578 {
579 Error.Throw("Expected type", token);
580 }
581
582 if(token.GetType() == typeof(TokenAssign))
583 {
584 tokens = tokens.Skip(1).ToList();
585 token = tokens[0];
586 } else
587 {
588 Error.Throw("Expected assign '='", token);
589 }
590
591 var (newtokens, expr) = ParseExpression(tokens.ToArray());
592
593 tokens = newtokens.ToList();
594
595 return (tokens.ToArray(), new ASTVariableDefine(label, type, expr));
596 }
597
598 public static (Token[], AST) ParseVariableReassign(Token[] tokens_, string label, Token op)
599 {
600 AssignOp asop = AssignOp.Assign;
601 if(op.GetType() == typeof(TokenAssign))
602 {
603 asop = AssignOp.Assign;
604 } else if(op.GetType() == typeof(TokenAssignDivide))
605 {
606 asop = AssignOp.Divide;
607 } else if(op.GetType() == typeof(TokenAssignMinus))
608 {
609 asop = AssignOp.Minus;
610 } else if(op.GetType() == typeof(TokenAssignMultiply))
611 {
612 asop = AssignOp.Multiply;
613 } else if(op.GetType() == typeof(TokenAssignPlus))
614 {
615 asop = AssignOp.Plus;
616 } else if(op.GetType() == typeof(TokenAssignPower))
617 {
618 asop = AssignOp.Power;
619 } else if(op.GetType() == typeof(TokenAssignModulo))
620 {
621 asop = AssignOp.Power;
622 } else
623 {
624 Error.Throw("Invalid operator", op);
625 }
626
627 List<Token> tokens = tokens_.ToList();
628
629 var token = tokens[0];
630
631 var (newtokens, expr) = ParseExpression(tokens.ToArray());
632
633 return (newtokens, new ASTVariableReassign(label, expr, asop));
634 }
635
636 public static Type[] ExprValues = new [] {typeof(TokenInt), typeof(TokenFloat), typeof(TokenString), typeof(TokenIdentifier)};
637
638 public static Dictionary<Type, (int, bool)> ExprOperatorsEquality = new()
639 {
640 {typeof(TokenEquals), (0, false)},
641 {typeof(TokenNotEquals), (0, false)},
642 {typeof(TokenGreater), (1, false)},
643 {typeof(TokenGreaterEquals), (1, false)},
644 {typeof(TokenLesser), (1, false)},
645 {typeof(TokenLesserEquals), (1, false)}
646 };
647
648 public static Dictionary<Type, (int, bool)> ExprOperatorsAlgebraic = new()
649 {
650 {typeof(TokenPlus), (2, false)},
651 {typeof(TokenMinus), (2, false)},
652 {typeof(TokenDivide), (3, false)},
653 {typeof(TokenMultiply), (3, false)},
654 {typeof(TokenModulo), (3, false)},
655 {typeof(TokenPower), (4, true)},
656 };
657
658 public static Dictionary<Type, (int, bool)> ExprOperatorsBoolean = new()
659 {
660 {typeof(TokenNot), (4, true)}
661 };
662
663 public static Dictionary<Type, (int, bool)> ExprOperators = new();
664
665 public static (Token[], Token) ParseArray(Token[] tokens_)
666 {
667 List<Token> tokens = tokens_.ToList();
668
669 Types type;
670 while(tokens.Count > 0)
671 {
672 var token = tokens[0];
673
674 if(token is TokenArrayEnd)
675 {
676 Token list;
677 if(type == null)
678 {
679 list = new TokenArrayInt(0, 0, 0, 0);
680 }
681
682 return (tokens.ToList(), )
683 }
684 }
685 }
686
687 public static (Token[], ASTExpression) ParseExpression(Token[] tokens_)
688 {
689 List<Token> tokens = tokens_.ToList();
690 List<AST> ast = new();
691
692 List<Token> OperatorQueue = new();
693 List<object> OutputQueue = new();
694
695 int leftParens = 0;
696 int rightParens = 0;
697
698 List<Token> fixedTokens = new();
699
700 foreach(var token in tokens)
701 {
702 if(token is not TokenArrayStart)
703 {
704 fixedTokens.Add(token);
705 } else
706 {
707 var (newtokens, list) = ParseArray(tokens.ToArray());
708 }
709 }
710
711 while(tokens.Count > 0)
712 {
713 var token = tokens[0];
714 tokens = tokens.Skip(1).ToList();
715
716 if(token.GetType() == typeof(TokenParenStart))
717 {
718 leftParens ++;
719 }
720 if(token.GetType() == typeof(TokenParenEnd))
721 {
722 rightParens++;
723 }
724
725 // Console.WriteLine("expr " + Tokenizer.GetTokenAsHuman(token));
726
727 // Tokenizer.Print(token);
728
729 if(
730 new [] {typeof(TokenEOL), typeof(TokenBlockStart), typeof(TokenComma), typeof(TokenColon)}.Contains(token.GetType()) ||
731 (
732 new [] {typeof(TokenEOL), typeof(TokenBlockStart), typeof(TokenComma)}.Contains(tokens[0].GetType()) &&
733 new [] {typeof(TokenParenEnd)}.Contains(token.GetType())
734 ) ||
735 (rightParens > leftParens)
736 )
737 {
738 while(OperatorQueue.Count > 0)
739 {
740 if(OperatorQueue.Last().GetType() == typeof(TokenParenStart))
741 Error.Throw("Can't be left parnthesis", OperatorQueue.Last());
742
743 OutputQueue.Add(OperatorQueue.Last());
744 OperatorQueue.RemoveAt(OperatorQueue.Count - 1);
745 }
746
747 return (tokens.ToArray(), new ASTExpression(OutputQueue));
748 }
749
750 if(ExprValues.Contains(token.GetType()))
751 {
752 if(token.GetType() == typeof(TokenIdentifier))
753 {
754 if(tokens[0].GetType() == typeof(TokenParenStart))
755 {
756 // Console.WriteLine("Parsing function");
757 tokens = tokens.Skip(1).ToList();
758 var (newtokens, newast) = ParseFunctionCall(tokens.ToArray(), token.value);
759 tokens = newtokens.ToList();
760 OutputQueue.Add(newast);
761 // Console.Write("Parsed fc ");
762 // Tokenizer.Print(tokens[0]);
763 // Console.WriteLine("done parse");
764 } else {
765 OutputQueue.Add(token);
766 }
767 } else
768 {
769 OutputQueue.Add(token);
770 }
771
772 } else if(ExprOperators.Keys.Contains(token.GetType()))
773 {
774 while(
775 (OperatorQueue.Count > 0 && OperatorQueue.Last().GetType() != typeof(TokenParenStart))
776 &&
777 (
778 ExprOperators[OperatorQueue.Last().GetType()].Item1 > ExprOperators[token.GetType()].Item1
779 ||
780 (ExprOperators[OperatorQueue.Last().GetType()].Item1 == ExprOperators[token.GetType()].Item1 && !ExprOperators[token.GetType()].Item2)
781 )
782 )
783 {
784 OutputQueue.Add(OperatorQueue.Last());
785 OperatorQueue.RemoveAt(OperatorQueue.Count - 1);
786 }
787
788 OperatorQueue.Add(token);
789 } else if(token.GetType() == typeof(TokenParenStart))
790 {
791 OperatorQueue.Add(token);
792 } else if(token.GetType() == typeof(TokenParenEnd))
793 {
794 while(
795 OperatorQueue.Last().GetType() != typeof(TokenParenStart)
796 ) {
797 if(OperatorQueue.Count == 0)
798 Error.Throw("Unmatched parnthesis", OperatorQueue.Last());
799
800 OutputQueue.Add(OperatorQueue.Last());
801 OperatorQueue.RemoveAt(OperatorQueue.Count - 1);
802 }
803
804 // if(OperatorQueue.Last().GetType() == typeof(TokenParenStart))
805 // Error.Throw("Expected left parnthesis", OperatorQueue.Last());
806
807 OperatorQueue.RemoveAt(OperatorQueue.Count - 1);
808 }
809 }
810
811 while(OperatorQueue.Count > 0)
812 {
813 if(OperatorQueue.Last().GetType() == typeof(TokenParenStart))
814 Error.Throw("Can't be left parnthesis", OperatorQueue.Last());
815
816 OutputQueue.Add(OperatorQueue.Last());
817 OperatorQueue.RemoveAt(OperatorQueue.Count - 1);
818 }
819
820 return (tokens.ToArray(), new ASTExpression(OutputQueue));
821 }
822}