Very minimal, but e2e hello world sort of working.
This commit is contained in:
parent
6593a1cfd1
commit
0960516c4a
46
Cargo.lock
generated
46
Cargo.lock
generated
@ -86,9 +86,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.23"
|
version = "4.5.60"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84"
|
checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@ -96,9 +96,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.23"
|
version = "4.5.60"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838"
|
checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@ -108,9 +108,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.5.18"
|
version = "4.5.55"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
|
checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@ -120,9 +120,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_lex"
|
name = "clap_lex"
|
||||||
version = "0.7.4"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codespan-reporting"
|
name = "codespan-reporting"
|
||||||
@ -135,6 +135,17 @@ dependencies = [
|
|||||||
"unicode-width",
|
"unicode-width",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "codespan-reporting"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af491d569909a7e4dee0ad7db7f5341fef5c614d5b8ec8cf765732aba3cff681"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"termcolor",
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorchoice"
|
name = "colorchoice"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
@ -186,7 +197,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"ast-generator",
|
"ast-generator",
|
||||||
"clap",
|
"clap",
|
||||||
"codespan-reporting",
|
"codespan-reporting 0.12.0",
|
||||||
"cst-test-generator",
|
"cst-test-generator",
|
||||||
"indoc",
|
"indoc",
|
||||||
"log",
|
"log",
|
||||||
@ -204,9 +215,26 @@ dependencies = [
|
|||||||
"crypto-common",
|
"crypto-common",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dm"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
"codespan-reporting 0.13.1",
|
||||||
|
"dmc-lib",
|
||||||
|
"dvm-lib",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dmc-lib"
|
name = "dmc-lib"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"dvm-lib",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dvm-lib"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs"
|
name = "encoding_rs"
|
||||||
|
|||||||
@ -3,9 +3,9 @@ name = "deimos"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[[bin]]
|
#[[bin]]
|
||||||
name = "dm"
|
#name = "dm"
|
||||||
path = "src/bin/dvm/main.rs"
|
#path = "src/bin/dvm/main.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "dmc"
|
name = "dmc"
|
||||||
@ -25,4 +25,4 @@ cst-test-generator = { path = "cst-test-generator" }
|
|||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "3"
|
resolver = "3"
|
||||||
members = ["ast-generator", "cst-test-generator", "dmc-lib"]
|
members = ["ast-generator", "cst-test-generator", "dm", "dmc-lib", "dvm-lib"]
|
||||||
|
|||||||
10
dm/Cargo.toml
Normal file
10
dm/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "dm"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
dmc-lib = { path = "../dmc-lib" }
|
||||||
|
dvm-lib = { path = "../dvm-lib" }
|
||||||
|
clap = { version = "4.5.60", features = ["derive"] }
|
||||||
|
codespan-reporting = "0.13.1"
|
||||||
72
dm/src/main.rs
Normal file
72
dm/src/main.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
use clap::Parser;
|
||||||
|
use dmc_lib::constants_table::ConstantsTable;
|
||||||
|
use dmc_lib::diagnostic::Diagnostic;
|
||||||
|
use dmc_lib::parser::parse_compilation_unit;
|
||||||
|
use dmc_lib::symbol_table::SymbolTable;
|
||||||
|
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||||
|
use dvm_lib::vm::{DvmContext, DvmState, call};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[derive(Debug, Parser)]
|
||||||
|
#[command(name = "dm", about = "Deimos", version = "0.1.0", long_about = None)]
|
||||||
|
struct Cli {
|
||||||
|
script: PathBuf,
|
||||||
|
|
||||||
|
#[arg(long)]
|
||||||
|
show_asm: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = Cli::parse();
|
||||||
|
let input = std::fs::read_to_string(&args.script).unwrap();
|
||||||
|
|
||||||
|
let mut compilation_unit = parse_compilation_unit(&input);
|
||||||
|
let mut symbol_table = SymbolTable::new();
|
||||||
|
|
||||||
|
let gather_names_diagnostics = compilation_unit.gather_declared_names(&mut symbol_table);
|
||||||
|
check_and_report_diagnostics(&gather_names_diagnostics);
|
||||||
|
|
||||||
|
let name_usages_diagnostics = compilation_unit.check_name_usages(&symbol_table);
|
||||||
|
check_and_report_diagnostics(&name_usages_diagnostics);
|
||||||
|
|
||||||
|
let type_check_diagnostics = compilation_unit.type_check(&symbol_table);
|
||||||
|
check_and_report_diagnostics(&type_check_diagnostics);
|
||||||
|
|
||||||
|
let mut constants_table = ConstantsTable::new();
|
||||||
|
let asm_functions = compilation_unit.assemble(&symbol_table, &mut constants_table);
|
||||||
|
|
||||||
|
if args.show_asm {
|
||||||
|
for asm_function in &asm_functions {
|
||||||
|
println!("{:?}", asm_function);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut dvm_context = DvmContext::new();
|
||||||
|
|
||||||
|
for asm_function in &asm_functions {
|
||||||
|
let function = asm_function.dvm();
|
||||||
|
dvm_context.add_function(function);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (name, content) in &constants_table.string_constants() {
|
||||||
|
dvm_context.add_constant(Constant::String(StringConstant::new(
|
||||||
|
Rc::from(name.clone()),
|
||||||
|
content.as_str(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut dvm_state = DvmState::new();
|
||||||
|
|
||||||
|
let result = call(&dvm_context, &mut dvm_state, "main", vec![]);
|
||||||
|
println!("{:?}", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_and_report_diagnostics(diagnostics: &[Diagnostic]) {
|
||||||
|
if !diagnostics.is_empty() {
|
||||||
|
for diagnostic in diagnostics {
|
||||||
|
println!("{:?}", diagnostic);
|
||||||
|
}
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,3 +4,4 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
dvm-lib = { path = "../dvm-lib" }
|
||||||
|
|||||||
@ -13,4 +13,8 @@ impl AsmBlock {
|
|||||||
instructions,
|
instructions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn instructions(&self) -> &[AsmInstruction] {
|
||||||
|
&self.instructions
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
use crate::asm::asm_block::AsmBlock;
|
use crate::asm::asm_block::AsmBlock;
|
||||||
|
use crate::asm::asm_instruction::AsmInstruction;
|
||||||
|
use dvm_lib::vm::function::Function;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AsmFunction {
|
pub struct AsmFunction {
|
||||||
@ -13,4 +15,15 @@ impl AsmFunction {
|
|||||||
blocks,
|
blocks,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dvm(&self) -> Function {
|
||||||
|
// very naive impl
|
||||||
|
let dvm_instructions = self
|
||||||
|
.blocks
|
||||||
|
.iter()
|
||||||
|
.flat_map(|block| block.instructions().iter().map(AsmInstruction::dvm))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
Function::new(&self.name, dvm_instructions, 16)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
use dvm_lib::instruction::Instruction;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum AsmInstruction {
|
pub enum AsmInstruction {
|
||||||
Move(Move),
|
Move(Move),
|
||||||
@ -7,11 +10,25 @@ pub enum AsmInstruction {
|
|||||||
LoadConstant(LoadConstant),
|
LoadConstant(LoadConstant),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AsmInstruction {
|
||||||
|
pub fn dvm(&self) -> Instruction {
|
||||||
|
match self {
|
||||||
|
AsmInstruction::Move(asm_move) => asm_move.dvm(),
|
||||||
|
AsmInstruction::Push(push) => push.dvm(),
|
||||||
|
AsmInstruction::Pop(pop) => pop.dvm(),
|
||||||
|
AsmInstruction::InvokePlatformStatic(invoke_platform_static) => {
|
||||||
|
invoke_platform_static.dvm()
|
||||||
|
}
|
||||||
|
AsmInstruction::LoadConstant(load_constant) => load_constant.dvm(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Operand {
|
pub enum Operand {
|
||||||
IntegerLiteral(i64),
|
IntegerLiteral(i32),
|
||||||
Register(usize),
|
Register(usize),
|
||||||
StackFrameOffset(usize),
|
StackFrameOffset(isize),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -27,6 +44,18 @@ impl Move {
|
|||||||
destination_register,
|
destination_register,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dvm(&self) -> Instruction {
|
||||||
|
match self.source {
|
||||||
|
Operand::IntegerLiteral(i) => Instruction::MoveInt(i, self.destination_register),
|
||||||
|
Operand::Register(register) => {
|
||||||
|
Instruction::MoveRegister(register, self.destination_register)
|
||||||
|
}
|
||||||
|
Operand::StackFrameOffset(offset) => {
|
||||||
|
Instruction::MoveStackFrameOffset(offset, self.destination_register)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -38,19 +67,37 @@ impl Push {
|
|||||||
pub fn new(source: Operand) -> Self {
|
pub fn new(source: Operand) -> Self {
|
||||||
Self { source }
|
Self { source }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dvm(&self) -> Instruction {
|
||||||
|
match self.source {
|
||||||
|
Operand::IntegerLiteral(i) => Instruction::PushInt(i),
|
||||||
|
Operand::Register(register) => Instruction::PushRegister(register),
|
||||||
|
Operand::StackFrameOffset(offset) => Instruction::PushStackFrameOffset(offset),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Pop {
|
pub struct Pop {
|
||||||
destination_register: usize,
|
destination_register: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pop {
|
impl Pop {
|
||||||
pub fn new(destination_register: usize) -> Self {
|
pub fn new(destination_register: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
destination_register,
|
destination_register: Some(destination_register),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
Self {
|
||||||
|
destination_register: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dvm(&self) -> Instruction {
|
||||||
|
Instruction::Pop(self.destination_register)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -62,6 +109,10 @@ impl InvokePlatformStatic {
|
|||||||
pub fn new(name: &str) -> Self {
|
pub fn new(name: &str) -> Self {
|
||||||
Self { name: name.into() }
|
Self { name: name.into() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dvm(&self) -> Instruction {
|
||||||
|
Instruction::InvokePlatformStatic(Rc::from(self.name.clone()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -77,4 +128,8 @@ impl LoadConstant {
|
|||||||
destination_register,
|
destination_register,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dvm(&self) -> Instruction {
|
||||||
|
Instruction::LoadStringConstant(Rc::from(self.name.clone()), self.destination_register)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,19 +3,19 @@ use crate::ir::ir_expression::IrExpression;
|
|||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
|
|
||||||
pub struct IntegerLiteral {
|
pub struct IntegerLiteral {
|
||||||
value: i64,
|
value: i32,
|
||||||
source_range: SourceRange,
|
source_range: SourceRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntegerLiteral {
|
impl IntegerLiteral {
|
||||||
pub fn new(value: i64, source_range: SourceRange) -> Self {
|
pub fn new(value: i32, source_range: SourceRange) -> Self {
|
||||||
Self {
|
Self {
|
||||||
value,
|
value,
|
||||||
source_range,
|
source_range,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value(&self) -> i64 {
|
pub fn value(&self) -> i32 {
|
||||||
self.value
|
self.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,4 +19,12 @@ impl ConstantsTable {
|
|||||||
self.strings_to_names.insert(s.into(), name.clone());
|
self.strings_to_names.insert(s.into(), name.clone());
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn string_constants(&self) -> HashMap<String, String> {
|
||||||
|
let mut constants = HashMap::new();
|
||||||
|
self.strings_to_names.iter().for_each(|(content, name)| {
|
||||||
|
constants.insert(name.clone(), content.clone());
|
||||||
|
});
|
||||||
|
constants
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,6 @@ use crate::ir::ir_variable::IrVariable;
|
|||||||
pub enum IrExpression {
|
pub enum IrExpression {
|
||||||
Call(IrCall),
|
Call(IrCall),
|
||||||
Constant(IrConstant),
|
Constant(IrConstant),
|
||||||
IntegerLiteral(i64),
|
IntegerLiteral(i32),
|
||||||
Variable(IrVariable),
|
Variable(IrVariable),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
mod asm;
|
pub mod asm;
|
||||||
mod ast;
|
pub mod ast;
|
||||||
mod constants_table;
|
pub mod constants_table;
|
||||||
mod diagnostic;
|
pub mod diagnostic;
|
||||||
mod ir;
|
pub mod ir;
|
||||||
mod lexer;
|
pub mod lexer;
|
||||||
mod parser;
|
pub mod parser;
|
||||||
mod scope;
|
pub mod scope;
|
||||||
mod source_range;
|
pub mod source_range;
|
||||||
mod symbol;
|
pub mod symbol;
|
||||||
mod symbol_table;
|
pub mod symbol_table;
|
||||||
mod token;
|
pub mod token;
|
||||||
mod type_info;
|
pub mod type_info;
|
||||||
|
|||||||
@ -181,7 +181,7 @@ impl<'a> Parser<'a> {
|
|||||||
let source_range = SourceRange::new(current.start(), current.end());
|
let source_range = SourceRange::new(current.start(), current.end());
|
||||||
self.advance();
|
self.advance();
|
||||||
Expression::IntegerLiteral(IntegerLiteral::new(
|
Expression::IntegerLiteral(IntegerLiteral::new(
|
||||||
i64::from_str(raw).unwrap(),
|
i32::from_str(raw).unwrap(),
|
||||||
source_range,
|
source_range,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,7 +35,7 @@ impl FunctionSymbol {
|
|||||||
pub struct ParameterSymbol {
|
pub struct ParameterSymbol {
|
||||||
name: Rc<str>,
|
name: Rc<str>,
|
||||||
type_info: TypeInfo,
|
type_info: TypeInfo,
|
||||||
stack_frame_offset: Option<usize>,
|
stack_frame_offset: Option<isize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParameterSymbol {
|
impl ParameterSymbol {
|
||||||
@ -59,11 +59,11 @@ impl ParameterSymbol {
|
|||||||
&self.type_info
|
&self.type_info
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_stack_frame_offset(&mut self, offset: usize) {
|
pub fn set_stack_frame_offset(&mut self, offset: isize) {
|
||||||
self.stack_frame_offset = Some(offset);
|
self.stack_frame_offset = Some(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stack_frame_offset(&self) -> usize {
|
pub fn stack_frame_offset(&self) -> isize {
|
||||||
self.stack_frame_offset.unwrap()
|
self.stack_frame_offset.unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
6
dvm-lib/Cargo.toml
Normal file
6
dvm-lib/Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "dvm-lib"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
21
dvm-lib/src/instruction.rs
Normal file
21
dvm-lib/src/instruction.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub type Register = usize;
|
||||||
|
pub type ConstantName = Rc<str>;
|
||||||
|
pub type FunctionName = Rc<str>;
|
||||||
|
|
||||||
|
pub enum Instruction {
|
||||||
|
MoveRegister(Register, Register),
|
||||||
|
MoveInt(i32, Register),
|
||||||
|
MoveStackFrameOffset(isize, Register),
|
||||||
|
|
||||||
|
PushRegister(Register),
|
||||||
|
PushInt(i32),
|
||||||
|
PushStackFrameOffset(isize),
|
||||||
|
|
||||||
|
InvokePlatformStatic(FunctionName),
|
||||||
|
|
||||||
|
LoadStringConstant(ConstantName, Register),
|
||||||
|
|
||||||
|
Pop(Option<Register>),
|
||||||
|
}
|
||||||
2
dvm-lib/src/lib.rs
Normal file
2
dvm-lib/src/lib.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod instruction;
|
||||||
|
pub mod vm;
|
||||||
31
dvm-lib/src/vm/constant.rs
Normal file
31
dvm-lib/src/vm/constant.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub enum Constant {
|
||||||
|
String(StringConstant),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StringConstant {
|
||||||
|
name: Rc<str>,
|
||||||
|
content: Rc<str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StringConstant {
|
||||||
|
pub fn new(name: Rc<str>, content: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
content: content.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name_owned(&self) -> Rc<str> {
|
||||||
|
self.name.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn content_owned(&self) -> Rc<str> {
|
||||||
|
self.content.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
34
dvm-lib/src/vm/function.rs
Normal file
34
dvm-lib/src/vm/function.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use crate::instruction::Instruction;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub struct Function {
|
||||||
|
name: Rc<str>,
|
||||||
|
instructions: Vec<Instruction>,
|
||||||
|
register_count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Function {
|
||||||
|
pub fn new(name: &str, instructions: Vec<Instruction>, register_count: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.into(),
|
||||||
|
instructions,
|
||||||
|
register_count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name_owned(&self) -> Rc<str> {
|
||||||
|
self.name.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn instructions(&self) -> &Vec<Instruction> {
|
||||||
|
&self.instructions
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_count(&self) -> usize {
|
||||||
|
self.register_count
|
||||||
|
}
|
||||||
|
}
|
||||||
187
dvm-lib/src/vm/mod.rs
Normal file
187
dvm-lib/src/vm/mod.rs
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
use crate::instruction::Instruction;
|
||||||
|
use crate::vm::constant::Constant;
|
||||||
|
use crate::vm::function::Function;
|
||||||
|
use crate::vm::value::Value;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub mod constant;
|
||||||
|
pub mod function;
|
||||||
|
pub mod value;
|
||||||
|
|
||||||
|
pub struct DvmContext {
|
||||||
|
functions: HashMap<Rc<str>, Function>,
|
||||||
|
constants: HashMap<Rc<str>, Constant>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DvmContext {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
functions: HashMap::new(),
|
||||||
|
constants: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_function(&mut self, function: Function) {
|
||||||
|
self.functions.insert(function.name_owned(), function);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn constants(&self) -> &HashMap<Rc<str>, Constant> {
|
||||||
|
&self.constants
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_constant(&mut self, constant: Constant) {
|
||||||
|
match &constant {
|
||||||
|
Constant::String(string_constant) => {
|
||||||
|
self.constants
|
||||||
|
.insert(string_constant.name_owned(), constant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DvmState {
|
||||||
|
stack: Vec<Value>,
|
||||||
|
registers: Vec<Value>,
|
||||||
|
ip: usize,
|
||||||
|
fp: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DvmState {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
stack: vec![],
|
||||||
|
registers: vec![],
|
||||||
|
ip: 0,
|
||||||
|
fp: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stack(&self) -> &Vec<Value> {
|
||||||
|
&self.stack
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stack_mut(&mut self) -> &mut Vec<Value> {
|
||||||
|
&mut self.stack
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn registers(&self) -> &Vec<Value> {
|
||||||
|
&self.registers
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn registers_mut(&mut self) -> &mut Vec<Value> {
|
||||||
|
&mut self.registers
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ensure_registers(&mut self, count: usize) {
|
||||||
|
self.registers.resize_with(count, Default::default);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ip(&self) -> usize {
|
||||||
|
self.ip
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn increment_ip(&mut self) {
|
||||||
|
self.ip += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fp(&self) -> usize {
|
||||||
|
self.fp
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_fp(&mut self, fp: usize) {
|
||||||
|
self.fp = fp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call(
|
||||||
|
context: &DvmContext,
|
||||||
|
state: &mut DvmState,
|
||||||
|
function_name: &str,
|
||||||
|
arguments: Vec<Value>,
|
||||||
|
) -> Option<Value> {
|
||||||
|
let function = context
|
||||||
|
.functions
|
||||||
|
.get(function_name)
|
||||||
|
.expect(&format!("Function {} not found", function_name));
|
||||||
|
|
||||||
|
let instructions = function.instructions();
|
||||||
|
state.ensure_registers(function.register_count());
|
||||||
|
|
||||||
|
// put each arg on the stack
|
||||||
|
for argument in arguments {
|
||||||
|
state.stack_mut().push(argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
while state.ip() < instructions.len() {
|
||||||
|
let instruction = &instructions[state.ip()];
|
||||||
|
match instruction {
|
||||||
|
/* Move instructions */
|
||||||
|
Instruction::MoveRegister(source, destination) => {
|
||||||
|
// copy value from one register to another register
|
||||||
|
let value = state.registers()[*source].clone();
|
||||||
|
state.registers_mut()[*destination] = value;
|
||||||
|
}
|
||||||
|
Instruction::MoveInt(value, destination) => {
|
||||||
|
state.registers_mut()[*destination] = Value::Int(*value);
|
||||||
|
}
|
||||||
|
Instruction::MoveStackFrameOffset(offset, destination) => {
|
||||||
|
// copy a value offset from the current frame pointer (fp) to a register
|
||||||
|
let value_index = state
|
||||||
|
.fp()
|
||||||
|
.checked_add_signed(*offset)
|
||||||
|
.expect("Overflow when adding offset to fp");
|
||||||
|
let value = state.stack()[value_index].clone();
|
||||||
|
state.registers_mut()[*destination] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Push instructions */
|
||||||
|
Instruction::PushRegister(source) => {
|
||||||
|
// copy a value from a register to the top of the stack
|
||||||
|
let value = state.registers()[*source].clone();
|
||||||
|
state.stack_mut().push(value);
|
||||||
|
}
|
||||||
|
Instruction::PushInt(value) => {
|
||||||
|
state.stack_mut().push(Value::Int(*value));
|
||||||
|
}
|
||||||
|
Instruction::PushStackFrameOffset(offset) => {
|
||||||
|
// copy a value from somewhere on the stack to the top of the stack
|
||||||
|
let value_index = state
|
||||||
|
.fp()
|
||||||
|
.checked_add_signed(*offset)
|
||||||
|
.expect("Overflow when adding offset to fp");
|
||||||
|
let value = state.stack()[value_index].clone();
|
||||||
|
state.stack_mut().push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Invoke instructions */
|
||||||
|
Instruction::InvokePlatformStatic(function_name) => {
|
||||||
|
if function_name.as_ref() == "println" {
|
||||||
|
println!("{:?}", state.stack());
|
||||||
|
println!("{:?}", state.registers());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load constant instructions */
|
||||||
|
Instruction::LoadStringConstant(constant_name, destination) => {
|
||||||
|
let constant = &context.constants()[constant_name];
|
||||||
|
match constant {
|
||||||
|
Constant::String(string_constant) => {
|
||||||
|
state.registers_mut()[*destination] =
|
||||||
|
Value::String(string_constant.content_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pop instructions */
|
||||||
|
Instruction::Pop(maybe_register) => {
|
||||||
|
let value = state.stack_mut().pop().unwrap();
|
||||||
|
if let Some(register) = maybe_register {
|
||||||
|
state.registers_mut()[*register] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.increment_ip();
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
14
dvm-lib/src/vm/value.rs
Normal file
14
dvm-lib/src/vm/value.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum Value {
|
||||||
|
Int(i32),
|
||||||
|
String(Rc<str>),
|
||||||
|
Null,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Value {
|
||||||
|
fn default() -> Value {
|
||||||
|
Value::Null
|
||||||
|
}
|
||||||
|
}
|
||||||
6
examples/hello.dm
Normal file
6
examples/hello.dm
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
fn println() end
|
||||||
|
|
||||||
|
fn main()
|
||||||
|
let x = "Hello, World!"
|
||||||
|
println(x)
|
||||||
|
end
|
||||||
Loading…
Reference in New Issue
Block a user