Updated dvm/main.rs to use new refactored dvm.
This commit is contained in:
parent
26d87acff5
commit
71ee49761e
@ -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>>>),
|
||||
Strings(Vec<Rc<String>>)
|
||||
Strings(Vec<Rc<String>>),
|
||||
}
|
||||
|
||||
impl DvmArray {
|
||||
|
@ -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,5 +1,6 @@
|
||||
use std::rc::Rc;
|
||||
use crate::vm::constant::DvmConstant;
|
||||
use crate::vm::source_code_location::SourceCodeLocation;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Instruction {
|
||||
@ -15,7 +16,7 @@ pub enum Instruction {
|
||||
source_register: usize,
|
||||
},
|
||||
Pop {
|
||||
destination_register: usize,
|
||||
destination_register: Option<usize>,
|
||||
},
|
||||
AllocateObject {
|
||||
implementation_name: Rc<String>,
|
||||
@ -133,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,
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
mod array;
|
||||
mod constant;
|
||||
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;
|
||||
@ -19,24 +19,27 @@ 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::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(state: &DvmState, message: &str) {
|
||||
pub fn dump_state(state: &DvmState, message: &str) {
|
||||
println!("----");
|
||||
println!("Deimos Virtual Machine: Panic!");
|
||||
println!("{}", message);
|
||||
println!("----");
|
||||
println!("Current Instruction: {:?}", state.current_instruction);
|
||||
println!(
|
||||
"Current Instruction: {:?}",
|
||||
state.current_instruction.clone().unwrap()
|
||||
);
|
||||
println!("Registers:");
|
||||
for (i, register) in state.registers.iter().enumerate() {
|
||||
println!("\tr{}: {:?}", i, register);
|
||||
println!("\tr{:x}: {:?}", i, register);
|
||||
}
|
||||
println!("Call stack:");
|
||||
for call in state.call_stack.iter() {
|
||||
@ -51,7 +54,7 @@ fn dvm_panic(state: &DvmState, message: &str) {
|
||||
|
||||
macro_rules! dvm_panic {
|
||||
($context: expr, $message: expr) => {
|
||||
dvm_panic($context, $message);
|
||||
dump_state($context, $message);
|
||||
panic!()
|
||||
};
|
||||
}
|
||||
@ -70,7 +73,7 @@ impl DvmState {
|
||||
DvmState {
|
||||
call_stack: vec![],
|
||||
current_instruction: None,
|
||||
registers: vec![],
|
||||
registers: vec![DvmValue::Empty; 16],
|
||||
stack: vec![],
|
||||
}
|
||||
}
|
||||
@ -80,22 +83,42 @@ impl DvmState {
|
||||
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() -> Self {
|
||||
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 {
|
||||
@ -257,12 +280,25 @@ fn immediate_to_value(immediate: &Immediate) -> DvmValue {
|
||||
}
|
||||
}
|
||||
|
||||
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], state: &mut DvmState, context: &DvmContext) {
|
||||
let mut index = 0;
|
||||
while index < instructions.len() {
|
||||
state.current_instruction = Some(instructions[index].clone());
|
||||
index += 1;
|
||||
use Instruction::*;
|
||||
match &instructions[index] {
|
||||
MoveImmediate {
|
||||
@ -287,7 +323,9 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont
|
||||
let value = state.stack.pop().unwrap_or_else(|| {
|
||||
dvm_panic!(state, "Stack underflow");
|
||||
});
|
||||
state.registers[*destination_register] = value;
|
||||
if let Some(register_index) = destination_register {
|
||||
state.registers[*register_index] = value;
|
||||
}
|
||||
}
|
||||
AllocateObject {
|
||||
implementation_name,
|
||||
@ -451,5 +489,6 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont
|
||||
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);
|
||||
|
@ -9,11 +9,11 @@ use std::rc::Rc;
|
||||
/// print(m: &(Byte | Int | Long | Double | USize | Boolean | Object | Empty))
|
||||
/// ```
|
||||
pub fn dm_print(state: &mut DvmState, context: &DvmContext) {
|
||||
print!("{}", get_string(state.pop_stack()));
|
||||
print!("{}", get_string(state.get_stack_argument(0)));
|
||||
}
|
||||
|
||||
pub fn dm_println(state: &mut DvmState, context: &DvmContext) {
|
||||
println!("{}", get_string(state.pop_stack()));
|
||||
println!("{}", get_string(state.get_stack_argument(0)));
|
||||
}
|
||||
|
||||
fn get_string(dvm_value: DvmValue) -> String {
|
||||
|
@ -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;
|
||||
@ -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,7 +110,10 @@ impl DvmValue {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_object_or_else(&self, f: impl FnOnce(&Self) -> DvmObject) -> Rc<RefCell<DvmObject>> {
|
||||
pub fn expect_object_or_else(
|
||||
&self,
|
||||
f: impl FnOnce(&Self) -> DvmObject,
|
||||
) -> Rc<RefCell<DvmObject>> {
|
||||
if let DvmValue::Object(o) = self {
|
||||
o.clone()
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user