1namespace Astrid;
2
3public static class Interpreter
4{
5 public static Token? Run(List<AST> block, Dictionary<string, (Types, Token)> Variables, Dictionary<string, (List<(string, Types)>, object, Types?)> Functions, string[] preAddedVars = null!, string[] preAddedFuncs = null!)
6 {
7 List<string> addedVars = new();
8 if(preAddedVars != null)
9 addedVars.AddRange(preAddedVars.ToList());
10
11 List<string> addedFuncs = new();
12 if(preAddedFuncs != null)
13 addedFuncs.AddRange(preAddedFuncs.ToList());
14
15 foreach(var ast in block)
16 {
17 if(ast.GetType() == typeof(ASTConditional))
18 {
19 var call = (ASTConditional)ast;
20 var cond = RunExpression(call.condition, Variables, Functions);
21
22 if(cond.GetType() == typeof(TokenBoolean))
23 {
24 var condbool = cond.value == "true";
25
26 if(condbool)
27 {
28 var t = Run(call.block, Variables, Functions);
29 if(t != null)
30 {
31 Error.Throw("Can't use return in if condition", t);
32 }
33 }
34 } else
35 {
36 Error.Throw("Condition must be bool in if", cond);
37 }
38 } else if(ast.GetType() == typeof(ASTWhile))
39 {
40 var call = (ASTWhile)ast;
41 var cond = RunExpression(call.condition, Variables, Functions);
42
43 if(cond.GetType() == typeof(TokenBoolean))
44 {
45 var condbool = cond.value == "true";
46
47 while(condbool)
48 {
49 cond = RunExpression(call.condition, Variables, Functions);
50 condbool = cond.value == "true";
51
52 var t = Run(call.block, Variables, Functions);
53 if(t != null)
54 {
55 Error.Throw("Can't use return in while", t);
56 }
57 }
58 } else
59 {
60 Error.Throw("Condition must be bool in while", cond);
61 }
62 } else if(ast.GetType() == typeof(ASTMatch))
63 {
64 var call = (ASTMatch)ast;
65
66 var toMatch = RunExpression(call.expr, Variables, Functions);
67
68 bool hasMatched = false;
69
70 call.matches.ToList().ForEach(e => {
71 bool hasRunDefault = false;
72
73 if(e.Key.expression[0] is TokenIdentifier id)
74 {
75 if(id.value == "_")
76 {
77 if(e.Key.expression.Count > 1)
78 {
79 Error.Throw("Default match can't have more expressions!", id);
80 }
81
82 hasRunDefault = true;
83 if(!hasMatched)
84 {
85 Run(e.Value, Variables, Functions);
86 }
87 }
88 }
89
90 if(!hasRunDefault)
91 {
92 var result = RunExpression(e.Key, Variables, Functions);
93
94 if(Parser.GetTypeFromValue(toMatch) != Parser.GetTypeFromValue(result))
95 {
96 Error.Throw($"Can't match {result} to {toMatch}", result);
97 }
98
99 if(toMatch.value == result.value)
100 {
101 hasMatched = true;
102 Run(e.Value, Variables, Functions);
103 }
104 }
105 });
106 } else if(ast.GetType() == typeof(ASTFunctionCall))
107 {
108 var call = (ASTFunctionCall)ast;
109
110 RunFunction(call, Variables, Functions);
111 } else if(ast.GetType() == typeof(ASTFunctionDefine))
112 {
113 var call = (ASTFunctionDefine)ast;
114
115 addedFuncs.Add(call.label);
116
117 Functions.Add(call.label, (
118 call.parameters,
119 call.block,
120 call.returnType
121 ));
122 } else if(ast.GetType() == typeof(ASTReturn))
123 {
124 var call = (ASTReturn)ast;
125
126 return RunExpression(call.expression, Variables, Functions);
127 } else if(ast.GetType() == typeof(ASTVariableDefine))
128 {
129 var call = (ASTVariableDefine)ast;
130
131 Variables.Add(call.label, (call.type, RunExpression(call.value, Variables, Functions)));
132 addedVars.Add(call.label);
133 } else if(ast is ASTVariableReassign call)
134 {
135 var value = RunExpression(call.value, Variables, Functions);
136 Types type = Types.Int;
137
138 // Console.WriteLine("reached as");
139
140 if(!Variables.Keys.Contains(call.label))
141 throw new Exception($"Variable {call.label} doens't exist so it can't be reassigned");
142
143 switch(Variables[call.label].Item1)
144 {
145 case Types.Int:
146 if(value.GetType() != typeof(TokenInt))
147 Error.Throw($"Cannot assign ${value.GetType()} to int", value);
148 type = Types.Int;
149 break;
150 case Types.Float:
151 if(value.GetType() != typeof(TokenFloat))
152 Error.Throw($"Cannot assign ${value.GetType()} to float", value);
153 type = Types.Float;
154 break;
155 case Types.String:
156 if(value.GetType() != typeof(TokenString))
157 Error.Throw($"Cannot assign ${value.GetType()} to string", value);
158 type = Types.String;
159 break;
160 default:
161 Error.Throw($"Invalid type in reassign {Variables[call.label].Item1}", Variables[call.label].Item2); break;
162 }
163
164 switch(call.asop)
165 {
166 case AssignOp.Assign: {
167 Variables[call.label] = (type, value);
168 } break;
169 case AssignOp.Plus: {
170 switch(type)
171 {
172 case Types.Int: {
173 Variables[call.label] = (type, new TokenInt((int.Parse(Variables[call.label].Item2.value) + int.Parse(value.value)).ToString(), value.lineStart, value.lineEnd, value.charStart, value.charEnd));
174 } break;
175 case Types.Float: {
176 Variables[call.label] = (type, new TokenFloat((float.Parse(Variables[call.label].Item2.value) + float.Parse(value.value)).ToString(), value.lineStart, value.lineEnd, value.charStart, value.charEnd));
177 } break;
178 case Types.String: {
179 Variables[call.label] = (type, new TokenString(Variables[call.label].Item2.value + value.value, value.lineStart, value.lineEnd, value.charStart, value.charEnd));
180 } break;
181 }
182 } break;
183 case AssignOp.Minus: {
184 switch(type)
185 {
186 case Types.Int: {
187 Variables[call.label] = (type, new TokenInt((int.Parse(Variables[call.label].Item2.value) - int.Parse(value.value)).ToString(), value.lineStart, value.lineEnd, value.charStart, value.charEnd));
188 } break;
189 case Types.Float: {
190 Variables[call.label] = (type, new TokenFloat((float.Parse(Variables[call.label].Item2.value) - float.Parse(value.value)).ToString(), value.lineStart, value.lineEnd, value.charStart, value.charEnd));
191 } break;
192 default: {
193 Error.Throw($"Can't use operator minus with {type}", Variables[call.label].Item2);
194 } break;
195 }
196 } break;
197 case AssignOp.Multiply: {
198 switch(type)
199 {
200 case Types.Int: {
201 Variables[call.label] = (type, new TokenInt((int.Parse(Variables[call.label].Item2.value) * int.Parse(value.value)).ToString(), value.lineStart, value.lineEnd, value.charStart, value.charEnd));
202 } break;
203 case Types.Float: {
204 Variables[call.label] = (type, new TokenFloat((float.Parse(Variables[call.label].Item2.value) * float.Parse(value.value)).ToString(), value.lineStart, value.lineEnd, value.charStart, value.charEnd));
205 } break;
206 default: {
207 Error.Throw($"Can't use operator multiply with {type}", Variables[call.label].Item2);
208 } break;
209 }
210 } break;
211 case AssignOp.Divide: {
212 switch(type)
213 {
214 case Types.Int: {
215 Variables[call.label] = (type, new TokenInt((int.Parse(Variables[call.label].Item2.value) / int.Parse(value.value)).ToString(), value.lineStart, value.lineEnd, value.charStart, value.charEnd));
216 } break;
217 case Types.Float: {
218 Variables[call.label] = (type, new TokenFloat((float.Parse(Variables[call.label].Item2.value) / float.Parse(value.value)).ToString(), value.lineStart, value.lineEnd, value.charStart, value.charEnd));
219 } break;
220 default: {
221 Error.Throw($"Can't use operator divide with {type}", Variables[call.label].Item2);
222 } break;
223 }
224 } break;
225 case AssignOp.Power: {
226 switch(type)
227 {
228 case Types.Int: {
229 Variables[call.label] = (type, new TokenInt(Math.Pow(int.Parse(Variables[call.label].Item2.value), int.Parse(value.value)).ToString(), value.lineStart, value.lineEnd, value.charStart, value.charEnd));
230 } break;
231 case Types.Float: {
232 Variables[call.label] = (type, new TokenFloat(Math.Pow(float.Parse(Variables[call.label].Item2.value), float.Parse(value.value)).ToString(), value.lineStart, value.lineEnd, value.charStart, value.charEnd));
233 } break;
234 default: {
235 Error.Throw($"Can't use operator power with {type}", Variables[call.label].Item2);
236 } break;
237 }
238 } break;
239 case AssignOp.Modulo: {
240 switch(type)
241 {
242 case Types.Int: {
243 Variables[call.label] = (type, new TokenInt((int.Parse(Variables[call.label].Item2.value) % int.Parse(value.value)).ToString(), value.lineStart, value.lineEnd, value.charStart, value.charEnd));
244 } break;
245 case Types.Float: {
246 Variables[call.label] = (type, new TokenFloat((float.Parse(Variables[call.label].Item2.value) % float.Parse(value.value)).ToString(), value.lineStart, value.lineEnd, value.charStart, value.charEnd));
247 } break;
248 default: {
249 Error.Throw($"Can't use operator modulo with {type}", Variables[call.label].Item2);
250 } break;
251 }
252 } break;
253 }
254 }
255 }
256
257 foreach(var d in addedVars)
258 {
259 Variables.Remove(d);
260 }
261
262 foreach(var d in addedFuncs)
263 {
264 Functions.Remove(d);
265 }
266
267 return null;
268 }
269
270 public static Token? RunFunction(ASTFunctionCall fc, Dictionary<string, (Types, Token)> Variables, Dictionary<string, (List<(string, Types)>, object, Types?)> Functions)
271 {
272 if(!Functions.Keys.Contains(fc.label))
273 {
274 Error.Throw("Function doesn't exist", new(0, 0, 0, 0));
275 }
276
277 // fc.value.ToList().ForEach(e => Console.WriteLine(e.Key));
278 // Functions[fc.label].Item1.ForEach(e => Console.WriteLine(e.Item1));
279
280 foreach(var i in fc.value)
281 {
282 bool contains = false;
283 Functions[fc.label].Item1.ForEach(e => {
284 if(!contains)
285 contains = e.Item1 == i.Key;
286 });
287 // if(!contains)
288 // {
289 // Error.Throw($"Parameter {i.Key} isn't satisifed", new(0, 0, 0, 0));
290 // }
291 }
292
293 // Functions[fc.label]
294
295 if(Functions[fc.label].Item2 is List<AST> block)
296 {
297 string[] preAdd = fc.value.Keys.ToArray();
298
299 fc.value.ToList().ForEach(e => {
300 var Tok = RunExpression(e.Value, Variables, Functions);
301 Variables.Add(e.Key, (Parser.GetTypeFromValue(Tok), Tok));
302 });
303 return Run(block, Variables, Functions, preAdd);
304 } else
305 {
306 var asd = (dynamic message) => {};
307
308 List<Token> parameters = fc.value.Select(e => RunExpression(e.Value, Variables, Functions)).ToList();
309
310 if(parameters.Count < Functions[fc.label].Item1.Count)
311 {
312 Error.Throw($"Parameters aren't satisifed in {fc.label}", new(0, 0, 0, 0));
313 }
314
315 var val = ((dynamic)Functions[fc.label].Item2).Invoke(parameters);
316 return val;
317 }
318 }
319
320
321 public static Token RunExpression(ASTExpression _expr, Dictionary<string, (Types, Token)> Variables, Dictionary<string, (List<(string, Types)>, object, Types?)> Functions)
322 {
323 List<object> tokensOld = _expr.expression;
324
325 // Console.WriteLine("a");
326 // foreach(var i in tokensOld)
327 // {
328 // Console.WriteLine(i);
329 // }
330
331 List<Token> tokens = new();
332
333 foreach(var tok in tokensOld)
334 {
335 if(tok.GetType() != typeof(ASTFunctionCall))
336 {
337 tokens.Add((Token)tok);
338 } else
339 {
340 // Console.WriteLine("func call");
341 var val = RunFunction((ASTFunctionCall)tok, Variables, Functions);
342 if(val == null && Functions[((ASTFunctionCall)tok).label].Item3 != null)
343 {
344 Error.Throw($"Return type must be {Functions[((ASTFunctionCall)tok).label].Item3}", new(0, 0, 0, 0));
345 } else if(Parser.GetTypeFromValue(val!) != Functions[((ASTFunctionCall)tok).label].Item3)
346 {
347 Error.Throw($"Return type must be {Functions[((ASTFunctionCall)tok).label].Item3}", val!);
348 }
349 if(val == null)
350 Error.Throw(((ASTFunctionCall)tok).label, default(Token)!);
351
352 tokens.Add(val!);
353 }
354 }
355
356 // foreach(var i in tokens)
357 // {
358 // Console.WriteLine("tok " + Tokenizer.GetTokenAsHuman(i));
359 // }
360
361 List<Token> stack = new();
362 var token = tokens[0];
363
364 while(tokens.Count > 0)
365 {
366 token = tokens[0];
367 tokens = tokens.Skip(1).ToList();
368
369 // Console.WriteLine("Intepret " + token);
370
371 if(Parser.ExprValues.Contains(token.GetType()))
372 {
373 if(token.GetType() != typeof(TokenIdentifier))
374 stack.Add(token);
375 else {
376 // Console.WriteLine("Id " + token.value + " to " + Tokenizer.GetTokenAsHuman(variables[token.value]));
377 stack.Add(Variables[token.value].Item2);
378 }
379 } else if(Parser.ExprOperators.Keys.Contains(token.GetType()))
380 {
381 if(new [] {typeof(TokenEquals), typeof(TokenNotEquals), typeof(TokenGreater), typeof(TokenGreaterEquals), typeof(TokenLesser), typeof(TokenLesserEquals)}.Contains(token.GetType())) {
382 if(stack.Count < 2)
383 throw new Exception("Stack doesn't contains two values");
384
385 Token left = stack[stack.Count - 2];
386 Token right = stack[stack.Count - 1];
387
388 if(left.GetType() == right.GetType())
389 {
390 string value = "";
391 if(token.GetType() == typeof(TokenEquals))
392 {
393 value = (left.value == right.value).ToString().ToLower();
394 } else if(token.GetType() == typeof(TokenNotEquals))
395 {
396 value = (left.value != right.value).ToString().ToLower();
397 } else if(token.GetType() == typeof(TokenGreater))
398 {
399 if(!new [] {typeof(TokenInt), typeof(TokenFloat)}.Contains(left.GetType()) || !new [] {typeof(TokenInt), typeof(TokenFloat)}.Contains(right.GetType()))
400 Error.Throw($"Cannot apply greater than to non int or float type, {Tokenizer.GetTokenAsHuman(left)}, {Tokenizer.GetTokenAsHuman(right)}", left);
401
402 value = (float.Parse(left.value) > float.Parse(right.value)).ToString().ToLower();
403 } else if(token.GetType() == typeof(TokenGreaterEquals))
404 {
405 if(!new [] {typeof(TokenInt), typeof(TokenFloat)}.Contains(left.GetType()) || !new [] {typeof(TokenInt), typeof(TokenFloat)}.Contains(right.GetType()))
406 Error.Throw($"Cannot apply greaterequals than to non int or float type, {Tokenizer.GetTokenAsHuman(left)}, {Tokenizer.GetTokenAsHuman(right)}", left);
407
408 value = (float.Parse(left.value) >= float.Parse(right.value)).ToString().ToLower();
409 } else if(token.GetType() == typeof(TokenLesser))
410 {
411 if(!new [] {typeof(TokenInt), typeof(TokenFloat)}.Contains(left.GetType()) || !new [] {typeof(TokenInt), typeof(TokenFloat)}.Contains(right.GetType()))
412 Error.Throw($"Cannot apply lesser than to non int or float type, {Tokenizer.GetTokenAsHuman(left)}, {Tokenizer.GetTokenAsHuman(right)}", left);
413
414 value = (float.Parse(left.value) < float.Parse(right.value)).ToString().ToLower();
415 } else if(token.GetType() == typeof(TokenLesserEquals))
416 {
417 if(!new [] {typeof(TokenInt), typeof(TokenFloat)}.Contains(left.GetType()) || !new [] {typeof(TokenInt), typeof(TokenFloat)}.Contains(right.GetType()))
418 Error.Throw($"Cannot apply lesserequals than to non int or float type, {Tokenizer.GetTokenAsHuman(left)}, {Tokenizer.GetTokenAsHuman(right)}", left);
419
420 value = (float.Parse(left.value) <= float.Parse(right.value)).ToString().ToLower();
421 }
422
423 stack.Add(new TokenBoolean(value, left.lineStart, left.lineEnd, left.charStart, left.charEnd));
424 stack.RemoveAt(stack.Count - 2);
425 stack.RemoveAt(stack.Count - 2);
426 } else
427 {
428 //Console.WriteLine("expr");
429 Error.Throw($"Types don't match in expression equals. Matching left: {left.GetType()}, right: {right.GetType()}", left);
430 }
431 } else if(Parser.ExprOperatorsAlgebraic.Keys.Contains(token.GetType()))
432 {
433 if(stack.Count < 2)
434 Error.Throw("Stack doesn't contain two values", token);
435
436 Token left = stack[stack.Count - 2];
437 Token right = stack[stack.Count - 1];
438
439 if(left.GetType() == typeof(TokenInt) && right.GetType() == typeof(TokenInt))
440 {
441 string value = "";
442 // Console.Write("int ");
443 if(token.GetType() == typeof(TokenPlus))
444 {
445 // Console.WriteLine($"{int.Parse(left.value)} + {int.Parse(right.value)}");
446 value = (int.Parse(left.value) + int.Parse(right.value)).ToString().ToLower();
447 } else if(token.GetType() == typeof(TokenMinus))
448 {
449 // Console.WriteLine($"{int.Parse(left.value)} - {int.Parse(right.value)}");
450 value = (int.Parse(left.value) - int.Parse(right.value)).ToString().ToLower();
451 } else if(token.GetType() == typeof(TokenDivide))
452 {
453 // Console.WriteLine($"{int.Parse(left.value)} / {int.Parse(right.value)}");
454 value = (int.Parse(left.value) / int.Parse(right.value)).ToString().ToLower();
455 } else if(token.GetType() == typeof(TokenMultiply))
456 {
457 // Console.WriteLine($"{int.Parse(left.value)} * {int.Parse(right.value)}");
458 value = (int.Parse(left.value) * int.Parse(right.value)).ToString().ToLower();
459 } else if(token.GetType() == typeof(TokenPower))
460 {
461 // Console.WriteLine($"{int.Parse(left.value)} ^ {int.Parse(right.value)}");
462 value = ((int)Math.Pow(int.Parse(left.value), int.Parse(right.value))).ToString().ToLower();
463 } else if(token.GetType() == typeof(TokenModulo))
464 {
465 // Console.WriteLine($"{int.Parse(left.value)} ^ {int.Parse(right.value)}");
466 value = (int.Parse(left.value) % int.Parse(right.value)).ToString().ToLower();
467 }
468
469 // Console.WriteLine("final value: " + value);
470 stack.Add(new TokenInt(value, left.lineStart, left.lineEnd, left.charStart, left.charEnd));
471 stack.RemoveAt(stack.Count - 2);
472 stack.RemoveAt(stack.Count - 2);
473 } else if(left.GetType() == typeof(TokenFloat) && right.GetType() == typeof(TokenFloat))
474 {
475 string value = "";
476 // Console.Write("float ");
477 if(token.GetType() == typeof(TokenPlus))
478 {
479 // Console.WriteLine($"{int.Parse(left.value)} + {int.Parse(right.value)}");
480 value = (float.Parse(left.value) + float.Parse(right.value)).ToString().ToLower();
481 } else if(token.GetType() == typeof(TokenMinus))
482 {
483 // Console.WriteLine($"{int.Parse(left.value)} - {int.Parse(right.value)}");
484 value = (float.Parse(left.value) - float.Parse(right.value)).ToString().ToLower();
485 } else if(token.GetType() == typeof(TokenDivide))
486 {
487 // Console.WriteLine($"{int.Parse(left.value)} / {int.Parse(right.value)}");
488 value = (float.Parse(left.value) / float.Parse(right.value)).ToString().ToLower();
489 } else if(token.GetType() == typeof(TokenMultiply))
490 {
491 // Console.WriteLine($"{int.Parse(left.value)} * {int.Parse(right.value)}");
492 value = (float.Parse(left.value) * float.Parse(right.value)).ToString().ToLower();
493 } else if(token.GetType() == typeof(TokenPower))
494 {
495 // Console.WriteLine($"{int.Parse(left.value)} ^ {int.Parse(right.value)}");
496 value = ((float)Math.Pow(float.Parse(left.value), float.Parse(right.value))).ToString().ToLower();
497 } else if(token.GetType() == typeof(TokenModulo))
498 {
499 // Console.WriteLine($"{int.Parse(left.value)} * {int.Parse(right.value)}");
500 value = (float.Parse(left.value) % float.Parse(right.value)).ToString().ToLower();
501 }
502
503 // Console.WriteLine("final value: " + value);
504 stack.Add(new TokenFloat(value, left.lineStart, left.lineEnd, left.charStart, left.charEnd));
505 stack.RemoveAt(stack.Count - 2);
506 stack.RemoveAt(stack.Count - 2);
507 } else if(left.GetType() == typeof(TokenString) && right.GetType() == typeof(TokenString))
508 {
509 string value = "";
510 // Console.Write("float ");
511 if(token.GetType() == typeof(TokenPlus))
512 {
513 // Console.WriteLine($"{int.Parse(left.value)} + {int.Parse(right.value)}");
514 value = left.value + right.value;
515 } else
516 {
517 Error.Throw($"Can't use operator {token.GetType()} with string", token);
518 }
519
520 // Console.WriteLine("final value: " + value);
521 stack.Add(new TokenString(value, left.lineStart, left.lineEnd, left.charStart, left.charEnd));
522 stack.RemoveAt(stack.Count - 2);
523 stack.RemoveAt(stack.Count - 2);
524 } else
525 {
526 Error.Throw($"Types don't match in expression equals. Matching left: {left.GetType()}, right: {right.GetType()}", left);
527 }
528 }
529 }
530 }
531
532 if(stack.Count > 1)
533 {
534 string st = "Stack exited longer than 1 ";
535 stack.ForEach(e => st += Tokenizer.GetTokenAsHuman(e));
536 Error.Throw(st, token);
537 }
538
539 return stack[0];
540 }
541}