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::function::DvmFunction; | ||||||
| use deimos::vm::implementation::DvmImplementation; | use deimos::vm::instruction::{Immediate, Instruction, Location}; | ||||||
| use deimos::vm::interface::DmInterface; | use deimos::vm::platform::get_std_lib_platform_functions; | ||||||
| use deimos::vm::lib::{DmConstant, DmLib}; | use deimos::vm::source_code_location::SourceCodeLocation; | ||||||
| use deimos::vm::method::DvmMethod; | use deimos::vm::{dump_state, run_main_function, DvmContext, DvmState}; | ||||||
| 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 std::rc::Rc; | use std::rc::Rc; | ||||||
| 
 | 
 | ||||||
| fn main() { | fn main() { | ||||||
|     // Goal:
 |     // Goal:
 | ||||||
|     // - write a single lib with a main()
 |     // - write a single lib with a main()
 | ||||||
|     // - call the main fn
 |     // - 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 main_function = DvmFunction::new( | ||||||
|     let mut array_lib = DmLib::new("std/core/array"); |         "greeter::main", | ||||||
| 
 |         &main_instructions, | ||||||
|     // std::core::Array
 |         SourceCodeLocation { | ||||||
|     let array_int = DmInterface::new("std::core::Array"); |             source_file_name: String::from("greeter.dm"), | ||||||
|     array_lib.add_interface(array_int); |             line: 3, | ||||||
|     let array_int_rc = array_lib |             char: 1, | ||||||
|         .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 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 state = DvmState::new(); | ||||||
|     let mut context = DvmContext::new(); |     let mut context = DvmContext::new(Rc::new(main_function)); | ||||||
|     context.load_libs(vec![ |     context.add_platform_functions(get_std_lib_platform_functions()); | ||||||
|         Rc::new(greeting_lib), |     let exit_code = run_main_function(&mut state, &context); | ||||||
|         Rc::new(string_lib), |  | ||||||
|         Rc::new(array_lib), |  | ||||||
|     ]); |  | ||||||
|     context.load_platform_fns(init_platform_functions()); |  | ||||||
| 
 | 
 | ||||||
|     let main_fn = context.fn_by_fqn("main").unwrap(); |     dump_state(&state, "After main!"); | ||||||
|     call_fn(&mut state, &context, &main_fn, vec![]); | 
 | ||||||
|  |     if exit_code != 0 { | ||||||
|  |         std::process::exit(exit_code); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| use crate::vm::object::DvmObject; | use crate::vm::object::DvmObject; | ||||||
| use crate::vm::pointer::DvmPointer; |  | ||||||
| use crate::vm::value::DvmValue; | use crate::vm::value::DvmValue; | ||||||
| use std::cell::RefCell; | use std::cell::RefCell; | ||||||
| use std::fmt::{Display, Write}; | use std::fmt::{Display, Write}; | ||||||
| @ -16,7 +15,7 @@ pub enum DvmArray { | |||||||
|     Booleans(Vec<bool>), |     Booleans(Vec<bool>), | ||||||
|     Objects(Vec<Rc<RefCell<DvmObject>>>), |     Objects(Vec<Rc<RefCell<DvmObject>>>), | ||||||
|     Arrays(Vec<Rc<RefCell<DvmArray>>>), |     Arrays(Vec<Rc<RefCell<DvmArray>>>), | ||||||
|     ConstantPointers(Vec<DvmPointer>), |     Strings(Vec<Rc<String>>), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl DvmArray { | impl DvmArray { | ||||||
| @ -30,7 +29,7 @@ impl DvmArray { | |||||||
|             DvmArray::Booleans(vec) => DvmValue::Boolean(vec[index]), |             DvmArray::Booleans(vec) => DvmValue::Boolean(vec[index]), | ||||||
|             DvmArray::Objects(vec) => DvmValue::Object(vec[index].clone()), |             DvmArray::Objects(vec) => DvmValue::Object(vec[index].clone()), | ||||||
|             DvmArray::Arrays(vec) => DvmValue::Array(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) => { |             DvmArray::Arrays(vec) => { | ||||||
|                 vec[index] = value.expect_array(); |                 vec[index] = value.expect_array(); | ||||||
|             } |             } | ||||||
|             DvmArray::ConstantPointers(vec) => { |             DvmArray::Strings(vec) => { | ||||||
|                 vec[index] = value.expect_constant_pointer(); |                 vec[index] = value.expect_string(); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -89,7 +88,7 @@ pub enum DvmArrayIter<'a> { | |||||||
|     Booleans(Iter<'a, bool>), |     Booleans(Iter<'a, bool>), | ||||||
|     Objects(Iter<'a, Rc<RefCell<DvmObject>>>), |     Objects(Iter<'a, Rc<RefCell<DvmObject>>>), | ||||||
|     Arrays(Iter<'a, Rc<RefCell<DvmArray>>>), |     Arrays(Iter<'a, Rc<RefCell<DvmArray>>>), | ||||||
|     ConstantPointers(Iter<'a, DvmPointer>), |     Strings(Iter<'a, Rc<String>>), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'a> Iterator for DvmArrayIter<'a> { | 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::Booleans(iter) => iter.next().map(|b| DvmValue::Boolean(*b)), | ||||||
|             DvmArrayIter::Objects(iter) => iter.next().map(|o| DvmValue::Object(o.clone())), |             DvmArrayIter::Objects(iter) => iter.next().map(|o| DvmValue::Object(o.clone())), | ||||||
|             DvmArrayIter::Arrays(iter) => iter.next().map(|a| DvmValue::Array(a.clone())), |             DvmArrayIter::Arrays(iter) => iter.next().map(|a| DvmValue::Array(a.clone())), | ||||||
|             DvmArrayIter::ConstantPointers(iter) => { |             DvmArrayIter::Strings(iter) => iter.next().map(|s| DvmValue::String(s.clone())), | ||||||
|                 iter.next().map(|p| DvmValue::ConstantPointer(p.clone())) |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -125,7 +122,7 @@ impl<'a> IntoIterator for &'a DvmArray { | |||||||
|             DvmArray::Booleans(v) => DvmArrayIter::Booleans(v.iter()), |             DvmArray::Booleans(v) => DvmArrayIter::Booleans(v.iter()), | ||||||
|             DvmArray::Objects(v) => DvmArrayIter::Objects(v.iter()), |             DvmArray::Objects(v) => DvmArrayIter::Objects(v.iter()), | ||||||
|             DvmArray::Arrays(v) => DvmArrayIter::Arrays(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::instruction::Instruction; | ||||||
|  | use crate::vm::source_code_location::SourceCodeLocation; | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct DvmFunction { | pub struct DvmFunction { | ||||||
|     fqn: String, |     fqn: String, | ||||||
|     instructions: Vec<Instruction>, |     instructions: Vec<Instruction>, | ||||||
|  |     source_code_location: SourceCodeLocation, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl DvmFunction { | impl DvmFunction { | ||||||
|     pub fn new(fqn: &str, instructions: &[Instruction]) -> Self { |     pub fn new( | ||||||
|  |         fqn: &str, | ||||||
|  |         instructions: &[Instruction], | ||||||
|  |         source_code_location: SourceCodeLocation, | ||||||
|  |     ) -> Self { | ||||||
|         DvmFunction { |         DvmFunction { | ||||||
|             fqn: fqn.to_string(), |             fqn: fqn.to_string(), | ||||||
|             instructions: Vec::from(instructions), |             instructions: Vec::from(instructions), | ||||||
|  |             source_code_location, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -21,6 +28,10 @@ impl DvmFunction { | |||||||
|     pub fn instructions(&self) -> &Vec<Instruction> { |     pub fn instructions(&self) -> &Vec<Instruction> { | ||||||
|         &self.instructions |         &self.instructions | ||||||
|     } |     } | ||||||
|  |     
 | ||||||
|  |     pub fn source_code_location(&self) -> &SourceCodeLocation { | ||||||
|  |         &self.source_code_location | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl PartialEq for DvmFunction { | impl PartialEq for DvmFunction { | ||||||
|  | |||||||
| @ -1,3 +1,5 @@ | |||||||
|  | use crate::vm::constant::DvmConstant; | ||||||
|  | use crate::vm::source_code_location::SourceCodeLocation; | ||||||
| use std::rc::Rc; | use std::rc::Rc; | ||||||
| 
 | 
 | ||||||
| #[derive(Debug, Clone)] | #[derive(Debug, Clone)] | ||||||
| @ -14,7 +16,7 @@ pub enum Instruction { | |||||||
|         source_register: usize, |         source_register: usize, | ||||||
|     }, |     }, | ||||||
|     Pop { |     Pop { | ||||||
|         destination_register: usize, |         destination_register: Option<usize>, | ||||||
|     }, |     }, | ||||||
|     AllocateObject { |     AllocateObject { | ||||||
|         implementation_name: Rc<String>, |         implementation_name: Rc<String>, | ||||||
| @ -29,8 +31,13 @@ pub enum Instruction { | |||||||
|         function_name: Rc<String>, |         function_name: Rc<String>, | ||||||
|         source_code_location: SourceCodeLocation, |         source_code_location: SourceCodeLocation, | ||||||
|     }, |     }, | ||||||
|     PlatformCall { |     InvokeStaticPlatform { | ||||||
|         platform_function_name: Rc<String>, |         function_name: Rc<String>, | ||||||
|  |         source_code_location: SourceCodeLocation, | ||||||
|  |     }, | ||||||
|  |     InvokeObjectPlatform { | ||||||
|  |         object_register: usize, | ||||||
|  |         function_name: Rc<String>, | ||||||
|         source_code_location: SourceCodeLocation, |         source_code_location: SourceCodeLocation, | ||||||
|     }, |     }, | ||||||
|     Add { |     Add { | ||||||
| @ -107,10 +114,7 @@ pub enum Immediate { | |||||||
|     Double(f64), |     Double(f64), | ||||||
|     Usize(usize), |     Usize(usize), | ||||||
|     Boolean(bool), |     Boolean(bool), | ||||||
|     ConstantPointer { |     Constant(DvmConstant), | ||||||
|         raw_pointer: *const u8, |  | ||||||
|         length: usize |  | ||||||
|     }, |  | ||||||
|     Empty, |     Empty, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -130,10 +134,3 @@ pub enum Location { | |||||||
|         offset: Option<isize>, |         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; | mod array; | ||||||
|  | pub mod constant; | ||||||
| mod field; | mod field; | ||||||
| mod function; | pub mod function; | ||||||
| pub mod implementation; | pub mod implementation; | ||||||
| mod instruction; | pub mod instruction; | ||||||
| mod interface; | mod interface; | ||||||
| pub mod lib; | pub mod lib; | ||||||
| mod method; | mod method; | ||||||
| pub mod object; | pub mod object; | ||||||
| pub mod op_codes; | pub mod op_codes; | ||||||
| pub mod platform; | pub mod platform; | ||||||
| mod pointer; | pub mod source_code_location; | ||||||
| pub mod r#type; | pub mod r#type; | ||||||
| pub mod util; | pub mod util; | ||||||
| pub mod value; | pub mod value; | ||||||
| mod virtual_method; | mod virtual_method; | ||||||
| 
 | 
 | ||||||
|  | use crate::vm::array::DvmArray; | ||||||
|  | use crate::vm::constant::{DvmConstant, DvmConstantArray}; | ||||||
| use crate::vm::implementation::DvmImplementation; | 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::object::DvmObject; | ||||||
| use crate::vm::pointer::DvmPointer; |  | ||||||
| use crate::vm::value::DvmValue; | use crate::vm::value::DvmValue; | ||||||
| use function::DvmFunction; | use function::DvmFunction; | ||||||
|  | use source_code_location::SourceCodeLocation; | ||||||
| use std::cell::RefCell; | use std::cell::RefCell; | ||||||
| use std::collections::HashMap; | use std::collections::HashMap; | ||||||
| use std::fmt::Display; | use std::fmt::Display; | ||||||
| use std::rc::Rc; | use std::rc::Rc; | ||||||
| 
 | 
 | ||||||
| fn dvm_panic(context: &DvmContext, message: &str) { | pub fn dump_state(state: &DvmState, message: &str) { | ||||||
|     println!("----"); |     println!("----"); | ||||||
|     println!("Deimos Virtual Machine: Panic!"); |  | ||||||
|     println!("{}", message); |     println!("{}", message); | ||||||
|     println!("----"); |     println!("----"); | ||||||
|     println!("Current Instruction: {:?}", context.current_instruction); |     println!( | ||||||
|  |         "Current Instruction: {:?}", | ||||||
|  |         state.current_instruction.clone().unwrap() | ||||||
|  |     ); | ||||||
|     println!("Registers:"); |     println!("Registers:"); | ||||||
|     for (i, register) in context.registers.iter().enumerate() { |     for (i, register) in state.registers.iter().enumerate() { | ||||||
|         println!("\tr{}: {:?}", i, register); |         println!("\tr{:x}: {:?}", i, register); | ||||||
|     } |     } | ||||||
|     println!("Call stack:"); |     println!("Call stack:"); | ||||||
|     for call in context.call_stack.iter() { |     for call in state.call_stack.iter() { | ||||||
|         println!("\t{}", call); |         println!("\t{}", call); | ||||||
|     } |     } | ||||||
|     println!("Stack:"); |     println!("Stack:"); | ||||||
|     for (i, value) in context.stack.iter().enumerate() { |     for (i, value) in state.stack.iter().enumerate() { | ||||||
|         println!("\t{}: {}", i, value); |         println!("\t{}: {}", i, value); | ||||||
|     } |     } | ||||||
|     println!("----"); |     println!("----"); | ||||||
| @ -49,33 +54,27 @@ fn dvm_panic(context: &DvmContext, message: &str) { | |||||||
| 
 | 
 | ||||||
| macro_rules! dvm_panic { | macro_rules! dvm_panic { | ||||||
|     ($context: expr, $message: expr) => { |     ($context: expr, $message: expr) => { | ||||||
|         dvm_panic($context, $message); |         dump_state($context, $message); | ||||||
|         panic!() |         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>, |     call_stack: Vec<DvmCall>, | ||||||
|     current_instruction: Option<Instruction>, |     current_instruction: Option<Instruction>, | ||||||
|     registers: Vec<DvmValue>, |     registers: Vec<DvmValue>, | ||||||
|     stack: 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 { |     pub fn new() -> Self { | ||||||
|         DvmContext { |         DvmState { | ||||||
|             call_stack: vec![], |             call_stack: vec![], | ||||||
|             current_instruction: None, |             current_instruction: None, | ||||||
|             registers: vec![], |             registers: vec![DvmValue::Empty; 16], | ||||||
|             stack: vec![], |             stack: vec![], | ||||||
|             implementations: HashMap::new(), |  | ||||||
|             static_functions: HashMap::new(), |  | ||||||
|             platform_functions: HashMap::new(), |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -84,6 +83,42 @@ impl DvmContext { | |||||||
|             dvm_panic!(self, "Stack underflow!"); |             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 { | pub struct DvmCall { | ||||||
| @ -114,16 +149,16 @@ fn update_index(index: &mut usize, offset: isize) { | |||||||
| fn push_call_frame( | fn push_call_frame( | ||||||
|     function_name: Rc<String>, |     function_name: Rc<String>, | ||||||
|     source_code_location: SourceCodeLocation, |     source_code_location: SourceCodeLocation, | ||||||
|     context: &mut DvmContext, |     state: &mut DvmState, | ||||||
| ) { | ) { | ||||||
|     context.call_stack.push(DvmCall { |     state.call_stack.push(DvmCall { | ||||||
|         function_name, |         function_name, | ||||||
|         source_code_location, |         source_code_location, | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn pop_call_frame(context: &mut DvmContext) { | fn pop_call_frame(state: &mut DvmState) { | ||||||
|     context.call_stack.pop(); |     state.call_stack.pop(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn compute_index_with_offset( | 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 { |     match source { | ||||||
|         Location::Register(register) => context.registers[*register].clone(), |         Location::Register(register) => state.registers[*register].clone(), | ||||||
|         Location::Stack { offset } => context.stack[*offset].clone(), |         Location::Stack { offset } => state.stack[*offset].clone(), | ||||||
|         Location::Field { |         Location::Field { | ||||||
|             object_register, |             object_register, | ||||||
|             field_name, |             field_name, | ||||||
|         } => context.registers[*object_register].map_object( |         } => state.registers[*object_register].map_object( | ||||||
|             |o| o.borrow().read_field(field_name).clone(), |             |o| o.borrow().read_field(field_name).clone(), | ||||||
|             |v| { |             |v| { | ||||||
|                 dvm_panic!(context, &format!("Expected an object, but found: {}", v)); |                 dvm_panic!(state, &format!("Expected an object, but found: {}", v)); | ||||||
|             }, |             }, | ||||||
|         ), |         ), | ||||||
|         Location::Array { |         Location::Array { | ||||||
| @ -164,30 +199,30 @@ fn copy_from_source(context: &DvmContext, source: &Location) -> DvmValue { | |||||||
|             index_register, |             index_register, | ||||||
|             offset, |             offset, | ||||||
|         } => { |         } => { | ||||||
|             let index = compute_index_with_offset(&context.registers, *index_register, offset); |             let index = compute_index_with_offset(&state.registers, *index_register, offset); | ||||||
|             context.registers[*array_register].map_array( |             state.registers[*array_register].map_array( | ||||||
|                 |a| a.borrow().read_element(index), |                 |a| a.borrow().read_element(index), | ||||||
|                 |v| { |                 |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 { |     match destination { | ||||||
|         Location::Register(register) => { |         Location::Register(register) => { | ||||||
|             context.registers[*register] = value; |             state.registers[*register] = value; | ||||||
|         } |         } | ||||||
|         Location::Stack { offset } => { |         Location::Stack { offset } => { | ||||||
|             context.stack[*offset] = value; |             state.stack[*offset] = value; | ||||||
|         } |         } | ||||||
|         Location::Field { |         Location::Field { | ||||||
|             object_register, |             object_register, | ||||||
|             field_name, |             field_name, | ||||||
|         } => { |         } => { | ||||||
|             context.registers[*object_register] |             state.registers[*object_register] | ||||||
|                 .expect_object() |                 .expect_object() | ||||||
|                 .borrow_mut() |                 .borrow_mut() | ||||||
|                 .write_field(field_name, value); |                 .write_field(field_name, value); | ||||||
| @ -197,8 +232,8 @@ fn write_to_destination(context: &mut DvmContext, destination: &Location, value: | |||||||
|             index_register, |             index_register, | ||||||
|             offset, |             offset, | ||||||
|         } => { |         } => { | ||||||
|             let index = compute_index_with_offset(&context.registers, *index_register, offset); |             let index = compute_index_with_offset(&state.registers, *index_register, offset); | ||||||
|             context.registers[*array_register] |             state.registers[*array_register] | ||||||
|                 .expect_array() |                 .expect_array() | ||||||
|                 .borrow_mut() |                 .borrow_mut() | ||||||
|                 .write_element(index, value); |                 .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 { | fn immediate_to_value(immediate: &Immediate) -> DvmValue { | ||||||
|     match immediate { |     match immediate { | ||||||
|         Immediate::Byte(b) => DvmValue::Byte(*b), |         Immediate::Byte(b) => DvmValue::Byte(*b), | ||||||
| @ -214,137 +275,220 @@ fn immediate_to_value(immediate: &Immediate) -> DvmValue { | |||||||
|         Immediate::Double(d) => DvmValue::Double(*d), |         Immediate::Double(d) => DvmValue::Double(*d), | ||||||
|         Immediate::Usize(s) => DvmValue::USize(*s), |         Immediate::Usize(s) => DvmValue::USize(*s), | ||||||
|         Immediate::Boolean(b) => DvmValue::Boolean(*b), |         Immediate::Boolean(b) => DvmValue::Boolean(*b), | ||||||
|         Immediate::ConstantPointer { |         Immediate::Constant(c) => constant_to_value(c), | ||||||
|             raw_pointer, |  | ||||||
|             length, |  | ||||||
|         } => DvmValue::ConstantPointer(DvmPointer { |  | ||||||
|             raw_pointer: *raw_pointer, |  | ||||||
|             length: *length, |  | ||||||
|         }), |  | ||||||
|         Immediate::Empty => DvmValue::Empty, |         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
 | // 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; |     let mut index = 0; | ||||||
|     while index < instructions.len() { |     while index < instructions.len() { | ||||||
|         context.current_instruction = Some(instructions[index].clone()); |         state.current_instruction = Some(instructions[index].clone()); | ||||||
|         index += 1; |         use Instruction::*; | ||||||
|         match &instructions[index] { |         match &instructions[index] { | ||||||
|             Instruction::MoveImmediate { |             MoveImmediate { | ||||||
|                 destination, |                 destination, | ||||||
|                 immediate, |                 immediate, | ||||||
|             } => { |             } => { | ||||||
|                 write_to_destination(context, destination, immediate_to_value(immediate)); |                 write_to_destination(state, destination, immediate_to_value(immediate)); | ||||||
|             } |             } | ||||||
|             Instruction::Copy { |             Copy { | ||||||
|                 source, |                 source, | ||||||
|                 destination, |                 destination, | ||||||
|             } => { |             } => { | ||||||
|                 let value = copy_from_source(context, source); |                 let value = copy_from_source(state, source); | ||||||
|                 write_to_destination(context, destination, value); |                 write_to_destination(state, destination, value); | ||||||
|             } |             } | ||||||
|             Instruction::Push { source_register } => { |             Push { source_register } => { | ||||||
|                 context |                 state.stack.push(state.registers[*source_register].clone()); | ||||||
|                     .stack |  | ||||||
|                     .push(context.registers[*source_register].clone()); |  | ||||||
|             } |             } | ||||||
|             Instruction::Pop { |             Pop { | ||||||
|                 destination_register, |                 destination_register, | ||||||
|             } => { |             } => { | ||||||
|                 let value = context.stack.pop().expect("Stack underflow"); |                 let value = state.stack.pop().unwrap_or_else(|| { | ||||||
|                 context.registers[*destination_register] = value; |                     dvm_panic!(state, "Stack underflow"); | ||||||
|  |                 }); | ||||||
|  |                 if let Some(register_index) = destination_register { | ||||||
|  |                     state.registers[*register_index] = value; | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|             Instruction::AllocateObject { |             AllocateObject { | ||||||
|                 implementation_name, |                 implementation_name, | ||||||
|                 destination_register, |                 destination_register, | ||||||
|             } => { |             } => { | ||||||
|                 let implementation = context |                 let implementation = context | ||||||
|                     .implementations |                     .implementations | ||||||
|                     .get(implementation_name.as_str()) |                     .get(implementation_name.as_str()) | ||||||
|                     .unwrap(); |                     .unwrap_or_else(|| { | ||||||
|                 let object = DvmObject::new(implementation.clone()); |                         dvm_panic!( | ||||||
|                 context.registers[*destination_register] = |                             state, | ||||||
|  |                             &format!("Cannot find implementation {}", implementation_name) | ||||||
|  |                         ); | ||||||
|  |                     }) | ||||||
|  |                     .clone(); | ||||||
|  |                 let object = DvmObject::new(implementation); | ||||||
|  |                 state.registers[*destination_register] = | ||||||
|                     DvmValue::Object(Rc::new(RefCell::new(object))); |                     DvmValue::Object(Rc::new(RefCell::new(object))); | ||||||
|             } |             } | ||||||
|             Instruction::InvokeStatic { |             InvokeStatic { | ||||||
|                 function_name, |                 function_name, | ||||||
|                 source_code_location, |                 source_code_location, | ||||||
|             } => { |             } => { | ||||||
|  |                 // Find function
 | ||||||
|                 let static_function = context |                 let static_function = context | ||||||
|                     .static_functions |                     .static_functions | ||||||
|                     .get(function_name.as_str()) |                     .get(function_name.as_str()) | ||||||
|                     .unwrap() |                     .unwrap_or_else(|| { | ||||||
|  |                         dvm_panic!( | ||||||
|  |                             state, | ||||||
|  |                             &format!("Cannot find static function {}", function_name) | ||||||
|  |                         ); | ||||||
|  |                     }) | ||||||
|                     .clone(); |                     .clone(); | ||||||
|                 push_call_frame(function_name.clone(), source_code_location.clone(), context); | 
 | ||||||
|                 run(static_function.instructions(), context); |                 // Do call
 | ||||||
|                 pop_call_frame(context); |                 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, |                 object_register, | ||||||
|                 function_name, |                 function_name, | ||||||
|                 source_code_location, |                 source_code_location, | ||||||
|             } => { |             } => { | ||||||
|                 let object = context.registers[*object_register].expect_object(); |                 // Find method and get instructions
 | ||||||
|                 let object_ref = object.borrow(); |                 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 |                 let method = object_ref | ||||||
|                     .get_method(function_name.as_str()) |                     .get_method(function_name.as_str()) | ||||||
|                     .expect(&format!( |                     .unwrap_or_else(|| { | ||||||
|                         "Cannot find method {} for object {:?}", |                         dvm_panic!( | ||||||
|                         function_name, object |                             state, | ||||||
|                     )); |                             &format!( | ||||||
|  |                                 "Cannot find method {} for object {:?}", | ||||||
|  |                                 function_name, object_ref | ||||||
|  |                             ) | ||||||
|  |                         ); | ||||||
|  |                     }); | ||||||
|                 let function = method.dm_fn(); |                 let function = method.dm_fn(); | ||||||
|                 let instructions = function.instructions(); |                 let instructions = function.instructions(); | ||||||
|                 push_call_frame(function_name.clone(), source_code_location.clone(), context); | 
 | ||||||
|                 run(instructions, context); |                 // Do call
 | ||||||
|                 pop_call_frame(context); |                 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 { |             InvokeStaticPlatform { | ||||||
|                 platform_function_name, |                 function_name, | ||||||
|                 source_code_location, |                 source_code_location, | ||||||
|             } => { |             } => { | ||||||
|  |                 // Find function
 | ||||||
|                 let platform_function = context |                 let platform_function = context | ||||||
|                     .platform_functions |                     .platform_functions | ||||||
|                     .get(platform_function_name.as_str()) |                     .get(function_name.as_str()) | ||||||
|                     .unwrap() |                     .unwrap_or_else(|| { | ||||||
|                     .clone(); |                         dvm_panic!( | ||||||
|                 push_call_frame( |                             state, | ||||||
|                     platform_function_name.clone(), |                             &format!("Cannot find static platform function {}", function_name) | ||||||
|                     source_code_location.clone(), |                         ); | ||||||
|                     context, |                     }); | ||||||
|                 ); | 
 | ||||||
|                 platform_function(context); |                 // Do call
 | ||||||
|                 pop_call_frame(context); |                 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 { .. } => {} |             InvokeObjectPlatform { | ||||||
|             Instruction::Subtract { .. } => {} |                 object_register, | ||||||
|             Instruction::Multiply { .. } => {} |                 function_name, | ||||||
|             Instruction::Divide { .. } => {} |                 source_code_location, | ||||||
|             Instruction::Modulo { .. } => {} |             } => { | ||||||
|             Instruction::Power { .. } => {} |                 // Find function
 | ||||||
|             Instruction::Jump { offset } => { |                 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); |                 update_index(&mut index, *offset); | ||||||
|             } |             } | ||||||
|             Instruction::JumpEqual { |             JumpEqual { | ||||||
|                 left_register, |                 left_register, | ||||||
|                 right_register, |                 right_register, | ||||||
|                 offset, |                 offset, | ||||||
|             } => { |             } => { | ||||||
|                 let left_value = &context.registers[*left_register]; |                 let left_value = &state.registers[*left_register]; | ||||||
|                 let right_value = &context.registers[*right_register]; |                 let right_value = &state.registers[*right_register]; | ||||||
|                 if left_value == right_value { |                 if left_value == right_value { | ||||||
|                     update_index(&mut index, *offset); |                     update_index(&mut index, *offset); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             Instruction::JumpNotEqual { .. } => {} |             JumpNotEqual { .. } => {} | ||||||
|             Instruction::JumpLessThan { .. } => {} |             JumpLessThan { .. } => {} | ||||||
|             Instruction::JumpGreaterThan { .. } => {} |             JumpGreaterThan { .. } => {} | ||||||
|             Instruction::JumpLessThanEqual { .. } => {} |             JumpLessThanEqual { .. } => {} | ||||||
|             Instruction::JumpGreaterThanEqual { .. } => {} |             JumpGreaterThanEqual { .. } => {} | ||||||
|             Instruction::Return => { |             Return => { | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         index += 1; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ use std::collections::HashMap; | |||||||
| 
 | 
 | ||||||
| mod std_lib; | 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(); |     let mut fns: HashMap<String, PlatformFunction> = HashMap::new(); | ||||||
|     fns.insert(String::from("std::core::print"), dm_print); |     fns.insert(String::from("std::core::print"), dm_print); | ||||||
|     fns.insert(String::from("std::core::println"), dm_println); |     fns.insert(String::from("std::core::println"), dm_println); | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| use crate::vm::object::DvmObject; | use crate::vm::object::DvmObject; | ||||||
| use crate::vm::value::DvmValue; | use crate::vm::value::DvmValue; | ||||||
| use crate::vm::DvmContext; | use crate::vm::{DvmContext, DvmState}; | ||||||
| use std::cell::RefCell; | use std::cell::RefCell; | ||||||
| use std::rc::Rc; | use std::rc::Rc; | ||||||
| 
 | 
 | ||||||
| @ -8,12 +8,12 @@ use std::rc::Rc; | |||||||
| /// // Signature
 | /// // Signature
 | ||||||
| /// print(m: &(Byte | Int | Long | Double | USize | Boolean | Object | Empty))
 | /// print(m: &(Byte | Int | Long | Double | USize | Boolean | Object | Empty))
 | ||||||
| /// ```
 | /// ```
 | ||||||
| pub fn dm_print(context: &mut DvmContext) { | pub fn dm_print(state: &mut DvmState, context: &DvmContext) { | ||||||
|     print!("{}", get_string(context.pop_stack())); |     print!("{}", get_string(state.get_stack_argument(0))); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn dm_println(context: &mut DvmContext) { | pub fn dm_println(state: &mut DvmState, context: &DvmContext) { | ||||||
|     println!("{}", get_string(context.pop_stack())); |     println!("{}", get_string(state.get_stack_argument(0))); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn get_string(dvm_value: DvmValue) -> String { | 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::Object(object) => object_to_string(object.clone()), | ||||||
|         DvmValue::USize(u) => u.to_string(), |         DvmValue::USize(u) => u.to_string(), | ||||||
|         DvmValue::Array(a) => a.borrow().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"), |         DvmValue::Empty => String::from("Empty"), | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn object_to_string(object: Rc<RefCell<DvmObject>>) -> String { | fn object_to_string(object: Rc<RefCell<DvmObject>>) -> String { | ||||||
|     if object.borrow().implementation().fqn() == "std::core::StringImpl" { |     todo!("Lookup to_string method!") | ||||||
|         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."); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -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::array::DvmArray; | ||||||
| use crate::vm::object::DvmObject; | use crate::vm::object::DvmObject; | ||||||
| use crate::vm::pointer::DvmPointer; |  | ||||||
| use std::cell::RefCell; | use std::cell::RefCell; | ||||||
| use std::fmt::{Display, Formatter}; | use std::fmt::{Display, Formatter}; | ||||||
| use std::rc::Rc; | use std::rc::Rc; | ||||||
| @ -21,8 +20,8 @@ pub enum DvmValue { | |||||||
|     // Array
 |     // Array
 | ||||||
|     Array(Rc<RefCell<DvmArray>>), |     Array(Rc<RefCell<DvmArray>>), | ||||||
| 
 | 
 | ||||||
|     // Pointer to constant u8
 |     // String
 | ||||||
|     ConstantPointer(DvmPointer), |     String(Rc<String>), | ||||||
| 
 | 
 | ||||||
|     // Null
 |     // Null
 | ||||||
|     Empty, |     Empty, | ||||||
| @ -45,7 +44,7 @@ impl Display for DvmValue { | |||||||
|             DvmValue::Boolean(b) => write!(f, "Boolean({})", b), |             DvmValue::Boolean(b) => write!(f, "Boolean({})", b), | ||||||
|             DvmValue::Object(o) => write!(f, "Object({:p})", &o), |             DvmValue::Object(o) => write!(f, "Object({:p})", &o), | ||||||
|             DvmValue::Array(a) => write!(f, "Array({:p})", &a), |             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"), |             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 { |     pub fn expect_long(&self) -> i64 { | ||||||
|         if let DvmValue::Long(l) = self { |         if let DvmValue::Long(l) = self { | ||||||
|             *l |             *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>( |     pub fn map_object<T>( | ||||||
|         &self, |         &self, | ||||||
|         mapper: impl FnOnce(Rc<RefCell<DvmObject>>) -> T, |         mapper: impl FnOnce(Rc<RefCell<DvmObject>>) -> T, | ||||||
| @ -183,14 +201,19 @@ impl DvmValue { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn expect_constant_pointer(&self) -> DvmPointer { |     pub fn expect_string(&self) -> Rc<String> { | ||||||
|         if let DvmValue::ConstantPointer(ptr) = self { |         if let DvmValue::String(s) = self { | ||||||
|             ptr.clone() |             s.clone() | ||||||
|         } else { |         } else { | ||||||
|             panic!( |             panic!("Expected DvmValue::String, but found DvmValue::{:?}", self); | ||||||
|                 "Expected DvmValue::ConstantPointer, 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