Compare commits
	
		
			2 Commits
		
	
	
		
			172e82025d
			...
			71ee49761e
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 71ee49761e | ||
|   | 26d87acff5 | 
| @ -1,163 +1,69 @@ | ||||
| use deimos::vm::field::DvmField; | ||||
| use deimos::vm::constant::DvmConstant; | ||||
| use deimos::vm::function::DvmFunction; | ||||
| use deimos::vm::implementation::DvmImplementation; | ||||
| use deimos::vm::interface::DmInterface; | ||||
| use deimos::vm::lib::{DmConstant, DmLib}; | ||||
| use deimos::vm::method::DvmMethod; | ||||
| use deimos::vm::op_codes::{ | ||||
|     add_alloc, add_dealloc, add_invoke_fn, add_mov_const, add_platform_call, add_store, | ||||
| }; | ||||
| use deimos::vm::platform::init_platform_functions; | ||||
| use deimos::vm::r#type::DvmType; | ||||
| use deimos::vm::{call_fn, DvmContext, DvmState}; | ||||
| use deimos::vm::instruction::{Immediate, Instruction, Location}; | ||||
| use deimos::vm::platform::get_std_lib_platform_functions; | ||||
| use deimos::vm::source_code_location::SourceCodeLocation; | ||||
| use deimos::vm::{dump_state, run_main_function, DvmContext, DvmState}; | ||||
| use std::rc::Rc; | ||||
| 
 | ||||
| fn main() { | ||||
|     // Goal:
 | ||||
|     // - write a single lib with a main()
 | ||||
|     // - call the main fn
 | ||||
|     // fn main() { println "Hello, World!" }
 | ||||
|     //
 | ||||
|     // ns greeter
 | ||||
|     //
 | ||||
|     // fn main() {
 | ||||
|     //     println "Hello, World!"
 | ||||
|     // }
 | ||||
|     let main_instructions = vec![ | ||||
|         Instruction::MoveImmediate { | ||||
|             destination: Location::Register(0), | ||||
|             immediate: Immediate::Constant(DvmConstant::String(String::from("Hello, World!"))), | ||||
|         }, | ||||
|         Instruction::Push { source_register: 0 }, | ||||
|         Instruction::InvokeStaticPlatform { | ||||
|             function_name: Rc::new(String::from("std::core::println")), | ||||
|             source_code_location: SourceCodeLocation { | ||||
|                 source_file_name: String::from("greeter.dm"), | ||||
|                 line: 4, | ||||
|                 char: 5, | ||||
|             }, | ||||
|         }, | ||||
|         Instruction::Pop { | ||||
|             // println return value
 | ||||
|             destination_register: None, | ||||
|         }, | ||||
|         Instruction::Pop { | ||||
|             // arg0 to println
 | ||||
|             destination_register: None, | ||||
|         }, | ||||
|         Instruction::MoveImmediate { | ||||
|             destination: Location::Register(1), | ||||
|             immediate: Immediate::Int(0), | ||||
|         }, | ||||
|         Instruction::Push { source_register: 1 }, | ||||
|         Instruction::Return, | ||||
|     ]; | ||||
| 
 | ||||
|     // std/core/array lib
 | ||||
|     let mut array_lib = DmLib::new("std/core/array"); | ||||
| 
 | ||||
|     // std::core::Array
 | ||||
|     let array_int = DmInterface::new("std::core::Array"); | ||||
|     array_lib.add_interface(array_int); | ||||
|     let array_int_rc = array_lib | ||||
|         .interfaces() | ||||
|         .iter() | ||||
|         .find(|interface| interface.fqn() == "std::core::Array") | ||||
|         .unwrap(); | ||||
| 
 | ||||
|     // std::core::ArrayImpl
 | ||||
|     let mut array_impl = DvmImplementation::new("std::core::ArrayImpl", Some(array_int_rc.clone())); | ||||
| 
 | ||||
|     let array_impl_ptr_address_fld = DvmField::new("ptr_address", DvmType::USize); | ||||
|     let array_impl_ptr_size_fld = DvmField::new("ptr_size", DvmType::USize); | ||||
|     let array_impl_length_fld = DvmField::new("length", DvmType::Long); | ||||
| 
 | ||||
|     array_impl.add_field(array_impl_ptr_address_fld); | ||||
|     array_impl.add_field(array_impl_ptr_size_fld); | ||||
|     array_impl.add_field(array_impl_length_fld); | ||||
| 
 | ||||
|     // std::core::ArrayImpl::_ctor_0(
 | ||||
|     //   r0: self
 | ||||
|     //   r1: USize ptr_address
 | ||||
|     //   r2: USize ptr_size
 | ||||
|     //   r3: Long length
 | ||||
|     // )
 | ||||
|     let mut array_impl_ctor_0_bytecode: Vec<u8> = Vec::new(); | ||||
| 
 | ||||
|     add_store(&mut array_impl_ctor_0_bytecode, 0, 0, 1); | ||||
|     add_store(&mut array_impl_ctor_0_bytecode, 0, 1, 2); | ||||
|     add_store(&mut array_impl_ctor_0_bytecode, 0, 2, 3); | ||||
| 
 | ||||
|     let array_impl_ctor_0_fn = DvmFunction::new( | ||||
|         "std::core::ArrayImpl::_ctor_0", | ||||
|         "_ctor_0", | ||||
|         array_impl_ctor_0_bytecode, | ||||
|         4, | ||||
|         None, | ||||
|     let main_function = DvmFunction::new( | ||||
|         "greeter::main", | ||||
|         &main_instructions, | ||||
|         SourceCodeLocation { | ||||
|             source_file_name: String::from("greeter.dm"), | ||||
|             line: 3, | ||||
|             char: 1, | ||||
|         }, | ||||
|     ); | ||||
|     let array_impl_ctor_0_method = DvmMethod::new(array_impl_ctor_0_fn, None); | ||||
|     array_impl.add_method(array_impl_ctor_0_method); | ||||
| 
 | ||||
|     array_lib.add_implementation(array_impl); | ||||
| 
 | ||||
|     // std::core::String
 | ||||
|     let mut string_lib = DmLib::new("std/core/string"); | ||||
| 
 | ||||
|     let string_int = DmInterface::new("std::core::String"); | ||||
|     string_lib.add_interface(string_int); | ||||
|     let string_int_rc = string_lib | ||||
|         .interfaces() | ||||
|         .iter() | ||||
|         .find(|interface| interface.fqn() == "std::core::String") | ||||
|         .unwrap(); | ||||
| 
 | ||||
|     let mut string_impl = | ||||
|         DvmImplementation::new("std::core::StringImpl", Some(string_int_rc.clone())); | ||||
| 
 | ||||
|     let bytes_field = DvmField::new("bytes", DvmType::Object); | ||||
|     string_impl.add_field(bytes_field); | ||||
| 
 | ||||
|     // std::core::String::_ctor_0(
 | ||||
|     //   r0: self
 | ||||
|     //   r1: Array<Byte> bytes
 | ||||
|     // )
 | ||||
|     let mut string_ctor_0_bytecode: Vec<u8> = Vec::new(); | ||||
|     add_store(&mut string_ctor_0_bytecode, 0, 0, 1); | ||||
| 
 | ||||
|     let string_ctor_0_fn = DvmFunction::new( | ||||
|         "std::core::StringImpl::_ctor_0", | ||||
|         "_ctor_0", | ||||
|         string_ctor_0_bytecode, | ||||
|         2, | ||||
|         None, | ||||
|     ); | ||||
| 
 | ||||
|     let string_ctor_0_method = DvmMethod::new(string_ctor_0_fn, None); | ||||
| 
 | ||||
|     string_impl.add_method(string_ctor_0_method); | ||||
| 
 | ||||
|     string_lib.add_implementation(string_impl); | ||||
| 
 | ||||
|     // greeting lib
 | ||||
|     let mut greeting_lib = DmLib::new("greeting"); | ||||
|     greeting_lib.add_constant(DmConstant::String("Hello, World!".to_string())); | ||||
| 
 | ||||
|     let mut main_byte_code = Vec::new(); | ||||
| 
 | ||||
|     // Move greeting
 | ||||
|     //   r0: greeting address
 | ||||
|     //   r1: greeting size
 | ||||
|     add_mov_const(&mut main_byte_code, 0, 1, "greeting", 0); | ||||
| 
 | ||||
|     // Alloc Array<Byte> greeting bytes
 | ||||
|     add_alloc(&mut main_byte_code, 2, "std::core::ArrayImpl"); | ||||
| 
 | ||||
|     // Call ArrayImpl(ptr_address, ptr_size, length)
 | ||||
|     add_invoke_fn( | ||||
|         &mut main_byte_code, | ||||
|         "std::core::ArrayImpl::_ctor_0", | ||||
|         3, | ||||
|         &[2, 0, 1, 1], | ||||
|     ); | ||||
| 
 | ||||
|     // Alloc StringImpl greeting
 | ||||
|     add_alloc(&mut main_byte_code, 4, "std::core::StringImpl"); | ||||
| 
 | ||||
|     // Call StringImpl(greeting_bytes)
 | ||||
|     add_invoke_fn( | ||||
|         &mut main_byte_code, | ||||
|         "std::core::StringImpl::_ctor_0", | ||||
|         5, | ||||
|         &[4, 2], | ||||
|     ); | ||||
| 
 | ||||
|     // Call println(greeting)
 | ||||
|     add_platform_call(&mut main_byte_code, "std::core::println", 6, &[4]); | ||||
| 
 | ||||
|     // Dealloc StringImpl
 | ||||
|     add_dealloc(&mut main_byte_code, 4); | ||||
| 
 | ||||
|     // Dealloc ArrayImpl
 | ||||
|     add_dealloc(&mut main_byte_code, 2); | ||||
| 
 | ||||
|     let main_dm_fn = DvmFunction::new("main", "main", main_byte_code, 7, None); | ||||
| 
 | ||||
|     greeting_lib.add_function(main_dm_fn); | ||||
| 
 | ||||
|     let mut state = DvmState::new(); | ||||
|     let mut context = DvmContext::new(); | ||||
|     context.load_libs(vec![ | ||||
|         Rc::new(greeting_lib), | ||||
|         Rc::new(string_lib), | ||||
|         Rc::new(array_lib), | ||||
|     ]); | ||||
|     context.load_platform_fns(init_platform_functions()); | ||||
|     let mut context = DvmContext::new(Rc::new(main_function)); | ||||
|     context.add_platform_functions(get_std_lib_platform_functions()); | ||||
|     let exit_code = run_main_function(&mut state, &context); | ||||
| 
 | ||||
|     let main_fn = context.fn_by_fqn("main").unwrap(); | ||||
|     call_fn(&mut state, &context, &main_fn, vec![]); | ||||
|     dump_state(&state, "After main!"); | ||||
| 
 | ||||
|     if exit_code != 0 { | ||||
|         std::process::exit(exit_code); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| use crate::vm::object::DvmObject; | ||||
| use crate::vm::pointer::DvmPointer; | ||||
| use crate::vm::value::DvmValue; | ||||
| use std::cell::RefCell; | ||||
| use std::fmt::{Display, Write}; | ||||
| @ -16,7 +15,7 @@ pub enum DvmArray { | ||||
|     Booleans(Vec<bool>), | ||||
|     Objects(Vec<Rc<RefCell<DvmObject>>>), | ||||
|     Arrays(Vec<Rc<RefCell<DvmArray>>>), | ||||
|     ConstantPointers(Vec<DvmPointer>), | ||||
|     Strings(Vec<Rc<String>>), | ||||
| } | ||||
| 
 | ||||
| impl DvmArray { | ||||
| @ -30,7 +29,7 @@ impl DvmArray { | ||||
|             DvmArray::Booleans(vec) => DvmValue::Boolean(vec[index]), | ||||
|             DvmArray::Objects(vec) => DvmValue::Object(vec[index].clone()), | ||||
|             DvmArray::Arrays(vec) => DvmValue::Array(vec[index].clone()), | ||||
|             DvmArray::ConstantPointers(vec) => DvmValue::ConstantPointer(vec[index].clone()), | ||||
|             DvmArray::Strings(vec) => DvmValue::String(vec[index].clone()), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -60,8 +59,8 @@ impl DvmArray { | ||||
|             DvmArray::Arrays(vec) => { | ||||
|                 vec[index] = value.expect_array(); | ||||
|             } | ||||
|             DvmArray::ConstantPointers(vec) => { | ||||
|                 vec[index] = value.expect_constant_pointer(); | ||||
|             DvmArray::Strings(vec) => { | ||||
|                 vec[index] = value.expect_string(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @ -89,7 +88,7 @@ pub enum DvmArrayIter<'a> { | ||||
|     Booleans(Iter<'a, bool>), | ||||
|     Objects(Iter<'a, Rc<RefCell<DvmObject>>>), | ||||
|     Arrays(Iter<'a, Rc<RefCell<DvmArray>>>), | ||||
|     ConstantPointers(Iter<'a, DvmPointer>), | ||||
|     Strings(Iter<'a, Rc<String>>), | ||||
| } | ||||
| 
 | ||||
| impl<'a> Iterator for DvmArrayIter<'a> { | ||||
| @ -104,9 +103,7 @@ impl<'a> Iterator for DvmArrayIter<'a> { | ||||
|             DvmArrayIter::Booleans(iter) => iter.next().map(|b| DvmValue::Boolean(*b)), | ||||
|             DvmArrayIter::Objects(iter) => iter.next().map(|o| DvmValue::Object(o.clone())), | ||||
|             DvmArrayIter::Arrays(iter) => iter.next().map(|a| DvmValue::Array(a.clone())), | ||||
|             DvmArrayIter::ConstantPointers(iter) => { | ||||
|                 iter.next().map(|p| DvmValue::ConstantPointer(p.clone())) | ||||
|             } | ||||
|             DvmArrayIter::Strings(iter) => iter.next().map(|s| DvmValue::String(s.clone())), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -125,7 +122,7 @@ impl<'a> IntoIterator for &'a DvmArray { | ||||
|             DvmArray::Booleans(v) => DvmArrayIter::Booleans(v.iter()), | ||||
|             DvmArray::Objects(v) => DvmArrayIter::Objects(v.iter()), | ||||
|             DvmArray::Arrays(v) => DvmArrayIter::Arrays(v.iter()), | ||||
|             DvmArray::ConstantPointers(v) => DvmArrayIter::ConstantPointers(v.iter()), | ||||
|             DvmArray::Strings(v) => DvmArrayIter::Strings(v.iter()), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										17
									
								
								src/vm/constant.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/vm/constant.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum DvmConstant { | ||||
|     String(String), | ||||
|     Array(DvmConstantArray) | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum DvmConstantArray { | ||||
|     Bytes(Vec<u8>), | ||||
|     Ints(Vec<i32>), | ||||
|     Longs(Vec<i64>), | ||||
|     Doubles(Vec<f64>), | ||||
|     USizes(Vec<usize>), | ||||
|     Booleans(Vec<bool>), | ||||
|     Strings(Vec<String>), | ||||
|     Arrays(Vec<DvmConstantArray>) | ||||
| } | ||||
| @ -1,16 +1,23 @@ | ||||
| use crate::vm::instruction::Instruction; | ||||
| use crate::vm::source_code_location::SourceCodeLocation; | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct DvmFunction { | ||||
|     fqn: String, | ||||
|     instructions: Vec<Instruction>, | ||||
|     source_code_location: SourceCodeLocation, | ||||
| } | ||||
| 
 | ||||
| impl DvmFunction { | ||||
|     pub fn new(fqn: &str, instructions: &[Instruction]) -> Self { | ||||
|     pub fn new( | ||||
|         fqn: &str, | ||||
|         instructions: &[Instruction], | ||||
|         source_code_location: SourceCodeLocation, | ||||
|     ) -> Self { | ||||
|         DvmFunction { | ||||
|             fqn: fqn.to_string(), | ||||
|             instructions: Vec::from(instructions), | ||||
|             source_code_location, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -21,6 +28,10 @@ impl DvmFunction { | ||||
|     pub fn instructions(&self) -> &Vec<Instruction> { | ||||
|         &self.instructions | ||||
|     } | ||||
|     
 | ||||
|     pub fn source_code_location(&self) -> &SourceCodeLocation { | ||||
|         &self.source_code_location | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl PartialEq for DvmFunction { | ||||
|  | ||||
| @ -1,3 +1,5 @@ | ||||
| use crate::vm::constant::DvmConstant; | ||||
| use crate::vm::source_code_location::SourceCodeLocation; | ||||
| use std::rc::Rc; | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| @ -14,7 +16,7 @@ pub enum Instruction { | ||||
|         source_register: usize, | ||||
|     }, | ||||
|     Pop { | ||||
|         destination_register: usize, | ||||
|         destination_register: Option<usize>, | ||||
|     }, | ||||
|     AllocateObject { | ||||
|         implementation_name: Rc<String>, | ||||
| @ -29,8 +31,13 @@ pub enum Instruction { | ||||
|         function_name: Rc<String>, | ||||
|         source_code_location: SourceCodeLocation, | ||||
|     }, | ||||
|     PlatformCall { | ||||
|         platform_function_name: Rc<String>, | ||||
|     InvokeStaticPlatform { | ||||
|         function_name: Rc<String>, | ||||
|         source_code_location: SourceCodeLocation, | ||||
|     }, | ||||
|     InvokeObjectPlatform { | ||||
|         object_register: usize, | ||||
|         function_name: Rc<String>, | ||||
|         source_code_location: SourceCodeLocation, | ||||
|     }, | ||||
|     Add { | ||||
| @ -107,10 +114,7 @@ pub enum Immediate { | ||||
|     Double(f64), | ||||
|     Usize(usize), | ||||
|     Boolean(bool), | ||||
|     ConstantPointer { | ||||
|         raw_pointer: *const u8, | ||||
|         length: usize | ||||
|     }, | ||||
|     Constant(DvmConstant), | ||||
|     Empty, | ||||
| } | ||||
| 
 | ||||
| @ -130,10 +134,3 @@ pub enum Location { | ||||
|         offset: Option<isize>, | ||||
|     }, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct SourceCodeLocation { | ||||
|     pub source_file_name: String, | ||||
|     pub line: i64, | ||||
|     pub char: i64, | ||||
| } | ||||
|  | ||||
							
								
								
									
										366
									
								
								src/vm/mod.rs
									
									
									
									
									
								
							
							
						
						
									
										366
									
								
								src/vm/mod.rs
									
									
									
									
									
								
							| @ -1,47 +1,52 @@ | ||||
| mod array; | ||||
| pub mod constant; | ||||
| mod field; | ||||
| mod function; | ||||
| pub mod function; | ||||
| pub mod implementation; | ||||
| mod instruction; | ||||
| pub mod instruction; | ||||
| mod interface; | ||||
| pub mod lib; | ||||
| mod method; | ||||
| pub mod object; | ||||
| pub mod op_codes; | ||||
| pub mod platform; | ||||
| mod pointer; | ||||
| pub mod source_code_location; | ||||
| pub mod r#type; | ||||
| pub mod util; | ||||
| pub mod value; | ||||
| mod virtual_method; | ||||
| 
 | ||||
| use crate::vm::array::DvmArray; | ||||
| use crate::vm::constant::{DvmConstant, DvmConstantArray}; | ||||
| use crate::vm::implementation::DvmImplementation; | ||||
| use crate::vm::instruction::{Immediate, Instruction, Location, SourceCodeLocation}; | ||||
| use crate::vm::instruction::{Immediate, Instruction, Location}; | ||||
| use crate::vm::object::DvmObject; | ||||
| use crate::vm::pointer::DvmPointer; | ||||
| use crate::vm::value::DvmValue; | ||||
| use function::DvmFunction; | ||||
| use source_code_location::SourceCodeLocation; | ||||
| use std::cell::RefCell; | ||||
| use std::collections::HashMap; | ||||
| use std::fmt::Display; | ||||
| use std::rc::Rc; | ||||
| 
 | ||||
| fn dvm_panic(context: &DvmContext, message: &str) { | ||||
| pub fn dump_state(state: &DvmState, message: &str) { | ||||
|     println!("----"); | ||||
|     println!("Deimos Virtual Machine: Panic!"); | ||||
|     println!("{}", message); | ||||
|     println!("----"); | ||||
|     println!("Current Instruction: {:?}", context.current_instruction); | ||||
|     println!( | ||||
|         "Current Instruction: {:?}", | ||||
|         state.current_instruction.clone().unwrap() | ||||
|     ); | ||||
|     println!("Registers:"); | ||||
|     for (i, register) in context.registers.iter().enumerate() { | ||||
|         println!("\tr{}: {:?}", i, register); | ||||
|     for (i, register) in state.registers.iter().enumerate() { | ||||
|         println!("\tr{:x}: {:?}", i, register); | ||||
|     } | ||||
|     println!("Call stack:"); | ||||
|     for call in context.call_stack.iter() { | ||||
|     for call in state.call_stack.iter() { | ||||
|         println!("\t{}", call); | ||||
|     } | ||||
|     println!("Stack:"); | ||||
|     for (i, value) in context.stack.iter().enumerate() { | ||||
|     for (i, value) in state.stack.iter().enumerate() { | ||||
|         println!("\t{}: {}", i, value); | ||||
|     } | ||||
|     println!("----"); | ||||
| @ -49,33 +54,27 @@ fn dvm_panic(context: &DvmContext, message: &str) { | ||||
| 
 | ||||
| macro_rules! dvm_panic { | ||||
|     ($context: expr, $message: expr) => { | ||||
|         dvm_panic($context, $message); | ||||
|         dump_state($context, $message); | ||||
|         panic!() | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| pub type PlatformFunction = fn(context: &mut DvmContext); | ||||
| pub type PlatformFunction = fn(state: &mut DvmState, context: &DvmContext); | ||||
| 
 | ||||
| pub struct DvmContext { | ||||
| pub struct DvmState { | ||||
|     call_stack: Vec<DvmCall>, | ||||
|     current_instruction: Option<Instruction>, | ||||
|     registers: Vec<DvmValue>, | ||||
|     stack: Vec<DvmValue>, | ||||
|     implementations: HashMap<String, Rc<DvmImplementation>>, | ||||
|     static_functions: HashMap<String, Rc<DvmFunction>>, | ||||
|     platform_functions: HashMap<String, PlatformFunction>, | ||||
| } | ||||
| 
 | ||||
| impl DvmContext { | ||||
| impl DvmState { | ||||
|     pub fn new() -> Self { | ||||
|         DvmContext { | ||||
|         DvmState { | ||||
|             call_stack: vec![], | ||||
|             current_instruction: None, | ||||
|             registers: vec![], | ||||
|             registers: vec![DvmValue::Empty; 16], | ||||
|             stack: vec![], | ||||
|             implementations: HashMap::new(), | ||||
|             static_functions: HashMap::new(), | ||||
|             platform_functions: HashMap::new(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -84,6 +83,42 @@ impl DvmContext { | ||||
|             dvm_panic!(self, "Stack underflow!"); | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_stack_argument(&self, index: usize) -> DvmValue { | ||||
|         self.stack | ||||
|             .get(self.stack.len() - 2 - index) | ||||
|             .unwrap_or_else(|| { | ||||
|                 dvm_panic!(self, "Stack underflow!"); | ||||
|             }) | ||||
|             .clone() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct DvmContext { | ||||
|     main_function: Rc<DvmFunction>, | ||||
|     implementations: HashMap<String, Rc<DvmImplementation>>, | ||||
|     static_functions: HashMap<String, Rc<DvmFunction>>, | ||||
|     platform_functions: HashMap<String, PlatformFunction>, | ||||
| } | ||||
| 
 | ||||
| impl DvmContext { | ||||
|     pub fn new(main_function: Rc<DvmFunction>) -> Self { | ||||
|         DvmContext { | ||||
|             main_function, | ||||
|             implementations: HashMap::new(), | ||||
|             static_functions: HashMap::new(), | ||||
|             platform_functions: HashMap::new(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn add_platform_functions( | ||||
|         &mut self, | ||||
|         platform_functions: HashMap<String, PlatformFunction>, | ||||
|     ) { | ||||
|         for (fqn, platform_function) in platform_functions { | ||||
|             self.platform_functions.insert(fqn, platform_function); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct DvmCall { | ||||
| @ -114,16 +149,16 @@ fn update_index(index: &mut usize, offset: isize) { | ||||
| fn push_call_frame( | ||||
|     function_name: Rc<String>, | ||||
|     source_code_location: SourceCodeLocation, | ||||
|     context: &mut DvmContext, | ||||
|     state: &mut DvmState, | ||||
| ) { | ||||
|     context.call_stack.push(DvmCall { | ||||
|     state.call_stack.push(DvmCall { | ||||
|         function_name, | ||||
|         source_code_location, | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| fn pop_call_frame(context: &mut DvmContext) { | ||||
|     context.call_stack.pop(); | ||||
| fn pop_call_frame(state: &mut DvmState) { | ||||
|     state.call_stack.pop(); | ||||
| } | ||||
| 
 | ||||
| fn compute_index_with_offset( | ||||
| @ -146,17 +181,17 @@ fn compute_index_with_offset( | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn copy_from_source(context: &DvmContext, source: &Location) -> DvmValue { | ||||
| fn copy_from_source(state: &DvmState, source: &Location) -> DvmValue { | ||||
|     match source { | ||||
|         Location::Register(register) => context.registers[*register].clone(), | ||||
|         Location::Stack { offset } => context.stack[*offset].clone(), | ||||
|         Location::Register(register) => state.registers[*register].clone(), | ||||
|         Location::Stack { offset } => state.stack[*offset].clone(), | ||||
|         Location::Field { | ||||
|             object_register, | ||||
|             field_name, | ||||
|         } => context.registers[*object_register].map_object( | ||||
|         } => state.registers[*object_register].map_object( | ||||
|             |o| o.borrow().read_field(field_name).clone(), | ||||
|             |v| { | ||||
|                 dvm_panic!(context, &format!("Expected an object, but found: {}", v)); | ||||
|                 dvm_panic!(state, &format!("Expected an object, but found: {}", v)); | ||||
|             }, | ||||
|         ), | ||||
|         Location::Array { | ||||
| @ -164,30 +199,30 @@ fn copy_from_source(context: &DvmContext, source: &Location) -> DvmValue { | ||||
|             index_register, | ||||
|             offset, | ||||
|         } => { | ||||
|             let index = compute_index_with_offset(&context.registers, *index_register, offset); | ||||
|             context.registers[*array_register].map_array( | ||||
|             let index = compute_index_with_offset(&state.registers, *index_register, offset); | ||||
|             state.registers[*array_register].map_array( | ||||
|                 |a| a.borrow().read_element(index), | ||||
|                 |v| { | ||||
|                     dvm_panic!(context, &format!("Expected an array, but found: {}", v)); | ||||
|                     dvm_panic!(state, &format!("Expected an array, but found: {}", v)); | ||||
|                 }, | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn write_to_destination(context: &mut DvmContext, destination: &Location, value: DvmValue) { | ||||
| fn write_to_destination(state: &mut DvmState, destination: &Location, value: DvmValue) { | ||||
|     match destination { | ||||
|         Location::Register(register) => { | ||||
|             context.registers[*register] = value; | ||||
|             state.registers[*register] = value; | ||||
|         } | ||||
|         Location::Stack { offset } => { | ||||
|             context.stack[*offset] = value; | ||||
|             state.stack[*offset] = value; | ||||
|         } | ||||
|         Location::Field { | ||||
|             object_register, | ||||
|             field_name, | ||||
|         } => { | ||||
|             context.registers[*object_register] | ||||
|             state.registers[*object_register] | ||||
|                 .expect_object() | ||||
|                 .borrow_mut() | ||||
|                 .write_field(field_name, value); | ||||
| @ -197,8 +232,8 @@ fn write_to_destination(context: &mut DvmContext, destination: &Location, value: | ||||
|             index_register, | ||||
|             offset, | ||||
|         } => { | ||||
|             let index = compute_index_with_offset(&context.registers, *index_register, offset); | ||||
|             context.registers[*array_register] | ||||
|             let index = compute_index_with_offset(&state.registers, *index_register, offset); | ||||
|             state.registers[*array_register] | ||||
|                 .expect_array() | ||||
|                 .borrow_mut() | ||||
|                 .write_element(index, value); | ||||
| @ -206,6 +241,32 @@ fn write_to_destination(context: &mut DvmContext, destination: &Location, value: | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn constant_array_to_array(constant_array: &DvmConstantArray) -> DvmArray { | ||||
|     match constant_array { | ||||
|         DvmConstantArray::Bytes(v) => DvmArray::Bytes(v.clone()), | ||||
|         DvmConstantArray::Ints(v) => DvmArray::Ints(v.clone()), | ||||
|         DvmConstantArray::Longs(v) => DvmArray::Longs(v.clone()), | ||||
|         DvmConstantArray::Doubles(v) => DvmArray::Doubles(v.clone()), | ||||
|         DvmConstantArray::USizes(v) => DvmArray::USizes(v.clone()), | ||||
|         DvmConstantArray::Booleans(v) => DvmArray::Booleans(v.clone()), | ||||
|         DvmConstantArray::Strings(vs) => { | ||||
|             DvmArray::Strings(vs.iter().map(|s| Rc::new(s.clone())).collect()) | ||||
|         } | ||||
|         DvmConstantArray::Arrays(va) => DvmArray::Arrays( | ||||
|             va.iter() | ||||
|                 .map(|a| Rc::new(RefCell::new(constant_array_to_array(a)))) | ||||
|                 .collect(), | ||||
|         ), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn constant_to_value(constant: &DvmConstant) -> DvmValue { | ||||
|     match constant { | ||||
|         DvmConstant::String(s) => DvmValue::String(Rc::new(s.clone())), | ||||
|         DvmConstant::Array(a) => DvmValue::Array(Rc::new(RefCell::new(constant_array_to_array(a)))), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn immediate_to_value(immediate: &Immediate) -> DvmValue { | ||||
|     match immediate { | ||||
|         Immediate::Byte(b) => DvmValue::Byte(*b), | ||||
| @ -214,137 +275,220 @@ fn immediate_to_value(immediate: &Immediate) -> DvmValue { | ||||
|         Immediate::Double(d) => DvmValue::Double(*d), | ||||
|         Immediate::Usize(s) => DvmValue::USize(*s), | ||||
|         Immediate::Boolean(b) => DvmValue::Boolean(*b), | ||||
|         Immediate::ConstantPointer { | ||||
|             raw_pointer, | ||||
|             length, | ||||
|         } => DvmValue::ConstantPointer(DvmPointer { | ||||
|             raw_pointer: *raw_pointer, | ||||
|             length: *length, | ||||
|         }), | ||||
|         Immediate::Constant(c) => constant_to_value(c), | ||||
|         Immediate::Empty => DvmValue::Empty, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn run_main_function(state: &mut DvmState, context: &DvmContext) -> i32 { | ||||
|     let main_function = context.main_function.clone(); | ||||
|     push_call_frame( | ||||
|         Rc::new(main_function.fqn().to_string()), | ||||
|         main_function.source_code_location().clone(), | ||||
|         state, | ||||
|     ); | ||||
|     run(main_function.instructions(), state, context); | ||||
|     pop_call_frame(state); | ||||
|     state.pop_stack().expect_int_or_else(|v| { | ||||
|         dvm_panic!(state, &format!("Expected DvmValue::Int, but found {}", v)); | ||||
|     }) | ||||
| } | ||||
| 
 | ||||
| // TODO: find all possible unwraps/expects and wrap with call to dvm_panic
 | ||||
| pub fn run(instructions: &[Instruction], context: &mut DvmContext) { | ||||
| pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmContext) { | ||||
|     let mut index = 0; | ||||
|     while index < instructions.len() { | ||||
|         context.current_instruction = Some(instructions[index].clone()); | ||||
|         index += 1; | ||||
|         state.current_instruction = Some(instructions[index].clone()); | ||||
|         use Instruction::*; | ||||
|         match &instructions[index] { | ||||
|             Instruction::MoveImmediate { | ||||
|             MoveImmediate { | ||||
|                 destination, | ||||
|                 immediate, | ||||
|             } => { | ||||
|                 write_to_destination(context, destination, immediate_to_value(immediate)); | ||||
|                 write_to_destination(state, destination, immediate_to_value(immediate)); | ||||
|             } | ||||
|             Instruction::Copy { | ||||
|             Copy { | ||||
|                 source, | ||||
|                 destination, | ||||
|             } => { | ||||
|                 let value = copy_from_source(context, source); | ||||
|                 write_to_destination(context, destination, value); | ||||
|                 let value = copy_from_source(state, source); | ||||
|                 write_to_destination(state, destination, value); | ||||
|             } | ||||
|             Instruction::Push { source_register } => { | ||||
|                 context | ||||
|                     .stack | ||||
|                     .push(context.registers[*source_register].clone()); | ||||
|             Push { source_register } => { | ||||
|                 state.stack.push(state.registers[*source_register].clone()); | ||||
|             } | ||||
|             Instruction::Pop { | ||||
|             Pop { | ||||
|                 destination_register, | ||||
|             } => { | ||||
|                 let value = context.stack.pop().expect("Stack underflow"); | ||||
|                 context.registers[*destination_register] = value; | ||||
|                 let value = state.stack.pop().unwrap_or_else(|| { | ||||
|                     dvm_panic!(state, "Stack underflow"); | ||||
|                 }); | ||||
|                 if let Some(register_index) = destination_register { | ||||
|                     state.registers[*register_index] = value; | ||||
|                 } | ||||
|             } | ||||
|             Instruction::AllocateObject { | ||||
|             AllocateObject { | ||||
|                 implementation_name, | ||||
|                 destination_register, | ||||
|             } => { | ||||
|                 let implementation = context | ||||
|                     .implementations | ||||
|                     .get(implementation_name.as_str()) | ||||
|                     .unwrap(); | ||||
|                 let object = DvmObject::new(implementation.clone()); | ||||
|                 context.registers[*destination_register] = | ||||
|                     .unwrap_or_else(|| { | ||||
|                         dvm_panic!( | ||||
|                             state, | ||||
|                             &format!("Cannot find implementation {}", implementation_name) | ||||
|                         ); | ||||
|                     }) | ||||
|                     .clone(); | ||||
|                 let object = DvmObject::new(implementation); | ||||
|                 state.registers[*destination_register] = | ||||
|                     DvmValue::Object(Rc::new(RefCell::new(object))); | ||||
|             } | ||||
|             Instruction::InvokeStatic { | ||||
|             InvokeStatic { | ||||
|                 function_name, | ||||
|                 source_code_location, | ||||
|             } => { | ||||
|                 // Find function
 | ||||
|                 let static_function = context | ||||
|                     .static_functions | ||||
|                     .get(function_name.as_str()) | ||||
|                     .unwrap() | ||||
|                     .unwrap_or_else(|| { | ||||
|                         dvm_panic!( | ||||
|                             state, | ||||
|                             &format!("Cannot find static function {}", function_name) | ||||
|                         ); | ||||
|                     }) | ||||
|                     .clone(); | ||||
|                 push_call_frame(function_name.clone(), source_code_location.clone(), context); | ||||
|                 run(static_function.instructions(), context); | ||||
|                 pop_call_frame(context); | ||||
| 
 | ||||
|                 // Do call
 | ||||
|                 state.stack.push(DvmValue::Empty); // space for return value
 | ||||
|                 push_call_frame(function_name.clone(), source_code_location.clone(), state); | ||||
|                 run(static_function.instructions(), state, context); | ||||
|                 pop_call_frame(state); | ||||
|             } | ||||
|             Instruction::InvokeObject { | ||||
|             InvokeObject { | ||||
|                 object_register, | ||||
|                 function_name, | ||||
|                 source_code_location, | ||||
|             } => { | ||||
|                 let object = context.registers[*object_register].expect_object(); | ||||
|                 let object_ref = object.borrow(); | ||||
|                 // Find method and get instructions
 | ||||
|                 let object_value = state.registers[*object_register].clone(); | ||||
|                 let object_rc = object_value.expect_object_or_else(|v| { | ||||
|                     dvm_panic!( | ||||
|                         state, | ||||
|                         &format!("Expected DvmValue::Object, but found {}", object_value) | ||||
|                     ); | ||||
|                 }); | ||||
|                 let object_ref = object_rc.borrow(); | ||||
|                 let method = object_ref | ||||
|                     .get_method(function_name.as_str()) | ||||
|                     .expect(&format!( | ||||
|                         "Cannot find method {} for object {:?}", | ||||
|                         function_name, object | ||||
|                     )); | ||||
|                     .unwrap_or_else(|| { | ||||
|                         dvm_panic!( | ||||
|                             state, | ||||
|                             &format!( | ||||
|                                 "Cannot find method {} for object {:?}", | ||||
|                                 function_name, object_ref | ||||
|                             ) | ||||
|                         ); | ||||
|                     }); | ||||
|                 let function = method.dm_fn(); | ||||
|                 let instructions = function.instructions(); | ||||
|                 push_call_frame(function_name.clone(), source_code_location.clone(), context); | ||||
|                 run(instructions, context); | ||||
|                 pop_call_frame(context); | ||||
| 
 | ||||
|                 // Do call
 | ||||
|                 state.stack.push(DvmValue::Empty); // space for return value
 | ||||
|                 state.stack.push(object_value); // self object
 | ||||
|                 push_call_frame(function_name.clone(), source_code_location.clone(), state); | ||||
|                 run(instructions, state, context); | ||||
|                 pop_call_frame(state); | ||||
|                 state.stack.pop(); // self object
 | ||||
|             } | ||||
|             Instruction::PlatformCall { | ||||
|                 platform_function_name, | ||||
|             InvokeStaticPlatform { | ||||
|                 function_name, | ||||
|                 source_code_location, | ||||
|             } => { | ||||
|                 // Find function
 | ||||
|                 let platform_function = context | ||||
|                     .platform_functions | ||||
|                     .get(platform_function_name.as_str()) | ||||
|                     .unwrap() | ||||
|                     .clone(); | ||||
|                 push_call_frame( | ||||
|                     platform_function_name.clone(), | ||||
|                     source_code_location.clone(), | ||||
|                     context, | ||||
|                 ); | ||||
|                 platform_function(context); | ||||
|                 pop_call_frame(context); | ||||
|                     .get(function_name.as_str()) | ||||
|                     .unwrap_or_else(|| { | ||||
|                         dvm_panic!( | ||||
|                             state, | ||||
|                             &format!("Cannot find static platform function {}", function_name) | ||||
|                         ); | ||||
|                     }); | ||||
| 
 | ||||
|                 // Do call
 | ||||
|                 state.stack.push(DvmValue::Empty); // space for return value
 | ||||
|                 push_call_frame(function_name.clone(), source_code_location.clone(), state); | ||||
|                 platform_function(state, context); | ||||
|                 pop_call_frame(state); | ||||
|             } | ||||
|             Instruction::Add { .. } => {} | ||||
|             Instruction::Subtract { .. } => {} | ||||
|             Instruction::Multiply { .. } => {} | ||||
|             Instruction::Divide { .. } => {} | ||||
|             Instruction::Modulo { .. } => {} | ||||
|             Instruction::Power { .. } => {} | ||||
|             Instruction::Jump { offset } => { | ||||
|             InvokeObjectPlatform { | ||||
|                 object_register, | ||||
|                 function_name, | ||||
|                 source_code_location, | ||||
|             } => { | ||||
|                 // Find function
 | ||||
|                 let object_platform_function = context | ||||
|                     .platform_functions | ||||
|                     .get(function_name.as_str()) | ||||
|                     .unwrap_or_else(|| { | ||||
|                         dvm_panic!( | ||||
|                             state, | ||||
|                             &format!("Cannot find object platform function {}", function_name) | ||||
|                         ); | ||||
|                     }); | ||||
| 
 | ||||
|                 // Get self object
 | ||||
|                 let object_value = state.registers[*object_register].clone(); | ||||
|                 if !object_value.is_object() { | ||||
|                     dvm_panic!( | ||||
|                         state, | ||||
|                         &format!( | ||||
|                             "Expected DvmValue::Object, but found DvmValue::{:?}", | ||||
|                             object_value | ||||
|                         ) | ||||
|                     ); | ||||
|                 } | ||||
| 
 | ||||
|                 // Do call
 | ||||
|                 state.stack.push(DvmValue::Empty); // space for return value
 | ||||
|                 state.stack.push(object_value); // self object
 | ||||
|                 push_call_frame(function_name.clone(), source_code_location.clone(), state); | ||||
|                 object_platform_function(state, context); | ||||
|                 pop_call_frame(state); | ||||
|                 state.stack.pop(); // self object
 | ||||
|             } | ||||
|             Add { .. } => {} | ||||
|             Subtract { .. } => {} | ||||
|             Multiply { .. } => {} | ||||
|             Divide { .. } => {} | ||||
|             Modulo { .. } => {} | ||||
|             Power { .. } => {} | ||||
|             Jump { offset } => { | ||||
|                 update_index(&mut index, *offset); | ||||
|             } | ||||
|             Instruction::JumpEqual { | ||||
|             JumpEqual { | ||||
|                 left_register, | ||||
|                 right_register, | ||||
|                 offset, | ||||
|             } => { | ||||
|                 let left_value = &context.registers[*left_register]; | ||||
|                 let right_value = &context.registers[*right_register]; | ||||
|                 let left_value = &state.registers[*left_register]; | ||||
|                 let right_value = &state.registers[*right_register]; | ||||
|                 if left_value == right_value { | ||||
|                     update_index(&mut index, *offset); | ||||
|                 } | ||||
|             } | ||||
|             Instruction::JumpNotEqual { .. } => {} | ||||
|             Instruction::JumpLessThan { .. } => {} | ||||
|             Instruction::JumpGreaterThan { .. } => {} | ||||
|             Instruction::JumpLessThanEqual { .. } => {} | ||||
|             Instruction::JumpGreaterThanEqual { .. } => {} | ||||
|             Instruction::Return => { | ||||
|             JumpNotEqual { .. } => {} | ||||
|             JumpLessThan { .. } => {} | ||||
|             JumpGreaterThan { .. } => {} | ||||
|             JumpLessThanEqual { .. } => {} | ||||
|             JumpGreaterThanEqual { .. } => {} | ||||
|             Return => { | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         index += 1; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -4,7 +4,7 @@ use std::collections::HashMap; | ||||
| 
 | ||||
| mod std_lib; | ||||
| 
 | ||||
| pub fn init_platform_functions() -> HashMap<String, PlatformFunction> { | ||||
| pub fn get_std_lib_platform_functions() -> HashMap<String, PlatformFunction> { | ||||
|     let mut fns: HashMap<String, PlatformFunction> = HashMap::new(); | ||||
|     fns.insert(String::from("std::core::print"), dm_print); | ||||
|     fns.insert(String::from("std::core::println"), dm_println); | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| use crate::vm::object::DvmObject; | ||||
| use crate::vm::value::DvmValue; | ||||
| use crate::vm::DvmContext; | ||||
| use crate::vm::{DvmContext, DvmState}; | ||||
| use std::cell::RefCell; | ||||
| use std::rc::Rc; | ||||
| 
 | ||||
| @ -8,12 +8,12 @@ use std::rc::Rc; | ||||
| /// // Signature
 | ||||
| /// print(m: &(Byte | Int | Long | Double | USize | Boolean | Object | Empty))
 | ||||
| /// ```
 | ||||
| pub fn dm_print(context: &mut DvmContext) { | ||||
|     print!("{}", get_string(context.pop_stack())); | ||||
| pub fn dm_print(state: &mut DvmState, context: &DvmContext) { | ||||
|     print!("{}", get_string(state.get_stack_argument(0))); | ||||
| } | ||||
| 
 | ||||
| pub fn dm_println(context: &mut DvmContext) { | ||||
|     println!("{}", get_string(context.pop_stack())); | ||||
| pub fn dm_println(state: &mut DvmState, context: &DvmContext) { | ||||
|     println!("{}", get_string(state.get_stack_argument(0))); | ||||
| } | ||||
| 
 | ||||
| fn get_string(dvm_value: DvmValue) -> String { | ||||
| @ -26,29 +26,11 @@ fn get_string(dvm_value: DvmValue) -> String { | ||||
|         DvmValue::Object(object) => object_to_string(object.clone()), | ||||
|         DvmValue::USize(u) => u.to_string(), | ||||
|         DvmValue::Array(a) => a.borrow().to_string(), | ||||
|         DvmValue::ConstantPointer(p) => p.to_string(), | ||||
|         DvmValue::String(s) => s.to_string(), | ||||
|         DvmValue::Empty => String::from("Empty"), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn object_to_string(object: Rc<RefCell<DvmObject>>) -> String { | ||||
|     if object.borrow().implementation().fqn() == "std::core::StringImpl" { | ||||
|         extract_string_from_string(object.clone()) | ||||
|     } else { | ||||
|         todo!("what happens if we don't have a String?") | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn extract_string_from_string(string_object: Rc<RefCell<DvmObject>>) -> String { | ||||
|     let object_ref = string_object.borrow(); | ||||
|     let bytes_field_value = object_ref.read_field("bytes"); | ||||
|     if let DvmValue::ConstantPointer(bytes_ptr) = bytes_field_value { | ||||
|         let mut v = Vec::new(); | ||||
|         for i in 0..bytes_ptr.length { | ||||
|             v.push(unsafe { bytes_ptr.raw_pointer.add(i).read() }); | ||||
|         } | ||||
|         String::from_utf8(v).unwrap() | ||||
|     } else { | ||||
|         panic!("StringImpl.bytes field is not a DvmValue::ConstantPointer."); | ||||
|     } | ||||
|     todo!("Lookup to_string method!") | ||||
| } | ||||
|  | ||||
| @ -1,13 +0,0 @@ | ||||
| use std::fmt::Display; | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq)] | ||||
| pub struct DvmPointer { | ||||
|     pub raw_pointer: *const u8, | ||||
|     pub length: usize, | ||||
| } | ||||
| 
 | ||||
| impl Display for DvmPointer { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         write!(f, "DvmPointer({:p}, {})", self.raw_pointer, self.length) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										6
									
								
								src/vm/source_code_location.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/vm/source_code_location.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct SourceCodeLocation { | ||||
|     pub source_file_name: String, | ||||
|     pub line: i64, | ||||
|     pub char: i64, | ||||
| } | ||||
| @ -1,6 +1,5 @@ | ||||
| use crate::vm::array::DvmArray; | ||||
| use crate::vm::object::DvmObject; | ||||
| use crate::vm::pointer::DvmPointer; | ||||
| use std::cell::RefCell; | ||||
| use std::fmt::{Display, Formatter}; | ||||
| use std::rc::Rc; | ||||
| @ -21,8 +20,8 @@ pub enum DvmValue { | ||||
|     // Array
 | ||||
|     Array(Rc<RefCell<DvmArray>>), | ||||
| 
 | ||||
|     // Pointer to constant u8
 | ||||
|     ConstantPointer(DvmPointer), | ||||
|     // String
 | ||||
|     String(Rc<String>), | ||||
| 
 | ||||
|     // Null
 | ||||
|     Empty, | ||||
| @ -45,7 +44,7 @@ impl Display for DvmValue { | ||||
|             DvmValue::Boolean(b) => write!(f, "Boolean({})", b), | ||||
|             DvmValue::Object(o) => write!(f, "Object({:p})", &o), | ||||
|             DvmValue::Array(a) => write!(f, "Array({:p})", &a), | ||||
|             DvmValue::ConstantPointer(p) => write!(f, "ConstantPointer({})", p), | ||||
|             DvmValue::String(s) => write!(f, "String({})", s), | ||||
|             DvmValue::Empty => write!(f, "Empty"), | ||||
|         } | ||||
|     } | ||||
| @ -72,6 +71,14 @@ impl DvmValue { | ||||
|         } | ||||
|     } | ||||
|     
 | ||||
|     pub fn expect_int_or_else(&self, f: impl FnOnce(&Self) -> i32) -> i32 { | ||||
|         if let DvmValue::Int(i) = self { | ||||
|             *i | ||||
|         } else { | ||||
|             f(self) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn expect_long(&self) -> i64 { | ||||
|         if let DvmValue::Long(l) = self { | ||||
|             *l | ||||
| @ -103,6 +110,17 @@ impl DvmValue { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn expect_object_or_else( | ||||
|         &self, | ||||
|         f: impl FnOnce(&Self) -> DvmObject, | ||||
|     ) -> Rc<RefCell<DvmObject>> { | ||||
|         if let DvmValue::Object(o) = self { | ||||
|             o.clone() | ||||
|         } else { | ||||
|             Rc::new(RefCell::new(f(self))) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn map_object<T>( | ||||
|         &self, | ||||
|         mapper: impl FnOnce(Rc<RefCell<DvmObject>>) -> T, | ||||
| @ -183,14 +201,19 @@ impl DvmValue { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn expect_constant_pointer(&self) -> DvmPointer { | ||||
|         if let DvmValue::ConstantPointer(ptr) = self { | ||||
|             ptr.clone() | ||||
|     pub fn expect_string(&self) -> Rc<String> { | ||||
|         if let DvmValue::String(s) = self { | ||||
|             s.clone() | ||||
|         } else { | ||||
|             panic!( | ||||
|                 "Expected DvmValue::ConstantPointer, but found DvmValue::{:?}", | ||||
|                 self | ||||
|             ); | ||||
|             panic!("Expected DvmValue::String, but found DvmValue::{:?}", self); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn expect_string_or_else(&self, f: impl FnOnce(&Self) -> String) -> Rc<String> { | ||||
|         if let DvmValue::String(s) = self { | ||||
|             s.clone() | ||||
|         } else { | ||||
|             Rc::new(f(self)) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user