From 32c2a20697a8d6e35be18d3a61bc3a50303f7521 Mon Sep 17 00:00:00 2001 From: afonya2 Date: Wed, 4 Jun 2025 19:38:59 +0200 Subject: [PATCH] added native functions, enviroment --- src/compiler.rs | 12 +++- src/enviroment.rs | 52 ++++++++++++++ src/virtualmachine.rs | 153 ++++++++++++++++++++++++++++++++++++------ test.as | 3 +- 4 files changed, 195 insertions(+), 25 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 499a866..998061b 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -183,7 +183,17 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va }, ASTPart::VarRead(var_read) => { if get_variable_by_name(variables, &var_read.variable, ops.len()).is_none() { - panic!("Variable {} does not exist", var_read.variable); + let reg = allocate_register(registers); + if reg.unbind_before { + ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None }); + } + let str_id = *next_string_id; + strings.insert(str_id, var_read.variable.clone()); + *next_string_id += 1; + ops.push(Operation { opcode: 1, arg1: Some(reg.register), arg2: Some(str_id as i64), arg3: None }); + ops.push(Operation { opcode: 30, arg1: Some(0), arg2: Some(reg.register as i64), arg3: Some(reg.register) }); + set_register(registers, RegisterState { id: reg.register, used: true, variable: 0, last_used: *op_count }); + return reg.register; } let reg = get_register_by_variable(registers, get_variable_by_name(variables, &var_read.variable, ops.len()).expect("Variable should exist")); if reg.id == 0 { diff --git a/src/enviroment.rs b/src/enviroment.rs index e69de29..b06ff45 100644 --- a/src/enviroment.rs +++ b/src/enviroment.rs @@ -0,0 +1,52 @@ +use std::collections::HashMap; + +use crate::virtualmachine::{Machine, VMMemory, VMMemoryNativeFunction, VMMemoryNull}; + +fn get_string_from_vmmem(mem: VMMemory) -> String { + let mut out = String::new(); + match mem { + VMMemory::String(s) => out.push_str(&s.value), + VMMemory::Number(n) => out.push_str(&n.value.to_string()), + VMMemory::Boolean(b) => out.push_str(if b.value { "true" } else { "false" }), + VMMemory::Null(_) => out.push_str("null"), + VMMemory::Table(tbl) => { + out.push_str("{ "); + for val in &tbl.values { + out.push_str(&get_string_from_vmmem(val.key.clone())); + out.push_str("="); + out.push_str(&get_string_from_vmmem(val.value.clone())); + out.push_str(", "); + } + out.pop(); + out.pop(); + out.push_str("}"); + }, + VMMemory::Function(func) => { + out.push_str("|function: "); + out.push_str(&func.id.to_string()); + out.push_str("|"); + }, + VMMemory::NativeFunction(_) => { + out.push_str("|native function|"); + }, + } + return out; +} + +fn ugass(_machine: &mut Machine, args: Vec) -> VMMemory { + let mut out = String::new(); + for arg in args { + out.push_str(&get_string_from_vmmem(arg)); + out.push_str(" "); + } + println!("{}", out.trim_end()); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); +} + +pub fn generate() -> HashMap { + let mut mem: HashMap = HashMap::new(); + + mem.insert(String::from("ugass"), VMMemory::NativeFunction(VMMemoryNativeFunction { func: ugass, variable_id: 0 })); + + return mem; +} \ No newline at end of file diff --git a/src/virtualmachine.rs b/src/virtualmachine.rs index 35df2e0..4b96fc2 100644 --- a/src/virtualmachine.rs +++ b/src/virtualmachine.rs @@ -1,5 +1,7 @@ use std::collections::HashMap; +use crate::enviroment; + const ASXVERSION: [u8; 3] = [0,1,0]; #[derive(Debug, Clone)] @@ -10,6 +12,7 @@ pub enum VMMemory { Function(VMMemoryFunction), Null(VMMemoryNull), Table(VMMemoryTable), + NativeFunction(VMMemoryNativeFunction), } #[derive(Debug, Clone)] @@ -46,6 +49,11 @@ pub struct TableValue { pub key: VMMemory, pub value: VMMemory } +#[derive(Debug, Clone)] +pub struct VMMemoryNativeFunction { + pub func: fn(&mut Machine, Vec) -> VMMemory, + pub variable_id: u32, +} #[derive(Debug, Clone)] struct DecompiledFunction { @@ -88,6 +96,7 @@ pub struct Machine { pub stack: Vec, pub registers: Vec, pub call_stack: Vec, + pub env: HashMap } fn read_be_num(input: &[u8]) -> usize { @@ -173,6 +182,7 @@ fn get_mem_pos_by_var_id(memory: &Vec, var_id: u32) -> Option { 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 } } @@ -188,6 +198,7 @@ fn set_mem_tbl_val(tbl: &mut VMMemoryTable, key: VMMemory, value: VMMemory) { (VMMemory::Null(_), VMMemory::Null(_)) => true, (VMMemory::Function(_), VMMemory::Function(_)) => false, (VMMemory::Table(_), VMMemory::Table(_)) => false, + (VMMemory::NativeFunction(_), VMMemory::NativeFunction(_)) => false, _ => false, }; if found { @@ -207,6 +218,7 @@ fn get_mem_tbl_val(tbl: &VMMemoryTable, key: VMMemory) -> Option<&VMMemory> { (VMMemory::Null(_), VMMemory::Null(_)) => true, (VMMemory::Function(_), VMMemory::Function(_)) => false, (VMMemory::Table(_), VMMemory::Table(_)) => false, + (VMMemory::NativeFunction(_), VMMemory::NativeFunction(_)) => false, _ => false, }; if found { @@ -342,6 +354,7 @@ fn do_operation_operation(registers: &mut Vec, memory: &mut Vec null.variable_id, VMMemory::Function(func) => func.variable_id, VMMemory::Table(tbl) => tbl.variable_id, + VMMemory::NativeFunction(func) => func.variable_id, }; match &mut result { VMMemory::String(str) => { @@ -362,6 +375,9 @@ fn do_operation_operation(registers: &mut Vec, memory: &mut Vec { tbl.variable_id = var_id; }, + VMMemory::NativeFunction(func) => { + func.variable_id = var_id; + }, } memory[reg3_pointer] = result; } @@ -423,6 +439,8 @@ fn load_func(data: Vec, offset: &mut usize) -> DecompiledFunction { }); } println!("Variables: {:?}", variables); + println!("Strings: {:?}", strings); + println!("Functions: {:?}", functions); return DecompiledFunction { body: body, variables: variables, @@ -451,7 +469,8 @@ impl Machine { func: 0, return_reg: 0, pc: 0, - }] + }], + env: enviroment::generate() }; } @@ -473,16 +492,16 @@ impl Machine { if self.call_stack.len() == 0 { return; } - let executed_func = self.functions.get(self.call_stack[self.call_stack.len()-1].func); + let func_clone = self.functions.clone(); + let executed_func = func_clone.get(self.call_stack[self.call_stack.len()-1].func); if executed_func.is_none() { panic!("Current function not found!"); } let mut executed_func = executed_func.unwrap(); - let last_stack = self.call_stack.len()-1; - let mut executed_stack = &mut self.call_stack[last_stack]; - while executed_stack.pc < executed_func.body.len() { - let operation = &executed_func.body[executed_stack.pc]; - executed_stack.pc += 1; + let mut executed_stack = self.call_stack.len()-1; + 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 @@ -527,7 +546,10 @@ impl Machine { }, 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 }); @@ -600,6 +622,9 @@ impl Machine { VMMemory::Table(tbl) => { tbl.variable_id = 0; }, + VMMemory::NativeFunction(func) => { + func.variable_id = 0; + }, } } match &mut self.memory[reg.pointer] { @@ -621,6 +646,9 @@ impl Machine { VMMemory::Table(tbl) => { tbl.variable_id = operation.arg2 as u32; }, + VMMemory::NativeFunction(func) => { + func.variable_id = operation.arg2 as u32; + }, } }, 8 => { @@ -674,6 +702,7 @@ impl Machine { VMMemory::Null(null) => null.variable_id, VMMemory::Function(func) => func.variable_id, VMMemory::Table(tbl) => tbl.variable_id, + VMMemory::NativeFunction(func) => func.variable_id, }; match &mut result { VMMemory::String(str) => { @@ -694,12 +723,15 @@ impl Machine { VMMemory::Table(tbl) => { tbl.variable_id = var_id; }, + VMMemory::NativeFunction(func) => { + func.variable_id = var_id; + }, } self.memory[reg2.unwrap().pointer] = result; }, 25 => { //JMP - executed_stack.pc = operation.arg2 as usize; + self.call_stack[executed_stack].pc = operation.arg2 as usize; }, 26 => { //CJP @@ -716,7 +748,7 @@ impl Machine { match &mem { VMMemory::Boolean(bool) => { if bool.value { - executed_stack.pc = operation.arg2 as usize; + self.call_stack[executed_stack].pc = operation.arg2 as usize; } } _ => panic!("Invalid memory type for CJP operation"), @@ -755,20 +787,27 @@ impl Machine { VMMemory::Null(null) => { null.variable_id = self.functions[func.id].variables[arg].id; }, - VMMemory::Function(func) => { - func.variable_id = self.functions[func.id].variables[arg].id; + VMMemory::Function(vfunc) => { + vfunc.variable_id = self.functions[func.id].variables[arg].id; }, VMMemory::Table(tbl) => { tbl.variable_id = self.functions[func.id].variables[arg].id; }, + VMMemory::NativeFunction(nfunc) => { + nfunc.variable_id = 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 = &self.functions[func.id]; - let last_stack = self.call_stack.len() - 1; - executed_stack = &mut self.call_stack[last_stack]; + 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(); }, _ => { panic!("Unable to call non-function memory type"); @@ -791,7 +830,7 @@ impl Machine { }, 29 => { //RET - let target_reg = get_register_by_id(&self.registers, executed_stack.return_reg as u8); + 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() { panic!("Return register or target register not found"); @@ -803,19 +842,85 @@ impl Machine { 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: executed_stack.return_reg as u8, pointer: target_reg_pointer }); + 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; } - let last_stack = self.call_stack.len() - 1; - executed_func = &self.functions[self.call_stack[last_stack].func]; - executed_stack = &mut self.call_stack[last_stack]; + 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() { + panic!("One or more registers not found for GET operation"); + } + let mem2 = self.memory.get(reg2.unwrap().pointer); + if mem2.is_none() { + panic!("Memory location not found for register {}", operation.arg2); + } + 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(); + } + }, + _ => { + panic!("Unable to get non-string key from enviroment"); + } + } + 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 = match &self.memory[reg3.unwrap().pointer] { + 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, + }; + match &mut result { + VMMemory::String(str) => { + str.variable_id = var_id; + }, + VMMemory::Number(num) => { + num.variable_id = var_id; + }, + VMMemory::Boolean(bool) => { + bool.variable_id = var_id; + }, + VMMemory::Null(null) => { + null.variable_id = var_id; + }, + VMMemory::Function(func) => { + func.variable_id = var_id; + }, + VMMemory::Table(tbl) => { + tbl.variable_id = var_id; + }, + VMMemory::NativeFunction(func) => { + func.variable_id = 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); @@ -840,14 +945,14 @@ impl Machine { } }, _ => { - panic!("Invalid memory type for SET operation"); + panic!("Invalid memory type for GET operation"); } } 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.arg2 as u8, pointer: reg3_pointer }); + set_register(&mut self.registers, Register { id: operation.arg3 as u8, pointer: reg3_pointer }); } let var_id = match &self.memory[reg3.unwrap().pointer] { VMMemory::String(str) => str.variable_id, @@ -856,6 +961,7 @@ impl Machine { VMMemory::Null(null) => null.variable_id, VMMemory::Function(func) => func.variable_id, VMMemory::Table(tbl) => tbl.variable_id, + VMMemory::NativeFunction(func) => func.variable_id, }; match &mut value { VMMemory::String(str) => { @@ -876,6 +982,9 @@ impl Machine { VMMemory::Table(tbl) => { tbl.variable_id = var_id; }, + VMMemory::NativeFunction(func) => { + func.variable_id = var_id; + }, } self.memory[reg3.unwrap().pointer] = value; }, diff --git a/test.as b/test.as index 732ebef..44bb932 100644 --- a/test.as +++ b/test.as @@ -1,2 +1 @@ -gethelj a = {1,2,3} -a[0] = 4 \ No newline at end of file +ugass(szaft"test"szaft, ugass) \ No newline at end of file