use crate::parser::{ASTPart, AstBool, AstFunction, AstNull, AstNumber, AstString}; #[derive(Debug, PartialEq)] pub enum State { Running, Paused, Finished, Error(String) } #[derive(Debug, Clone, PartialEq)] pub enum MemoryData { Number(MemoryNumber), String(MemoryString), Boolean(MemoryBoolean), Null(MemoryNull), Function(MemoryFunction) } #[derive(Debug, Clone, PartialEq)] pub struct MemoryNumber { pub key: String, pub value: i64 } #[derive(Debug, Clone, PartialEq)] pub struct MemoryString { pub key: String, pub value: String } #[derive(Debug, Clone, PartialEq)] pub struct MemoryBoolean { pub key: String, pub value: bool } #[derive(Debug, Clone, PartialEq)] pub struct MemoryNull { pub key: String, } #[derive(Debug, Clone, PartialEq)] pub struct MemoryFunction { pub key: String, pub args: Vec, pub body: Vec } pub struct Executor { pub code: Vec, pub pos: usize, pub memory: Vec>, pub state: State, pub breakpoints: Vec, pub max_oppr: usize } impl Executor { pub fn new(code: Vec, max_oppr: usize) -> Executor { return Executor { code, pos: 0, memory: vec![ vec![] ], breakpoints: vec![], state: State::Paused, max_oppr, }; } fn read_memory(&mut self, key: String, check_mode: bool) -> ASTPart { for scope in (0..self.memory.len()).rev() { for data in &self.memory[scope] { match data { MemoryData::Number(num) => { if num.key == key { return ASTPart::Number(AstNumber { value: num.value, pos: 0 }); } }, MemoryData::String(str) => { if str.key == key { return ASTPart::String(AstString { value: str.value.clone(), pos: 0 }); } }, MemoryData::Boolean(bool_data) => { if bool_data.key == key { return ASTPart::Boolean(AstBool { value: bool_data.value, pos: 0 }); } }, MemoryData::Null(null_data) => { if null_data.key == key { return ASTPart::Null(AstNull { pos: 0 }); } }, MemoryData::Function(func) => { if func.key == key { return ASTPart::Function(AstFunction { args: func.args.clone(), body: func.body.clone(), pos: 0 }); } } } } if check_mode { return ASTPart::NOOP; } } return ASTPart::Null(AstNull { pos: 0 }); } fn delete_memory(&mut self, key: String) -> bool { let current_scope = self.memory.len() - 1; for data in 0..self.memory[current_scope].len() { match &self.memory[current_scope][data] { MemoryData::Number(num) => { if num.key == key { self.memory[current_scope].remove(data); return true; } }, MemoryData::String(str) => { if str.key == key { self.memory[current_scope].remove(data); return true; } }, MemoryData::Boolean(bool_data) => { if bool_data.key == key { self.memory[current_scope].remove(data); return true; } }, MemoryData::Null(null_data) => { if null_data.key == key { self.memory[current_scope].remove(data); return true; } }, MemoryData::Function(func) => { if func.key == key { self.memory[current_scope].remove(data); return true; } } } } return false; } fn write_memory(&mut self, key: String, value: ASTPart, update: bool) { if !update { self.delete_memory(key.clone()); } else { let red = self.read_memory(key.clone(), true); match red { ASTPart::NOOP => { self.state = State::Error(format!("Unable to update non-existing memory key: {}", key)); return; }, _ => { self.delete_memory(key.clone()); } } } let current_scope = self.memory.len() - 1; match value { ASTPart::Number(num) => { self.memory[current_scope].push(MemoryData::Number(MemoryNumber { key: key, value: num.value })); }, ASTPart::String(str) => { self.memory[current_scope].push(MemoryData::String(MemoryString { key: key, value: str.value })); }, ASTPart::Boolean(bool_data) => { self.memory[current_scope].push(MemoryData::Boolean(MemoryBoolean { key: key, value: bool_data.value })); }, ASTPart::Null(_) => { self.memory[current_scope].push(MemoryData::Null(MemoryNull { key: key })); }, ASTPart::Function(func) => { self.memory[current_scope].push(MemoryData::Function(MemoryFunction { key: key, args: func.args.clone(), body: func.body.clone() })); } _ => { self.state = State::Error(format!("Unable to write to memory: {:?}", value)); return; } } } fn process_code(&mut self, code: &ASTPart, op_count: &mut usize) -> ASTPart { println!("Processing code: {:?}", code); if self.state != State::Running { return ASTPart::NOOP; } if *op_count >= self.max_oppr { self.state = State::Error(String::from("Too long without yielding!")); return ASTPart::NOOP; } *op_count += 1; match code { ASTPart::String(_) => { return code.clone(); }, ASTPart::Number(_) => { return code.clone(); }, ASTPart::Boolean(_) => { return code.clone(); }, ASTPart::Function(_) => { return code.clone(); }, ASTPart::Assigment(assign) => { let value = self.process_code(&assign.value, op_count); if self.state != State::Running { return ASTPart::NOOP; } self.write_memory(assign.variable.clone(), value, false); return ASTPart::NOOP; }, ASTPart::Operation(op) => { let left = self.process_code(&op.left, op_count); let right = self.process_code(&op.right, op_count); if self.state != State::Running { return ASTPart::NOOP; } if op.operator == "+" { match (&left, &right) { (ASTPart::Number(left_num), ASTPart::Number(right_num)) => { return ASTPart::Number(AstNumber { value: left_num.value + right_num.value, pos: 0 }); }, (ASTPart::String(left_str), ASTPart::String(right_str)) => { return ASTPart::String(AstString { value: left_str.value.clone() + &right_str.value, pos: 0 }); }, _ => { self.state = State::Error(format!("Unable to do operation '+' on {:?} with {:?} at {}", left, right, op.pos)); return ASTPart::NOOP; } } } else if op.operator == "-" { match (&left, &right) { (ASTPart::Number(left_num), ASTPart::Number(right_num)) => { return ASTPart::Number(AstNumber { value: left_num.value - right_num.value, pos: 0 }); }, _ => { self.state = State::Error(format!("Unable to do operation '-' on {:?} with {:?} at {}", left, right, op.pos)); return ASTPart::NOOP; } } } else if op.operator == "*" { match (&left, &right) { (ASTPart::Number(left_num), ASTPart::Number(right_num)) => { return ASTPart::Number(AstNumber { value: left_num.value * right_num.value, pos: 0 }); }, _ => { self.state = State::Error(format!("Unable to do operation '*' on {:?} with {:?} at {}", left, right, op.pos)); return ASTPart::NOOP; } } } else if op.operator == "/" { match (&left, &right) { (ASTPart::Number(left_num), ASTPart::Number(right_num)) => { if right_num.value == 0 { self.state = State::Error(format!("Unable to divide by zero at {}", op.pos)); return ASTPart::NOOP; } return ASTPart::Number(AstNumber { value: left_num.value / right_num.value, pos: 0 }); }, _ => { self.state = State::Error(format!("Unable to do operation '/' on {:?} with {:?} at {}", left, right, op.pos)); return ASTPart::NOOP; } } } else if op.operator == "^" { match (&left, &right) { (ASTPart::Number(left_num), ASTPart::Number(right_num)) => { return ASTPart::Number(AstNumber { value: left_num.value.pow(right_num.value as u32), pos: 0 }); }, _ => { self.state = State::Error(format!("Unable to do operation '^' on {:?} with {:?} at {}", left, right, op.pos)); return ASTPart::NOOP; } } } else if op.operator == "%" { match (&left, &right) { (ASTPart::Number(left_num), ASTPart::Number(right_num)) => { if right_num.value == 0 { self.state = State::Error(format!("Unable to divide by zero at {}", op.pos)); return ASTPart::NOOP; } return ASTPart::Number(AstNumber { value: left_num.value % right_num.value, pos: 0 }); }, _ => { self.state = State::Error(format!("Unable to do operation '%' on {:?} with {:?} at {}", left, right, op.pos)); return ASTPart::NOOP; } } } else { self.state = State::Error(format!("Unknown operator: {} at {}", op.operator, op.pos)); return ASTPart::NOOP; } }, ASTPart::VarRead(var) => { let data = self.read_memory(var.variable.clone(), false); return data; }, ASTPart::VarUpdate(updt) => { let value = self.process_code(&updt.value, op_count); if self.state != State::Running { return ASTPart::NOOP; } self.write_memory(updt.variable.clone(), value, true); return ASTPart::NOOP; }, _ => { return ASTPart::NOOP; } } } pub fn resume(&mut self) { if self.state != State::Paused { panic!("Cannot resume executor, it is not paused."); } self.state = State::Running; let mut op_count: usize = 0; while self.pos < self.code.len() { if self.breakpoints.len() > 0 && self.breakpoints[0] == self.pos { self.state = State::Paused; self.breakpoints.remove(0); break; } self.process_code(&self.code[self.pos].clone(), &mut op_count); if op_count >= self.max_oppr { self.state = State::Error(String::from("Too long without yielding!")); break; } if self.state != State::Running { break; } self.pos += 1; } if self.pos >= self.code.len() { self.state = State::Finished; } } }