private static void initMethodTable() { { Unit Clone(VM vm) { TableUnit this_table = vm.GetTable(0); Dictionary <Unit, Unit> table_copy = new Dictionary <Unit, Unit>(); foreach (KeyValuePair <Unit, Unit> entry in this_table.Map) { table_copy.Add(entry.Key, entry.Value); } TableUnit copy = new TableUnit(table_copy); copy.ExtensionTable = this_table.ExtensionTable; return(new Unit(copy)); } methodTable.Set("clone", new IntrinsicUnit("table_clone", Clone, 1)); ////////////////////////////////////////////////////// Unit Count(VM vm) { TableUnit this_table = vm.GetTable(0); int count = this_table.Count; return(new Unit(count)); } methodTable.Set("count", new IntrinsicUnit("table_count", Count, 1)); ////////////////////////////////////////////////////// Unit Clear(VM vm) { TableUnit this_table = vm.GetTable(0); this_table.Map.Clear(); return(new Unit(UnitType.Null)); } methodTable.Set("clear", new IntrinsicUnit("table_clear", Clear, 1)); ////////////////////////////////////////////////////// Unit ToString(VM vm) { TableUnit this_table = vm.GetTable(0); string value = ""; bool first = true; foreach (KeyValuePair <Unit, Unit> entry in this_table.Map) { if (first) { value += System.Text.RegularExpressions.Regex.Unescape(entry.Key.ToString()) + " : " + System.Text.RegularExpressions.Regex.Unescape(entry.Value.ToString()); first = false; } else { value += ", " + System.Text.RegularExpressions.Regex.Unescape(entry.Key.ToString()) + " : " + System.Text.RegularExpressions.Regex.Unescape(entry.Value.ToString()); } } return(new Unit(value)); } methodTable.Set("to_string", new IntrinsicUnit("table_to_string", ToString, 1)); ////////////////////////////////////////////////////// Unit MakeIterator(VM vm) { TableUnit this_table = vm.GetTable(0); System.Collections.IDictionaryEnumerator enumerator = this_table.Map.GetEnumerator(); TableUnit iterator = new TableUnit(null); iterator.Set("key", new Unit(UnitType.Null)); iterator.Set("value", new Unit(UnitType.Null)); Unit next(VM vm) { if (enumerator.MoveNext()) { iterator.Set("key", (Unit)(enumerator.Key)); iterator.Set("value", (Unit)(enumerator.Value)); return(new Unit(true)); } return(new Unit(false)); }; iterator.Set("next", new IntrinsicUnit("table_iterator_next", next, 0)); return(new Unit(iterator)); } methodTable.Set("iterator", new IntrinsicUnit("table_iterator", MakeIterator, 1)); ////////////////////////////////////////////////////// Unit MakeNumericIterator(VM vm) { TableUnit this_table = vm.GetTable(0); System.Collections.IDictionaryEnumerator enumerator = this_table.Map.GetEnumerator(); TableUnit iterator = new TableUnit(null); iterator.Set("key", new Unit(UnitType.Null)); iterator.Set("value", new Unit(UnitType.Null)); Unit next(VM vm) { while (true) { if (enumerator.MoveNext()) { if (Unit.IsNumeric((Unit)enumerator.Key)) { iterator.Set("key", (Unit)(enumerator.Key)); iterator.Set("value", (Unit)(enumerator.Value)); return(new Unit(true)); } } else { return(new Unit(false)); } } }; iterator.Set("next", new IntrinsicUnit("table_iterator_next", next, 0)); return(new Unit(iterator)); } methodTable.Set("numeric_iterator", new IntrinsicUnit("table_numeric_iterator", MakeNumericIterator, 1)); ////////////////////////////////////////////////////// Unit Indexes(VM vm) { TableUnit this_table = vm.GetTable(0); ListUnit indexes = new ListUnit(null); foreach (Unit v in this_table.Map.Keys) { indexes.Elements.Add(v); } return(new Unit(indexes)); } methodTable.Set("indexes", new IntrinsicUnit("table_indexes", Indexes, 1)); ////////////////////////////////////////////////////// Unit NumericIndexes(VM vm) { TableUnit this_table = vm.GetTable(0); ListUnit indexes = new ListUnit(null); foreach (Unit v in this_table.Map.Keys) { if (Unit.IsNumeric(v)) { indexes.Elements.Add(v); } } return(new Unit(indexes)); } methodTable.Set("numeric_indexes", new IntrinsicUnit("table_numeric_indexes", NumericIndexes, 1)); ////////////////////////////////////////////////////// Unit SetExtensionTable(VM vm) { Unit this_unit = vm.GetUnit(0); TableUnit extension_table = vm.GetTable(1); if (extension_table.GetExtensionTable() != null) { throw new Exception("Extension Table has an Extention Table!"); } if (this_unit.heapUnitValue.GetExtensionTable() != null) { throw new Exception("Table already has an Extention Table!"); } this_unit.heapUnitValue.SetExtensionTable(extension_table); return(new Unit(UnitType.Null)); } methodTable.Set("set_extension_table", new IntrinsicUnit("table_set_extension_table", SetExtensionTable, 2)); ////////////////////////////////////////////////////// Unit UnsetExtensionTable(VM vm) { Unit this_unit = vm.GetUnit(0); this_unit.heapUnitValue.UnsetExtensionTable(); return(new Unit(UnitType.Null)); } methodTable.Set("unset_extension_table", new IntrinsicUnit("table_unset_extension_table", UnsetExtensionTable, 1)); ////////////////////////////////////////////////////// Unit GetExtensionTable(VM vm) { Unit this_unit = vm.GetUnit(0); TableUnit extension_table = this_unit.heapUnitValue.GetExtensionTable(); if (extension_table == null) { return(new Unit(UnitType.Null)); } return(new Unit(extension_table)); } methodTable.Set("get_extension_table", new IntrinsicUnit("table_get_extension_table", GetExtensionTable, 1)); ////////////////////////////////////////////////////// Unit Merge(VM vm) { TableUnit this_table = vm.GetTable(0); TableUnit merging_table = vm.GetTable(1); foreach (KeyValuePair <Unit, Unit> u in merging_table.Map) { if (!this_table.Map.ContainsKey(u.Key)) { this_table.Map.Add(u.Key, u.Value); } } return(new Unit(UnitType.Null)); } methodTable.Set("merge", new IntrinsicUnit("merge", Merge, 2)); } }
private VMResult Run() { Instruction instruction; while (true) { instruction = instructionsCache[IP]; switch (instruction.opCode) { case OpCode.POP: IP++; stack.Pop(); break; case OpCode.DUP: IP++; stack.Push(stack.Peek()); break; case OpCode.LOAD_DATA: IP++; stack.Push(data[instruction.opA]); break; case OpCode.LOAD_VARIABLE: IP++; stack.Push(variables.GetAt(instruction.opA, CalculateEnvShift(instruction.opB))); break; case OpCode.LOAD_GLOBAL: IP++; if (parallelVM == true) { lock (globals.Get(instruction.opA).heapUnitValue) // needed because global may be loaded from parallel functions stack.Push(globals.Get(instruction.opA)); } else { stack.Push(globals.Get(instruction.opA)); } break; case OpCode.LOAD_IMPORTED_GLOBAL: IP++; stack.Push(modules[instruction.opB].GetGlobal(instruction.opA)); break; case OpCode.LOAD_IMPORTED_DATA: IP++; stack.Push(modules[instruction.opB].GetData(instruction.opA)); break; case OpCode.LOAD_UPVALUE: IP++; if (parallelVM == true) { lock (upValues.GetAt(instruction.opA)) // needed because upvalue may be loaded from parallel functions stack.Push(upValues.GetAt(instruction.opA).UpValue); } else { stack.Push(upValues.GetAt(instruction.opA).UpValue); } break; case OpCode.LOAD_NIL: IP++; stack.Push(new Unit(UnitType.Null)); break; case OpCode.LOAD_TRUE: IP++; stack.Push(new Unit(true)); break; case OpCode.LOAD_FALSE: IP++; stack.Push(new Unit(false)); break; case OpCode.LOAD_INTRINSIC: IP++; stack.Push(new Unit(Intrinsics[instruction.opA])); break; case OpCode.DECLARE_VARIABLE: IP++; variables.Add(stack.Pop()); break; case OpCode.DECLARE_GLOBAL: IP++; // lock(globals) // not needed because global declaration can not happen inside parallel functions globals.Add(stack.Pop()); break; case OpCode.DECLARE_FUNCTION: { IP++; Operand env = instruction.opA; Operand is_function_expression = instruction.opB; Operand new_fun_address = instruction.opC; Unit this_callable = data[new_fun_address]; if (this_callable.Type == UnitType.Function) { if (is_function_expression == 0) { if (env == 0) // Global { // lock(globals) // not needed because global declaration can not happen inside parallel functions globals.Add(this_callable); } else { variables.Add(this_callable); } } else { stack.Push(this_callable); } } else { ClosureUnit this_closure = (ClosureUnit)(this_callable.heapUnitValue); // new upvalues List <UpValueUnit> new_upValues = new List <UpValueUnit>(); foreach (UpValueUnit u in this_closure.UpValues) { // here we convert env from shift based to absolute based UpValueUnit new_upvalue = registeredUpValues.Get(u.Address, CalculateEnvShiftUpVal(u.Env)); new_upValues.Add(new_upvalue); } ClosureUnit new_closure = new ClosureUnit(this_closure.Function, new_upValues); Unit new_closure_unit = new Unit(new_closure); if (is_function_expression == 0) { if (env == 0) // yes they exist! { // lock(globals) // not needed because global declaration can not happen inside parallel functions globals.Add(new_closure_unit); } else { variables.Add(new_closure_unit); } } else { stack.Push(new_closure_unit); } } break; } case OpCode.ASSIGN_VARIABLE: { IP++; Unit old_value = variables.GetAt(instruction.opA, CalculateEnvShift(instruction.opB)); Unit result; switch (instruction.opC) { case ASSIGN: variables.SetAt(stack.Peek(), instruction.opA, CalculateEnvShift(instruction.opB)); break; case ADDITION_ASSIGN: result = old_value + stack.Peek(); variables.SetAt(result, instruction.opA, CalculateEnvShift(instruction.opB)); break; case SUBTRACTION_ASSIGN: result = old_value - stack.Peek(); variables.SetAt(result, instruction.opA, CalculateEnvShift(instruction.opB)); break; case MULTIPLICATION_ASSIGN: result = old_value * stack.Peek(); variables.SetAt(result, instruction.opA, CalculateEnvShift(instruction.opB)); break; case DIVISION_ASSIGN: result = old_value / stack.Peek(); variables.SetAt(result, instruction.opA, CalculateEnvShift(instruction.opB)); break; default: throw new Exception("Unknown operator"); } break; } case OpCode.ASSIGN_GLOBAL: { IP++; Operand address = instruction.opA; Operand op = instruction.opB; Unit new_value = stack.Peek(); if (parallelVM == true) { switch (op) { case ASSIGN: lock (globals.Get(address).heapUnitValue) globals.Set(new_value, address); break; case ADDITION_ASSIGN: lock (globals.Get(address).heapUnitValue){ Unit result = globals.Get(address) + new_value; globals.Set(result, address); } break; case SUBTRACTION_ASSIGN: lock (globals.Get(address).heapUnitValue){ Unit result = globals.Get(address) - new_value; globals.Set(result, address); } break; case MULTIPLICATION_ASSIGN: lock (globals.Get(address).heapUnitValue){ Unit result = globals.Get(address) * new_value; globals.Set(result, address); } break; case DIVISION_ASSIGN: lock (globals.Get(address).heapUnitValue){ Unit result = globals.Get(address) / new_value; globals.Set(result, address); } break; default: throw new Exception("Unknown operator"); } } else { Unit result; switch (op) { case ASSIGN: globals.Set(new_value, address); break; case ADDITION_ASSIGN: result = globals.Get(address) + new_value; globals.Set(result, address); break; case SUBTRACTION_ASSIGN: result = globals.Get(address) - new_value; globals.Set(result, address); break; case MULTIPLICATION_ASSIGN: result = globals.Get(address) * new_value; globals.Set(result, address); break; case DIVISION_ASSIGN: result = globals.Get(address) / new_value; globals.Set(result, address); break; default: throw new Exception("Unknown operator"); } } break; } case OpCode.ASSIGN_IMPORTED_GLOBAL: IP++; modules[instruction.opB].SetOpGlobal(stack.Peek(), instruction.opC, instruction.opA); break; case OpCode.ASSIGN_UPVALUE: IP++; if (parallelVM == true) { UpValueUnit this_upValue; this_upValue = upValues.GetAt(instruction.opA); switch (instruction.opB) { case ASSIGN: lock (this_upValue) this_upValue.UpValue = stack.Peek(); break; case ADDITION_ASSIGN: lock (this_upValue) this_upValue.UpValue = upValues.GetAt(instruction.opA).UpValue + stack.Peek(); break; case SUBTRACTION_ASSIGN: lock (this_upValue) this_upValue.UpValue = upValues.GetAt(instruction.opA).UpValue - stack.Peek(); break; case MULTIPLICATION_ASSIGN: lock (this_upValue) this_upValue.UpValue = upValues.GetAt(instruction.opA).UpValue *stack.Peek(); break; case DIVISION_ASSIGN: lock (this_upValue) this_upValue.UpValue = upValues.GetAt(instruction.opA).UpValue / stack.Peek(); break; default: throw new Exception("Unknown operator"); } } else { UpValueUnit this_upValue = upValues.GetAt(instruction.opA); switch (instruction.opB) { case ASSIGN: this_upValue.UpValue = stack.Peek(); break; case ADDITION_ASSIGN: this_upValue.UpValue = this_upValue.UpValue + stack.Peek(); break; case SUBTRACTION_ASSIGN: this_upValue.UpValue = this_upValue.UpValue - stack.Peek(); break; case MULTIPLICATION_ASSIGN: this_upValue.UpValue = this_upValue.UpValue * stack.Peek(); break; case DIVISION_ASSIGN: this_upValue.UpValue = this_upValue.UpValue / stack.Peek(); break; default: throw new Exception("Unknown operator"); } } break; case OpCode.GET: { IP++; Operand indexes_counter = instruction.opA; Unit[] indexes = new Unit[indexes_counter]; for (int i = indexes_counter - 1; i >= 0; i--) { indexes[i] = stack.Pop(); } Unit value = stack.Pop(); foreach (Unit v in indexes) { value = (value.heapUnitValue).Get(v); } stack.Push(value); break; } case OpCode.SET: { IP++; Operand indexes_counter = instruction.opA; Operand op = instruction.opB; Unit[] indexes = new Unit[indexes_counter]; for (int i = indexes_counter - 1; i >= 0; i--) { indexes[i] = stack.Pop(); } Unit this_table = stack.Pop(); for (int i = 0; i < indexes_counter - 1; i++) { Unit v = indexes[i]; this_table = (this_table.heapUnitValue).Get(v); } Unit new_value = stack.Peek(); Unit index = indexes[indexes_counter - 1]; UnitType index_type = indexes[indexes_counter - 1].Type; if (op == ASSIGN) { ((this_table.heapUnitValue)).Set(index, new_value); } else if (parallelVM == true) { Unit old_value; Unit result; switch (op) { case ADDITION_ASSIGN: lock (this_table.heapUnitValue){ old_value = ((TableUnit)(this_table.heapUnitValue)).Get(index); result = old_value + new_value; (this_table.heapUnitValue).Set(index, result); } break; case SUBTRACTION_ASSIGN: lock (this_table.heapUnitValue){ old_value = ((TableUnit)(this_table.heapUnitValue)).Get(index); result = old_value - new_value; (this_table.heapUnitValue).Set(index, result); } break; case MULTIPLICATION_ASSIGN: lock (this_table.heapUnitValue){ old_value = ((TableUnit)(this_table.heapUnitValue)).Get(index); result = old_value * new_value; (this_table.heapUnitValue).Set(index, result); } break; case DIVISION_ASSIGN: lock (this_table.heapUnitValue){ old_value = ((TableUnit)(this_table.heapUnitValue)).Get(index); result = old_value / new_value; (this_table.heapUnitValue).Set(index, result); } break; default: throw new Exception("Unknown operator"); } } else { Unit old_value = (this_table.heapUnitValue).Get(index); Unit result; switch (op) { case ADDITION_ASSIGN: result = old_value + new_value; break; case SUBTRACTION_ASSIGN: result = old_value - new_value; break; case MULTIPLICATION_ASSIGN: result = old_value * new_value; break; case DIVISION_ASSIGN: result = old_value / new_value; break; default: throw new Exception("Unknown operator"); } (this_table.heapUnitValue).Set(index, result); } break; } case OpCode.JUMP: IP += instruction.opA; break; case OpCode.JUMP_IF_NOT_TRUE: if (stack.Pop().ToBool() == false) { IP += instruction.opA; } else { IP++; } break; case OpCode.JUMP_BACK: IP -= instruction.opA; break; case OpCode.OPEN_ENV: IP++; EnvPush(); break; case OpCode.CLOSE_ENV: IP++; EnvPop(); break; case OpCode.RETURN: IP = instructions.PopRET(); break; case OpCode.RETURN_SET: instructions.PushRET((Operand)(instruction.opA + IP)); IP++; break; case OpCode.ADD: { IP++; Unit opB = stack.Pop(); stack.Push(stack.Pop() + opB); break; } case OpCode.APPEND: { IP++; Unit opB = stack.Pop(); string result = stack.Pop().ToString() + opB.ToString(); stack.Push(new Unit(result)); break; } case OpCode.SUBTRACT: { IP++; Unit opB = stack.Pop(); stack.Push(stack.Pop() - opB); break; } case OpCode.MULTIPLY: IP++; stack.Push(stack.Pop() * stack.Pop()); break; case OpCode.DIVIDE: { IP++; Unit opB = stack.Pop(); stack.Push(stack.Pop() / opB); break; } case OpCode.NEGATE: IP++; stack.Push(-stack.Pop()); break; case OpCode.INCREMENT: IP++; stack.Push(stack.Pop() + 1); break; case OpCode.DECREMENT: IP++; stack.Push(stack.Pop() - 1); break; case OpCode.EQUALS: IP++; stack.Push(new Unit(stack.Pop().Equals(stack.Pop()))); break; case OpCode.NOT_EQUALS: IP++; stack.Push(new Unit(!stack.Pop().Equals(stack.Pop()))); break; case OpCode.GREATER_EQUALS: IP++; // the values are popped out of order from stack, so the logic is inverted! stack.Push(new Unit(stack.Pop().floatValue <= stack.Pop().floatValue)); break; case OpCode.LESS_EQUALS: IP++; // the values are popped out of order from stack, so the logic is inverted! stack.Push(new Unit(stack.Pop().floatValue >= stack.Pop().floatValue)); break; case OpCode.GREATER: IP++; // the values are popped out of order from stack, so the logic is inverted! stack.Push(new Unit(stack.Pop().floatValue < stack.Pop().floatValue)); break; case OpCode.LESS: IP++; // the values are popped out of order from stack, so the logic is inverted! stack.Push(new Unit(stack.Pop().floatValue > stack.Pop().floatValue)); break; case OpCode.NOT: IP++; stack.Push(new Unit(!stack.Pop().ToBool())); break; case OpCode.AND: { IP++; Unit opB = stack.Pop(); stack.Push(new Unit(stack.Pop().ToBool() && opB.ToBool())); break; } case OpCode.OR: { IP++; Unit opB = stack.Pop(); stack.Push(new Unit(stack.Pop().ToBool() || opB.ToBool())); break; } case OpCode.XOR: { IP++; Unit opB = stack.Pop(); stack.Push(new Unit(stack.Pop().ToBool() ^ opB.ToBool())); break; } case OpCode.NAND: { IP++; Unit opB = stack.Pop(); stack.Push(new Unit(!(stack.Pop().ToBool() && opB.ToBool()))); break; } case OpCode.NOR: { IP++; Unit opB = stack.Pop(); stack.Push(new Unit(!(stack.Pop().ToBool() || opB.ToBool()))); break; } case OpCode.XNOR: { IP++; Unit opB = stack.Pop(); stack.Push(new Unit(!(stack.Pop().ToBool() ^ opB.ToBool()))); break; } case OpCode.CLOSE_CLOSURE: upValues.PopEnv(); EnvSet(instructions.TargetEnv); IP = instructions.PopFunction(out instructionsCache); break; case OpCode.CLOSE_FUNCTION: EnvSet(instructions.TargetEnv); IP = instructions.PopFunction(out instructionsCache); break; case OpCode.NEW_TABLE: { IP++; TableUnit new_table = new TableUnit(null); int n_table = instruction.opA; for (int i = 0; i < n_table; i++) { Unit val = stack.Pop(); Unit key = stack.Pop(); new_table.Map.Add(key, val); } stack.Push(new Unit(new_table)); break; } case OpCode.NEW_LIST: { IP++; ListUnit new_list = new ListUnit(null); int n_table = instruction.opA; for (int i = 0; i < n_table; i++) { Unit val = stack.Pop(); new_list.Elements.Add(val); } stack.Push(new Unit(new_list)); break; } case OpCode.CALL: { IP++; Unit this_callable = stack.Pop(); UnitType this_type = this_callable.Type; if (this_type == UnitType.Function) { FunctionUnit this_func = (FunctionUnit)this_callable.heapUnitValue; instructions.PushRET(IP); instructions.PushFunction(this_func, Env, out instructionsCache); IP = 0; } else if (this_type == UnitType.Closure) { ClosureUnit this_closure = (ClosureUnit)this_callable.heapUnitValue; upValues.PushEnv(); foreach (UpValueUnit u in this_closure.UpValues) { upValues.Add(u); } instructions.PushRET(IP); instructions.PushFunction(this_closure.Function, Env, out instructionsCache); IP = 0; } else if (this_type == UnitType.Intrinsic) { IntrinsicUnit this_intrinsic = (IntrinsicUnit)this_callable.heapUnitValue; Unit result = this_intrinsic.Function(this); stack.top -= this_intrinsic.Arity; stack.Push(result); } else { Error("Trying to call a " + this_callable.Type); return(new VMResult(VMResultType.OK, new Unit(UnitType.Null))); } break; } case OpCode.PUSH_STASH: IP++; stack.PushStash(); break; case OpCode.POP_STASH: IP++; stack.PopStash(); break; case OpCode.EXIT: if (stack.top > 0) { return(new VMResult(VMResultType.OK, stack.Pop())); } return(new VMResult(VMResultType.OK, new Unit(UnitType.Null))); default: Error("Unkown OpCode: " + instruction.opCode); return(new VMResult(VMResultType.ERROR, new Unit(UnitType.Null))); } } }
private static void initMethodTable() { { ////////////////////////////////////////////////////// Unit Clone(VM vm) { ListUnit this_list = vm.GetList(0); List <Unit> new_list_elements = new List <Unit>(); foreach (Unit v in this_list.Elements) { new_list_elements.Add(v); } ListUnit new_list = new ListUnit(new_list_elements); new_list.MethodTable = this_list.MethodTable; return(new Unit(new_list)); } methodTable.Set("clone", new IntrinsicUnit("list_clone", Clone, 1)); ////////////////////////////////////////////////////// Unit Count(VM vm) { ListUnit this_list = vm.GetList(0); int count = this_list.Count; return(new Unit(count)); } methodTable.Set("count", new IntrinsicUnit("list_count", Count, 1)); ////////////////////////////////////////////////////// Unit Clear(VM vm) { ListUnit this_list = vm.GetList(0); this_list.Elements.Clear(); return(new Unit(UnitType.Null)); } methodTable.Set("clear", new IntrinsicUnit("list_clear", Clear, 1)); ////////////////////////////////////////////////////// Unit ToString(VM vm) { ListUnit this_list = vm.GetList(0); bool first = true; string value = ""; foreach (Unit v in this_list.Elements) { if (first) { value += System.Text.RegularExpressions.Regex.Unescape(v.ToString()); first = false; } else { value += ", " + System.Text.RegularExpressions.Regex.Unescape(v.ToString()); } } return(new Unit(value)); } methodTable.Set("to_string", new IntrinsicUnit("list_to_string", ToString, 1)); ////////////////////////////////////////////////////// Unit MakeIndexesIterator(VM vm) { ListUnit this_list = vm.GetList(0); int i = -1; TableUnit iterator = new TableUnit(null); Unit next(VM vm) { if (i < (this_list.Count - 1)) { i++; iterator.Set("key", i); iterator.Set("value", this_list.Elements[i]); return(new Unit(true)); } return(new Unit(false)); }; iterator.Set("next", new IntrinsicUnit("list_index_iterator_next", next, 0)); return(new Unit(iterator)); } methodTable.Set("index_iterator", new IntrinsicUnit("list_index_iterator", MakeIndexesIterator, 1)); ////////////////////////////////////////////////////// Unit MakeIterator(VM vm) { ListUnit this_list = vm.GetList(0); int i = -1; Unit value = new Unit(UnitType.Null); TableUnit iterator = new TableUnit(null); Unit next(VM vm) { if (i < (this_list.Count - 1)) { i++; iterator.Set("value", this_list.Elements[i]); return(new Unit(true)); } return(new Unit(false)); }; iterator.Set("next", new IntrinsicUnit("list_iterator_next", next, 0)); return(new Unit(iterator)); } methodTable.Set("iterator", new IntrinsicUnit("list_iterator", MakeIterator, 1)); ////////////////////////////////////////////////////// Unit Init(VM vm) { ListUnit this_list = vm.GetList(0); Integer new_end = vm.GetInteger(1); int size = this_list.Count; for (int i = size; i < new_end; i++) { this_list.Elements.Add(new Unit(UnitType.Null)); } return(new Unit(UnitType.Null)); } methodTable.Set("init", new IntrinsicUnit("list_init", Init, 2)); ////////////////////////////////////////////////////// Unit Push(VM vm) { ListUnit this_list = vm.GetList(0); Unit value = vm.GetUnit(1); this_list.Elements.Add(value); return(new Unit(UnitType.Null)); } methodTable.Set("push", new IntrinsicUnit("list_push", Push, 2)); ////////////////////////////////////////////////////// Unit Pop(VM vm) { ListUnit this_list = vm.GetList(0); Float value = this_list.Elements[^ 1].floatValue;