989 lines
No EOL
47 KiB
Rust
989 lines
No EOL
47 KiB
Rust
use std::{collections::HashMap, process, vec};
|
|
use crate::{enviroment, errors::{create_error, print_error, ErrorSubType, ErrorType}, Context};
|
|
|
|
const ASXVERSION: [u8; 3] = [0,1,0];
|
|
|
|
#[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: i64,
|
|
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<TableValue>,
|
|
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, Vec<VMMemory>) -> VMMemory,
|
|
pub variable_id: u32,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
struct DecompiledFunction {
|
|
body: Vec<DecompiledOperation>,
|
|
variables: Vec<Variable>,
|
|
strings: HashMap<u32, String>,
|
|
functions: HashMap<u32, u32>
|
|
}
|
|
#[derive(Debug, Clone)]
|
|
struct DecompiledOperation {
|
|
opcode: u8,
|
|
arg1: u8,
|
|
arg2: i64,
|
|
arg3: u8,
|
|
pos: usize,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct Register {
|
|
id: u8,
|
|
pointer: usize
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
struct Variable {
|
|
name: String,
|
|
id: u32,
|
|
start: usize,
|
|
end: usize
|
|
}
|
|
|
|
pub struct CallStack {
|
|
func: usize,
|
|
return_reg: usize,
|
|
pc: usize,
|
|
}
|
|
|
|
pub struct Machine {
|
|
pub memory: Vec<VMMemory>,
|
|
functions: Vec<DecompiledFunction>,
|
|
pub stack: Vec<VMMemory>,
|
|
pub registers: Vec<Register>,
|
|
pub call_stack: Vec<CallStack>,
|
|
pub env: HashMap<String, VMMemory>,
|
|
pub ctx: Vec<Context>,
|
|
}
|
|
|
|
fn read_be_num(input: &[u8]) -> usize {
|
|
let mut result: usize = 0;
|
|
for i in 0..input.len() {
|
|
result <<= 8;
|
|
result |= input[i] as usize;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
fn read_str(input: &[u8]) -> String {
|
|
let mut result = String::new();
|
|
for &byte in input {
|
|
result.push(byte as char);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
fn read_bin(input: &[u8]) -> String {
|
|
let mut result = String::new();
|
|
for &byte in input {
|
|
result.push_str(&format!("{:08b}", byte));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
fn bin_to_num(bin: String) -> usize {
|
|
let mut result: usize = 0;
|
|
for (i, c) in bin.chars().rev().enumerate() {
|
|
if c == '1' {
|
|
result += 1 << i;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
fn bin_to_snum(bin: String) -> i64 {
|
|
let mut result: i64 = 0;
|
|
let mut is_negative = false;
|
|
for (i, c) in bin.chars().rev().enumerate() {
|
|
if c == '1' {
|
|
if i == bin.len() - 1 {
|
|
is_negative = true;
|
|
} else {
|
|
result += 1 << i;
|
|
}
|
|
}
|
|
}
|
|
if is_negative {
|
|
result = -result;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
fn get_register_by_id(registers: &Vec<Register>, id: u8) -> Option<&Register> {
|
|
for reg in registers {
|
|
if reg.id == id {
|
|
return Some(reg);
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
fn set_register(registers: &mut Vec<Register>, 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<VMMemory>, var_id: u32) -> Option<usize> {
|
|
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 operation_to_name(opcode: u8) -> String {
|
|
match opcode {
|
|
0 => "HLT".to_string(),
|
|
1 => "LDS".to_string(),
|
|
2 => "LDM".to_string(),
|
|
3 => "LDI".to_string(),
|
|
4 => "LDB".to_string(),
|
|
5 => "LDF".to_string(),
|
|
6 => "LDN".to_string(),
|
|
7 => "ASS".to_string(),
|
|
8 => "UNB".to_string(),
|
|
9 => "MOV".to_string(),
|
|
10 => "ADD".to_string(),
|
|
11 => "SUB".to_string(),
|
|
12 => "MUL".to_string(),
|
|
13 => "DIV".to_string(),
|
|
14 => "POW".to_string(),
|
|
15 => "MOD".to_string(),
|
|
16 => "AND".to_string(),
|
|
17 => "OR".to_string(),
|
|
18 => "EQ".to_string(),
|
|
19 => "NEQ".to_string(),
|
|
20 => "GRE".to_string(),
|
|
21 => "GRQ".to_string(),
|
|
22 => "LES".to_string(),
|
|
23 => "LEQ".to_string(),
|
|
24 => "NOT".to_string(),
|
|
25 => "JMP".to_string(),
|
|
26 => "CJP".to_string(),
|
|
27 => "CAL".to_string(),
|
|
28 => "PSH".to_string(),
|
|
29 => "RET".to_string(),
|
|
30 => "GET".to_string(),
|
|
31 => "SET".to_string(),
|
|
_ => panic!("Unknown operation code: {}", opcode),
|
|
}
|
|
}
|
|
|
|
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<Register>, memory: &mut Vec<VMMemory>, 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);
|
|
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);
|
|
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 {
|
|
let err = create_error(&format!("Division by zero"), operation.pos, ErrorType::MathError, ErrorSubType::DivisionByZero);
|
|
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.pow(num2.value as u32), 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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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;
|
|
}
|
|
|
|
fn load_func(data: Vec<u8>, offset: &mut usize) -> DecompiledFunction {
|
|
let var_id_len = read_be_num(&data[*offset..*offset + 4]);
|
|
*offset += 4;
|
|
let mut variables: Vec<Variable> = vec![];
|
|
for _ in 0..var_id_len {
|
|
let name_len = read_be_num(&data[*offset..*offset + 4]);
|
|
*offset += 4;
|
|
let name = read_str(&data[*offset..*offset + name_len]);
|
|
*offset += name_len;
|
|
let var_id = read_be_num(&data[*offset..*offset + 3]) as u32;
|
|
*offset += 3;
|
|
let start = read_be_num(&data[*offset..*offset + 4]);
|
|
*offset += 4;
|
|
let end = read_be_num(&data[*offset..*offset + 4]);
|
|
*offset += 4;
|
|
variables.push(Variable { name: name, id: var_id, start: start, end: end });
|
|
}
|
|
let mut strings: HashMap<u32, String> = HashMap::new();
|
|
let string_count = read_be_num(&data[*offset..*offset + 4]);
|
|
*offset += 4;
|
|
for _ in 0..string_count {
|
|
let str_id = read_be_num(&data[*offset..*offset + 3]) as u32;
|
|
*offset += 3;
|
|
let str_len = read_be_num(&data[*offset..*offset + 4]);
|
|
*offset += 4;
|
|
let str_value = read_str(&data[*offset..*offset + str_len]);
|
|
*offset += str_len;
|
|
strings.insert(str_id, str_value);
|
|
}
|
|
let mut functions: HashMap<u32, u32> = HashMap::new();
|
|
let function_count = read_be_num(&data[*offset..*offset + 4]);
|
|
*offset += 4;
|
|
for _ in 0..function_count {
|
|
let func_id = read_be_num(&data[*offset..*offset + 3]) as u32;
|
|
*offset += 3;
|
|
let func_pos = read_be_num(&data[*offset..*offset + 4]) as u32;
|
|
*offset += 4;
|
|
functions.insert(func_id, func_pos);
|
|
}
|
|
let mut body: Vec<DecompiledOperation> = Vec::new();
|
|
let instr_len: usize = read_be_num(&data[*offset..*offset + 4]);
|
|
*offset += 4;
|
|
for _ in 0..instr_len {
|
|
let op = read_bin(&data[*offset..*offset + 10]);
|
|
*offset += 10;
|
|
let op_code = bin_to_num(op[0..5].to_string());
|
|
let arg1 = bin_to_num(op[5..9].to_string());
|
|
let arg2 = bin_to_snum(op[9..73].to_string());
|
|
let arg3 = bin_to_num(op[73..77].to_string());
|
|
let pos = read_be_num(&data[*offset..*offset + 4]);
|
|
*offset += 4;
|
|
body.push(DecompiledOperation {
|
|
opcode: op_code as u8,
|
|
arg1: arg1 as u8,
|
|
arg2: arg2,
|
|
arg3: arg3 as u8,
|
|
pos: pos,
|
|
});
|
|
}
|
|
println!("Variables: {:?}", variables);
|
|
println!("Strings: {:?}", strings);
|
|
println!("Functions: {:?}", functions);
|
|
return DecompiledFunction {
|
|
body: body,
|
|
variables: variables,
|
|
strings: strings,
|
|
functions: functions,
|
|
};
|
|
}
|
|
|
|
impl Machine {
|
|
pub fn new(ctx: Vec<Context>) -> Self {
|
|
let mut registers = Vec::new();
|
|
for i in 0..17 {
|
|
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,
|
|
};
|
|
}
|
|
|
|
pub fn load(&mut self, data: Vec<u8>) {
|
|
if data[0..3] != *"ASX".as_bytes() {
|
|
panic!("Invalid ASX file header");
|
|
}
|
|
if data[3..6] != ASXVERSION {
|
|
panic!("Unsupported ASX version");
|
|
}
|
|
let _func_count = read_be_num(&data[6..10]);
|
|
let mut offset = 10;
|
|
while offset < data.len() {
|
|
let func = load_func(data.clone(), &mut offset);
|
|
self.functions.push(func);
|
|
}
|
|
}
|
|
|
|
pub fn run(&mut self) {
|
|
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);
|
|
print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone());
|
|
process::exit(1);
|
|
}
|
|
let mut executed_func = executed_func.unwrap();
|
|
while self.call_stack[executed_stack].pc < executed_func.body.len() {
|
|
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);
|
|
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);
|
|
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);
|
|
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, 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);
|
|
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);
|
|
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 {
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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) => {
|
|
(nfunc.func)(self, self.stack.clone());
|
|
self.stack.clear();
|
|
},
|
|
_ => {
|
|
let err = create_error(&format!("Unable to call non-function type"), operation.pos, ErrorType::MachineError, ErrorSubType::NonFunctionCall);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone());
|
|
process::exit(1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |