diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 16317f2..aebec28 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -1,23 +1,62 @@ mod module; mod op_codes; mod util; +mod platform; +mod types; use op_codes::*; +use platform::PlatformCallFrame; use std::alloc::{alloc_zeroed, dealloc, Layout}; +use std::collections::HashMap; +use types::DmType; use util::{get_32_le, get_64_le}; +use crate::vm::module::DmFunction; + +pub type PlatformFunction = fn (&mut PlatformCallFrame) -> Result, String>; pub struct DmVirtualMachine { registers: Vec, - register_types: Vec, + register_types: Vec, + platform_functions: HashMap } -struct DmObject { - pointer: *mut u8, +impl DmVirtualMachine { + pub fn call( + &self, + dm_function: &DmFunction, + args: Vec, + arg_types: Vec + ) -> Result<(u64, DmType), String> { + run(&dm_function.byte_code, todo!(), todo!()); + todo!() + } +} + +pub struct DmObjectType { + name: String, + properties: HashMap, + fields: HashMap, + methods: HashMap +} + +pub struct DmObject { + object_type: Box, + data: *mut u8, size: usize, layout: Layout, } -pub fn run(code: &Vec, registers: &mut Vec, register_types: &mut Vec) { +pub struct DmObjectProperty { + name: String, + property_type: DmType, +} + +pub struct DmObjectField { + name: String, + field_type: DmType, +} + +pub fn run(code: &Vec, registers: &mut Vec, register_types: &mut Vec) { let mut i = 0; while i < code.len() { match code[i] { @@ -25,14 +64,14 @@ pub fn run(code: &Vec, registers: &mut Vec, register_types: &mut Vec { let target_register = code[i + 1] as usize; let operand = get_64_le!(code, i, 2, u64); registers[target_register] = operand; - register_types[target_register] = RegisterType::Long; + register_types[target_register] = DmType::Long; i += 10; } MOV_DOUBLE => { /* todo */ } @@ -49,13 +88,14 @@ pub fn run(code: &Vec, registers: &mut Vec, register_types: &mut Vec { @@ -63,22 +103,22 @@ pub fn run(code: &Vec, registers: &mut Vec, register_types: &mut Vec { let target_register = code[i + 1] as usize; - if register_types[target_register] != RegisterType::Pointer { + if register_types[target_register] != DmType::Pointer { panic!("target_register {} is not a Pointer", target_register); } let offset = get_32_le!(code, i, 2, isize); let box_address = registers[target_register]; let new_address = unsafe { let dm_object = Box::from_raw(box_address as *mut DmObject); - let pointer = dm_object.pointer; + let pointer = dm_object.data; pointer.offset(offset).write(code[i + 6]); pointer.offset(offset + 1).write(code[i + 7]); pointer.offset(offset + 2).write(code[i + 8]); @@ -98,8 +138,8 @@ mod tests { use super::*; use std::alloc::dealloc; - fn init_registers(n_registers: usize) -> (Vec, Vec) { - (vec![0; n_registers], vec![RegisterType::Int; n_registers]) + fn init_registers(n_registers: usize) -> (Vec, Vec) { + (vec![0; n_registers], vec![DmType::Int; n_registers]) } #[test] @@ -145,13 +185,13 @@ mod tests { add_alloc(&mut code, 0, 4); add_mov_int_to(&mut code, 0, 0, 0xff); let mut registers = vec![0; 16]; - let mut register_types = vec![RegisterType::Int; 16]; + let mut register_types = vec![DmType::Int; 16]; run(&code, &mut registers, &mut register_types); let box_address = registers[0]; unsafe { let dm_object = Box::from_raw(box_address as *mut DmObject); - assert_eq!(0xff, *dm_object.pointer); - dealloc(dm_object.pointer, dm_object.layout); + assert_eq!(0xff, *dm_object.data); + dealloc(dm_object.data, dm_object.layout); } } @@ -163,6 +203,6 @@ mod tests { let (mut registers, mut register_types) = init_registers(1); run(&code, &mut registers, &mut register_types); assert_eq!(0, registers[0]); - assert_eq!(RegisterType::Int, register_types[0]); + assert_eq!(DmType::Int, register_types[0]); } } diff --git a/src/vm/module.rs b/src/vm/module.rs index 6595fc7..d8e4283 100644 --- a/src/vm/module.rs +++ b/src/vm/module.rs @@ -22,8 +22,8 @@ pub enum DmConstant { } pub struct DmFunction { - name: String, - byte_code: Vec, + pub name: String, + pub byte_code: Vec, } const CONST_SYMBOL: u8 = 0x01; diff --git a/src/vm/op_codes.rs b/src/vm/op_codes.rs index 9e202ef..7b0bdde 100644 --- a/src/vm/op_codes.rs +++ b/src/vm/op_codes.rs @@ -1,3 +1,5 @@ +use crate::push_bytes; + /// ## mov(register: u8, operand: u32) /// - 0: opcode /// - 1: register @@ -35,20 +37,24 @@ pub const MOV_LONG_TO: u8 = 0x08; pub const MOV_DOUBLE_TO: u8 = 0x09; pub const MOV_REGISTER_TO: u8 = 0x0a; -#[derive(PartialEq, Eq, Clone, Debug)] -pub enum RegisterType { - Int, - Long, - Double, - Pointer, +pub const PLATFORM_CALL: u8 = 0x10; + +macro_rules! push_number { + ( $dest: expr, $num: expr ) => { + push_bytes!($dest, $num.to_le_bytes()) + } +} + +macro_rules! push_string { + ( $dest: expr, $s: expr ) => { + push_bytes!($dest, $s.bytes()) + }; } pub fn add_mov_int(code: &mut Vec, register: u8, operand: u32) { code.push(MOV_INT); code.push(register); - for b in operand.to_le_bytes() { - code.push(b); - } + push_number!(code, operand); } pub fn add_mov_register(code: &mut Vec, target_register: u8, source_register: u8) { @@ -60,9 +66,7 @@ pub fn add_mov_register(code: &mut Vec, target_register: u8, source_register pub fn add_alloc(code: &mut Vec, register: u8, size: u32) { code.push(ALLOC); code.push(register); - for b in size.to_le_bytes() { - code.push(b); - } + push_number!(code, size); } pub fn add_dealloc(code: &mut Vec, register: u8) { @@ -73,10 +77,12 @@ pub fn add_dealloc(code: &mut Vec, register: u8) { pub fn add_mov_int_to(code: &mut Vec, register: u8, offset: u32, operand: u32) { code.push(MOV_INT_TO); code.push(register); - for b in offset.to_le_bytes() { - code.push(b); - } - for b in operand.to_le_bytes() { - code.push(b); - } + push_number!(code, offset); + push_number!(code, operand); +} + +pub fn add_platform_call_to(code: &mut Vec, symbol_name: &String) { + code.push(PLATFORM_CALL); + push_number!(code, symbol_name.len()); + push_string!(code, symbol_name); } diff --git a/src/vm/platform/mod.rs b/src/vm/platform/mod.rs new file mode 100644 index 0000000..5fd67b8 --- /dev/null +++ b/src/vm/platform/mod.rs @@ -0,0 +1,17 @@ +use std::collections::HashMap; +use crate::vm::{DmVirtualMachine, PlatformFunction}; +use crate::vm::platform::std_lib::core::dm_print; + +mod std_lib; + +pub struct PlatformCallFrame { + args: Vec, + arg_types: Vec, + vm: DmVirtualMachine +} + +pub fn init_platform_functions() -> HashMap { + let mut m: HashMap = HashMap::new(); + m.insert(String::from("std::core::print"), dm_print); + m +} \ No newline at end of file diff --git a/src/vm/platform/std_lib/core.rs b/src/vm/platform/std_lib/core.rs new file mode 100644 index 0000000..af809b2 --- /dev/null +++ b/src/vm/platform/std_lib/core.rs @@ -0,0 +1,42 @@ +use crate::vm::platform::PlatformCallFrame; +use crate::vm::types::DmType; +use crate::vm::DmObject; +use DmType::*; + +pub struct DmString { + data: String +} + +pub fn dm_print(frame: &mut PlatformCallFrame) -> Result, String> { + if frame.args.len() != 1 { + return Err(String::from("std::core::print requires one argument.")); + } + match frame.arg_types[0] { + Int => { + print!("{}", frame.args[0] as i32); + } + Long => { + print!("{}", frame.args[0] as i64); + } + Double => { + print!("{}", frame.args[0] as f64); + } + Pointer => unsafe { + let dm_object = Box::from_raw(frame.args[0] as *mut DmObject); + if let Some(&ref to_string_method) = dm_object.object_type.methods.get(&String::from("to_string")) { + let call_result = frame.vm.call(to_string_method, vec![frame.args[0]], vec![Pointer]); + if call_result.is_err() { + return Err(call_result.unwrap_err()); + } + let (dm_string_address, _) = call_result?; + // TODO: check that it's actually a DmString + let dm_string = Box::from_raw(dm_string_address as *mut DmString); + print!("{}", dm_string.data); + } else { + print!("{}@{:?}", dm_object.object_type.name, dm_object.data); + } + } + } + Ok(None) +} + diff --git a/src/vm/platform/std_lib/mod.rs b/src/vm/platform/std_lib/mod.rs new file mode 100644 index 0000000..689cad3 --- /dev/null +++ b/src/vm/platform/std_lib/mod.rs @@ -0,0 +1 @@ +pub mod core; \ No newline at end of file diff --git a/src/vm/types.rs b/src/vm/types.rs new file mode 100644 index 0000000..2c3ecab --- /dev/null +++ b/src/vm/types.rs @@ -0,0 +1,7 @@ +#[derive(PartialEq, Eq, Clone, Debug)] +pub enum DmType { + Int, + Long, + Double, + Pointer, +} \ No newline at end of file diff --git a/src/vm/util.rs b/src/vm/util.rs index b9dbf7d..f08cfff 100644 --- a/src/vm/util.rs +++ b/src/vm/util.rs @@ -22,5 +22,15 @@ macro_rules! get_64_le { }; } +#[macro_export] +macro_rules! push_bytes { + ( $dest: expr, $src: expr ) => { + for b in $src { + $dest.push(b); + } + }; +} + pub use get_32_le; pub use get_64_le; +pub use push_bytes;