341 lines
No EOL
13 KiB
Rust
341 lines
No EOL
13 KiB
Rust
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<String>,
|
|
pub body: Vec<ASTPart>
|
|
}
|
|
|
|
pub struct Executor {
|
|
pub code: Vec<ASTPart>,
|
|
pub pos: usize,
|
|
pub memory: Vec<Vec<MemoryData>>,
|
|
pub state: State,
|
|
pub breakpoints: Vec<usize>,
|
|
pub max_oppr: usize
|
|
}
|
|
|
|
impl Executor {
|
|
pub fn new(code: Vec<ASTPart>, 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;
|
|
}
|
|
}
|
|
} |