From 9dfdcd716b9f67c15ed9ca4e69a317140019143d Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Wed, 19 Nov 2025 23:22:26 -0600 Subject: [PATCH] Modest implementation of lowering to IR and Instruction code. --- examples/hello_42.dm | 5 + src/bin/dmc/ir.rs | 33 ++ src/bin/dmc/main.rs | 11 + src/bin/dmc/name_analysis.rs | 5 +- src/bin/dvm/main.rs | 4 +- src/ir/lower_ast.rs | 315 +++++++++++ src/ir/lower_ir.rs | 131 +++++ src/ir/mod.rs | 583 ++++++++++++++++---- src/name_analysis/symbol/function_symbol.rs | 4 + src/vm/instruction.rs | 24 +- src/vm/mod.rs | 18 +- 11 files changed, 1013 insertions(+), 120 deletions(-) create mode 100644 examples/hello_42.dm create mode 100644 src/bin/dmc/ir.rs create mode 100644 src/ir/lower_ast.rs create mode 100644 src/ir/lower_ir.rs diff --git a/examples/hello_42.dm b/examples/hello_42.dm new file mode 100644 index 0000000..a427e8a --- /dev/null +++ b/examples/hello_42.dm @@ -0,0 +1,5 @@ +use std::core::println + +fn main(args: Array) + let hello = 42 +end \ No newline at end of file diff --git a/src/bin/dmc/ir.rs b/src/bin/dmc/ir.rs new file mode 100644 index 0000000..bb1055a --- /dev/null +++ b/src/bin/dmc/ir.rs @@ -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, Box> { + 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) +} \ No newline at end of file diff --git a/src/bin/dmc/main.rs b/src/bin/dmc/main.rs index 524669c..535c491 100644 --- a/src/bin/dmc/main.rs +++ b/src/bin/dmc/main.rs @@ -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, }, + Ir { + paths: Vec, + } } 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!(), } } diff --git a/src/bin/dmc/name_analysis.rs b/src/bin/dmc/name_analysis.rs index 9d88644..dd9001c 100644 --- a/src/bin/dmc/name_analysis.rs +++ b/src/bin/dmc/name_analysis.rs @@ -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>, @@ -33,7 +34,7 @@ impl Display for ParseErrors { impl std::error::Error for ParseErrors {} -pub fn name_analysis(paths: &[PathBuf]) -> Result<(), Box> { +pub fn name_analysis(paths: &[PathBuf]) -> Result, Box> { let mut paths_and_sources: HashMap = 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 } } - Ok(()) + Ok(compilation_units) } diff --git a/src/bin/dvm/main.rs b/src/bin/dvm/main.rs index edd9c3f..537b740 100644 --- a/src/bin/dvm/main.rs +++ b/src/bin/dvm/main.rs @@ -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 diff --git a/src/ir/lower_ast.rs b/src/ir/lower_ast.rs new file mode 100644 index 0000000..5d3161d --- /dev/null +++ b/src/ir/lower_ast.rs @@ -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 { + let mut result: Vec = 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 { + 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, +} + +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 { + 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 = 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>]) -> Vec { + 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, Vec) { + 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, Vec) { + let mut statements: Vec = vec![]; + let mut consts: Vec = 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, + locals_table: &mut LocalsTable +) -> Vec { + 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, + locals_table: &mut LocalsTable +) -> Vec { + let mut result: Vec = 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, + consts_pool: &mut Vec, + 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, + consts_pool: &mut Vec, + 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!() + } + } +} diff --git a/src/ir/lower_ir.rs b/src/ir/lower_ir.rs new file mode 100644 index 0000000..ef61c4f --- /dev/null +++ b/src/ir/lower_ir.rs @@ -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 { + let mut instructions: Vec = 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 { + 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 { + 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 { + let mut instructions: Vec = 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, + 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 { + let mut instructions: Vec = 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 { + let mut instructions: Vec = 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 +} \ No newline at end of file diff --git a/src/ir/mod.rs b/src/ir/mod.rs index e0f89df..8b874f9 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -1,29 +1,88 @@ -pub enum DvmIr { - Struct(Box), - 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), + Function(Box), + PlatformFunction(Box), + Const(Box), } -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, is_public: bool, - members: Vec> + members: Vec, } -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, + kind: Box, is_public: bool, is_mut: bool, } -pub enum DvmIrKind { - Primitive(Box), - Struct(Box), +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), + Struct(Box), +} + +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), + Array(Box), String, - Closure(Box), - Ref(Box), + Closure(Box), + Ref(Box), 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>, - return_type: Box, +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, + return_type: Box, +} + +pub struct IrFunction { name: String, - parameters: Vec>, - return_type: Box, - statements: Vec>, + parameters: Vec, + return_type: Box, + statements: Vec, + locals_table: Box, } -pub enum DvmIrStatement { - Alloc(DvmIrAlloc), - Call(DvmIrCallStmt), - Ret(DvmIrRet), - Assign(DvmIrAssign), - MakeClosure(DvmIrMakeClosure), - Drop(DvmIrDrop), +impl IrFunction { + pub fn new( + name: String, + parameters: Vec, + return_type: Box, + statements: Vec, + locals_table: Box, + ) -> 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), - Array(Box), +pub struct IrPlatformFunction { + name: String, + parameters: Vec, + return_type: Box, } -pub enum DvmIrArrayKind { - StaticSize(Box), - DynamicSize(Box) +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, +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), + Array(Box), +} + +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), + DynamicSize(Box), +} + +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, size: usize, } -pub struct DvmIrDynamicArrayKind { - inner_kind: Box, - size_expr: Box +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, +pub struct IrDynamicArrayKind { + inner_kind: Box, + size_expr: Box, +} + +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, + declared_kind: Box, + kind_to_alloc: Box, } -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, } -pub enum DvmIrExpr { - Call(Box), - Variable(Box), - ConstRef(Box), - Literal(Box) +pub enum IrExpression { + Variable(Box), + ConstRef(Box), + Literal(Box), } -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, - name: String, - call_expr: Box, +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>, +pub struct IrCall { + result_name: String, + declared_type: Box, + function_name: String, + arguments: Vec, } -pub struct DvmIrAssign { - lhs: Box, - rhs: Box +impl IrCall { + pub fn new( + result_name: &str, + declared_type: Box, + function_name: &str, + arguments: Vec, + ) -> 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, - suffixes: Vec> +pub struct IrAssign { + lhs: Box, + rhs: Box, } -pub enum DvmIrAssignLhsSuffix { - Index(DvmIrAssignLhsIndex), - Property(DvmIrAssignLhsProperty) +impl IrAssign { + pub fn new(lhs: Box, rhs: Box) -> 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, +pub struct IrReturn { + expression: Box, } -pub struct DvmIrAssignLhsProperty { - name: String, +impl IrReturn { + pub fn new(expression: Box) -> Self { + Self { expression } + } + + pub fn expression(&self) -> &Box { + &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 -} - -pub enum DvmIrReturnable { - Variable(DvmIrVariable), - Literal(DvmIrLiteral) -} - -pub struct DvmIrMakeClosure { - captures_kind: Option>, - parameters: Vec>, - return_type: Box, +pub struct IrMakeClosure { + captures_kind: Option>, + parameters: Vec, + return_type: Box, name: String, fn_name: String, - captures_variable: Box, + captures_variable: Box, } -pub struct DvmIrDrop { - variable: Box, -} \ No newline at end of file +impl IrMakeClosure { + pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result { + todo!() + } +} diff --git a/src/name_analysis/symbol/function_symbol.rs b/src/name_analysis/symbol/function_symbol.rs index 8f8a7a1..4f44e6c 100644 --- a/src/name_analysis/symbol/function_symbol.rs +++ b/src/name_analysis/symbol/function_symbol.rs @@ -78,6 +78,10 @@ impl FunctionSymbol { pub fn set_parameter_symbols(&mut self, parameter_symbols: Vec>>) { 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); diff --git a/src/vm/instruction.rs b/src/vm/instruction.rs index f18206d..9cb448e 100644 --- a/src/vm/instruction.rs +++ b/src/vm/instruction.rs @@ -18,6 +18,7 @@ pub enum Instruction { Pop { destination_register: Option, }, + PopFrame, AllocateObject { implementation_name: Rc, 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 { diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 050abdb..3b8b9ed 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -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,