use std::{any::Any, collections::HashMap, process, vec}; use crate::{decompiler::{operation_to_name, process, DecompiledFunction, DecompiledOperation}, enviroment, errors::{create_error, print_error, ASLError, ErrorSubType, ErrorType}, Context}; #[derive(Debug, Clone)] pub enum VMMemory { String(VMMemoryString), Number(VMMemoryNumber), Boolean(VMMemoryBoolean), Function(VMMemoryFunction), Null(VMMemoryNull), Table(VMMemoryTable), NativeFunction(VMMemoryNativeFunction), } #[derive(Debug, Clone)] pub struct VMMemoryString { pub value: String, pub variable_id: u32, } #[derive(Debug, Clone)] pub struct VMMemoryNumber { pub value: f64, pub variable_id: u32, } #[derive(Debug, Clone)] pub struct VMMemoryBoolean { pub value: bool, pub variable_id: u32, } #[derive(Debug, Clone)] pub struct VMMemoryFunction { pub id: usize, pub variable_id: u32, } #[derive(Debug, Clone)] pub struct VMMemoryNull { pub variable_id: u32, } #[derive(Debug, Clone)] pub struct VMMemoryTable { pub values: Vec, pub variable_id: u32, } #[derive(Debug, Clone)] pub struct TableValue { pub key: VMMemory, pub value: VMMemory } #[derive(Debug, Clone)] pub struct VMMemoryNativeFunction { pub func: fn(&mut Machine, &DecompiledOperation, Vec) -> VMMemory, pub variable_id: u32, } #[derive(Debug, Clone)] pub struct Register { id: u8, pointer: usize } pub struct CallStack { pub func: usize, pub return_reg: usize, pub pc: usize, } #[derive(Debug, Clone)] enum VMState { Running, Paused, Finished, Error(ASLError), } pub struct Machine { pub memory: Vec, functions: Vec, pub stack: Vec, pub registers: Vec, pub call_stack: Vec, pub env: HashMap, pub ctx: Vec, pub storage: Vec>, pub state: VMState, } fn get_register_by_id(registers: &Vec, id: u8) -> Option<&Register> { for reg in registers { if reg.id == id { return Some(reg); } } None } fn set_register(registers: &mut Vec, new_register: Register) { if new_register.id == 0 { return; } for (i, reg) in registers.iter().enumerate() { if reg.id == new_register.id { registers[i] = new_register; return; } } } fn get_mem_pos_by_var_id(memory: &Vec, var_id: u32) -> Option { for i in 0..memory.len() { match &memory[i] { VMMemory::String(str) if str.variable_id == var_id => return Some(i), VMMemory::Number(num) if num.variable_id == var_id => return Some(i), VMMemory::Boolean(bool) if bool.variable_id == var_id => return Some(i), VMMemory::Null(null) if null.variable_id == var_id => return Some(i), VMMemory::Function(func) if func.variable_id == var_id => return Some(i), VMMemory::Table(tbl) if tbl.variable_id == var_id => return Some(i), VMMemory::NativeFunction(func) if func.variable_id == var_id => return Some(i), _ => continue } } None } fn set_mem_tbl_val(tbl: &mut VMMemoryTable, key: VMMemory, value: VMMemory) { for i in 0..tbl.values.len() { let found = match (&tbl.values[i].key, &key) { (VMMemory::Number(num1), VMMemory::Number(num2)) => num1.value == num2.value, (VMMemory::String(str1), VMMemory::String(str2)) => str1.value == str2.value, (VMMemory::Boolean(bool1), VMMemory::Boolean(bool2)) => bool1.value == bool2.value, (VMMemory::Null(_), VMMemory::Null(_)) => true, (VMMemory::Function(_), VMMemory::Function(_)) => false, (VMMemory::Table(_), VMMemory::Table(_)) => false, (VMMemory::NativeFunction(_), VMMemory::NativeFunction(_)) => false, _ => false, }; if found { tbl.values[i].value = value; return; } } tbl.values.push(TableValue { key, value }); } fn get_mem_tbl_val(tbl: &VMMemoryTable, key: VMMemory) -> Option<&VMMemory> { for i in 0..tbl.values.len() { let found = match (&tbl.values[i].key, &key) { (VMMemory::Number(num1), VMMemory::Number(num2)) => num1.value == num2.value, (VMMemory::String(str1), VMMemory::String(str2)) => str1.value == str2.value, (VMMemory::Boolean(bool1), VMMemory::Boolean(bool2)) => bool1.value == bool2.value, (VMMemory::Null(_), VMMemory::Null(_)) => true, (VMMemory::Function(_), VMMemory::Function(_)) => false, (VMMemory::Table(_), VMMemory::Table(_)) => false, (VMMemory::NativeFunction(_), VMMemory::NativeFunction(_)) => false, _ => false, }; if found { return Some(&tbl.values[i].value); } } None } fn get_var_id(var: &VMMemory) -> u32 { match var { VMMemory::String(str) => str.variable_id, VMMemory::Number(num) => num.variable_id, VMMemory::Boolean(bool) => bool.variable_id, VMMemory::Null(null) => null.variable_id, VMMemory::Function(func) => func.variable_id, VMMemory::Table(tbl) => tbl.variable_id, VMMemory::NativeFunction(func) => func.variable_id, } } fn set_var_id(var: &mut VMMemory, target: u32) { match var { VMMemory::String(str) => str.variable_id = target, VMMemory::Number(num) => num.variable_id = target, VMMemory::Boolean(bool) => bool.variable_id = target, VMMemory::Null(null) => null.variable_id = target, VMMemory::Function(func) => func.variable_id = target, VMMemory::Table(tbl) => tbl.variable_id = target, VMMemory::NativeFunction(func) => func.variable_id = target, } } fn do_operation_operation(registers: &mut Vec, memory: &mut Vec, operation: &DecompiledOperation, ctx: &Context) { let reg_clone = registers.clone(); let reg1 = get_register_by_id(®_clone, operation.arg1); let reg2 = get_register_by_id(®_clone, operation.arg2 as u8); let reg3 = get_register_by_id(®_clone, operation.arg3); if reg1.is_none() || reg2.is_none() || reg3.is_none() { let err = create_error(&format!("One or more registers not found for operation"), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, ctx); print_error(&err, &ctx); process::exit(1); } let mem1 = reg1.unwrap().pointer; let mem2 = reg2.unwrap().pointer; if mem1 >= memory.len() || mem2 >= memory.len() || mem1 < 1 || mem2 < 1 { let err = create_error(&format!("Memory location out of bounds `{}` or `{}`", mem1, mem2), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds, ctx); print_error(&err, &ctx); process::exit(1); } let mut result: VMMemory; match (&memory[mem1], &memory[mem2]) { (VMMemory::Number(num1), VMMemory::Number(num2)) => { match operation.opcode { 10 => { result = VMMemory::Number(VMMemoryNumber { value: num1.value + num2.value, variable_id: 0 }); }, 11 => { result = VMMemory::Number(VMMemoryNumber { value: num1.value - num2.value, variable_id: 0 }); }, 12 => { result = VMMemory::Number(VMMemoryNumber { value: num1.value * num2.value, variable_id: 0 }); }, 13 => { if num2.value == 0.0 { let err = create_error(&format!("Division by zero"), operation.pos, ErrorType::MathError, ErrorSubType::DivisionByZero, ctx); print_error(&err, &ctx); process::exit(1); } result = VMMemory::Number(VMMemoryNumber { value: num1.value / num2.value, variable_id: 0 }); }, 14 => { result = VMMemory::Number(VMMemoryNumber { value: num1.value.powf(num2.value), variable_id: 0 }); }, 15 => { result = VMMemory::Number(VMMemoryNumber { value: num1.value % num2.value, variable_id: 0 }); }, 18 => { result = VMMemory::Boolean(VMMemoryBoolean { value: num1.value == num2.value, variable_id: 0 }); }, 19 => { result = VMMemory::Boolean(VMMemoryBoolean { value: num1.value != num2.value, variable_id: 0 }); }, 20 => { result = VMMemory::Boolean(VMMemoryBoolean { value: num1.value > num2.value, variable_id: 0 }); }, 21 => { result = VMMemory::Boolean(VMMemoryBoolean { value: num1.value >= num2.value, variable_id: 0 }); }, 22 => { result = VMMemory::Boolean(VMMemoryBoolean { value: num1.value < num2.value, variable_id: 0 }); }, 23 => { result = VMMemory::Boolean(VMMemoryBoolean { value: num1.value <= num2.value, variable_id: 0 }); }, _ => { let err = create_error(&format!("Unknown operation code for number operation: `{}`", operation.opcode), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownOPCode, ctx); print_error(&err, &ctx); process::exit(1); } }; }, (VMMemory::String(str1), VMMemory::String(str2)) => { match operation.opcode { 10 => { result = VMMemory::String(VMMemoryString { value: str1.value.clone() + &str2.value, variable_id: 0 }); }, 18 => { result = VMMemory::Boolean(VMMemoryBoolean { value: str1.value == str2.value, variable_id: 0 }); }, 19 => { result = VMMemory::Boolean(VMMemoryBoolean { value: str1.value != str2.value, variable_id: 0 }); }, _ => { let err = create_error(&format!("Unknown operation code for string operation: `{}`", operation.opcode), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownOPCode, ctx); print_error(&err, &ctx); process::exit(1); } }; }, (VMMemory::Boolean(bool1), VMMemory::Boolean(bool2)) => { match operation.opcode { 16 => { result = VMMemory::Boolean(VMMemoryBoolean { value: bool1.value && bool2.value, variable_id: 0 }); }, 17 => { result = VMMemory::Boolean(VMMemoryBoolean { value: bool1.value || bool2.value, variable_id: 0 }); }, 18 => { result = VMMemory::Boolean(VMMemoryBoolean { value: bool1.value == bool2.value, variable_id: 0 }); }, 19 => { result = VMMemory::Boolean(VMMemoryBoolean { value: bool1.value != bool2.value, variable_id: 0 }); }, _ => { let err = create_error(&format!("Unknown operation code for boolean operation: `{}`", operation.opcode), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownOPCode, ctx); print_error(&err, &ctx); process::exit(1); } }; }, (VMMemory::Null(_), VMMemory::Null(_)) => { match operation.opcode { 18 => { result = VMMemory::Boolean(VMMemoryBoolean { value: true, variable_id: 0 }); }, 19 => { result = VMMemory::Boolean(VMMemoryBoolean { value: false, variable_id: 0 }); }, _ => { let err = create_error(&format!("Unknown operation code for null operation: `{}`", operation.opcode), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownOPCode, ctx); print_error(&err, &ctx); process::exit(1); } }; }, _ => { let err = create_error(&format!("Wrong memory types for operation: `{}`, position: `{}` and `{}`", operation_to_name(operation.opcode), mem1, mem2), operation.pos, ErrorType::TypeError, ErrorSubType::WrongType, ctx); print_error(&err, &ctx); process::exit(1); } } let mut reg3_pointer = reg3.unwrap().pointer; if reg3_pointer < 1 { reg3_pointer = memory.len(); memory.push(VMMemory::Null(VMMemoryNull { variable_id: 0 })); set_register(registers, Register { id: operation.arg3, pointer: reg3_pointer }); } let var_id = get_var_id(&memory[reg3_pointer]); set_var_id(&mut result, var_id); memory[reg3_pointer] = result; } impl Machine { pub fn new(ctx: Vec) -> Self { let mut registers = Vec::new(); for i in 0..16 { registers.push(Register { id: i, pointer: 0, }); } return Machine { memory: vec![ VMMemory::Null(VMMemoryNull { variable_id: 0 }) ], functions: Vec::new(), stack: Vec::new(), registers: registers, call_stack: vec![CallStack { func: 0, return_reg: 0, pc: 0, }], env: enviroment::generate(), ctx: ctx, storage: Vec::new(), state: VMState::Finished }; } pub fn load(&mut self, data: &Vec) { let dec = process(data); self.functions = dec.functions; self.state = VMState::Paused } pub fn resume(&mut self) { match self.state { VMState::Paused => {}, _ => { panic!("Unable to resume VM, current state is not paused"); } }; if self.call_stack.len() == 0 { return; } let func_clone = self.functions.clone(); let executed_func = func_clone.get(self.call_stack[self.call_stack.len()-1].func); let mut executed_stack = self.call_stack.len()-1; if executed_func.is_none() { let err = create_error(&format!("Current function not found"), 1, ErrorType::MachineError, ErrorSubType::UnknownFunction, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let mut executed_func = executed_func.unwrap(); self.state = VMState::Running; while self.call_stack[executed_stack].pc < executed_func.body.len() { match self.state { VMState::Running => {}, _ => { return; } }; let operation = &executed_func.body[self.call_stack[executed_stack].pc]; self.call_stack[executed_stack].pc += 1; match operation.opcode { 0 => { //HLT return; }, 1 => { //LDS let str = executed_func.strings.get(&(operation.arg2 as u32)); if str.is_none() { let err = create_error(&format!("String with ID `{}` not found", operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownString, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let str = str.unwrap(); self.memory.push(VMMemory::String(VMMemoryString { value: str.clone(), variable_id: 0 })); set_register(&mut self.registers, Register { id: operation.arg1, pointer: self.memory.len() - 1 }); }, 2 => { //LDM let mem = get_mem_pos_by_var_id(&self.memory, operation.arg2 as u32); if mem.is_none() { let err = create_error(&format!("Memory with variable ID `{}` not found", operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownMemoryLocation, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let mem = mem.unwrap(); if mem >= self.memory.len() || mem < 1 { let err = create_error(&format!("Memory location out of bounds for variable ID `{}`", operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let mut nmem = self.memory[mem].clone(); match &mut nmem { VMMemory::Number(num) => { num.variable_id = 0; }, VMMemory::String(str) => { str.variable_id = 0; }, VMMemory::Boolean(bool) => { bool.variable_id = 0; }, VMMemory::Null(null) => { null.variable_id = 0; }, VMMemory::Function(func) => { func.variable_id = 0; }, VMMemory::Table(tbl) => { tbl.variable_id = 0; }, VMMemory::NativeFunction(func) => { func.variable_id = 0; }, } self.memory.push(nmem); set_register(&mut self.registers, Register { id: operation.arg1, pointer: self.memory.len() - 1 }); }, 3 => { //LDI self.memory.push(VMMemory::Number(VMMemoryNumber { value: operation.arg2, variable_id: 0 })); set_register(&mut self.registers, Register { id: operation.arg1, pointer: self.memory.len() - 1 }); }, 4 => { //LDB self.memory.push(VMMemory::Boolean(VMMemoryBoolean { value: operation.arg2 != 0.0, variable_id: 0 })); set_register(&mut self.registers, Register { id: operation.arg1, pointer: self.memory.len() - 1 }); }, 5 => { //LDF let func_pos = executed_func.functions.get(&(operation.arg2 as u32)); if func_pos.is_none() { let err = create_error(&format!("Function with ID `{}` not found", operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownFunction, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let func_pos = func_pos.unwrap(); let func = self.functions.get(*func_pos as usize); if func.is_none() { let err = create_error(&format!("Function with position `{}` not found", func_pos), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownFunction, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } self.memory.push(VMMemory::Function(VMMemoryFunction { id: *func_pos as usize, variable_id: 0, })); set_register(&mut self.registers, Register { id: operation.arg1, pointer: self.memory.len() - 1 }); }, 6 => { //LDN if operation.arg2 > 0.0 { self.memory.push(VMMemory::Table(VMMemoryTable { values: vec![], variable_id: 0 })); set_register(&mut self.registers, Register { id: operation.arg1, pointer: self.memory.len() - 1 }); } else { self.memory.push(VMMemory::Null(VMMemoryNull { variable_id: 0 })); set_register(&mut self.registers, Register { id: operation.arg1, pointer: self.memory.len() - 1 }); } }, 7 => { //ASS let reg = get_register_by_id(&self.registers, operation.arg1); if reg.is_none() { let err = create_error(&format!("Register `{}` not found", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let reg = reg.unwrap(); if reg.pointer >= self.memory.len() || reg.pointer < 1 { let err = create_error(&format!("Register `{}` points to an invalid memory location", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let used_var = get_mem_pos_by_var_id(&self.memory, operation.arg2 as u32); if let Some(pos) = used_var { set_var_id(&mut self.memory[pos], 0); } set_var_id(&mut self.memory[reg.pointer], operation.arg2 as u32); }, 8 => { //UNB set_register(&mut self.registers, Register { id: operation.arg1, pointer: 0 }); }, 9 => { //MOV let temp_regs = self.registers.clone(); let reg1 = get_register_by_id(&temp_regs, operation.arg1); if reg1.is_none() { let err = create_error(&format!("Register `{}` not found", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let reg1 = reg1.unwrap(); set_register(&mut self.registers, Register { id: operation.arg2 as u8, pointer: reg1.pointer }); }, 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 => { do_operation_operation(&mut self.registers, &mut self.memory, operation, &self.ctx[self.call_stack[executed_stack].func].clone()); }, 24 => { //NOT let reg_clone = self.registers.clone(); let reg1 = get_register_by_id(®_clone, operation.arg1); let reg2 = get_register_by_id(®_clone, operation.arg2 as u8); if reg1.is_none() || reg2.is_none() { let err = create_error(&format!("Register `{}` or `{}` not found", operation.arg1, operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let mem1 = reg1.unwrap().pointer; if mem1 >= self.memory.len() || mem1 < 1 { let err = create_error(&format!("Memory location out of bounds for register `{}`", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let mut result: VMMemory; match &self.memory[mem1] { VMMemory::Boolean(bool) => { result = VMMemory::Boolean(VMMemoryBoolean { value: !bool.value, variable_id: 0 }); }, _ => { let err = create_error(&format!("Wrong memory type for NOT operation, position: `{}`", mem1), operation.pos, ErrorType::TypeError, ErrorSubType::WrongType, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } } let mut reg2_pointer = reg2.unwrap().pointer; if reg2_pointer >= self.memory.len() || reg2_pointer < 1 { reg2_pointer = self.memory.len(); self.memory.push(VMMemory::Null(VMMemoryNull { variable_id: 0 })); set_register(&mut self.registers, Register { id: operation.arg2 as u8, pointer: reg2_pointer }); } let var_id = get_var_id(&self.memory[reg2_pointer]); set_var_id(&mut result, var_id); self.memory[reg2_pointer] = result; }, 25 => { //JMP self.call_stack[executed_stack].pc = operation.arg2 as usize; }, 26 => { //CJP let reg = get_register_by_id(&self.registers, operation.arg1); if reg.is_none() { let err = create_error(&format!("Register `{}` not found", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let reg = reg.unwrap(); let mem = self.memory.get(reg.pointer); if mem.is_none() { let err = create_error(&format!("Memory location not found for register `{}`", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownMemoryLocation, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let mem = mem.unwrap(); match &mem { VMMemory::Boolean(bool) => { if bool.value { self.call_stack[executed_stack].pc = operation.arg2 as usize; } } _ => { let err = create_error(&format!("Wrong memory type for CJP operation, position: `{}`", reg.pointer), operation.pos, ErrorType::TypeError, ErrorSubType::WrongType, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); }, } }, 27 => { //CAL let reg = get_register_by_id(&self.registers, operation.arg1); if reg.is_none() { let err = create_error(&format!("Register `{}` not found", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let reg = reg.unwrap(); let mem = self.memory.get(reg.pointer); if mem.is_none() { let err = create_error(&format!("Memory location not found for register `{}`", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownMemoryLocation, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let mem = mem.unwrap().clone(); match mem { VMMemory::Function(func) => { let arg = 0; for i in &self.stack { let mut new_mem = i.clone(); if self.functions[func.id].variables.len() <= arg || self.functions[func.id].variables[arg].start != 0 { let err = create_error(&format!("Too many arguments supplied for function: `{}`", func.id), operation.pos, ErrorType::SemanticError, ErrorSubType::TooManyArguments, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } set_var_id(&mut new_mem, self.functions[func.id].variables[arg].id); self.memory.push(new_mem); } self.stack.clear(); self.call_stack.push(CallStack { func: func.id, return_reg: operation.arg2 as usize, pc: 0 }); executed_func = &func_clone[func.id]; executed_stack = self.call_stack.len() - 1; }, VMMemory::NativeFunction(nfunc) => { let mut result = (nfunc.func)(self, &operation, self.stack.clone()); let ret_reg = get_register_by_id(&self.registers, operation.arg2 as u8); if ret_reg.is_none() { let err = create_error(&format!("Register `{}` not found", operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let mut ret_pointer = ret_reg.unwrap().pointer; if ret_pointer >= self.memory.len() || ret_pointer < 1 { self.memory.push(VMMemory::Null(VMMemoryNull { variable_id: 0 })); ret_pointer = self.memory.len() - 1; set_register(&mut self.registers, Register { id: operation.arg2 as u8, pointer: ret_pointer }); } let var_id = get_var_id(&self.memory[ret_pointer]); set_var_id(&mut result, var_id); self.memory[ret_pointer] = result; self.stack.clear(); }, _ => { let err = create_error(&format!("Unable to call non-function type"), operation.pos, ErrorType::MachineError, ErrorSubType::NonFunctionCall, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } } }, 28 => { //PSH let reg = get_register_by_id(&self.registers, operation.arg1); if reg.is_none() { let err = create_error(&format!("Register `{}` not found", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let reg = reg.unwrap(); let mem = self.memory.get(reg.pointer); if mem.is_none() { let err = create_error(&format!("Memory location not found for register `{}`", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let mem = mem.unwrap(); self.stack.push(mem.clone()); }, 29 => { //RET let target_reg = get_register_by_id(&self.registers, self.call_stack[executed_stack].return_reg as u8); let ret_reg = get_register_by_id(&self.registers, operation.arg1); if target_reg.is_none() || ret_reg.is_none() { let err = create_error(&format!("Register `{}` or `{}` not found", self.call_stack[executed_stack].return_reg, operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let ret_mem = self.memory.get(ret_reg.unwrap().pointer); if ret_mem.is_none() { let err = create_error(&format!("Memory location not found for register `{}`", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let return_value = ret_mem.unwrap().clone(); let target_reg_pointer = self.memory.len(); self.memory.push(VMMemory::Null(VMMemoryNull { variable_id: 0 })); set_register(&mut self.registers, Register { id: self.call_stack[executed_stack].return_reg as u8, pointer: target_reg_pointer }); self.memory[target_reg_pointer] = return_value; self.call_stack.pop(); if self.call_stack.len() < 1 { return; } executed_stack = self.call_stack.len() - 1; executed_func = &func_clone[self.call_stack[executed_stack].func]; }, 30 => { //GET let reg_clone = self.registers.clone(); if operation.arg1 == 0 { //We use the enviroment instead of a table let reg2 = get_register_by_id(®_clone, operation.arg2 as u8); let reg3 = get_register_by_id(®_clone, operation.arg3); if reg2.is_none() || reg3.is_none() { let err = create_error(&format!("Register `{}` or `{}` not found", operation.arg2, operation.arg3), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let mem2 = self.memory.get(reg2.unwrap().pointer); if mem2.is_none() { let err = create_error(&format!("Memory location out of bounds for register `{}`", operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let mem2 = mem2.unwrap().clone(); let mut result: VMMemory; match mem2 { VMMemory::String(str) => { let ret = self.env.get(&str.value); if ret.is_none() { result = VMMemory::Null(VMMemoryNull { variable_id: 0 }); } else { result = ret.unwrap().clone(); } }, _ => { let err = create_error(&format!("Only string keys are allowed for GET enviroment"), operation.pos, ErrorType::TypeError, ErrorSubType::WrongType, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } } let mut reg3_pointer = reg3.unwrap().pointer; if reg3_pointer >= self.memory.len() || reg3_pointer < 1 { reg3_pointer = self.memory.len(); self.memory.push(VMMemory::Null(VMMemoryNull { variable_id: 0 })); set_register(&mut self.registers, Register { id: operation.arg3, pointer: reg3_pointer }); } let var_id = get_var_id(&self.memory[reg3_pointer]); set_var_id(&mut result, var_id); self.memory[reg3_pointer] = result; continue; } let reg = get_register_by_id(®_clone, operation.arg1); let reg2 = get_register_by_id(®_clone, operation.arg2 as u8); let reg3 = get_register_by_id(®_clone, operation.arg3); if reg.is_none() || reg2.is_none() || reg3.is_none() { let err = create_error(&format!("Register `{}` or `{}` or `{}` not found", operation.arg1, operation.arg2, operation.arg3), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let mem1 = self.memory.get(reg.unwrap().pointer); let mem2 = self.memory.get(reg2.unwrap().pointer); if mem1.is_none() || mem2.is_none() { let err = create_error(&format!("Memory location not found for register `{}` or `{}`", operation.arg1, operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let mem1 = mem1.unwrap().clone(); let mem2 = mem2.unwrap().clone(); let mut value: VMMemory; match mem1 { VMMemory::Table(tbl) => { let tvalue = get_mem_tbl_val(&tbl, mem2); if tvalue.is_none() { value = VMMemory::Null(VMMemoryNull { variable_id: 0 }); } else { value = tvalue.unwrap().clone(); } }, _ => { let err = create_error(&format!("Wrong memory type for GET operation, position: `{}`", reg.unwrap().pointer), operation.pos, ErrorType::TypeError, ErrorSubType::WrongType, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } } let mut reg3_pointer = reg3.unwrap().pointer; if reg3_pointer >= self.memory.len() || reg3_pointer < 1 { reg3_pointer = self.memory.len(); self.memory.push(VMMemory::Null(VMMemoryNull { variable_id: 0 })); set_register(&mut self.registers, Register { id: operation.arg3 as u8, pointer: reg3_pointer }); } let var_id = get_var_id(&self.memory[reg3_pointer]); set_var_id(&mut value, var_id); self.memory[reg3_pointer] = value; }, 31 => { //SET let reg = get_register_by_id(&self.registers, operation.arg1); let reg2 = get_register_by_id(&self.registers, operation.arg2 as u8); let reg3 = get_register_by_id(&self.registers, operation.arg3); if reg.is_none() || reg2.is_none() || reg3.is_none() { let err = create_error(&format!("Register `{}` or `{}` or `{}` not found", operation.arg1, operation.arg2, operation.arg3), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let mem1 = self.memory.get(reg.unwrap().pointer); let mem2 = self.memory.get(reg2.unwrap().pointer); let mem3 = self.memory.get(reg3.unwrap().pointer); if mem1.is_none() || mem2.is_none() || mem3.is_none() { let err = create_error(&format!("Memory location not found for register `{}` or `{}` or `{}`", operation.arg1, operation.arg2, operation.arg3), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } let mem2 = mem2.unwrap().clone(); let mem3 = mem3.unwrap().clone(); let mem1 = self.memory.get_mut(reg.unwrap().pointer).expect("Memory location should exist"); match mem1 { VMMemory::Table(tbl) => { set_mem_tbl_val(tbl, mem2, mem3); }, _ => { let err = create_error(&format!("Wrong memory type for SET operation, position: `{}`", reg.unwrap().pointer), operation.pos, ErrorType::TypeError, ErrorSubType::WrongType, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } } }, _ => { let err = create_error(&format!("Unknown operation code: `{}`", operation.opcode), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownOPCode, &self.ctx[self.call_stack[executed_stack].func].clone()); print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); process::exit(1); } } } self.state = VMState::Finished; } }