Modest implementation of lowering to IR and Instruction code.

This commit is contained in:
Jesse Brault 2025-11-19 23:22:26 -06:00
parent f21128fd68
commit 9dfdcd716b
11 changed files with 1013 additions and 120 deletions

5
examples/hello_42.dm Normal file
View File

@ -0,0 +1,5 @@
use std::core::println
fn main(args: Array<String>)
let hello = 42
end

33
src/bin/dmc/ir.rs Normal file
View File

@ -0,0 +1,33 @@
use std::path::PathBuf;
use deimos::ast::node::CompilationUnit;
use deimos::ir::Ir;
use deimos::ir::lower_ast::lower_compilation_unit;
use deimos::ir::lower_ir::lower_ir_function;
use deimos::util::indent_writer::IndentWriter;
use crate::name_analysis::name_analysis;
pub fn compile_to_ir(paths: &[PathBuf]) -> Result<Vec<CompilationUnit>, Box<dyn std::error::Error>> {
let compilation_units = name_analysis(&paths)?;
for compilation_unit in &compilation_units {
let cu_irs = lower_compilation_unit(compilation_unit);
let mut out = String::new();
let mut indent_writer = IndentWriter::new(0, " ", &mut out);
for ir in &cu_irs {
ir.pretty_print(&mut indent_writer)?;
}
println!("{}", &out);
for ir in &cu_irs {
match ir {
Ir::Function(ir_function) => {
let instructions = lower_ir_function(ir_function);
println!("{:#?}", instructions);
}
_ => {}
}
}
}
Ok(compilation_units)
}

View File

@ -1,3 +1,4 @@
mod ir;
mod name_analysis;
mod p3;
// mod unparse;
@ -8,6 +9,7 @@ use crate::name_analysis::name_analysis;
use crate::p3::pretty_print_parse;
// use crate::unparse::unparse;
use clap::{Parser, Subcommand};
use crate::ir::compile_to_ir;
#[derive(Debug, Parser)]
#[command(name = "dmc")]
@ -29,6 +31,9 @@ enum Commands {
NameAnalysis {
paths: Vec<PathBuf>,
},
Ir {
paths: Vec<PathBuf>,
}
}
fn main() {
@ -50,6 +55,12 @@ fn main() {
eprintln!("{}", e)
}
}
Commands::Ir { paths } => {
let result = compile_to_ir(&paths);
if let Err(e) = result {
eprintln!("{}", e)
}
}
_ => todo!(),
}
}

View File

@ -10,6 +10,7 @@ use pest::Parser;
use std::collections::HashMap;
use std::fmt::{Debug, Display, Formatter};
use std::path::PathBuf;
use deimos::ast::node::CompilationUnit;
struct ParseErrors {
errors: Vec<pest::error::Error<Rule>>,
@ -33,7 +34,7 @@ impl Display for ParseErrors {
impl std::error::Error for ParseErrors {}
pub fn name_analysis(paths: &[PathBuf]) -> Result<(), Box<dyn std::error::Error>> {
pub fn name_analysis(paths: &[PathBuf]) -> Result<Vec<CompilationUnit>, Box<dyn std::error::Error>> {
let mut paths_and_sources: HashMap<String, String> = HashMap::new();
for path in paths {
let src = std::fs::read_to_string(path).unwrap();
@ -79,5 +80,5 @@ pub fn name_analysis(paths: &[PathBuf]) -> Result<(), Box<dyn std::error::Error>
}
}
Ok(())
Ok(compilation_units)
}

View File

@ -87,7 +87,7 @@ fn main() {
// return 0
MoveImmediate {
destination_register: 2,
immediate: Immediate::Int(0),
immediate: Immediate::I32(0),
},
SetReturnValue { source_register: 2 },
Return, // explicit, not needed
@ -106,7 +106,7 @@ fn main() {
let foo_function_instructions = vec![
MoveImmediate {
destination_register: 0,
immediate: Immediate::Int(42),
immediate: Immediate::I32(42),
},
SetReturnValue { source_register: 0 },
Return, // explicit, not needed

315
src/ir/lower_ast.rs Normal file
View File

@ -0,0 +1,315 @@
use crate::ast::node::{
CompilationUnit, Expression, Function, FunctionBlockBody, FunctionBody, Literal,
ModuleLevelDeclaration, Statement, VariableDeclaration,
};
use crate::ir::{
Ir, IrAssign, IrConst, IrExpression, IrFunction, IrKind, IrLiteral, IrPrimitiveKind,
IrStatement, IrVariable,
};
use crate::name_analysis::symbol::{ParameterSymbol, PrimitiveTypeSymbol, TypeSymbol};
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
pub fn lower_compilation_unit(compilation_unit: &CompilationUnit) -> Vec<Ir> {
let mut result: Vec<Ir> = vec![];
for declaration in compilation_unit.module_level_declarations() {
result.append(&mut lower_module_level_declaration(declaration));
}
result
}
fn lower_module_level_declaration(declaration: &ModuleLevelDeclaration) -> Vec<Ir> {
match declaration {
ModuleLevelDeclaration::Module(module) => {
todo!()
}
ModuleLevelDeclaration::Interface(interface) => {
todo!()
}
ModuleLevelDeclaration::Class(class) => {
todo!()
}
ModuleLevelDeclaration::Function(function) => lower_function(function),
ModuleLevelDeclaration::PlatformFunction(platform_function) => {
todo!()
}
}
}
pub struct LocalsTable {
t_count: usize,
stack_slot_count: usize,
stack_slots: HashMap<IrVariable, usize>,
}
impl LocalsTable {
pub fn new() -> Self {
Self {
t_count: 0,
stack_slot_count: 0,
stack_slots: HashMap::new(),
}
}
pub fn next_t_var(&mut self) -> IrVariable {
let t_num = self.t_count;
self.t_count += 1;
let t_name = format!("__t{}", t_num);
let t_var = IrVariable::new(&t_name);
self.register_stack_local(&t_var);
t_var
}
pub fn register_stack_local(&mut self, ir_variable: &IrVariable) {
let stack_slot = self.stack_slot_count;
self.stack_slot_count += 1;
self.stack_slots.insert(ir_variable.clone(), stack_slot);
}
pub fn get_stack_slot(&self, ir_variable: &IrVariable) -> usize {
*self.stack_slots.get(ir_variable).unwrap()
}
}
fn lower_function(function: &Function) -> Vec<Ir> {
let function_symbol = function.function_symbol().unwrap().borrow();
let name = function_symbol.fqn_parts_owned().join("::");
let parameters = lower_parameter_symbols(function_symbol.parameter_symbols());
let return_type = lower_type_symbol(function_symbol.return_type().unwrap());
let mut locals_table = LocalsTable::new();
let (statements, consts) = lower_function_body(function.function_body(), &mut locals_table);
let mut result: Vec<Ir> = vec![];
result.push(Ir::Function(Box::new(IrFunction::new(
name,
parameters,
Box::new(return_type),
statements,
Box::new(locals_table),
))));
result.append(
&mut consts
.into_iter()
.map(|constant| Ir::Const(Box::new(constant)))
.collect(),
);
result
}
fn lower_parameter_symbols(parameter_symbols: &[Rc<RefCell<ParameterSymbol>>]) -> Vec<IrKind> {
parameter_symbols
.iter()
.map(|parameter_symbol_rc| parameter_symbol_rc.borrow())
.map(|parameter_symbol| lower_type_symbol(parameter_symbol.type_symbol().unwrap()))
.collect()
}
fn lower_type_symbol(type_symbol: &TypeSymbol) -> IrKind {
match type_symbol {
TypeSymbol::Primitive(primitive_type_symbol) => {
lower_primitive_type_symbol(primitive_type_symbol)
}
TypeSymbol::Class(class_type_symbol) => {
todo!()
}
TypeSymbol::Interface(interface_type_symbol) => {
todo!()
}
TypeSymbol::Generic(generic_type_symbol) => {
todo!()
}
}
}
fn lower_primitive_type_symbol(primitive_type_symbol: &PrimitiveTypeSymbol) -> IrKind {
IrKind::Primitive(Box::new(match primitive_type_symbol {
PrimitiveTypeSymbol::Byte => IrPrimitiveKind::I8,
PrimitiveTypeSymbol::Char => IrPrimitiveKind::I8,
PrimitiveTypeSymbol::Short => IrPrimitiveKind::I16,
PrimitiveTypeSymbol::Int => IrPrimitiveKind::I32,
PrimitiveTypeSymbol::Long => IrPrimitiveKind::I64,
PrimitiveTypeSymbol::Float => IrPrimitiveKind::Float,
PrimitiveTypeSymbol::Double => IrPrimitiveKind::Double,
PrimitiveTypeSymbol::Boolean => IrPrimitiveKind::Boolean,
PrimitiveTypeSymbol::String => IrPrimitiveKind::String,
PrimitiveTypeSymbol::TypedArray { inner_type } => {
IrPrimitiveKind::Array(Box::new(lower_type_symbol(inner_type.as_ref().unwrap())))
}
PrimitiveTypeSymbol::Any => {
todo!()
}
PrimitiveTypeSymbol::Void => IrPrimitiveKind::Void,
}))
}
fn lower_function_body(
function_body: &FunctionBody,
locals_table: &mut LocalsTable
) -> (Vec<IrStatement>, Vec<IrConst>) {
match function_body {
FunctionBody::FunctionAliasBody(alias_body) => {
todo!()
}
FunctionBody::FunctionEqualsBody(equals_body) => {
todo!()
}
FunctionBody::FunctionBlockBody(block_body) => {
lower_function_block_body(block_body, locals_table)
}
}
}
fn lower_function_block_body(
body: &FunctionBlockBody,
locals_table: &mut LocalsTable
) -> (Vec<IrStatement>, Vec<IrConst>) {
let mut statements: Vec<IrStatement> = vec![];
let mut consts: Vec<IrConst> = vec![];
for statement in body.statements() {
statements.append(&mut lower_statement(statement, &mut consts, locals_table));
}
(statements, consts)
}
fn lower_statement(
statement: &Statement,
consts_pool: &mut Vec<IrConst>,
locals_table: &mut LocalsTable
) -> Vec<IrStatement> {
match statement {
Statement::VariableDeclaration(variable_declaration) => {
lower_variable_declaration(variable_declaration, consts_pool, locals_table)
}
Statement::AssignmentStatement(assignment_statement) => {
todo!()
}
Statement::ExpressionStatement(expression_statement) => {
todo!()
}
Statement::UseStatement(use_statement) => {
todo!()
}
Statement::IfStatement(if_statement) => {
todo!()
}
Statement::WhileStatement(while_statement) => {
todo!()
}
Statement::ForStatement(for_statement) => {
todo!()
}
}
}
fn lower_variable_declaration(
variable_declaration: &VariableDeclaration,
consts_pool: &mut Vec<IrConst>,
locals_table: &mut LocalsTable
) -> Vec<IrStatement> {
let mut result: Vec<IrStatement> = vec![];
let expression_t_var = lower_expression(
variable_declaration.expression().unwrap(),
&mut result,
consts_pool,
locals_table,
);
let target = IrVariable::new(variable_declaration.identifier().name());
locals_table.register_stack_local(&target);
let assign_stmt = IrAssign::new(
Box::new(target),
Box::new(IrExpression::Variable(Box::new(expression_t_var))),
);
result.push(IrStatement::Assign(assign_stmt));
result
}
fn lower_expression(
expression: &Expression,
target: &mut Vec<IrStatement>,
consts_pool: &mut Vec<IrConst>,
locals_table: &mut LocalsTable
) -> IrVariable {
match expression {
Expression::Ternary(ternary) => {
todo!()
}
Expression::Or(or) => {
todo!()
}
Expression::And(and) => {
todo!()
}
Expression::Comparison(comparison) => {
todo!()
}
Expression::Shift(shift) => {
todo!()
}
Expression::Additive(additive) => {
todo!()
}
Expression::Multiplicative(multiplicative) => {
todo!()
}
Expression::Prefix(prefix) => {
todo!()
}
Expression::Suffix(suffix) => {
todo!()
}
Expression::Literal(literal) => lower_literal(literal, target, consts_pool, locals_table),
Expression::Identifier(identifier) => {
todo!()
}
Expression::Fqn(fqn) => {
todo!()
}
Expression::Closure(closure) => {
todo!()
}
Expression::List(list) => {
todo!()
}
}
}
fn lower_literal(
literal: &Literal,
statements: &mut Vec<IrStatement>,
consts_pool: &mut Vec<IrConst>,
locals_table: &mut LocalsTable
) -> IrVariable {
match literal {
Literal::IntLiteral(int_literal) => {
let t_var = locals_table.next_t_var();
let assign_stmt = IrAssign::new(
Box::new(t_var.clone()),
Box::new(IrExpression::Literal(Box::new(IrLiteral::I32(
*int_literal,
)))),
);
statements.push(IrStatement::Assign(assign_stmt));
t_var
}
Literal::LongLiteral(long_literal) => {
todo!()
}
Literal::DoubleLiteral(double_literal) => {
todo!()
}
Literal::SingleQuoteString(sq_string) => {
todo!()
}
Literal::DString(d_string) => {
todo!()
}
Literal::BacktickString(b_string) => {
todo!()
}
Literal::BooleanLiteral(boolean_literal) => {
todo!()
}
}
}

131
src/ir/lower_ir.rs Normal file
View File

@ -0,0 +1,131 @@
use crate::ir::lower_ast::LocalsTable;
use crate::ir::{IrAllocable, IrAllocate, IrAssign, IrCall, IrExpression, IrFunction, IrLiteral, IrReturn, IrStatement};
use crate::vm::instruction::{Immediate, Instruction, Location};
use std::ops::Deref;
use std::rc::Rc;
pub fn lower_ir_function(ir_function: &IrFunction) -> Vec<Instruction> {
let mut instructions: Vec<Instruction> = vec![];
for statement in ir_function.statements() {
instructions.append(&mut lower_ir_statement(
statement,
ir_function.locals_table(),
));
}
instructions
}
fn lower_ir_statement(ir_statement: &IrStatement, locals_table: &LocalsTable) -> Vec<Instruction> {
match ir_statement {
IrStatement::Allocate(allocate) => lower_ir_allocate(allocate),
IrStatement::Call(call) => lower_ir_call(call, locals_table),
IrStatement::Return(ir_return) => lower_return(ir_return, locals_table),
IrStatement::Assign(assign) => {
lower_ir_assign(assign, locals_table)
}
IrStatement::MakeClosure(make_closure) => {
todo!()
}
}
}
fn lower_ir_allocate(ir_allocate: &IrAllocate) -> Vec<Instruction> {
let allocate_instruction = match ir_allocate.kind_to_alloc() {
IrAllocable::Struct(struct_kind) => Instruction::AllocateObject {
implementation_name: Rc::new(struct_kind.name().to_string()),
destination_register: 0,
},
IrAllocable::Array(array_kind) => {
todo!()
}
};
let push_instruction = Instruction::Push { source_register: 0 };
vec![allocate_instruction, push_instruction]
}
fn lower_ir_call(ir_call: &IrCall, locals_table: &LocalsTable) -> Vec<Instruction> {
let mut instructions: Vec<Instruction> = vec![];
// push args
for argument in ir_call.arguments() {
lower_ir_expression(argument, &mut instructions, locals_table);
}
instructions
}
fn lower_ir_expression(
ir_expression: &IrExpression,
instructions: &mut Vec<Instruction>,
locals_table: &LocalsTable,
) {
match ir_expression {
IrExpression::Variable(variable) => instructions.append(&mut vec![
Instruction::Copy {
source: Location::FramePointer {
offset: locals_table.get_stack_slot(variable) as isize,
},
destination: Location::Register(0),
},
Instruction::Push { source_register: 0 },
]),
IrExpression::ConstRef(const_ref) => {
todo!()
}
IrExpression::Literal(literal) => {
let immediate = match literal.deref() {
IrLiteral::I8(v) => Immediate::I8(*v),
IrLiteral::I16(v) => Immediate::I16(*v),
IrLiteral::I32(v) => Immediate::I32(*v),
IrLiteral::I64(v) => Immediate::I64(*v),
IrLiteral::I128(v) => Immediate::I128(*v),
IrLiteral::ISize(v) => Immediate::ISize(*v),
IrLiteral::U8(v) => Immediate::U8(*v),
IrLiteral::U16(v) => Immediate::U16(*v),
IrLiteral::U32(v) => Immediate::U32(*v),
IrLiteral::U64(v) => Immediate::U64(*v),
IrLiteral::U128(v) => Immediate::U128(*v),
IrLiteral::USize(v) => Immediate::USize(*v),
IrLiteral::Boolean(v) => Immediate::Boolean(*v),
IrLiteral::Float(v) => Immediate::Float(*v),
IrLiteral::Double(v) => Immediate::Double(*v),
};
instructions.append(&mut vec![
Instruction::MoveImmediate {
destination_register: 0,
immediate,
},
Instruction::Push { source_register: 0 },
])
}
}
}
fn lower_return(ir_return: &IrReturn, locals_table: &LocalsTable) -> Vec<Instruction> {
let mut instructions: Vec<Instruction> = vec![];
lower_ir_expression(ir_return.expression(), &mut instructions, locals_table);
instructions.append(&mut vec![
Instruction::Pop {
destination_register: Some(0),
},
Instruction::PopFrame,
Instruction::Push { source_register: 0 },
Instruction::Return,
]);
instructions
}
fn lower_ir_assign(ir_assign: &IrAssign, locals_table: &LocalsTable) -> Vec<Instruction> {
let mut instructions: Vec<Instruction> = vec![];
lower_ir_expression(ir_assign.rhs(), &mut instructions, locals_table);
instructions.append(&mut vec![
Instruction::Pop {
destination_register: Some(0),
},
Instruction::Copy {
source: Location::Register(0),
destination: Location::FramePointer {
offset: locals_table.get_stack_slot(ir_assign.lhs()) as isize,
}
}
]);
instructions
}

View File

@ -1,29 +1,88 @@
pub enum DvmIr {
Struct(Box<DvmIrStruct>),
Function(DvmIrFunction),
Const(DvmIrConst),
use crate::ir::lower_ast::LocalsTable;
use crate::util::indent_writer::IndentWriter;
pub mod lower_ast;
pub mod lower_ir;
pub enum Ir {
Struct(Box<IrStruct>),
Function(Box<IrFunction>),
PlatformFunction(Box<IrPlatformFunction>),
Const(Box<IrConst>),
}
pub struct DvmIrStruct {
impl Ir {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
match self {
Ir::Struct(ir_struct) => ir_struct.pretty_print(writer),
Ir::Function(ir_function) => ir_function.pretty_print(writer),
Ir::PlatformFunction(ir_platform_function) => ir_platform_function.pretty_print(writer),
Ir::Const(ir_const) => ir_const.pretty_print(writer),
}
}
}
pub struct IrStruct {
name: String,
kind: Box<DvmIrKind>,
is_public: bool,
members: Vec<Box<DvmIrStructMember>>
members: Vec<IrStructMember>,
}
pub struct DvmIrStructMember {
impl IrStruct {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
if self.is_public {
writer.writeln(&format!("pub struct {} {{", self.name))?;
} else {
writer.writeln(&format!("struct {} {{", self.name))?;
}
writer.increase_indent();
for member in &self.members {
member.pretty_print(writer)?;
writer.write("\n")?;
}
writer.decrease_indent();
writer.writeln("}")?;
Ok(())
}
}
pub struct IrStructMember {
name: String,
kind: Box<DvmIrKind>,
kind: Box<IrKind>,
is_public: bool,
is_mut: bool,
}
pub enum DvmIrKind {
Primitive(Box<DvmIrPrimitiveKind>),
Struct(Box<DvmIrStructKind>),
impl IrStructMember {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
if self.is_public {
writer.write("pub ")?;
}
if self.is_mut {
writer.write("mut ")?;
}
writer.write(&self.name)?;
writer.write(": ")?;
self.kind.pretty_print(writer)?;
Ok(())
}
}
pub enum DvmIrPrimitiveKind {
pub enum IrKind {
Primitive(Box<IrPrimitiveKind>),
Struct(Box<IrStructKind>),
}
impl IrKind {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
match self {
IrKind::Primitive(primitive) => primitive.pretty_print(writer),
IrKind::Struct(struct_kind) => struct_kind.pretty_print(writer),
}
}
}
pub enum IrPrimitiveKind {
I8,
I16,
I32,
@ -36,97 +95,342 @@ pub enum DvmIrPrimitiveKind {
U64,
U128,
USize,
Float,
Double,
Boolean,
Array(Box<DvmIrKind>),
Array(Box<IrKind>),
String,
Closure(Box<DvmIrClosureKind>),
Ref(Box<DvmIrKind>),
Closure(Box<IrClosureKind>),
Ref(Box<IrKind>),
Void,
}
pub struct DvmIrStructKind {
impl IrPrimitiveKind {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
match self {
IrPrimitiveKind::I8 => writer.write("i8"),
IrPrimitiveKind::I16 => writer.write("i16"),
IrPrimitiveKind::I32 => writer.write("i32"),
IrPrimitiveKind::I64 => writer.write("i64"),
IrPrimitiveKind::I128 => writer.write("i128"),
IrPrimitiveKind::ISize => writer.write("isize"),
IrPrimitiveKind::U8 => writer.write("u8"),
IrPrimitiveKind::U16 => writer.write("u16"),
IrPrimitiveKind::U32 => writer.write("u32"),
IrPrimitiveKind::U64 => writer.write("u64"),
IrPrimitiveKind::U128 => writer.write("u128"),
IrPrimitiveKind::USize => writer.write("usize"),
IrPrimitiveKind::Float => writer.write("f32"),
IrPrimitiveKind::Double => writer.write("f64"),
IrPrimitiveKind::Boolean => writer.write("boolean"),
IrPrimitiveKind::Array(kind) => {
writer.write("Array<")?;
kind.pretty_print(writer)?;
writer.write(">")?;
Ok(())
}
IrPrimitiveKind::String => writer.write("String"),
IrPrimitiveKind::Closure(closure_kind) => writer.write("Closure"),
IrPrimitiveKind::Ref(ref_kind) => {
todo!()
}
IrPrimitiveKind::Void => writer.write("Void"),
}
}
}
pub struct IrStructKind {
name: String,
}
pub struct DvmIrClosureKind {
captures_name: String,
parameters: Vec<Box<DvmIrKind>>,
return_type: Box<DvmIrKind>,
impl IrStructKind {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
writer.write(&self.name)
}
}
pub struct DvmIrFunction {
pub struct IrClosureKind {
captures_struct_name: String,
parameters: Vec<IrKind>,
return_type: Box<IrKind>,
}
pub struct IrFunction {
name: String,
parameters: Vec<Box<DvmIrKind>>,
return_type: Box<DvmIrKind>,
statements: Vec<Box<DvmIrStatement>>,
parameters: Vec<IrKind>,
return_type: Box<IrKind>,
statements: Vec<IrStatement>,
locals_table: Box<LocalsTable>,
}
pub enum DvmIrStatement {
Alloc(DvmIrAlloc),
Call(DvmIrCallStmt),
Ret(DvmIrRet),
Assign(DvmIrAssign),
MakeClosure(DvmIrMakeClosure),
Drop(DvmIrDrop),
impl IrFunction {
pub fn new(
name: String,
parameters: Vec<IrKind>,
return_type: Box<IrKind>,
statements: Vec<IrStatement>,
locals_table: Box<LocalsTable>,
) -> Self {
Self {
name,
parameters,
return_type,
statements,
locals_table,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn parameters(&self) -> &[IrKind] {
&self.parameters
}
pub fn return_type(&self) -> &IrKind {
&self.return_type
}
pub fn statements(&self) -> &[IrStatement] {
&self.statements
}
pub fn locals_table(&self) -> &LocalsTable {
&self.locals_table
}
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
writer.write("fn ")?;
writer.write(&self.name)?;
writer.write("(")?;
for (i, parameter) in self.parameters.iter().enumerate() {
parameter.pretty_print(writer)?;
if i != self.parameters.len() - 1 {
writer.write(", ")?;
}
}
writer.write(") -> ")?;
self.return_type.pretty_print(writer)?;
writer.write(" {\n")?;
writer.increase_indent();
for statement in &self.statements {
statement.pretty_print(writer)?;
}
writer.decrease_indent();
writer.writeln("}")
}
}
pub enum DvmIrAllocable {
Struct(Box<DvmIrStructKind>),
Array(Box<DvmIrArrayKind>),
pub struct IrPlatformFunction {
name: String,
parameters: Vec<IrKind>,
return_type: Box<IrKind>,
}
pub enum DvmIrArrayKind {
StaticSize(Box<DvmIrStaticArrayKind>),
DynamicSize(Box<DvmIrDynamicArrayKind>)
impl IrPlatformFunction {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
writer.write("platform fn ")?;
writer.write(&self.name)?;
writer.write("(")?;
for (i, parameter) in self.parameters.iter().enumerate() {
parameter.pretty_print(writer)?;
if i != self.parameters.len() - 1 {
writer.write(", ")?;
}
}
writer.write(") -> ")?;
self.return_type.pretty_print(writer)?;
writer.write("\n")?;
Ok(())
}
}
pub struct DvmIrStaticArrayKind {
inner_kind: Box<DvmIrKind>,
pub enum IrStatement {
Allocate(IrAllocate),
Call(IrCall),
Return(IrReturn),
Assign(IrAssign),
MakeClosure(IrMakeClosure),
}
impl IrStatement {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
match self {
IrStatement::Allocate(allocate) => allocate.pretty_print(writer),
IrStatement::Call(call) => call.pretty_print(writer),
IrStatement::Return(ir_return) => ir_return.pretty_print(writer),
IrStatement::Assign(assign) => assign.pretty_print(writer),
IrStatement::MakeClosure(make_closure) => make_closure.pretty_print(writer),
}
}
}
pub enum IrAllocable {
Struct(Box<IrStructKind>),
Array(Box<IrArrayKind>),
}
impl IrAllocable {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
match self {
IrAllocable::Struct(struct_kind) => struct_kind.pretty_print(writer),
IrAllocable::Array(array_kind) => array_kind.pretty_print(writer),
}
}
}
pub enum IrArrayKind {
StaticSize(Box<IrStaticArrayKind>),
DynamicSize(Box<IrDynamicArrayKind>),
}
impl IrArrayKind {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
match self {
IrArrayKind::StaticSize(static_array_kind) => static_array_kind.pretty_print(writer),
IrArrayKind::DynamicSize(dynamic_array_kind) => dynamic_array_kind.pretty_print(writer),
}
}
}
pub struct IrStaticArrayKind {
inner_kind: Box<IrKind>,
size: usize,
}
pub struct DvmIrDynamicArrayKind {
inner_kind: Box<DvmIrKind>,
size_expr: Box<DvmIrExpr>
impl IrStaticArrayKind {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
writer.write("[")?;
self.inner_kind.pretty_print(writer)?;
writer.write(&format!("; {}]", self.size))?;
Ok(())
}
}
pub struct DvmIrAlloc {
declared_kind: Box<DvmIrAllocable>,
pub struct IrDynamicArrayKind {
inner_kind: Box<IrKind>,
size_expr: Box<IrExpression>,
}
impl IrDynamicArrayKind {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
writer.write("[")?;
self.inner_kind.pretty_print(writer)?;
writer.write("; ")?;
self.size_expr.pretty_print(writer)?;
writer.write("]")?;
Ok(())
}
}
pub struct IrAllocate {
name: String,
kind_to_alloc: Box<DvmIrAllocable>,
declared_kind: Box<IrAllocable>,
kind_to_alloc: Box<IrAllocable>,
}
pub enum DvmIrConst {
String(DvmIrStringConst),
StringArray(DvmIrStringArrayConst),
impl IrAllocate {
pub fn name(&self) -> &str {
&self.name
}
pub fn declared_kind(&self) -> &IrAllocable {
&self.declared_kind
}
pub fn kind_to_alloc(&self) -> &IrAllocable {
&self.kind_to_alloc
}
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
writer.write_indented(&format!("let {}: ", self.name))?;
self.declared_kind.pretty_print(writer)?;
writer.write(" = alloc")?;
self.kind_to_alloc.pretty_print(writer)?;
Ok(())
}
}
pub struct DvmIrStringConst {
pub enum IrConst {
String(IrStringConst),
StringArray(IrStringArrayConst),
}
impl IrConst {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
todo!()
}
}
pub struct IrStringConst {
name: String,
value: String,
}
pub struct DvmIrStringArrayConst {
pub struct IrStringArrayConst {
name: String,
value: Vec<String>,
}
pub enum DvmIrExpr {
Call(Box<DvmIrCallExpr>),
Variable(Box<DvmIrVariable>),
ConstRef(Box<DvmIrConstRef>),
Literal(Box<DvmIrLiteral>)
pub enum IrExpression {
Variable(Box<IrVariable>),
ConstRef(Box<IrConstRef>),
Literal(Box<IrLiteral>),
}
pub struct DvmIrVariable {
impl IrExpression {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
match self {
IrExpression::Variable(variable) => variable.pretty_print(writer),
IrExpression::ConstRef(const_ref) => const_ref.pretty_print(writer),
IrExpression::Literal(literal) => literal.pretty_print(writer),
}
}
}
#[derive(Clone, Hash, Eq, PartialEq)]
pub struct IrVariable {
name: String,
}
pub struct DvmIrConstRef {
name: String,
impl IrVariable {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
writer.write(&self.name)
}
}
pub enum DvmIrLiteral {
pub struct IrConstRef {
name: String,
}
impl IrConstRef {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
writer.write(&self.name)
}
}
pub enum IrLiteral {
I8(i8),
I16(i16),
I32(i32),
@ -140,60 +444,145 @@ pub enum DvmIrLiteral {
U128(u128),
USize(usize),
Boolean(bool),
Float(f32),
Double(f64),
}
pub struct DvmIrCallStmt {
declared_type: Box<DvmIrKind>,
name: String,
call_expr: Box<DvmIrCallExpr>,
impl IrLiteral {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
match self {
IrLiteral::I8(v) => writer.write(&format!("{}", v)),
IrLiteral::I16(v) => writer.write(&format!("{}", v)),
IrLiteral::I32(v) => writer.write(&format!("{}", v)),
IrLiteral::I64(v) => writer.write(&format!("{}", v)),
IrLiteral::I128(v) => writer.write(&format!("{}", v)),
IrLiteral::ISize(v) => writer.write(&format!("{}", v)),
IrLiteral::U8(v) => writer.write(&format!("{}", v)),
IrLiteral::U16(v) => writer.write(&format!("{}", v)),
IrLiteral::U32(v) => writer.write(&format!("{}", v)),
IrLiteral::U64(v) => writer.write(&format!("{}", v)),
IrLiteral::U128(v) => writer.write(&format!("{}", v)),
IrLiteral::USize(v) => writer.write(&format!("{}", v)),
IrLiteral::Boolean(v) => writer.write(&format!("{}", v)),
IrLiteral::Float(v) => writer.write(&format!("{}", v)),
IrLiteral::Double(v) => writer.write(&format!("{}", v)),
}
}
}
pub struct DvmIrCallExpr {
name: String,
arguments: Vec<Box<DvmIrExpr>>,
pub struct IrCall {
result_name: String,
declared_type: Box<IrKind>,
function_name: String,
arguments: Vec<IrExpression>,
}
pub struct DvmIrAssign {
lhs: Box<DvmIrAssignLhs>,
rhs: Box<DvmIrExpr>
impl IrCall {
pub fn new(
result_name: &str,
declared_type: Box<IrKind>,
function_name: &str,
arguments: Vec<IrExpression>,
) -> Self {
Self {
result_name: result_name.to_string(),
declared_type,
function_name: function_name.to_string(),
arguments,
}
}
pub fn result_name(&self) -> &str {
&self.result_name
}
pub fn declared_type(&self) -> &IrKind {
&self.declared_type
}
pub fn function_name(&self) -> &str {
&self.function_name
}
pub fn arguments(&self) -> &[IrExpression] {
&self.arguments
}
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
writer.write_indented(&format!("let {}: ", self.result_name))?;
self.declared_type.pretty_print(writer)?;
writer.write(&format!(" = call {}(", self.function_name))?;
for (i, argument) in self.arguments.iter().enumerate() {
argument.pretty_print(writer)?;
if i != self.arguments.len() - 1 {
writer.write(", ")?;
}
}
writer.write(")\n")?;
Ok(())
}
}
pub struct DvmIrAssignLhs {
base: Box<DvmIrVariable>,
suffixes: Vec<Box<DvmIrAssignLhsSuffix>>
pub struct IrAssign {
lhs: Box<IrVariable>,
rhs: Box<IrExpression>,
}
pub enum DvmIrAssignLhsSuffix {
Index(DvmIrAssignLhsIndex),
Property(DvmIrAssignLhsProperty)
impl IrAssign {
pub fn new(lhs: Box<IrVariable>, rhs: Box<IrExpression>) -> Self {
Self { lhs, rhs }
}
pub fn lhs(&self) -> &IrVariable {
&self.lhs
}
pub fn rhs(&self) -> &IrExpression {
&self.rhs
}
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
writer.write_indented("")?;
self.lhs.pretty_print(writer)?;
writer.write(" = ")?;
self.rhs.pretty_print(writer)?;
writer.write("\n")?;
Ok(())
}
}
pub struct DvmIrAssignLhsIndex {
expr: Box<DvmIrExpr>,
pub struct IrReturn {
expression: Box<IrExpression>,
}
pub struct DvmIrAssignLhsProperty {
name: String,
impl IrReturn {
pub fn new(expression: Box<IrExpression>) -> Self {
Self { expression }
}
pub fn expression(&self) -> &Box<IrExpression> {
&self.expression
}
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
writer.write_indented("return ")?;
self.expression.pretty_print(writer)?;
writer.write("\n")?;
Ok(())
}
}
pub struct DvmIrRet {
value: Box<DvmIrReturnable>
}
pub enum DvmIrReturnable {
Variable(DvmIrVariable),
Literal(DvmIrLiteral)
}
pub struct DvmIrMakeClosure {
captures_kind: Option<Box<DvmIrStructKind>>,
parameters: Vec<Box<DvmIrKind>>,
return_type: Box<DvmIrKind>,
pub struct IrMakeClosure {
captures_kind: Option<Box<IrStructKind>>,
parameters: Vec<IrKind>,
return_type: Box<IrKind>,
name: String,
fn_name: String,
captures_variable: Box<DvmIrVariable>,
captures_variable: Box<IrVariable>,
}
pub struct DvmIrDrop {
variable: Box<DvmIrVariable>,
}
impl IrMakeClosure {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
todo!()
}
}

View File

@ -78,6 +78,10 @@ impl FunctionSymbol {
pub fn set_parameter_symbols(&mut self, parameter_symbols: Vec<Rc<RefCell<ParameterSymbol>>>) {
self.parameters = parameter_symbols;
}
pub fn return_type(&self) -> Option<&TypeSymbol> {
self.return_type.as_ref()
}
pub fn set_return_type(&mut self, type_symbol: TypeSymbol) {
self.return_type = Some(type_symbol);

View File

@ -18,6 +18,7 @@ pub enum Instruction {
Pop {
destination_register: Option<usize>,
},
PopFrame,
AllocateObject {
implementation_name: Rc<String>,
destination_register: usize,
@ -117,12 +118,21 @@ pub enum Instruction {
#[derive(Debug, Clone)]
pub enum Immediate {
Byte(u8),
Int(i32),
Long(i64),
Double(f64),
Usize(usize),
I8(i8),
I16(i16),
I32(i32),
I64(i64),
I128(i128),
ISize(isize),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
U128(u128),
USize(usize),
Boolean(bool),
Float(f32),
Double(f64),
Constant(DvmConstant),
Empty,
}
@ -130,10 +140,10 @@ pub enum Immediate {
#[derive(Debug, Clone)]
pub enum Location {
Register(usize),
StackFrameBase {
FramePointer {
offset: isize,
},
StackTop {
StackPointer {
offset: isize,
},
Field {

View File

@ -224,7 +224,7 @@ fn compute_index_with_offset(
fn copy_from_source(state: &DvmState, source: &Location) -> DvmValue {
match source {
Location::Register(register) => state.registers[*register].clone(),
Location::StackFrameBase { offset } => {
Location::FramePointer { offset } => {
let index = if offset.is_negative() {
state.frame_base_index - offset.unsigned_abs()
} else {
@ -232,7 +232,7 @@ fn copy_from_source(state: &DvmState, source: &Location) -> DvmValue {
};
state.stack[index].clone()
}
Location::StackTop { offset } => {
Location::StackPointer { offset } => {
if *offset >= 0 {
dvm_panic!(
state,
@ -272,7 +272,7 @@ fn write_to_destination(state: &mut DvmState, destination: &Location, value: Dvm
Location::Register(register) => {
state.registers[*register] = value;
}
Location::StackFrameBase { offset } => {
Location::FramePointer { offset } => {
let index = if offset.is_negative() {
state.frame_base_index - offset.unsigned_abs()
} else {
@ -280,7 +280,7 @@ fn write_to_destination(state: &mut DvmState, destination: &Location, value: Dvm
};
state.stack[index] = value;
}
Location::StackTop { offset } => {
Location::StackPointer { offset } => {
if *offset >= 0 {
dvm_panic!(
state,
@ -344,14 +344,7 @@ fn constant_to_value(constant: &DvmConstant) -> DvmValue {
fn immediate_to_value(immediate: &Immediate) -> DvmValue {
match immediate {
Immediate::Byte(b) => DvmValue::Byte(*b),
Immediate::Int(i) => DvmValue::Int(*i),
Immediate::Long(l) => DvmValue::Long(*l),
Immediate::Double(d) => DvmValue::Double(*d),
Immediate::Usize(s) => DvmValue::USize(*s),
Immediate::Boolean(b) => DvmValue::Boolean(*b),
Immediate::Constant(c) => constant_to_value(c),
Immediate::Empty => DvmValue::Empty,
_ => todo!()
}
}
@ -411,6 +404,7 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont
state.registers[*register_index] = value;
}
}
PopFrame => {}
AllocateObject {
implementation_name,
destination_register,