ScriptStack 1.0.5
Loading...
Searching...
No Matches
Interpreter.cs
Go to the documentation of this file.
3using System;
4using System.Collections;
5using System.Collections.Generic;
6using System.Collections.ObjectModel;
7using System.Text;
8
10{
11
17 public class Interpreter
18 {
19
20 #region Private Classes
21
26 private class FunctionFrame
27 {
28 public Function function;
30 public int nextInstruction;
31 }
32
33 #endregion
34
35 #region Private Variables
36
37 private Function function;
38 private Script script;
40 private Stack<FunctionFrame> functionStack;
41 private Stack<object> parameterStack;
42 private Dictionary<object, Instruction> locks;
43 private List<Interpreter> jobs;
46 private bool interrupt;
47 private bool interrupted;
48 private bool finished;
49 private ClrBridge _clr;
51
52
53 #endregion
54
55 #region Private Methods
56
57 private Host host;
58
59 private int ToInt32Bitwise(object value, string opName = "bitwise")
60 {
61 if (value == null) throw new ExecutionException($"Cannot apply {opName} operation to null.");
62 if (value is NullReference) throw new ExecutionException($"Cannot apply {opName} operation to 'null'.");
63
64 Type t = value.GetType();
65
66 try
67 {
68 switch (Type.GetTypeCode(t))
69 {
70 case TypeCode.Int32: return (int)value;
71 case TypeCode.Boolean: return ((bool)value) ? 1 : 0;
72 case TypeCode.Char: return (char)value;
73 case TypeCode.SByte: return (sbyte)value;
74 case TypeCode.Byte: return (byte)value;
75 case TypeCode.Int16: return (short)value;
76 case TypeCode.UInt16: return (ushort)value;
77 case TypeCode.UInt32: { uint u = (uint)value; if (u > int.MaxValue) throw new OverflowException(); return (int)u; }
78 case TypeCode.Int64: { long l = (long)value; if (l < int.MinValue || l > int.MaxValue) throw new OverflowException(); return (int)l; }
79 case TypeCode.UInt64: { ulong ul = (ulong)value; if (ul > (ulong)int.MaxValue) throw new OverflowException(); return (int)ul; }
80 case TypeCode.Single: { float f = (float)value; if (float.IsNaN(f) || float.IsInfinity(f) || f < int.MinValue || f > int.MaxValue) throw new OverflowException(); return (int)f; }
81 case TypeCode.Double: { double d = (double)value; if (double.IsNaN(d) || double.IsInfinity(d) || d < int.MinValue || d > int.MaxValue) throw new OverflowException(); return (int)d; }
82 case TypeCode.Decimal: return decimal.ToInt32((decimal)value);
83 default: throw new InvalidCastException();
84 }
85 }
86 catch
87 {
88 throw new ExecutionException($"Values of type '{t.Name}' cannot be used in {opName} operations.");
89 }
90 }
91
92
93 private object Evaluate(Operand operand)
94 {
95
96 object src = null;
97
98 switch (operand.Type)
99 {
100
101 case OperandType.Literal:
102 return operand.Value;
103
104 case OperandType.Variable:
105 return localMemory[(string) operand.Value];
106
107 /*
108 * Members are indexed with a '.' like
109 *
110 * var a = [];
111 * a.b = 1;
112 *
113 * currently only arrays can have members but strings can be numerically indexed
114 *
115 */
116 case OperandType.Member:
117
118 src = localMemory[(string)operand.Value];
119
120 if (src.GetType() == typeof(ArrayList))
121 {
122
123 /*
124 * An array has an internal member "toString"
125 * \deprecated
126 */
127 if ((string)operand.Member == "toString")
128 {
129
130 ArrayList array = (ArrayList)src;
131
132 StringBuilder sb = new StringBuilder();
133
134 foreach (KeyValuePair<object, object> element in array)
135 {
136 sb.Append(element.Value.ToString());
137 }
138
139 return sb;
140
141 }
142
143 ArrayList associativeArray = (ArrayList)src;
144
145 object objectValue = associativeArray[operand.Member];
146
147 return objectValue;
148 }
149
150 else if (src.GetType() == typeof(string))
151 {
152
153 string strSource = (string)src;
154
155 object objectIndex = operand.Member;
156
157 if (objectIndex.GetType() == typeof(string))
158 if (((string)objectIndex) == "length")
159 return strSource.Length;
160
161 if (objectIndex.GetType() != typeof(int))
162 throw new ExecutionException("Ein String ist nur numerisch indexierbar.");
163
164 return strSource[(int)objectIndex] + "";
165
166 }
167
168 else
169 {
170 src = localMemory[(string)operand.Value];
171 var memberName = operand.Member?.ToString() ?? "";
172 return _clr.GetMember(src, memberName);
173 }
174
175 //else throw new ExecutionException("Der Typ '"+ operand.Type + "' kann an dieser Stelle nicht verarbeitet werden.");
176
177 /*
178 * Arrays can be indexed with a "string" like
179 *
180 * var a = [];
181 * a["str"] = "Hello world";
182 *
183 * accually a pointer is an associative array
184 *
185 */
186 case OperandType.Pointer:
187
188 src = localMemory[(string)operand.Value];
189
190 if (src.GetType() == typeof(ArrayList))
191 {
192
193 object objectIndex = localMemory[operand.Pointer];
194
195 return ((ArrayList)src)[objectIndex];
196
197 }
198
199 else if (src.GetType() == typeof(string))
200 {
201
202 string strSource = (string)src;
203
204 object objectIndex = localMemory[operand.Pointer];
205
206 if (objectIndex.GetType() != typeof(int))
207 throw new ExecutionException("Ein String ist nur numerisch indexierbar.");
208
209 return strSource[(int)objectIndex] + "";
210
211 }
212
213 else
214 {
215 // IDictionary / Indexer-Property
216 object objectIndex = localMemory[operand.Pointer];
217 if (_clr.TryGetIndex(src, objectIndex, out var v))
218 return v;
219 throw new ExecutionException("Nur Arrays, Dictionaries und Strings sind indexierbar.");
220 }
221
222
223 default:
224 throw new ExecutionException("Der Typ '"+ operand.Type + "' kann an dieser Stelle nicht verarbeitet werden.");
225
226 }
227
228 }
229
235 private void Assignment(Operand dst, object val)
236 {
237
238 string identifier = (string)dst.Value;
239
240 switch (dst.Type)
241 {
242
243 case OperandType.Variable:
244 localMemory[identifier] = val;
245 break;
246
247 case OperandType.Member:
248 {
249 object target = localMemory.Exists(identifier) ? localMemory[identifier] : NullReference.Instance;
250
251 if (target is ArrayList arr)
252 {
253 arr[dst.Member] = val;
254 break;
255 }
256
257 // NEU: C# Objekt Member setzen
258 _clr.SetMember(target, dst.Member.ToString()!, val);
259 break;
260 }
261 case OperandType.Pointer:
262 {
263 object container = localMemory.Exists(identifier) ? localMemory[identifier] : NullReference.Instance;
264 object key = localMemory[dst.Pointer];
265
266 // ScriptStack Array
267 if (container is ArrayList arr)
268 {
269 arr[key] = val;
270 break;
271 }
272
273 // Strings are read-only in this language
274 if (container is string)
275 throw new ExecutionException("Ein String ist nicht schreibbar.");
276
277 // CLR arrays / lists / dictionaries / indexers
278 if (_clr.TrySetIndex(container, key, val))
279 break;
280
281 throw new ExecutionException($"Das Ziel '{dst}' vom Typ '{container?.GetType().FullName}' ist nicht indexierbar.");
282 }
283
284 case OperandType.Literal:
285 throw new ExecutionException("Einem Literal kann nichts zugewiesen werden.");
286
287 }
288
289 }
290
298 private void Arithmetic()
299 {
300
301 String strIdentifierDest = (String)instruction.First.Value;
302
303 object objectValueDest = Evaluate(instruction.First);
304 object objectValueSource = Evaluate(instruction.Second);
305
306 Type typeDest = objectValueDest.GetType();
307 Type typeSource = objectValueSource.GetType();
308
309 // handle array and string concatenation
310 if (instruction.OpCode == OpCode.ADD)
311 {
312 if (typeDest == typeof(String))
313 {
314 Assignment(instruction.First, objectValueDest.ToString() + objectValueSource.ToString());
315 return;
316 }
317
318 if (typeDest == typeof(ArrayList))
319 {
320 ((ArrayList)objectValueDest).Add(objectValueSource);
321 return;
322 }
323 }
324
325 // handle array and string subtraction
326 if (instruction.OpCode == OpCode.SUB)
327 {
328 if (typeDest == typeof(String))
329 {
331 objectValueDest.ToString().Replace(objectValueSource.ToString(), ""));
332 return;
333 }
334 if (typeDest == typeof(ArrayList))
335 {
336 ((ArrayList)objectValueDest).Subtract(objectValueSource);
337 return;
338 }
339 }
340
341 /*
342 float fValueDest = 0.0f;
343 float fValueSource = 0.0f;
344 float fResult = 0.0f;
345 */
346
347 /*
348 var fValueDest = 0.0;
349 var fValueSource = 0.0;
350 var fResult = 0.0;
351
352 if (typeDest == typeof(int))
353 fValueDest = (float)(int)objectValueDest;
354 else if (typeDest == typeof(float))
355 fValueDest = (float)objectValueDest;
356 else if (typeDest == typeof(double))
357 fValueDest = (double)objectValueDest;
358 else if (typeDest == typeof(decimal))
359 fValueDest = (decimal)objectValueDest;
360 else
361 throw new ScriptStackException("Values of type '" + typeDest.Name + "' cannot be used in arithmetic instructions.");
362
363 if (typeSource == typeof(int))
364 fValueSource = (float)(int)objectValueSource;
365 else if (typeSource == typeof(float))
366 fValueSource = (float)objectValueSource;
367 else if (typeSource == typeof(float))
368 fValueSource = (double)objectValueSource;
369 else if (typeSource == typeof(decimal))
370 fValueSource = (decimal)objectValueSource;
371 else
372 throw new ScriptStackException("Values of type '" + typeSource.Name + "' cannot be used in arithmetic instructions.");
373
374 switch (instruction.OpCode)
375 {
376 case OpCode.ADD: fResult = fValueDest + fValueSource; break;
377 case OpCode.SUB: fResult = fValueDest - fValueSource; break;
378 case OpCode.MUL: fResult = fValueDest * fValueSource; break;
379 case OpCode.DIV: fResult = fValueDest / fValueSource; break;
380 case OpCode.MOD: fResult = fValueDest % fValueSource; break;
381 default:
382 throw new ExecutionException("Invalid arithmetic instruction '" + instruction.OpCode + "'.");
383 }
384
385 if (typeDest == typeof(int) && typeSource == typeof(int))
386 Assignment(instruction.First, (int)fResult);
387 else if (typeDest == typeof(float) && typeSource == typeof(float))
388 Assignment(instruction.First, (float)fResult);
389 else if (typeDest == typeof(double) && typeSource == typeof(double))
390 Assignment(instruction.First, (double)fResult);
391 else
392 Assignment(instruction.First, (decimal)fResult);
393 */
394
395 /*
396 decimal a = ToDecimal(objectValueDest, typeDest);
397 decimal b = ToDecimal(objectValueSource, typeSource);
398
399 decimal r = instruction.OpCode switch
400 {
401 OpCode.ADD => a + b,
402 OpCode.SUB => a - b,
403 OpCode.MUL => a * b,
404 OpCode.DIV => a / b,
405 OpCode.MOD => a % b,
406 _ => throw new ExecutionException($"Invalid arithmetic instruction '{instruction.OpCode}'.")
407 };
408
409 // Ergebnis in den Zieltyp (dest) zurück
410 if (typeDest == typeof(int)) Assignment(instruction.First, (int)r);
411 else if (typeDest == typeof(float)) Assignment(instruction.First, (float)r);
412 else if (typeDest == typeof(double)) Assignment(instruction.First, (double)r);
413 else if (typeDest == typeof(decimal)) Assignment(instruction.First, r);
414 else throw new ScriptStackException($"Values of type '{typeDest.Name}' cannot be used in arithmetic instructions.");
415 */
416
417 decimal valueDest;
418 decimal valueSource;
419 decimal result;
420
421 // DEST -> decimal
422 switch (Type.GetTypeCode(typeDest))
423 {
424 case TypeCode.Int32: valueDest = (int)objectValueDest; break;
425 case TypeCode.Single: valueDest = (decimal)(float)objectValueDest; break;
426 case TypeCode.Double: valueDest = (decimal)(double)objectValueDest; break;
427 case TypeCode.Decimal: valueDest = (decimal)objectValueDest; break;
428 default:
429 throw new ScriptStackException("Values of type '" + typeDest.Name + "' cannot be used as destination in arithmetic instructions.");
430 }
431
432 // SOURCE -> decimal
433 switch (Type.GetTypeCode(typeSource))
434 {
435 case TypeCode.Int32: valueSource = (int)objectValueSource; break;
436 case TypeCode.Single: valueSource = (decimal)(float)objectValueSource; break;
437 case TypeCode.Double: valueSource = (decimal)(double)objectValueSource; break;
438 case TypeCode.Decimal: valueSource = (decimal)objectValueSource; break;
439 default:
440 throw new ScriptStackException("Values of type '" + typeSource.Name + "' cannot be used as source in arithmetic instructions.");
441 }
442
443 // Arithmetic (decimal)
444 switch (instruction.OpCode)
445 {
446 case OpCode.ADD: result = valueDest + valueSource; break;
447 case OpCode.SUB: result = valueDest - valueSource; break;
448 case OpCode.MUL: result = valueDest * valueSource; break;
449 case OpCode.DIV: result = valueDest / valueSource; break;
450 case OpCode.MOD: result = valueDest % valueSource; break;
451 default:
452 throw new ExecutionException("Invalid arithmetic instruction '" + instruction.OpCode + "'.");
453 }
454
455 // Back to DEST type
456 switch (Type.GetTypeCode(typeDest))
457 {
458 case TypeCode.Int32: Assignment(instruction.First, (int)result); break;
459 case TypeCode.Single: Assignment(instruction.First, (float)result); break;
460 case TypeCode.Double: Assignment(instruction.First, (double)result); break;
461 case TypeCode.Decimal: Assignment(instruction.First, result); break;
462 default:
463 // eigentlich schon oben abgefangen, aber zur Sicherheit:
464 throw new ScriptStackException("Values of type '" + typeDest.Name + "' cannot be used in arithmetic instructions.");
465 }
466
467 }
468
480 private void Relation()
481 {
482
483 string identifier = (string)instruction.First.Value;
484
485 object dst = Evaluate(instruction.First);
486
487 object src = Evaluate(instruction.Second);
488
489 Type typeDest = dst.GetType();
490
491 Type typeSource = src.GetType();
492
493 bool result = false;
494
499 if (typeDest == typeof(NullReference) || typeSource == typeof(NullReference))
500 {
501
502 switch (instruction.OpCode)
503 {
504
505 case OpCode.CEQ:
506 result = dst == src;
507 break;
508
509 case OpCode.CNE:
510 result = dst != src;
511 break;
512
513 default:
514 string message = "";
515
516 if (typeDest == typeof(NullReference) && typeSource == typeof(NullReference))
517 message = "Die Operation '" + instruction.OpCode + "' kann nicht auf den Typ 'null' angewendet werden.";
518
519 else if (typeDest == typeof(NullReference))
520 message = "Die Operation '" + instruction.OpCode + "' kann nicht auf den Typ 'null' als Ziel (links des Operators) angewendet werden.";
521
522 else
523 message = "Die Operation '" + instruction.OpCode + "' kann nicht auf den Typ 'null' als Quelle (rechts des Operators) angewendet werden.";
524
525 throw new ExecutionException(message);
526
527
528 }
529
530 // As a last resort, just assign it
531 Assignment(instruction.First, result);
532
533 return;
534
535 }
536
541 if (typeDest == typeof(string) || typeSource == typeof(string))
542 {
543
544 string strDst = "" + dst;
545
546 string strSrc = "" + src;
547
548 switch (instruction.OpCode)
549 {
550
551 case OpCode.CEQ:
552 result = strDst == strSrc;
553 break;
554
555 case OpCode.CNE:
556 result = strDst != strSrc;
557 break;
558
559 case OpCode.CG:
560 result = strDst.CompareTo(strSrc) > 0;
561 break;
562
563 case OpCode.CGE:
564 result = strDst.CompareTo(strSrc) >= 0;
565 break;
566
567 case OpCode.CL:
568 result = strDst.CompareTo(strSrc) < 0;
569 break;
570
571 case OpCode.CLE:
572 result = strDst.CompareTo(strSrc) <= 0;
573 break;
574
575 default:
576 throw new ExecutionException("Die Operation '" + instruction.OpCode + "' kann nicht auf den Typ 'String' angewendet werden.");
577
578 }
579
580 Assignment(instruction.First, result);
581
582 return;
583
584 }
585
586 // NEW: CLR/object support while preserving ScriptStack numeric semantics
587 bool numericDest =
588 typeDest == typeof(int) ||
589 typeDest == typeof(float) ||
590 typeDest == typeof(double) ||
591 typeDest == typeof(char);
592
593 bool numericSource =
594 typeSource == typeof(int) ||
595 typeSource == typeof(float) ||
596 typeSource == typeof(double) ||
597 typeSource == typeof(char);
598
599 // Equality/inequality for arbitrary CLR objects (and ScriptStack objects),
600 // BUT keep the old numeric cross-type behaviour (int == float etc.)
601 if ((instruction.OpCode == OpCode.CEQ || instruction.OpCode == OpCode.CNE) && !(numericDest && numericSource))
602 {
603 bool eq = Equals(ClrBridge.ScriptNullToClr(dst), ClrBridge.ScriptNullToClr(src));
604 result = (instruction.OpCode == OpCode.CEQ) ? eq : !eq;
605 Assignment(instruction.First, result);
606 return;
607 }
608
609 // Ordering comparisons for arbitrary CLR objects via IComparable,
610 // again only when we are NOT in the numeric fast-path.
611 if (!(numericDest && numericSource) &&
612 (instruction.OpCode == OpCode.CG || instruction.OpCode == OpCode.CGE || instruction.OpCode == OpCode.CL || instruction.OpCode == OpCode.CLE) &&
613 dst is IComparable cmpDst)
614 {
615 int cmp;
616 try
617 {
618 cmp = cmpDst.CompareTo(ClrBridge.ScriptNullToClr(src));
619 }
620 catch
621 {
622 // last resort: string compare
623 cmp = string.Compare(dst.ToString(), src.ToString(), StringComparison.Ordinal);
624 }
625
626 switch (instruction.OpCode)
627 {
628 case OpCode.CG: result = cmp > 0; break;
629 case OpCode.CGE: result = cmp >= 0; break;
630 case OpCode.CL: result = cmp < 0; break;
631 case OpCode.CLE: result = cmp <= 0; break;
632 }
633
634 Assignment(instruction.First, result);
635 return;
636 }
637
638 double dstVal = 0.0;
639
640 double srcVal = 0.0;
641
642 if (typeDest == typeof(int))
643 dstVal = double.Parse("" + (int)dst);
644
645 else if (typeDest == typeof(float))
646 dstVal = double.Parse("" + (float)dst);
647
648 else if (typeDest == typeof(char))
649 dstVal = double.Parse("" + (char)dst);
650
651 else if (typeDest == typeof(double))
652 dstVal = (double)dst;
653
654 else
655 throw new ExecutionException("Der Typ '" + typeDest.Name + "' kann in relationalen Operationen als Ziel (links des Operators) nicht verarbeitet werden.");
656
657 if (typeSource == typeof(int))
658 srcVal = double.Parse("" + (int)src);
659
660 else if (typeSource == typeof(float))
661 srcVal = double.Parse("" + (float)src);
662
663 else if (typeSource == typeof(char))
664 srcVal = double.Parse("" + (char)src);
665
666 else if (typeSource == typeof(double))
667 srcVal = (double)src;
668
669 else
670 throw new ExecutionException("Der Typ '" + typeSource.Name + "' kann in relationalen Operationen als Quelle (rechts des Operators) nicht verarbeitet werden.");
671
672 switch (instruction.OpCode)
673 {
674
675 case OpCode.CEQ:
676 result = dstVal == srcVal;
677 break;
678
679 case OpCode.CNE:
680 result = dstVal != srcVal;
681 break;
682
683 case OpCode.CG:
684 result = dstVal > srcVal;
685 break;
686
687 case OpCode.CGE:
688 result = dstVal >= srcVal;
689 break;
690
691 case OpCode.CL:
692 result = dstVal < srcVal;
693 break;
694
695 case OpCode.CLE:
696 result = dstVal <= srcVal;
697 break;
698
699 default:
700 throw new ExecutionException("Der OpCode '" + instruction.OpCode + "' kann in einer relationalen Operation nicht verarbeitet werden.");
701
702 }
703
704 Assignment(instruction.First, result);
705
706 }
707
713 private void Logic()
714 {
715
716 string identifier = (string)instruction.First.Value;
717
718 object dst = Evaluate(instruction.First);
719
720 object src = Evaluate(instruction.Second);
721
722 Type typeDest = dst.GetType();
723
724 Type typeSource = src.GetType();
725
726 bool result = false;
727
728 bool dstVal = false;
729
730 bool srcVal = false;
731
732 if (typeSource == typeof(bool))
733 srcVal = (bool)src;
734
735 else if (typeSource == typeof(NullReference))
736 srcVal = false;
737
738 else
739 srcVal = ((double)src != 0.0) ? true : false;
740
741
742 if (typeDest == typeof(bool))
743 dstVal = (bool)dst;
744
745 else if (typeDest == typeof(NullReference))
746 dstVal = false;
747
748 else
749 dstVal = ((double)dst != 0.0) ? true : false;
750
751 switch (instruction.OpCode)
752 {
753
754 case OpCode.AND:
755 result = dstVal && srcVal;
756 break;
757
758 case OpCode.OR:
759 result = dstVal || srcVal;
760 break;
761
762 default:
763 throw new ExecutionException("Der OpCode '" + instruction.OpCode + "' kann in einer logischen Operation nicht verarbeitet werden.");
764
765 }
766
767 Assignment(instruction.First, result);
768
769 }
770
771 private void Iterator(ArrayList array)
772 {
773
774 if (array.Count == 0)
775 return;
776
777 object iterator = Evaluate(instruction.First);
778
779 bool key = false;
780
781 object next = null;
782
783 foreach (object tmp in array.Keys)
784 {
785
786 if (key)
787 {
788 next = tmp;
789 break;
790 }
791
792 if (Equals(tmp, iterator))
793 key = true;
794
795 }
796
797 if (!key)
798 {
799
800 Dictionary<object, object>.KeyCollection.Enumerator keys = array.Keys.GetEnumerator();
801
802 keys.MoveNext();
803
804 next = keys.Current;
805
806 }
807
808 if (next == null)
809 next = NullReference.Instance;
810
811 localMemory[instruction.First.Value.ToString()] = next;
812
813 }
814
815 private void Iterator(IDictionary dict)
816 {
817
818 if (dict.Count == 0)
819 return;
820
821 object iterator = Evaluate(instruction.First);
822
823 bool found = false;
824
825 object next = null;
826
827 foreach (object tmp in dict.Keys)
828 {
829
830 if (found)
831 {
832 next = tmp;
833 break;
834 }
835
836 if (Equals(tmp, iterator))
837 found = true;
838
839 }
840
841 if (!found)
842 {
843 IDictionaryEnumerator en = dict.GetEnumerator();
844 if (en.MoveNext())
845 next = en.Key;
846 }
847
848 if (next == null)
849 next = NullReference.Instance;
850
851 localMemory[instruction.First.Value.ToString()] = next;
852
853 }
854
855
856 private void Iterator(string str)
857 {
858
859 if (str.Length == 0)
860 return;
861
862 object iterator = Evaluate(instruction.First);
863
864 if (iterator.GetType() != typeof(int))
865 {
866
867 localMemory[instruction.First.Value.ToString()] = 0;
868
869 return;
870
871 }
872
873 int elements = (int)iterator;
874
875 if (elements < str.Length - 1)
876 localMemory[instruction.First.Value.ToString()] = elements + 1;
877
878 else
879 localMemory[instruction.First.Value.ToString()] = NullReference.Instance;
880
881 }
882
883
884
885 private void DBG()
886 {
887 }
888
889 private void NOP()
890 {
891 }
892
893 private void INT()
894 {
895 interrupted = true;
896 }
897
901 private void RET()
902 {
903
904 functionStack.Pop();
905
906 if (functionStack.Count == 0)
907 {
908 finished = true;
909 return;
910 }
911
912 localMemory = functionStack.Peek().localMemory;
913
914 }
915
916
917
918 private void PUSH()
919 {
921 }
922
926 private void POP()
927 {
928
929 object tmp = parameterStack.Pop();
930
931 Operand operand = instruction.First;
932
933 // Delegate to the unified Assignment() so Member/Pointer also work for CLR objects.
934 Assignment(operand, tmp);
935
936 }
937
941 private void MOV()
942 {
943
945 }
946
947
951 private void ADD()
952 {
953 Arithmetic();
954 }
955
959 private void SUB()
960 {
961 Arithmetic();
962 }
963
967 private void MUL()
968 {
969 Arithmetic();
970 }
971
975 private void DIV()
976 {
977 Arithmetic();
978 }
979
983 private void MOD()
984 {
985 Arithmetic();
986 }
987
988
989
993 private void INC()
994 {
995
996 string identifier = (string)instruction.First.Value;
997
998 object val = Evaluate(instruction.First);
999
1000 Type typeDest = val.GetType();
1001
1002 if (typeDest == typeof(char))
1003 {
1004 char c = (char)val;
1005 localMemory[identifier] = (char)(c + 1);
1006 }
1007 else if (typeDest == typeof(int))
1008 localMemory[identifier] = (int)val + 1;
1009
1010 else if (typeDest == typeof(float))
1011 localMemory[identifier] = (float)val + 1;
1012
1013 else if (typeDest == typeof(double))
1014 localMemory[identifier] = (double)val + 1;
1015
1016 else if (typeDest == typeof(decimal))
1017 localMemory[identifier] = (decimal)val + 1;
1018
1019 else
1020 throw new ExecutionException("Der Typ '" + typeDest.Name + "' kann nicht inkrementiert werden.");
1021
1022 }
1023
1027 private void DEC()
1028 {
1029
1030 string identifier = (string)instruction.First.Value;
1031
1032 object val = Evaluate(instruction.First);
1033
1034 Type typeDest = val.GetType();
1035
1036 if (typeDest == typeof(char))
1037 {
1038 char c = (char)val;
1039 localMemory[identifier] = (char)(c - 1);
1040 }
1041 else if (typeDest == typeof(int))
1042 localMemory[identifier] = (int)val - 1;
1043
1044 else if (typeDest == typeof(float))
1045 localMemory[identifier] = (float)val - 1;
1046
1047 else if (typeDest == typeof(double))
1048 localMemory[identifier] = (double)val - 1;
1049
1050 else if (typeDest == typeof(decimal))
1051 localMemory[identifier] = (decimal)val - 1;
1052
1053 else
1054 throw new ExecutionException("Der Typ '" + typeDest.Name + "' kann nicht dekrementiert werden.");
1055
1056 }
1057
1061 private void NEG()
1062 {
1063
1064 string identifier = (string)instruction.First.Value;
1065
1066 object val = Evaluate(instruction.First);
1067
1068 Type typeDest = val.GetType();
1069
1070 if (typeDest == typeof(int))
1071 localMemory[identifier] = (int)val * -1;
1072
1073 else if (typeDest == typeof(float))
1074 localMemory[identifier] = (float)val * -1;
1075
1076 else if (typeDest == typeof(double))
1077 localMemory[identifier] = (double)val * -1;
1078
1079 else if (typeDest == typeof(char))
1080 localMemory[identifier] = (char)val * -1;
1081
1082 else
1083 throw new ExecutionException("Der Typ '" + typeDest.Name + "' kann nicht negiert werden.");
1084
1085 }
1086
1090 private void SHL()
1091 {
1092
1093 string identifier = null;
1094
1095 object val = Evaluate(instruction.Second);
1096
1097 Operand operand = instruction.First;
1098
1099 switch (operand.Type)
1100 {
1101
1102 case OperandType.Variable:
1103 int res = (int)localMemory[(string)operand.Value] << (int)val;
1104
1105 identifier = operand.Value.ToString();
1106
1107 localMemory[identifier] = res;
1108
1109 break;
1110
1111 default:
1112 throw new ExecutionException("Der Typ '" + operand.Type + "' kann in Bitoperationen nicht verarbeitet werden.");
1113
1114 }
1115
1116 }
1117
1121 private void SHR()
1122 {
1123
1124 string identifier = null;
1125
1126 object val = Evaluate(instruction.Second);
1127
1128 Operand operand = instruction.First;
1129
1130 switch (operand.Type)
1131 {
1132
1133 case OperandType.Variable:
1134 int res = (int)localMemory[(string)operand.Value] >> (int)val;
1135
1136 identifier = operand.Value.ToString();
1137
1138 localMemory[identifier] = res;
1139
1140 break;
1141
1142 default:
1143 throw new ExecutionException("Der Typ '" + operand.Type + "' kann in Bitoperationen nicht verarbeitet werden.");
1144
1145 }
1146
1147 }
1148
1149
1150
1151 private void TEST()
1152 {
1153
1154 string identifier = (string)instruction.First.Value;
1155
1156 object val = Evaluate(instruction.First);
1157
1158 localMemory[identifier] = val == NullReference.Instance;
1159
1160 }
1161
1165 private void CEQ()
1166 {
1167 Relation();
1168 }
1169
1173 private void CNE()
1174 {
1175 Relation();
1176 }
1177
1181 private void CG()
1182 {
1183 Relation();
1184 }
1185
1189 private void CGE()
1190 {
1191 Relation();
1192 }
1193
1197 private void CL()
1198 {
1199 Relation();
1200 }
1201
1205 private void CLE()
1206 {
1207 Relation();
1208 }
1209
1210
1211
1212 private void OR()
1213 {
1214 Logic();
1215 }
1216
1217 private void AND()
1218 {
1219 Logic();
1220 }
1221
1227 private void NOT()
1228 {
1229
1230 string identifier = (string)instruction.First.Value;
1231
1232 object val = Evaluate(instruction.First);
1233
1234 Type typeDest = val.GetType();
1235
1236 if (typeDest != typeof(bool) && typeDest != typeof(int))
1237 throw new ExecutionException("Der Typ '" + typeDest.Name + "' kann nicht negiert werden.");
1238
1239 if (typeDest == typeof(bool))
1240 localMemory[identifier] = !((bool)val);
1241
1242 else if (typeDest == typeof(int))
1243 localMemory[identifier] = (int)val * -1;
1244
1245 }
1246
1247
1248
1249 private void ORB()
1250 {
1251
1252 string identifier = null;
1253
1254 object val = Evaluate(instruction.Second);
1255
1256 Operand operand = instruction.First;
1257
1258 switch (operand.Type)
1259 {
1260
1261 case OperandType.Variable:
1262 //int res = (int)val | (int)localMemory[(string)operand.Value];
1263 int res = ToInt32Bitwise(localMemory[(string)operand.Value], "|") | ToInt32Bitwise(val, "|");
1264
1265 identifier = operand.Value.ToString();
1266
1267 localMemory[identifier] = res;
1268
1269 break;
1270
1271 default:
1272 throw new ExecutionException("Der Typ '" + operand.Type + "' kann an dieser Stelle nicht verarbeitet werden.");
1273
1274 }
1275
1276 }
1277
1278 private void ANDB()
1279 {
1280
1281 string identifier = null;
1282
1283 object val = Evaluate(instruction.Second);
1284
1285 Operand operand = instruction.First;
1286
1287 switch (operand.Type)
1288 {
1289
1290 case OperandType.Variable:
1291 //int res = (int)localMemory[(string)operand.Value] & (int)val;
1292 int res = ToInt32Bitwise(localMemory[(string)operand.Value], "&") & ToInt32Bitwise(val, "&");
1293
1294 identifier = operand.Value.ToString();
1295
1296 localMemory[identifier] = res;
1297
1298 break;
1299
1300 default:
1301 throw new ExecutionException("Operand type '" + operand.Type + "' not supported by logical AND instruction.");
1302
1303 }
1304
1305 }
1306
1307 private void NOTB()
1308 {
1309
1310 if (instruction.First.Type != OperandType.Variable)
1311 throw new ExecutionException("Operand type '" + instruction.First.Type + "' not supported by NOTB instruction.");
1312
1313 string dest = (string)instruction.First.Value;
1314
1315 object srcObj = Evaluate(instruction.Second);
1316
1317 // (aktuell unterstützt dein Interpreter bei BitOps sowieso int)
1318 int src = (int)srcObj;
1319
1320 localMemory[dest] = ~src;
1321
1322 }
1323
1324 private void XOR()
1325 {
1326
1327 string identifier = null;
1328
1329 object val = Evaluate(instruction.Second);
1330
1331 Operand operand = instruction.First;
1332
1333 switch (operand.Type)
1334 {
1335
1336 case OperandType.Variable:
1337 //int res = (int)val ^ (int)localMemory[(string)operand.Value];
1338 int res = ToInt32Bitwise(localMemory[(string)operand.Value], "^") ^ ToInt32Bitwise(val, "^");
1339
1340 identifier = operand.Value.ToString();
1341
1342 localMemory[identifier] = res;
1343
1344 break;
1345
1346 default:
1347 throw new ExecutionException("Der Typ '" + operand.Type + "' kann an dieser Stelle nicht verarbeitet werden.");
1348
1349 }
1350
1351 }
1352
1356 private void JMP()
1357 {
1358
1359 FunctionFrame frame = functionStack.Peek();
1360
1361 frame.nextInstruction = (int)instruction.First.InstructionPointer.Address;
1362
1363 }
1364
1368 private void JZ()
1369 {
1370
1371 if ((bool)Evaluate(instruction.First))
1372 return;
1373
1374 Instruction target = instruction.Second.InstructionPointer;
1375
1376 FunctionFrame frame = functionStack.Peek();
1377
1378 frame.nextInstruction = (int)target.Address;
1379
1380 }
1381
1385 private void JNZ()
1386 {
1387
1388 if (!(bool)Evaluate(instruction.First))
1389 return;
1390
1391 FunctionFrame frame = functionStack.Peek();
1392
1393 frame.nextInstruction = (int)instruction.Second.InstructionPointer.Address;
1394
1395 }
1396
1397
1398
1399 private void DSB()
1400 {
1401
1402 throw new ExecutionException("DCG opcodes cannot be executed within a function frame.");
1403
1404 }
1405
1406 private void DB()
1407 {
1408
1409 localMemory[(string)instruction.First.Value] = NullReference.Instance;
1410
1411 }
1412
1413 private void DC()
1414 {
1415
1416 if (instruction.First.Type != OperandType.Variable)
1417 throw new ExecutionException("Error in array declaration.");
1418
1419 ArrayList array = new ArrayList();
1420
1421 localMemory[instruction.First.Value.ToString()] = array;
1422
1423 }
1424
1425 private void DCO()
1426 {
1427
1428 string strIdentifier = null;
1429
1430 object objectValue = Evaluate(instruction.Second);
1431
1432 Operand operand = instruction.First;
1433
1434 switch (operand.Type)
1435 {
1436
1437 case OperandType.Variable:
1438 int res = (int)objectValue ^ (int)localMemory[(string)operand.Value];
1439
1440 strIdentifier = operand.Value.ToString();
1441
1442 localMemory[strIdentifier] = res;
1443
1444 break;
1445
1446 default:
1447 throw new ExecutionException("Operand type '" + operand.Type + "' not supported by logical LNEG instruction.");
1448
1449 }
1450
1451 }
1452
1457 private void PTR()
1458 {
1459
1460 if (instruction.First.Type != OperandType.Variable)
1461 throw new ExecutionException("Error in PTR.");
1462
1463 if (instruction.Second.Type != OperandType.Variable)
1464 throw new ExecutionException("Error in PTR.");
1465
1466 string enumerableVar = instruction.Second.Value.ToString();
1467 object enumerable = localMemory[enumerableVar];
1468
1469 if (enumerable is ArrayList a)
1470 {
1471 Iterator(a);
1472 return;
1473 }
1474
1475 if (enumerable is string s)
1476 {
1477 Iterator(s);
1478 return;
1479 }
1480
1481 if (enumerable is IList list)
1482 {
1483 Iterator(list);
1484 return;
1485 }
1486
1487
1488 if (enumerable is IDictionary dict)
1489 {
1490 Iterator(dict);
1491 return;
1492 }
1493
1494 // Any other IEnumerable (e.g. HashSet, IEnumerable<T>, LINQ results)
1495 if (enumerable is IEnumerable en)
1496 {
1497 var materialized = new ArrayList();
1498 foreach (var item in en)
1499 materialized.Add(item ?? NullReference.Instance);
1500
1501 // Replace variable with materialized ArrayList so the existing foreach bytecode
1502 // (which indexes via array[key]) keeps working.
1503 localMemory[enumerableVar] = materialized;
1504 Iterator(materialized);
1505 return;
1506 }
1507
1508 throw new ExecutionException("Error in PTR.");
1509
1510 }
1511
1512
1513 // if any errors add "localMemory = frame.localMemory;" after the allocation
1517 private void CALL()
1518 {
1519
1520 Function function = instruction.First.FunctionPointer;
1521
1522 FunctionFrame frame = new FunctionFrame();
1523
1524 frame.function = function;
1525
1526 frame.localMemory = Memory.AllocateLocalMemory(executable.ScriptMemory);
1527
1528 frame.nextInstruction = (int) function.EntryPoint.Address;
1529
1530 functionStack.Push(frame);
1531
1532 }
1533
1540 private void INV()
1541 {
1542
1543 Routine routine = instruction.First.RoutinePointer;
1544
1545 Host stackHandler = null;
1546
1547 if (routine.Handler == null)
1548 {
1549 if (host != null)
1550 stackHandler = host;
1551 }
1552
1553 else
1554 stackHandler = routine.Handler;
1555
1556 List<object> parameters = new List<object>();
1557
1558 for (int i = 0; i < routine.ParameterTypes.Count; i++)
1559 parameters.Insert(0, parameterStack.Pop());
1560
1561 routine.Verify(parameters);
1562
1563 object objectResult = null;
1564
1565 if (stackHandler != null)
1566 {
1567
1568 try {
1569 objectResult = stackHandler.Invoke(routine.Name, parameters);
1570 }
1571 catch (Exception) {
1572
1573 parameterStack.Push(NullReference.Instance);
1574 return;
1575
1576 }
1577
1578 routine.Verify(objectResult);
1579
1580 }
1581
1582 if (objectResult == null)
1583 objectResult = NullReference.Instance;
1584
1585 parameterStack.Push(objectResult);
1586
1587 if (interrupt)
1588 interrupted = true;
1589
1590 }
1591
1598 private void MIV()
1599 {
1600
1601 if (instruction.First.Type != OperandType.Member)
1602 throw new ExecutionException("Error in MIV.");
1603
1604 string targetIdentifier = instruction.First.Value.ToString();
1605 string methodName = instruction.First.Member?.ToString() ?? "";
1606
1607 int argc = 0;
1608 if (instruction.Second != null)
1609 {
1610 object raw = instruction.Second.Value;
1611 if (raw is int i) argc = i;
1612 else if (raw is string s && int.TryParse(s, out var j)) argc = j;
1613 else throw new ExecutionException("Error in MIV.");
1614 }
1615
1616 object target = localMemory[targetIdentifier];
1617 if (target == null || target is NullReference)
1618 {
1619 parameterStack.Push(NullReference.Instance);
1620 return;
1621 }
1622
1623 // Collect args (preserve order)
1624 List<object> args = new List<object>(argc);
1625 for (int i = 0; i < argc; i++)
1626 args.Insert(0, parameterStack.Pop());
1627
1628 object result = _clr.Invoke(target, methodName, args);
1629 if (result == null)
1630 result = NullReference.Instance;
1631
1632 parameterStack.Push(result);
1633
1634 if (interrupt)
1635 interrupted = true;
1636
1637 }
1638
1639
1715 private void RUN()
1716 {
1717
1718 Function function = instruction.First.FunctionPointer;
1719
1720 List<object> parameters = new List<object>();
1721
1722 for (int i = 0; i < function.ParameterCount; i++)
1723 parameters.Insert(0, parameterStack.Pop());
1724
1725 Interpreter job = new Interpreter(function, parameters, _options);
1726
1727 job.Handler = host;
1728
1729 jobs.Add(job);
1730
1731 }
1732
1733 private void LOCK()
1734 {
1735
1736 object first = Evaluate(instruction.First);
1737
1738 if (first.GetType() == typeof(NullReference))
1739 throw new ExecutionException("Lock key must be a literal value.");
1740
1741 if (script.Manager.Locks.ContainsKey(first))
1742 {
1743
1744 Interpreter locked = script.Manager.Locks[first];
1745
1746 if (locked == this && locks[first] != instruction)
1747 throw new ExecutionException("Nested locks cannot share the same locking key.");
1748
1749 FunctionFrame functionFrame = functionStack.Peek();
1750 --functionFrame.nextInstruction;
1751 interrupted = true;
1752
1753 }
1754
1755 else
1756 {
1757
1758 script.Manager.Locks[first] = this;
1759
1760 locks[first] = instruction;
1761
1762 }
1763
1764 }
1765
1766 private void FREE()
1767 {
1768
1769 object first = Evaluate(instruction.First);
1770
1771 if (first.GetType() == typeof(NullReference))
1772 throw new ExecutionException("Lock key must be a literal value.");
1773
1774 if (!script.Manager.Locks.ContainsKey(first))
1775 throw new ExecutionException("Lock '" + first + "' is already unlocked.");
1776
1777 locks.Remove(first);
1778
1779 script.Manager.Locks.Remove(first);
1780
1781 }
1782
1783
1785 {
1786
1787 uint executed = 0;
1788
1789 foreach (Interpreter job in jobs)
1790 if (!job.Finished)
1791 executed += job.Interpret(1);
1792
1793 for (int i = jobs.Count - 1; i >= 0; i--)
1794 if (jobs[i].Finished)
1795 jobs.RemoveAt(i);
1796
1797 return executed;
1798
1799 }
1800
1801 private void ExecuteInstruction()
1802 {
1803
1804 instruction = executable.InstructionsInternal[functionStack.Peek().nextInstruction++];
1805
1806 switch (instruction.OpCode)
1807 {
1808
1809 case OpCode.DBG: DBG(); break;
1810 case OpCode.NOP: NOP(); break;
1811
1812 case OpCode.INT: INT(); break;
1813 case OpCode.RET: RET(); break;
1814
1815 case OpCode.PUSH: PUSH(); break;
1816 case OpCode.POP: POP(); break;
1817 case OpCode.MOV: MOV(); break;
1818
1819 case OpCode.ADD: Arithmetic(); break;
1820 case OpCode.SUB: Arithmetic(); break;
1821 case OpCode.MUL: Arithmetic(); break;
1822 case OpCode.DIV: Arithmetic(); break;
1823 case OpCode.MOD: Arithmetic(); break;
1824
1825 case OpCode.INC: INC(); break;
1826 case OpCode.DEC: DEC(); break;
1827 case OpCode.NEG: NEG(); break;
1828 case OpCode.SHL: SHL(); break;
1829 case OpCode.SHR: SHR(); break;
1830
1831 case OpCode.TEST: TEST(); break;
1832 case OpCode.CEQ: CEQ(); break;
1833 case OpCode.CNE: CNE(); break;
1834 case OpCode.CG: CG(); break;
1835 case OpCode.CGE: CGE(); break;
1836 case OpCode.CL: CL(); break;
1837 case OpCode.CLE: CLE(); break;
1838
1839 case OpCode.OR: OR(); break;
1840 case OpCode.AND: AND(); break;
1841 case OpCode.NOT: NOT(); break;
1842
1843 case OpCode.ORB: ORB(); break;
1844 case OpCode.ANDB: ANDB(); break;
1845 case OpCode.NOTB: NOTB(); break;
1846 case OpCode.XOR: XOR(); break;
1847
1848 case OpCode.JMP: JMP(); break;
1849 case OpCode.JZ: JZ(); break;
1850 case OpCode.JNZ: JNZ(); break;
1851
1852 case OpCode.DSB: DSB(); break;
1853 case OpCode.DB: DB(); break;
1854 case OpCode.DC: DC(); break;
1855 case OpCode.DCO: DCO(); break;
1856 case OpCode.PTR: PTR(); break;
1857
1858 case OpCode.CALL: CALL(); break;
1859 case OpCode.INV: INV(); break;
1860 case OpCode.MIV: MIV(); break;
1861 case OpCode.RUN: RUN(); break;
1862
1863 case OpCode.LOCK: LOCK(); break;
1864 case OpCode.FREE: FREE(); break;
1865
1866 }
1867
1868 }
1869
1870 #endregion
1871
1872 #region Public Methods
1873
1874 public Interpreter(Function function, List<object> parameters, InterpreterOptions? options = null)
1875 {
1876
1877 if (function.ParameterCount != parameters.Count)
1878 throw new ExecutionException("Die Funktion '" + function.Name + "' wurde mit " + parameters.Count + " statt erwartet " + function.ParameterCount + " Parametern aufgerufen.");
1879
1880 _options = options ?? new InterpreterOptions();
1881 _clr = new ClrBridge(_options.ResolveClrPolicy());
1882
1883 this.function = function;
1884
1885 script = function.Executable.Script;
1886
1887 executable = script.Executable;
1888
1889 functionStack = new Stack<FunctionFrame>();
1890
1891 parameterStack = new Stack<object>();
1892
1893 locks = new Dictionary<object, Instruction>();
1894
1895 jobs = new List<Interpreter>();
1896
1897 host = null;
1898
1899 interrupt = false;
1900
1901 Reset();
1902
1903 foreach (object parameter in parameters)
1904 {
1905
1906 if (parameter == null)
1907 parameterStack.Push(NullReference.Instance);
1908
1909 else
1910 {
1911
1912 Type parameterType = parameter.GetType();
1913
1914 if (parameterType == typeof(NullReference))
1915 parameterStack.Push(NullReference.Instance);
1916
1917 else if (parameterType == typeof(int)
1918 || parameterType == typeof(float)
1919 || parameterType == typeof(double)
1920 || parameterType == typeof(bool)
1921 || parameterType == typeof(string)
1922 || parameterType == typeof(char)
1923 || parameterType == typeof(ArrayList))
1924 parameterStack.Push(parameter);
1925
1926 else
1927 throw new ExecutionException("Der Typ '" + parameterType.Name + "' ist kein generischer Typ.");
1928
1929 }
1930
1931 }
1932
1933 }
1934
1935 public Interpreter(Function function) :
1936 this(function, new List<object>())
1937 {
1938 }
1939
1940 public Interpreter(Script script, List<object> parameters, InterpreterOptions? options = null) :
1941 this(script.Executable.MainFunction, parameters, options)
1942 {
1943 }
1944
1945 public Interpreter(Script script, InterpreterOptions? options = null) :
1946 this(script.Executable.MainFunction, new List<object>(), options)
1947 {
1948 }
1949
1950 public void Reset()
1951 {
1952
1953 functionStack.Clear();
1954
1955 FunctionFrame functionFrame = new FunctionFrame();
1956
1957 functionFrame.function = function;
1958
1959 functionFrame.localMemory = Memory.AllocateLocalMemory(executable.ScriptMemory);
1960
1961 functionFrame.nextInstruction = (int) function.EntryPoint.Address;
1962
1963 functionStack.Push(functionFrame);
1964
1965 parameterStack.Clear();
1966
1967 instruction = null;
1968
1969 localMemory = functionFrame.localMemory;
1970
1971 foreach (object currentLock in locks.Keys)
1972 script.Manager.Locks.Remove(currentLock);
1973
1974 locks.Clear();
1975
1976 finished = false;
1977
1978 interrupted = false;
1979
1980 }
1981
1982 public uint Interpret(uint instructions)
1983 {
1984
1985 localMemory.ExposeTemporaryVariables();
1986
1987 interrupted = false;
1988
1989 uint executed = 0;
1990
1991 while (!Finished && !interrupted && executed < instructions)
1992 {
1993
1995
1996 ++executed;
1997
1998 executed += ExecuteBackgroundJobs();
1999
2000 }
2001
2002 localMemory.HideTemporaryVariables();
2003
2004 return executed;
2005
2006 }
2007
2008 public uint Interpret(TimeSpan interval)
2009 {
2010
2011 DateTime end = DateTime.Now + interval;
2012
2013 localMemory.ExposeTemporaryVariables();
2014
2015 interrupted = false;
2016
2017 uint executed = 0;
2018
2019 while (!Finished && !interrupted)
2020 {
2021
2023
2024 ++executed;
2025
2026 executed += ExecuteBackgroundJobs();
2027
2028 if (DateTime.Now >= end)
2029 break;
2030
2031 }
2032
2033 localMemory.HideTemporaryVariables();
2034
2035 return executed;
2036
2037 }
2038
2039 public uint Interpret()
2040 {
2041
2042 localMemory.ExposeTemporaryVariables();
2043
2044 interrupted = false;
2045
2046 uint executed = 0;
2047
2048 while (!Finished && !interrupted)
2049 {
2050
2052
2053 ++executed;
2054
2055 executed += ExecuteBackgroundJobs();
2056
2057 }
2058
2059 localMemory.HideTemporaryVariables();
2060
2061 return executed;
2062
2063 }
2064
2065 #endregion
2066
2067 #region Public Properties
2068
2070 {
2071 get { return script; }
2072 }
2073
2074 public bool Interrupt
2075 {
2076 get { return interrupt; }
2077 set { interrupt = value; }
2078 }
2079
2080 public ReadOnlyCollection<Interpreter> Jobs
2081 {
2082 get { return jobs.AsReadOnly(); }
2083 }
2084
2085 public bool Interrupted
2086 {
2087 get { return interrupted; }
2088 }
2089
2090 public bool Finished
2091 {
2092 get { return finished; }
2093 }
2094
2096 {
2097 get
2098 {
2099 if (functionStack.Count == 0) return -1;
2100 return functionStack.Peek().nextInstruction;
2101 }
2102 }
2103
2104 public ReadOnlyCollection<Function> FunctionStack
2105 {
2106 get
2107 {
2108 List<Function> listFunctions = new List<Function>();
2109 foreach (FunctionFrame functionFrame in functionStack)
2110 listFunctions.Add(functionFrame.function);
2111 return new List<Function>(listFunctions).AsReadOnly();
2112 }
2113 }
2114
2115 public ReadOnlyCollection<object> ParameterStack
2116 {
2117 get { return new List<object>(parameterStack).AsReadOnly(); }
2118 }
2119
2121 {
2122 get { return localMemory; }
2123 }
2124
2126 {
2127 get { return host; }
2128 set { host = value; }
2129 }
2130
2131 #endregion
2132
2133
2134 private void Iterator(IList list)
2135 {
2136 if (list.Count == 0)
2137 return;
2138
2139 object iterator = Evaluate(instruction.First);
2140
2141 if (iterator.GetType() != typeof(int))
2142 {
2143 localMemory[instruction.First.Value.ToString()] = 0;
2144 return;
2145 }
2146
2147 int i = (int)iterator;
2148
2149 if (i < list.Count - 1)
2150 localMemory[instruction.First.Value.ToString()] = i + 1;
2151 else
2152 localMemory[instruction.First.Value.ToString()] = NullReference.Instance;
2153 }
2154
2155 }
2156
2157}
2158
Centralized CLR interop bridge for ScriptStack. Handles reflection-based member access,...
Definition ClrBridge.cs:17
A function, forward declared in a script.
Definition Function.cs:15
An instruction in a virtual intermediate language.
For every forward declared function, a new function frame is created including a memory object holdin...
void CALL()
Call a Function.
InterpreterOptions _options
Interpreter(Script script, InterpreterOptions? options=null)
void JZ()
Jump to the instruction the second operand is pointing at if the first operand is true.
void Assignment(Operand dst, object val)
Dictionary< object, Instruction > locks
void POP()
Pop a value from the stack into an atom.
ReadOnlyCollection< object > ParameterStack
void NEG()
Negate a literal (* -1).
void Iterator(IDictionary dict)
void JMP()
Jump to the address the first operator points at.
void Iterator(ArrayList array)
int ToInt32Bitwise(object value, string opName="bitwise")
void PTR()
A pointer in foreach loops.
void RUN()
Run a Function in Background.
uint Interpret(TimeSpan interval)
void MOV()
Basic assignment.
void NOT()
Negate a boolean or int.
ReadOnlyCollection< Interpreter > Jobs
Stack< FunctionFrame > functionStack
ReadOnlyCollection< Function > FunctionStack
void JNZ()
Jump to the instruction the second operand is pointing at if the first operand is false.
uint Interpret(uint instructions)
void RET()
Return from current function frame to the last one on the stack, copying local memory to the new one.
void MIV()
Invoke a CLR instance method via reflection.
Interpreter(Script script, List< object > parameters, InterpreterOptions? options=null)
void Arithmetic()
Ausführung arithmetischer Operationen.
void Logic()
Usually its a boolean operation but it allows numerics too.
object Evaluate(Operand operand)
void INV()
Invoke a Routine, if no result is specified a null is pushed onto the stack.
void Relation()
Ausführung einer Vergleichsoperation.
Interpreter(Function function, List< object > parameters, InterpreterOptions? options=null)
Options for the ScriptStack interpreter.
static Memory AllocateLocalMemory(Memory scriptMemory)
Definition Memory.cs:65
A Routine is an abstract representation of a method.
Definition Routine.cs:70
void Verify(List< object > parameters)
Verify the parameter types of a Routine. If null or void was specified values arent verified.
Definition Routine.cs:224
List< Type > ParameterTypes
Definition Routine.cs:313
The main interface to create a Host. A Host can implement Routine's to extend its functionality.
Definition Host.cs:80
object Invoke(string routine, List< object > parameters)
Called when a Routine is invoked.