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]]
|
||||
name = "clap"
|
||||
version = "4.5.23"
|
||||
version = "4.5.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84"
|
||||
checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@ -96,9 +96,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.23"
|
||||
version = "4.5.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838"
|
||||
checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@ -108,9 +108,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.18"
|
||||
version = "4.5.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
|
||||
checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
@ -120,9 +120,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.4"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||
checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831"
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
@ -135,6 +135,17 @@ dependencies = [
|
||||
"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]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.3"
|
||||
@ -186,7 +197,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"ast-generator",
|
||||
"clap",
|
||||
"codespan-reporting",
|
||||
"codespan-reporting 0.12.0",
|
||||
"cst-test-generator",
|
||||
"indoc",
|
||||
"log",
|
||||
@ -204,9 +215,26 @@ dependencies = [
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dm"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"codespan-reporting 0.13.1",
|
||||
"dmc-lib",
|
||||
"dvm-lib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dmc-lib"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"dvm-lib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dvm-lib"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
|
||||
@ -3,9 +3,9 @@ name = "deimos"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
name = "dm"
|
||||
path = "src/bin/dvm/main.rs"
|
||||
#[[bin]]
|
||||
#name = "dm"
|
||||
#path = "src/bin/dvm/main.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "dmc"
|
||||
@ -25,4 +25,4 @@ cst-test-generator = { path = "cst-test-generator" }
|
||||
|
||||
[workspace]
|
||||
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"
|
||||
|
||||
[dependencies]
|
||||
dvm-lib = { path = "../dvm-lib" }
|
||||
|
||||
@ -13,4 +13,8 @@ impl AsmBlock {
|
||||
instructions,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn instructions(&self) -> &[AsmInstruction] {
|
||||
&self.instructions
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
use crate::asm::asm_block::AsmBlock;
|
||||
use crate::asm::asm_instruction::AsmInstruction;
|
||||
use dvm_lib::vm::function::Function;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AsmFunction {
|
||||
@ -13,4 +15,15 @@ impl AsmFunction {
|
||||
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)]
|
||||
pub enum AsmInstruction {
|
||||
Move(Move),
|
||||
@ -7,11 +10,25 @@ pub enum AsmInstruction {
|
||||
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)]
|
||||
pub enum Operand {
|
||||
IntegerLiteral(i64),
|
||||
IntegerLiteral(i32),
|
||||
Register(usize),
|
||||
StackFrameOffset(usize),
|
||||
StackFrameOffset(isize),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -27,6 +44,18 @@ impl Move {
|
||||
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)]
|
||||
@ -38,19 +67,37 @@ impl Push {
|
||||
pub fn new(source: Operand) -> Self {
|
||||
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)]
|
||||
pub struct Pop {
|
||||
destination_register: usize,
|
||||
destination_register: Option<usize>,
|
||||
}
|
||||
|
||||
impl Pop {
|
||||
pub fn new(destination_register: usize) -> 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)]
|
||||
@ -62,6 +109,10 @@ impl InvokePlatformStatic {
|
||||
pub fn new(name: &str) -> Self {
|
||||
Self { name: name.into() }
|
||||
}
|
||||
|
||||
pub fn dvm(&self) -> Instruction {
|
||||
Instruction::InvokePlatformStatic(Rc::from(self.name.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -77,4 +128,8 @@ impl LoadConstant {
|
||||
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;
|
||||
|
||||
pub struct IntegerLiteral {
|
||||
value: i64,
|
||||
value: i32,
|
||||
source_range: SourceRange,
|
||||
}
|
||||
|
||||
impl IntegerLiteral {
|
||||
pub fn new(value: i64, source_range: SourceRange) -> Self {
|
||||
pub fn new(value: i32, source_range: SourceRange) -> Self {
|
||||
Self {
|
||||
value,
|
||||
source_range,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn value(&self) -> i64 {
|
||||
pub fn value(&self) -> i32 {
|
||||
self.value
|
||||
}
|
||||
|
||||
|
||||
@ -19,4 +19,12 @@ impl ConstantsTable {
|
||||
self.strings_to_names.insert(s.into(), name.clone());
|
||||
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 {
|
||||
Call(IrCall),
|
||||
Constant(IrConstant),
|
||||
IntegerLiteral(i64),
|
||||
IntegerLiteral(i32),
|
||||
Variable(IrVariable),
|
||||
}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
mod asm;
|
||||
mod ast;
|
||||
mod constants_table;
|
||||
mod diagnostic;
|
||||
mod ir;
|
||||
mod lexer;
|
||||
mod parser;
|
||||
mod scope;
|
||||
mod source_range;
|
||||
mod symbol;
|
||||
mod symbol_table;
|
||||
mod token;
|
||||
mod type_info;
|
||||
pub mod asm;
|
||||
pub mod ast;
|
||||
pub mod constants_table;
|
||||
pub mod diagnostic;
|
||||
pub mod ir;
|
||||
pub mod lexer;
|
||||
pub mod parser;
|
||||
pub mod scope;
|
||||
pub mod source_range;
|
||||
pub mod symbol;
|
||||
pub mod symbol_table;
|
||||
pub mod token;
|
||||
pub mod type_info;
|
||||
|
||||
@ -181,7 +181,7 @@ impl<'a> Parser<'a> {
|
||||
let source_range = SourceRange::new(current.start(), current.end());
|
||||
self.advance();
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(
|
||||
i64::from_str(raw).unwrap(),
|
||||
i32::from_str(raw).unwrap(),
|
||||
source_range,
|
||||
))
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ impl FunctionSymbol {
|
||||
pub struct ParameterSymbol {
|
||||
name: Rc<str>,
|
||||
type_info: TypeInfo,
|
||||
stack_frame_offset: Option<usize>,
|
||||
stack_frame_offset: Option<isize>,
|
||||
}
|
||||
|
||||
impl ParameterSymbol {
|
||||
@ -59,11 +59,11 @@ impl ParameterSymbol {
|
||||
&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);
|
||||
}
|
||||
|
||||
pub fn stack_frame_offset(&self) -> usize {
|
||||
pub fn stack_frame_offset(&self) -> isize {
|
||||
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