Work on vm and DvmValues and DmTypes. Added pest to get parser off the ground.

This commit is contained in:
Jesse Brault 2024-12-06 10:58:19 -06:00
parent d99ccf8807
commit cccbc6d819
15 changed files with 819 additions and 427 deletions

398
Cargo.lock generated
View File

@ -2,6 +2,404 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "anstream"
version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]]
name = "anstyle-parse"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.5.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
[[package]]
name = "colorchoice"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "cpufeatures"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
dependencies = [
"libc",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "deimos"
version = "0.1.0"
dependencies = [
"clap",
"pest",
"pest_derive",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "libc"
version = "0.2.167"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "once_cell"
version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "pest"
version = "2.7.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442"
dependencies = [
"memchr",
"thiserror",
"ucd-trie",
]
[[package]]
name = "pest_derive"
version = "2.7.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd"
dependencies = [
"pest",
"pest_generator",
]
[[package]]
name = "pest_generator"
version = "2.7.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "pest_meta"
version = "2.7.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d"
dependencies = [
"once_cell",
"pest",
"sha2",
]
[[package]]
name = "proc-macro2"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "sha2"
version = "0.10.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "ucd-trie"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
[[package]]
name = "unicode-ident"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

View File

@ -12,3 +12,6 @@ name = "dm"
path = "src/bin/dvm/main.rs"
[dependencies]
pest = "2.7.14"
clap = { version = "4.5.23", features = ["derive"] }
pest_derive = "2.7.14"

View File

@ -1,11 +1,22 @@
use deimos::vm::op_codes::{add_mov_int, add_platform_call_to};
use deimos::vm::DmVirtualMachine;
use deimos::vm::dvm_value::DvmValue;
fn main() {
// TODO:
// - write a single module with a main() fn which takes cli args
// - call the main fn
let mut code: Vec<u8> = Vec::new();
add_mov_int(&mut code, 0, 42);
add_platform_call_to(&mut code, &String::from("std::core::print"), 0, 1, &vec![0u8]);
add_mov_int(&mut code, 0, 0x2a); // 42
add_platform_call_to(
&mut code,
&String::from("std::core::println"),
0,
1,
&vec![0u8],
);
let mut vm = DmVirtualMachine::new(Vec::new());
vm.run(&mut code);
println!()
}
vm.run_raw(&mut code);
vm.call_by_fqn("default::main", vec![DvmValue::Unit; 0]); // will throw
}

37
src/parser/deimos.pest Normal file
View File

@ -0,0 +1,37 @@
compilation_unit = { SOI ~ namespace? ~ declaration* ~ EOI }
namespace = { "ns" ~ fqn }
fqn = { identifier ~ ( "::" ~ fqn )* }
identifier = @{ identifier_start_char ~ identifier_char* }
identifier_start_char = { 'a'..'z' | 'A'..'Z' | "_" }
identifier_char = { 'a'..'z' | 'A'..'Z' | '0'..'9' | "_" }
declaration = { "decl"? ~ "pub"? ~ ( interface | module | property | function ) }
interface = { "int" ~ identifier ~ generics_declaration? ~ interface_extends_list? ~ "{" ~ declaration* ~ "}"}
interface_extends_list = { ":" ~ type ~ ( "+" ~ type )* }
module = { "mod" ~ identifier ~ "{" ~ declaration* ~ "}" }
property = { identifier ~ ":" ~ type }
function = { "fn" ~ generics_declaration? ~ identifier ~ "(" ~ args_list? ~ ")" ~ ( ":" ~ type )? ~ ( "{" ~ "}" )? }
function_equals_body = { "=" ~ expression }
function_body = { "{" ~ "}" }
type = { identifier ~ generics_declaration? }
generics_declaration = { "<" ~ identifier ~ ( "," ~ identifier )* ~ ">"}
args_list = { arg ~ ( "," ~ arg )* }
arg = { identifier ~ ( ":" ~ "..."? ~ type )? }
expression = { literal }
literal = { number_literal }
number_literal = { int_literal }
int_literal = { '0'..'9'+ }
WHITESPACE = { " " | "\t" | "\n" | "\r" }

View File

@ -2,7 +2,17 @@ mod types;
use crate::lexer::Token;
use crate::parser::types::AstNode;
use pest::Parser;
use pest_derive::Parser;
#[derive(Parser)]
#[grammar = "parser/deimos.pest"]
struct DeimosParser;
pub fn parse(tokens: &Vec<Token>) -> Result<AstNode, String> {
let p = DeimosParser::parse(Rule::compilation_unit, "ns std::core")
.expect("unable to parse")
.next()
.unwrap();
todo!()
}

45
src/vm/dm_type.rs Normal file
View File

@ -0,0 +1,45 @@
use std::rc::Rc;
use crate::vm::object_type::DmObjectType;
#[derive(Debug, PartialEq, Eq)]
pub enum DmType {
Primitive(DmPrimitiveType),
Object(Rc<DmObjectType>),
}
#[derive(Debug, PartialEq, Eq)]
pub enum DmPrimitiveType {
Byte,
Int,
Long,
Double,
Boolean,
Pointer(Rc<DmType>),
ByteArray(usize),
IntArray(usize),
LongArray(usize),
DoubleArray(usize),
BooleanArray(usize),
PointerArray(usize, Rc<DmType>),
Unit,
}
impl DmPrimitiveType {
pub fn size_in_bytes(&self) -> usize {
match self {
DmPrimitiveType::Byte => size_of::<u8>(),
DmPrimitiveType::Int => size_of::<i32>(),
DmPrimitiveType::Long => size_of::<i64>(),
DmPrimitiveType::Double => size_of::<f64>(),
DmPrimitiveType::Boolean => size_of::<bool>(),
DmPrimitiveType::Pointer(_) => size_of::<usize>(),
DmPrimitiveType::ByteArray(length) => *length * size_of::<u8>(),
DmPrimitiveType::IntArray(length) => *length * size_of::<i32>(),
DmPrimitiveType::LongArray(length) => *length * size_of::<i64>(),
DmPrimitiveType::DoubleArray(length) => *length * size_of::<f64>(),
DmPrimitiveType::BooleanArray(length) => *length * size_of::<bool>(),
DmPrimitiveType::PointerArray(length, _) => *length * size_of::<usize>(),
DmPrimitiveType::Unit => todo!("Need to determine size of Unit... is it dependent on the size of the thing which is Unit?")
}
}
}

16
src/vm/dvm_value.rs Normal file
View File

@ -0,0 +1,16 @@
#[derive(Debug, Clone, PartialEq)]
pub enum DvmValue {
Byte(u8),
Int(i32),
Long(i64),
Double(f64),
Boolean(bool),
Pointer(Box<DvmValue>),
ByteArray(Vec<u8>),
IntArray(Vec<i32>),
LongArray(Vec<i64>),
DoubleArray(Vec<f64>),
BooleanArray(Vec<bool>),
PointerArray(Vec<Box<DvmValue>>),
Unit,
}

View File

@ -1,78 +1,95 @@
use crate::vm::types::{DmImplementation, DmProperty, DmType};
use crate::vm::values::DmValue;
use crate::vm::dm_type::DmPrimitiveType;
use crate::vm::dvm_value::DvmValue;
use crate::vm::object_type::DmProperty;
use crate::vm::object_type::DmImplementation;
use std::alloc::Layout;
use std::rc::Rc;
pub struct DmAllocObject<'a> {
pub struct DmAllocObject {
pub data: *mut u8,
pub size: usize,
pub layout: Layout,
pub object_type: &'a DmImplementation<'a>,
pub implementation: Rc<DmImplementation>,
}
pub unsafe fn get_property_value(dm_property: &DmProperty, dm_property_object: &DmAllocObject) -> DmValue {
let mut data: Vec<u8> = Vec::with_capacity(dm_property.dm_type.size_in_bytes());
for i in dm_property.data_offset..(dm_property.data_offset + dm_property.dm_type.size_in_bytes()) {
data.push(dm_property_object.data.offset(i as isize).read());
pub unsafe fn get_property_value(
dm_property: &DmProperty,
self_object: &DmAllocObject,
) -> DvmValue {
let data_size = dm_property.primitive_type.size_in_bytes();
let mut raw_data: Vec<u8> = Vec::with_capacity(data_size);
for i in dm_property.data_offset..(dm_property.data_offset + data_size) {
raw_data.push(self_object.data.offset(i as isize).read());
}
match dm_property.dm_type {
DmType::Byte => {
DmValue::DmByte(data[0])
match dm_property.primitive_type.as_ref() {
DmPrimitiveType::Byte => DvmValue::Byte(raw_data[0]),
DmPrimitiveType::Int => DvmValue::Int(i32::from_ne_bytes(
raw_data[0..data_size].try_into().unwrap(),
)),
DmPrimitiveType::Long => DvmValue::Long(i64::from_ne_bytes(
raw_data[0..data_size].try_into().unwrap(),
)),
DmPrimitiveType::Double => DvmValue::Double(f64::from_ne_bytes(
raw_data[0..data_size].try_into().unwrap(),
)),
DmPrimitiveType::Boolean => DvmValue::Boolean(raw_data[0] == 1),
DmPrimitiveType::Pointer(_) => {
// read the pointer's (address) value
let address = usize::from_ne_bytes(raw_data[0..data_size].try_into().unwrap());
DvmValue::Pointer(Box::from_raw(address as *mut DvmValue))
}
DmType::Int => {
DmValue::DmInt(i32::from_ne_bytes(data[0..4].try_into().unwrap()))
DmPrimitiveType::ByteArray(_) => DvmValue::ByteArray(raw_data),
DmPrimitiveType::IntArray(length) => DvmValue::IntArray(read_i32_array(&raw_data, *length)),
DmPrimitiveType::LongArray(length) => {
DvmValue::LongArray(read_i64_array(&raw_data, *length))
}
DmType::Long => {
DmValue::DmLong(i64::from_ne_bytes(data[0..8].try_into().unwrap()))
DmPrimitiveType::DoubleArray(length) => {
DvmValue::DoubleArray(read_f64_array(&raw_data, *length))
}
DmType::Double => {
DmValue::DmDouble(f64::from_ne_bytes(data[0..8].try_into().unwrap()))
}
DmType::Boolean => {
DmValue::DmBoolean(i32::from_ne_bytes(data[0..4].try_into().unwrap()) != 0)
}
DmType::ObjectPointer(_) => {
DmValue::DmPointer(usize::from_ne_bytes(data[0..8].try_into().unwrap()) as *mut DmAllocObject)
}
DmType::ByteArray(_) => {
DmValue::DmByteArray(data)
}
DmType::IntArray(length) => {
let mut result = Vec::with_capacity(length);
for i in 0..length {
result.push(i32::from_ne_bytes(data[(i * 4)..(i * 4 + 4)].try_into().unwrap()));
}
DmValue::DmIntArray(result)
}
DmType::LongArray(length) => {
let mut result = Vec::with_capacity(length);
for i in 0..length {
result.push(i64::from_ne_bytes(data[i * 8..(i * 8 + 8)].try_into().unwrap()));
}
DmValue::DmLongArray(result)
}
DmType::DoubleArray(length) => {
let mut result = Vec::with_capacity(length);
for i in 0..length {
result.push(f64::from_ne_bytes(data[i * 8..(i * 8 + 8)].try_into().unwrap()));
}
DmValue::DmDoubleArray(result)
}
DmType::BooleanArray(length) => {
let mut result = Vec::with_capacity(length);
for i in 0..length {
result.push(i32::from_ne_bytes(data[(i * 4)..(i * 4 + 4)].try_into().unwrap()) != 0);
}
DmValue::DmBooleanArray(result)
}
DmType::ObjectPointerArray(length, _) => {
let mut result = Vec::with_capacity(length);
for i in 0..length {
result.push(usize::from_ne_bytes(data[(i * 8)..(i * 8 + 8)].try_into().unwrap()) as *mut DmAllocObject);
}
DmValue::DmPointerArray(result)
}
DmType::Unit => {
DmValue::DmUnit
DmPrimitiveType::BooleanArray(length) => {
DvmValue::BooleanArray(read_bool_array(&raw_data))
}
DmPrimitiveType::PointerArray(length, _) => DvmValue::PointerArray(
read_usize_array(&raw_data, *length)
.iter()
.map(|raw_usize| Box::from_raw(*raw_usize as *mut DvmValue))
.collect(),
),
DmPrimitiveType::Unit => DvmValue::Unit,
}
}
}
macro_rules! read_array {
( $T: ty, $raw_data: expr, $length: expr ) => {{
let t_size = size_of::<$T>();
let mut arr: Vec<$T> = Vec::with_capacity($length);
for i in 0..$length {
arr.push(<$T>::from_ne_bytes(
$raw_data[(i * t_size)..(i * t_size + t_size)]
.try_into()
.unwrap(),
))
}
arr
}};
}
fn read_i32_array(raw_data: &Vec<u8>, length: usize) -> Vec<i32> {
read_array!(i32, raw_data, length)
}
fn read_i64_array(raw_data: &Vec<u8>, length: usize) -> Vec<i64> {
read_array!(i64, raw_data, length)
}
fn read_f64_array(raw_data: &Vec<u8>, length: usize) -> Vec<f64> {
read_array!(f64, raw_data, length)
}
fn read_bool_array(raw_data: &Vec<u8>) -> Vec<bool> {
raw_data.iter().map(|b| *b == 1).collect()
}
fn read_usize_array(raw_data: &Vec<u8>, length: usize) -> Vec<usize> {
read_array!(usize, raw_data, length)
}

View File

@ -1,49 +1,46 @@
pub mod dm_type;
pub mod dvm_value;
mod mem;
pub mod module;
mod object_type;
pub mod op_codes;
pub mod platform;
pub mod types;
pub mod util;
pub mod values;
mod mem;
use crate::vm::mem::DmAllocObject;
use crate::vm::dvm_value::DvmValue;
use crate::vm::module::DmModule;
use crate::vm::object_type::DmFn;
use crate::vm::platform::init_platform_functions;
use crate::vm::types::{DmFn, DmImplementation};
use op_codes::*;
use std::alloc::{alloc_zeroed, dealloc, Layout};
use std::collections::HashMap;
use types::DmType;
use util::{get_32_le, get_64_le};
use values::DmValue;
use values::DmValue::*;
pub type PlatformFunction = fn(args: Vec<DmValue>, &mut DmVirtualMachine) -> DmValue;
pub type PlatformFunction = fn(args: Vec<DvmValue>, &mut DmVirtualMachine) -> DvmValue;
enum CallFrame {
PlatformCall(PlatformCallFrame),
DeimosCall(DeimosCallFrame)
DeimosCall(DeimosCallFrame),
}
pub struct PlatformCallFrame {
pub name: String,
pub args: Vec<DmValue>,
pub args: Vec<DvmValue>,
}
struct DeimosCallFrame {
return_address: usize,
}
pub struct DmVirtualMachine<'a> {
modules: Vec<DmModule<'a>>,
pub struct DmVirtualMachine {
modules: Vec<DmModule>,
platform_functions: HashMap<String, PlatformFunction>,
ip: usize,
call_stack: Vec<CallFrame>,
registers: Vec<DmValue>,
register_state_stack: Vec<Vec<DmValue>>,
registers: Vec<DvmValue>,
register_state_stack: Vec<Vec<DvmValue>>,
}
impl DmVirtualMachine<'_> {
impl DmVirtualMachine {
pub fn new(modules: Vec<DmModule>) -> DmVirtualMachine {
DmVirtualMachine {
modules,
@ -55,11 +52,11 @@ impl DmVirtualMachine<'_> {
}
}
pub fn call(
&mut self,
dm_function: &DmFn,
args: Vec<DmValue>,
) -> DmValue {
pub fn call_by_fqn(&mut self, fn_fqn: &str, args: Vec<DvmValue>) -> DvmValue {
todo!()
}
pub fn call_fn(&mut self, dm_function: &DmFn, args: Vec<DvmValue>) -> DvmValue {
// save current state
self.call_stack.push(CallFrame::DeimosCall(DeimosCallFrame {
return_address: self.ip,
@ -68,7 +65,7 @@ impl DmVirtualMachine<'_> {
// zero registers and make sure there are enough for dm_function
self.registers.clear();
self.registers.resize(args.len(), DmValue::DmUnit);
self.registers.resize(args.len(), DvmValue::Unit);
// push args
for i in 0..args.len() {
@ -76,7 +73,7 @@ impl DmVirtualMachine<'_> {
}
// run the byte code
self.run(&dm_function.byte_code);
self.run_raw(&dm_function.byte_code);
// restore state
self.registers = self.register_state_stack.pop().unwrap();
@ -88,20 +85,22 @@ impl DmVirtualMachine<'_> {
self.registers.get(0).unwrap().clone()
}
pub fn run(&mut self, code: &Vec<u8>) {
pub fn run_raw(&mut self, code: &Vec<u8>) {
let mut i = 0;
while i < code.len() {
match code[i] {
MOV_INT => {
let target_register = code[i + 1] as usize;
let operand = get_32_le!(code, i, 2, u32);
self.registers.insert(target_register, DmInt(operand as i32));
self.registers
.insert(target_register, DvmValue::Int(operand as i32));
i += 6;
}
MOV_LONG => {
let target_register = code[i + 1] as usize;
let operand = get_64_le!(code, i, 2, u64);
self.registers.insert(target_register, DmLong(operand as i64));
self.registers
.insert(target_register, DvmValue::Long(operand as i64));
i += 10;
}
MOV_DOUBLE => { /* todo */ }
@ -113,75 +112,13 @@ impl DmVirtualMachine<'_> {
i += 3;
}
ALLOC => {
i += 1;
let target_register = code[i] as usize;
i += 1;
let symbol_name_length = get_32_le!(code, i, 0, usize);
i += 4;
let raw_symbol_name = code[i..(i + symbol_name_length)].to_vec();
i += symbol_name_length;
let symbol_name = String::from_utf8(raw_symbol_name).unwrap();
// find implementation
let mut implementation_result: Option<&DmImplementation> = None;
'module_find: for module in self.modules.iter() {
if let Some(dm_implementation) = module.implementations.get(&symbol_name) {
implementation_result = Some(dm_implementation);
break 'module_find;
}
}
if implementation_result == None {
panic!("Implementation {} not found", symbol_name);
}
let dm_implementation = implementation_result.unwrap();
let size = dm_implementation.size_in_bytes;
let layout = Layout::from_size_align(size, 4).unwrap();
let pointer = unsafe { alloc_zeroed(layout) };
let dm_object = Box::new(DmAllocObject {
object_type: dm_implementation,
data: pointer,
size,
layout,
});
let dm_object_pointer = Box::into_raw(dm_object);
self.registers.insert(target_register, DmPointer(dm_object_pointer));
i += 6;
todo!()
}
DEALLOC => {
let target_register = code[i + 1] as usize;
let target_value = self.registers.get(target_register).unwrap();
match target_value {
DmPointer(ptr) => unsafe {
let dm_object = Box::from_raw(ptr.clone());
dealloc(dm_object.data, dm_object.layout);
}
_ => {
panic!("Attempt to deallocate at the address stored in a register that is not a pointer.");
}
}
self.registers.insert(target_register, DmUnit);
i += 2;
todo!()
}
MOV_INT_TO => {
let target_register = code[i + 1] as usize;
let target_value = self.registers.get(target_register).unwrap();
if let DmPointer(dm_object_ptr) = target_value {
let offset = get_32_le!(code, i, 2, isize);
let new_address = unsafe {
let dm_object = Box::from_raw(dm_object_ptr.clone());
let data_ptr = dm_object.data;
data_ptr.offset(offset).write(code[i + 6]);
data_ptr.offset(offset + 1).write(code[i + 7]);
data_ptr.offset(offset + 2).write(code[i + 8]);
data_ptr.offset(offset + 3).write(code[i + 9]);
Box::into_raw(dm_object)
};
self.registers.insert(target_register, DmPointer(new_address));
i += 10;
} else {
panic!("target_register {} is not a Pointer", target_register);
}
todo!()
}
PLATFORM_CALL => {
i += 1;
@ -222,13 +159,11 @@ impl DmVirtualMachine<'_> {
}
}
}
}
#[cfg(test)]
mod dvm_run_tests {
use super::*;
use std::alloc::dealloc;
macro_rules! assert_register {
( $expected: expr, $register: expr ) => {
@ -241,8 +176,8 @@ mod dvm_run_tests {
let mut code = Vec::new();
add_mov_int(&mut code, 0, 1);
let mut vm = DmVirtualMachine::new(Vec::new());
vm.run(&code);
assert_register!(DmInt(1), vm.registers.get(0));
vm.run_raw(&code);
assert_register!(DvmValue::Int(1), vm.registers.get(0));
}
#[test]
@ -250,8 +185,8 @@ mod dvm_run_tests {
let mut code = Vec::new();
add_mov_int(&mut code, 0, 0xffff);
let mut vm = DmVirtualMachine::new(Vec::new());
vm.run(&code);
assert_register!(DmInt(0xffff), vm.registers.get(0));
vm.run_raw(&code);
assert_register!(DvmValue::Int(0xffff), vm.registers.get(0));
}
#[test]
@ -259,8 +194,8 @@ mod dvm_run_tests {
let mut code = Vec::new();
add_mov_int(&mut code, 0, 0x0fff_ffff);
let mut vm = DmVirtualMachine::new(Vec::new());
vm.run(&code);
assert_register!(DmInt(0x0fff_ffff), vm.registers.get(0));
vm.run_raw(&code);
assert_register!(DvmValue::Int(0x0fff_ffff), vm.registers.get(0));
}
#[test]
@ -269,38 +204,34 @@ mod dvm_run_tests {
add_mov_int(&mut code, 1, 1);
add_mov_register(&mut code, 0, 1);
let mut vm = DmVirtualMachine::new(Vec::new());
vm.registers.resize(2, DmUnit);
vm.run(&code);
assert_register!(DmInt(1), vm.registers.get(0));
vm.registers.resize(2, DvmValue::Unit);
vm.run_raw(&code);
assert_register!(DvmValue::Int(1), vm.registers.get(0));
}
#[test]
#[ignore]
fn mov_int_to_register_as_address() {
let mut code = Vec::new();
add_alloc(&mut code, 0, 4);
add_mov_int_to(&mut code, 0, 0, 0xff);
let mut vm = DmVirtualMachine::new(Vec::new());
vm.run(&code);
let box_address = vm.registers.get(0).unwrap().clone();
match box_address {
DmPointer(ptr) => unsafe {
let dm_object = Box::from_raw(ptr);
assert_eq!(0xff, *dm_object.data);
dealloc(dm_object.data, dm_object.layout);
},
vm.run_raw(&code);
let actual = vm.registers.get(0).unwrap().clone();
match actual {
DvmValue::Pointer(value_box) => {
assert_eq!(DvmValue::Int(0xff), *value_box);
}
_ => panic!("Target register is not a pointer"),
}
}
#[test]
#[ignore]
fn alloc_and_dealloc_expect_register_cleared() {
let mut code = Vec::new();
add_alloc(&mut code, 0, 4);
add_dealloc(&mut code, 0);
let mut vm = DmVirtualMachine::new(Vec::new());
vm.run(&code);
assert_register!(DmUnit, vm.registers.get(0));
vm.run_raw(&code);
assert_register!(DvmValue::Unit, vm.registers.get(0));
}
}

View File

@ -1,5 +1,5 @@
use crate::get_32_le;
use crate::vm::types::{DmFn, DmImplementation, DmInterface};
use crate::vm::object_type::{DmFn, DmImplementation, DmInterface};
use std::collections::HashMap;
pub const DEIMOS_MAGIC_NUMBER: u64 = 0x00_00_64_65_69_6d_6f_73; // ascii 'deimos'
@ -7,13 +7,13 @@ pub const DEIMOS_MAGIC_STRING: [u8; 6] = [0x64, 0x65, 0x69, 0x6d, 0x6f, 0x73]; /
pub const COMPILER_VERSION_STRING: &str = "0.1.0";
pub struct DmModule<'a> {
pub struct DmModule {
pub compiler_version: String,
pub fqn: String,
pub short_name: String,
pub constants: HashMap<String, DmConstant>,
pub interfaces: HashMap<String, DmInterface<'a>>,
pub implementations: HashMap<String, DmImplementation<'a>>,
pub interfaces: HashMap<String, DmInterface>,
pub implementations: HashMap<String, DmImplementation>,
pub functions: HashMap<String, DmFn>,
}

128
src/vm/object_type.rs Normal file
View File

@ -0,0 +1,128 @@
use crate::vm::dm_type::DmPrimitiveType;
use crate::vm::mem::DmAllocObject;
use std::collections::HashMap;
use std::fmt::Debug;
use std::rc::Rc;
#[derive(Debug, PartialEq, Eq)]
pub enum DmObjectType {
Interface(DmInterface),
Implementation(DmImplementation),
}
#[derive(Debug, Eq)]
pub struct DmFn {
pub fqn: String,
pub short_name: String,
pub byte_code: Vec<u8>,
pub num_registers: usize,
}
impl PartialEq for DmFn {
fn eq(&self, other: &Self) -> bool {
self.fqn == other.fqn
}
}
#[derive(Debug, Eq)]
pub struct DmInterface {
fqn: String,
short_name: String,
properties: HashMap<String, DmProperty>,
virtual_methods: HashMap<String, DmVirtualMethod>,
impl_methods: HashMap<String, DmFn>,
}
impl PartialEq for DmInterface {
fn eq(&self, other: &Self) -> bool {
self.fqn == other.fqn
}
}
impl DmInterface {
fn get_fqn(&self) -> &str {
&self.fqn
}
fn get_method<'a>(&'a self, name: &str, self_object: &'a DmAllocObject) -> Option<&'a DmFn> {
if self.impl_methods.contains_key(name) {
self.impl_methods.get(name)
} else if self.virtual_methods.contains_key(name) {
self_object.implementation.get_method(name, self_object)
} else {
None
}
}
fn get_property(&self, name: &str, self_object: &DmAllocObject) -> Option<&DmProperty> {
self.properties.get(name)
}
}
#[derive(Debug, Eq)]
pub struct DmVirtualMethod {
pub fqn: String,
pub short_name: String,
}
impl PartialEq for DmVirtualMethod {
fn eq(&self, other: &Self) -> bool {
self.fqn == other.fqn
}
}
#[derive(Debug, Eq)]
pub struct DmImplementation {
pub fqn: String,
pub short_name: String,
pub interface: Rc<DmInterface>,
pub properties: HashMap<String, DmProperty>,
pub fields: HashMap<String, DmField>,
pub size_in_bytes: usize,
pub methods: HashMap<String, DmFn>,
}
impl PartialEq for DmImplementation {
fn eq(&self, other: &Self) -> bool {
self.fqn == other.fqn
}
}
impl DmImplementation {
fn get_fqn(&self) -> &str {
&self.fqn
}
fn get_method<'a>(&'a self, name: &str, self_object: &'a DmAllocObject) -> Option<&'a DmFn> {
self.methods.get(name)
}
fn get_property(&self, name: &str, self_object: &DmAllocObject) -> Option<&DmProperty> {
self.properties.get(name)
}
}
#[derive(Debug, Eq)]
pub struct DmProperty {
pub name: String,
pub data_offset: usize,
pub primitive_type: Rc<DmPrimitiveType>,
}
impl PartialEq for DmProperty {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
#[derive(Debug, Eq)]
pub struct DmField {
name: String,
primitive_type: Rc<DmPrimitiveType>,
}
impl PartialEq for DmField {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}

View File

@ -1,4 +1,4 @@
use crate::vm::platform::std_lib::core::dm_print;
use crate::vm::platform::std_lib::core::{dm_print, dm_println};
use crate::vm::PlatformFunction;
use std::collections::HashMap;
@ -7,5 +7,6 @@ mod std_lib;
pub fn init_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);
fns
}

View File

@ -1,61 +1,36 @@
use crate::vm::DmValue::*;
use crate::vm::{mem, DmValue, DmVirtualMachine};
use crate::vm::dvm_value::DvmValue;
use crate::vm::DmVirtualMachine;
pub fn dm_print(args: Vec<DmValue>, vm: &mut DmVirtualMachine) -> DmValue {
pub fn dm_print(args: Vec<DvmValue>, vm: &mut DmVirtualMachine) -> DvmValue {
if args.len() != 1 {
return DmUnit // TODO: make exception
return DvmValue::Unit; // TODO: make exception
}
print!("{}", get_string(&args[0]));
DvmValue::Unit
}
pub fn dm_println(args: Vec<DvmValue>, vm: &mut DmVirtualMachine) -> DvmValue {
if args.len() != 1 {
return DvmValue::Unit;
}
println!("{}", get_string(&args[0]));
DvmValue::Unit
}
fn get_string(dvm_value: &DvmValue) -> String {
match dvm_value {
DvmValue::Byte(b) => b.to_string(),
DvmValue::Int(i) => i.to_string(),
DvmValue::Long(l) => l.to_string(),
DvmValue::Double(d) => d.to_string(),
DvmValue::Boolean(b) => b.to_string(),
DvmValue::Pointer(value_box) => get_string(value_box),
DvmValue::ByteArray(_) => todo!(),
DvmValue::IntArray(_) => todo!(),
DvmValue::LongArray(_) => todo!(),
DvmValue::DoubleArray(_) => todo!(),
DvmValue::BooleanArray(_) => todo!(),
DvmValue::PointerArray(_) => todo!(),
DvmValue::Unit => String::from("Unit"),
}
match &args[0] {
DmByte(b) => {
print!("{}", *b);
}
DmInt(i) => {
print!("{}", *i);
}
DmLong(l) => {
print!("{}", *l);
}
DmDouble(d) => {
print!("{}", *d);
}
DmBoolean(b) => {
print!("{}", *b);
}
DmPointer(ptr) => unsafe {
let dm_alloc_object = Box::from_raw(*ptr);
let dm_object_type = &dm_alloc_object.object_type;
if let Some(to_string_method) = dm_object_type.get_method(String::from("std::core::Object::to_string"), &dm_alloc_object) {
let call_result = vm.call(to_string_method, vec![args[0].clone()]);
if let DmPointer(dm_string_pointer) = call_result {
let dm_string_object = Box::from_raw(dm_string_pointer);
let bytes_property = dm_string_object.object_type.get_property(String::from("bytes"), &dm_string_object).unwrap();
let string_bytes_value = mem::get_property_value(bytes_property, &dm_string_object);
if let DmByteArray(raw_string_bytes) = string_bytes_value {
// TODO: other encodings
print!("{}", String::from_utf8(raw_string_bytes).unwrap());
} else {
panic!("Expected std::core::String.bytes to be a ByteArray.")
}
} else {
panic!("Expected {} to return a string.", to_string_method.fqn)
}
} else {
println!("{}@{:?}", dm_object_type.get_fqn(), dm_alloc_object.data)
}
},
DmByteArray(bs) => {
}
DmIntArray(is) => {
}
DmLongArray(ls) => {}
DmDoubleArray(ds) => {}
DmBooleanArray(bs) => {}
DmPointerArray(ptrs) => {}
DmUnit => {
print!("Unit")
},
}
DmUnit
}

View File

@ -1,162 +0,0 @@
use crate::vm::mem::DmAllocObject;
use std::collections::HashMap;
#[derive(Debug, PartialEq, Eq)]
pub enum DmType<'a> {
Byte,
Int,
Long,
Double,
Boolean,
ObjectPointer(&'a dyn DmObjectType),
ByteArray(usize),
IntArray(usize),
LongArray(usize),
DoubleArray(usize),
BooleanArray(usize),
ObjectPointerArray(usize, &'a dyn DmObjectType),
Unit,
}
impl DmType<'_> {
pub fn size_in_bytes(&self) -> usize {
match self {
DmType::Byte => 1,
DmType::Int => 4,
DmType::Long => 8,
DmType::Double => 8,
DmType::Boolean => 4,
DmType::ObjectPointer(_) => 8,
DmType::ByteArray(length) => *length,
DmType::IntArray(length) => *length * 4,
DmType::LongArray(length) => *length * 8,
DmType::DoubleArray(length) => *length * 8,
DmType::BooleanArray(length) => *length * 4,
DmType::ObjectPointerArray(length, _) => length * 8,
DmType::Unit => 0
}
}
}
pub trait DmObjectType {
fn get_fqn(&self) -> &String;
fn get_method(&self, name: String, self_object: &DmAllocObject) -> Option<&DmFn>;
fn get_property(&self, name: String, self_object: &DmAllocObject) -> Option<&DmProperty>;
}
#[derive(Debug, Eq)]
pub struct DmFn {
pub fqn: String,
pub short_name: String,
pub byte_code: Vec<u8>,
pub num_registers: usize,
}
impl PartialEq for DmFn {
fn eq(&self, other: &Self) -> bool {
self.fqn == other.fqn
}
}
#[derive(Debug, Eq)]
pub struct DmInterface<'a> {
fqn: String,
short_name: String,
properties: HashMap<String, DmProperty<'a>>,
virtual_methods: HashMap<String, DmVirtualMethod>,
impl_methods: HashMap<String, DmFn>,
}
impl PartialEq for DmInterface<'_> {
fn eq(&self, other: &Self) -> bool {
self.fqn == other.fqn
}
}
impl DmObjectType for DmInterface<'_> {
fn get_fqn(&self) -> &String {
&self.fqn
}
fn get_method(&self, name: String, self_object: &DmAllocObject) -> Option<&DmFn> {
if self.impl_methods.contains_key(&name) {
self.impl_methods.get(&name)
} else if self.virtual_methods.contains_key(&name) {
self_object.object_type.get_method(name, &self_object)
} else {
None
}
}
fn get_property(&self, name: String, self_object: &DmAllocObject) -> Option<&DmProperty> {
self.properties.get(&name)
}
}
#[derive(Debug, Eq)]
pub struct DmVirtualMethod {
pub fqn: String,
pub short_name: String,
}
impl PartialEq for DmVirtualMethod {
fn eq(&self, other: &Self) -> bool {
self.fqn == other.fqn
}
}
#[derive(Debug, Eq)]
pub struct DmImplementation<'a> {
pub fqn: String,
pub short_name: String,
pub interface: &'a DmInterface<'a>,
pub properties: HashMap<String, DmProperty<'a>>,
pub fields: HashMap<String, DmField<'a>>,
pub size_in_bytes: usize,
pub methods: HashMap<String, DmFn>
}
impl PartialEq for DmImplementation<'_> {
fn eq(&self, other: &Self) -> bool {
self.fqn == other.fqn
}
}
impl DmObjectType for DmImplementation<'_> {
fn get_fqn(&self) -> &String {
&self.fqn
}
fn get_method(&self, name: String, self_object: &DmAllocObject) -> Option<&DmFn> {
self.methods.get(&name)
}
fn get_property(&self, name: String, self_object: &DmAllocObject) -> Option<&DmProperty> {
self.properties.get(&name)
}
}
#[derive(Debug, Eq)]
pub struct DmProperty<'a> {
pub name: String,
pub data_offset: usize,
pub dm_type: DmType<'a>
}
impl PartialEq for DmProperty<'_> {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
#[derive(Debug, Eq)]
pub struct DmField<'a> {
name: String,
dm_type: DmType<'a>,
}
impl PartialEq for DmField<'_> {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}

View File

@ -1,18 +0,0 @@
use crate::vm::mem::DmAllocObject;
#[derive(Debug, Clone, PartialEq)]
pub enum DmValue {
DmByte(u8),
DmInt(i32),
DmLong(i64),
DmDouble(f64),
DmBoolean(bool),
DmPointer(*mut DmAllocObject),
DmByteArray(Vec<u8>),
DmIntArray(Vec<i32>),
DmLongArray(Vec<i64>),
DmDoubleArray(Vec<f64>),
DmBooleanArray(Vec<bool>),
DmPointerArray(Vec<*mut DmAllocObject>),
DmUnit,
}