diff --git a/dmc-lib/src/asm/asm_block.rs b/dmc-lib/src/asm/asm_block.rs index eea1e35..4291e22 100644 --- a/dmc-lib/src/asm/asm_block.rs +++ b/dmc-lib/src/asm/asm_block.rs @@ -2,12 +2,15 @@ use crate::asm::asm_instruction::AsmInstruction; #[derive(Debug)] pub struct AsmBlock { - id: usize, + name: String, instructions: Vec, } impl AsmBlock { - pub fn new(id: usize, instructions: Vec) -> Self { - Self { id, instructions } + pub fn new(name: &str, instructions: Vec) -> Self { + Self { + name: name.into(), + instructions, + } } } diff --git a/dmc-lib/src/asm/asm_instruction.rs b/dmc-lib/src/asm/asm_instruction.rs index a3a1f49..6436460 100644 --- a/dmc-lib/src/asm/asm_instruction.rs +++ b/dmc-lib/src/asm/asm_instruction.rs @@ -11,6 +11,7 @@ pub enum AsmInstruction { pub enum Operand { IntegerLiteral(i64), Register(usize), + StackFrameOffset(usize), } #[derive(Debug)] diff --git a/dmc-lib/src/asm/mod.rs b/dmc-lib/src/asm/mod.rs index 0459706..a4dc20a 100644 --- a/dmc-lib/src/asm/mod.rs +++ b/dmc-lib/src/asm/mod.rs @@ -5,8 +5,7 @@ pub mod asm_instruction; #[cfg(test)] mod smoke_tests { use crate::asm::asm_function::AsmFunction; - use crate::ir::assemble_context::AssembleContext; - use crate::ir::Ir; + use crate::constants_table::ConstantsTable; use crate::parser::parse_compilation_unit; use crate::symbol_table::SymbolTable; @@ -16,17 +15,7 @@ mod smoke_tests { compilation_unit.gather_declared_names(&mut symbol_table); compilation_unit.check_name_usages(&symbol_table); compilation_unit.type_check(&symbol_table); - let irs = compilation_unit.lower_to_ir(); - let mut asm_functions = vec![]; - for ir in &irs { - match ir { - Ir::Function(ir_function) => { - asm_functions.push(ir_function.assemble(&mut AssembleContext::new())); - } - _ => {} - } - } - asm_functions + compilation_unit.assemble(&symbol_table, &mut ConstantsTable::new()) } #[test] diff --git a/dmc-lib/src/ast/assemble_context.rs b/dmc-lib/src/ast/assemble_context.rs new file mode 100644 index 0000000..7343369 --- /dev/null +++ b/dmc-lib/src/ast/assemble_context.rs @@ -0,0 +1,114 @@ +use crate::asm::asm_block::AsmBlock; +use crate::asm::asm_function::AsmFunction; +use crate::asm::asm_instruction::AsmInstruction; +use crate::source_range::SourceRange; + +pub struct AssembleContext { + functions: Vec, + current_function: Option, +} + +impl AssembleContext { + pub fn new() -> Self { + Self { + functions: vec![], + current_function: None, + } + } + + pub fn take_functions(&mut self) -> Vec { + std::mem::take(&mut self.functions) + } + + pub fn new_function(&mut self, name: &str, source_range: &SourceRange) { + self.current_function = Some(FunctionAssembler::new(name, source_range)); + } + + pub fn complete_function(&mut self) { + let mut function_assembler = self.current_function.take().unwrap(); + function_assembler.complete_block(); + let asm_function = function_assembler.result(); + self.functions.push(asm_function); + } + + pub fn new_block(&mut self, name: &str) { + self.current_function.as_mut().unwrap().new_block(name); + } + + pub fn new_local_register(&mut self) -> usize { + self.current_function.as_mut().unwrap().new_local_register() + } + + pub fn instruction(&mut self, to_add: AsmInstruction) { + self.current_function.as_mut().unwrap().instruction(to_add); + } +} + +struct FunctionAssembler { + name: String, + source_range: SourceRange, + blocks: Vec, + current_block: Option, + local_register_counter: usize, +} + +impl FunctionAssembler { + fn new(name: &str, source_range: &SourceRange) -> Self { + Self { + name: name.into(), + source_range: source_range.clone(), + blocks: vec![], + current_block: None, + local_register_counter: 0, + } + } + + fn new_block(&mut self, name: &str) { + let maybe_block_assembler = self.current_block.take(); + if let Some(mut block_assembler) = maybe_block_assembler { + self.blocks.push(block_assembler.result()); + } + self.current_block = Some(BlockAssembler::new(name)) + } + + fn complete_block(&mut self) { + let mut block_assembler = self.current_block.take().unwrap(); + self.blocks.push(block_assembler.result()); + } + + fn result(&mut self) -> AsmFunction { + AsmFunction::new(&self.name, std::mem::take(&mut self.blocks)) + } + + fn new_local_register(&mut self) -> usize { + let register = self.local_register_counter; + self.local_register_counter += 1; + register + } + + fn instruction(&mut self, to_add: AsmInstruction) { + self.current_block.as_mut().unwrap().instruction(to_add); + } +} + +struct BlockAssembler { + name: String, + instructions: Vec, +} + +impl BlockAssembler { + fn new(name: &str) -> Self { + Self { + name: name.into(), + instructions: vec![], + } + } + + fn instruction(&mut self, to_add: AsmInstruction) { + self.instructions.push(to_add); + } + + fn result(&mut self) -> AsmBlock { + AsmBlock::new(&self.name, std::mem::take(&mut self.instructions)) + } +} diff --git a/dmc-lib/src/ast/call.rs b/dmc-lib/src/ast/call.rs index 7f0b125..7e85571 100644 --- a/dmc-lib/src/ast/call.rs +++ b/dmc-lib/src/ast/call.rs @@ -1,9 +1,15 @@ +use crate::asm::asm_instruction::{ + AsmInstruction, InvokePlatformStatic, LoadConstant, Operand, Push, +}; +use crate::ast::assemble_context::AssembleContext; use crate::ast::expression::Expression; use crate::ast::function::FunctionLoweringContext; +use crate::constants_table::ConstantsTable; use crate::diagnostic::Diagnostic; use crate::ir::ir_call::IrCall; use crate::ir::ir_expression::IrExpression; use crate::source_range::SourceRange; +use crate::symbol::ExpressibleSymbol; use crate::symbol_table::SymbolTable; use crate::type_info::TypeInfo; @@ -90,6 +96,63 @@ impl Call { IrExpression::Call(IrCall::new(function_name, arguments)) } + pub fn assemble( + &self, + context: &mut AssembleContext, + symbol_table: &SymbolTable, + constants_table: &mut ConstantsTable, + ) { + // push all args + for argument in &self.arguments { + match argument { + Expression::Call(call) => { + call.assemble(context, symbol_table, constants_table); // will leave return val on stack + } + Expression::IntegerLiteral(integer_literal) => { + context.instruction(AsmInstruction::Push(Push::new(Operand::IntegerLiteral( + integer_literal.value(), + )))); + } + Expression::String(string_literal) => { + let name = constants_table.insert_string(string_literal.content()); + let temp_register = context.new_local_register(); + context.instruction(AsmInstruction::LoadConstant(LoadConstant::new( + &name, + temp_register, + ))); + context.instruction(AsmInstruction::Push(Push::new(Operand::Register( + temp_register, + )))); + } + Expression::Identifier(identifier) => match identifier.expressible_symbol() { + ExpressibleSymbol::Function(_) => { + panic!("Pushing function symbols not supported.") + } + ExpressibleSymbol::Parameter(parameter_symbol) => { + context.instruction(AsmInstruction::Push(Push::new( + Operand::StackFrameOffset( + parameter_symbol.borrow().stack_frame_offset(), + ), + ))); + } + ExpressibleSymbol::Variable(variable_symbol) => { + context.instruction(AsmInstruction::Push(Push::new(Operand::Register( + variable_symbol.borrow().register(), + )))) + } + }, + } + } + let function_name = match self.callee() { + Expression::Identifier(identifier) => identifier.name(), + _ => panic!("Calling things other than identifiers not yet supported."), + }; + + context.instruction(AsmInstruction::InvokePlatformStatic( + InvokePlatformStatic::new(function_name), + )); + } + pub fn source_range(&self) -> &SourceRange { &self.source_range } diff --git a/dmc-lib/src/ast/compilation_unit.rs b/dmc-lib/src/ast/compilation_unit.rs index 15e54fc..7f3aa75 100644 --- a/dmc-lib/src/ast/compilation_unit.rs +++ b/dmc-lib/src/ast/compilation_unit.rs @@ -1,4 +1,7 @@ +use crate::asm::asm_function::AsmFunction; +use crate::ast::assemble_context::AssembleContext; use crate::ast::function::Function; +use crate::constants_table::ConstantsTable; use crate::diagnostic::Diagnostic; use crate::ir::Ir; use crate::symbol_table::SymbolTable; @@ -49,4 +52,16 @@ impl CompilationUnit { } irs } + + pub fn assemble( + &self, + symbol_table: &SymbolTable, + constants_table: &mut ConstantsTable, + ) -> Vec { + let mut context = AssembleContext::new(); + for function in &self.functions { + function.assemble(&mut context, symbol_table, constants_table); + } + context.take_functions() + } } diff --git a/dmc-lib/src/ast/expression_statement.rs b/dmc-lib/src/ast/expression_statement.rs index 4e919d2..ea6120e 100644 --- a/dmc-lib/src/ast/expression_statement.rs +++ b/dmc-lib/src/ast/expression_statement.rs @@ -1,5 +1,7 @@ +use crate::ast::assemble_context::AssembleContext; use crate::ast::expression::Expression; use crate::ast::function::FunctionLoweringContext; +use crate::constants_table::ConstantsTable; use crate::diagnostic::Diagnostic; use crate::ir::ir_expression::IrExpression; use crate::ir::ir_statement::IrStatement; @@ -49,4 +51,18 @@ impl ExpressionStatement { } } } + + pub fn assemble( + &self, + context: &mut AssembleContext, + symbol_table: &SymbolTable, + constants_table: &mut ConstantsTable, + ) { + match self.expression.as_ref() { + Expression::Call(call) => { + call.assemble(context, symbol_table, constants_table); + } + _ => unreachable!(), + } + } } diff --git a/dmc-lib/src/ast/function.rs b/dmc-lib/src/ast/function.rs index 36f4383..2645e51 100644 --- a/dmc-lib/src/ast/function.rs +++ b/dmc-lib/src/ast/function.rs @@ -1,4 +1,6 @@ +use crate::ast::assemble_context::AssembleContext; use crate::ast::statement::Statement; +use crate::constants_table::ConstantsTable; use crate::diagnostic::Diagnostic; use crate::ir::Ir; use crate::ir::ir_constant::IrConstant; @@ -93,6 +95,20 @@ impl Function { irs.push(Ir::Function(ir_function)); irs } + + pub fn assemble( + &self, + context: &mut AssembleContext, + symbol_table: &SymbolTable, + constants_table: &mut ConstantsTable, + ) { + context.new_function(&self.declared_name, &self.declared_name_source_range); + context.new_block(&format!("{}_enter", self.declared_name)); + for statement in &self.statements { + statement.assemble(context, symbol_table, constants_table); + } + context.complete_function(); + } } pub struct FunctionLoweringContext { diff --git a/dmc-lib/src/ast/identifier.rs b/dmc-lib/src/ast/identifier.rs index 32b4834..b35e67c 100644 --- a/dmc-lib/src/ast/identifier.rs +++ b/dmc-lib/src/ast/identifier.rs @@ -56,11 +56,19 @@ impl Identifier { ExpressibleSymbol::Function(function_symbol) => { TypeInfo::Function(function_symbol.clone()) } - ExpressibleSymbol::Parameter(parameter_symbol) => parameter_symbol.type_info().clone(), - ExpressibleSymbol::Variable(variable_symbol) => variable_symbol.type_info().clone(), + ExpressibleSymbol::Parameter(parameter_symbol) => { + parameter_symbol.borrow().type_info().clone() + } + ExpressibleSymbol::Variable(variable_symbol) => { + variable_symbol.borrow().type_info().clone() + } } } + pub fn expressible_symbol(&self) -> &ExpressibleSymbol { + self.expressible_symbol.as_ref().unwrap() + } + pub fn lower_to_ir(&self, context: &mut FunctionLoweringContext) -> IrExpression { IrExpression::Variable(IrVariable::new(self.name())) } diff --git a/dmc-lib/src/ast/let_statement.rs b/dmc-lib/src/ast/let_statement.rs index c04f862..1521a5e 100644 --- a/dmc-lib/src/ast/let_statement.rs +++ b/dmc-lib/src/ast/let_statement.rs @@ -1,17 +1,21 @@ +use crate::asm::asm_instruction::{AsmInstruction, LoadConstant, Move, Operand, Pop}; +use crate::ast::assemble_context::AssembleContext; use crate::ast::expression::Expression; use crate::ast::function::FunctionLoweringContext; +use crate::constants_table::ConstantsTable; use crate::diagnostic::Diagnostic; use crate::ir::ir_assign::IrAssign; use crate::ir::ir_statement::IrStatement; use crate::ir::ir_variable::IrVariable; use crate::source_range::SourceRange; -use crate::symbol::VariableSymbol; +use crate::symbol::{ExpressibleSymbol, VariableSymbol}; use crate::symbol_table::{SymbolInsertError, SymbolTable}; pub struct LetStatement { declared_name: String, declared_name_source_range: SourceRange, initializer: Box, + scope_id: Option, } impl LetStatement { @@ -24,6 +28,7 @@ impl LetStatement { declared_name: declared_name.to_string(), declared_name_source_range, initializer: initializer.into(), + scope_id: None, } } @@ -60,6 +65,7 @@ impl LetStatement { } } } + self.scope_id = Some(symbol_table.current_scope_id()); diagnostics } @@ -79,4 +85,62 @@ impl LetStatement { let assign_statement = IrAssign::new(destination, data); context.add_statement(IrStatement::Assign(assign_statement)); } + + pub fn assemble( + &self, + context: &mut AssembleContext, + symbol_table: &SymbolTable, + constants_table: &mut ConstantsTable, + ) { + let destination_register = context.new_local_register(); + + // save register to symbol + let variable_symbol = + symbol_table.get_variable_symbol(self.scope_id.unwrap(), self.declared_name()); + variable_symbol + .borrow_mut() + .set_register(destination_register); + + match self.initializer() { + Expression::Call(call) => { + call.assemble(context, symbol_table, constants_table); + context.instruction(AsmInstruction::Pop(Pop::new(destination_register))); + } + Expression::IntegerLiteral(integer_literal) => { + context.instruction(AsmInstruction::Move(Move::new( + Operand::IntegerLiteral(integer_literal.value()), + destination_register, + ))); + } + Expression::String(string_literal) => { + let name = constants_table.insert_string(string_literal.content()); + context.instruction(AsmInstruction::LoadConstant(LoadConstant::new( + &name, + destination_register, + ))); + } + Expression::Identifier(identifier) => { + let expressible_symbol = identifier.expressible_symbol(); + match expressible_symbol { + ExpressibleSymbol::Function(_) => { + panic!("Moving functions to registers not yet supported"); + } + ExpressibleSymbol::Parameter(parameter_symbol) => { + context.instruction(AsmInstruction::Move(Move::new( + Operand::StackFrameOffset( + parameter_symbol.borrow().stack_frame_offset(), + ), + destination_register, + ))); + } + ExpressibleSymbol::Variable(variable_symbol) => { + context.instruction(AsmInstruction::Move(Move::new( + Operand::Register(variable_symbol.borrow().register()), + destination_register, + ))); + } + } + } + } + } } diff --git a/dmc-lib/src/ast/mod.rs b/dmc-lib/src/ast/mod.rs index 039fd80..a9f637e 100644 --- a/dmc-lib/src/ast/mod.rs +++ b/dmc-lib/src/ast/mod.rs @@ -1,3 +1,4 @@ +mod assemble_context; pub mod call; pub mod compilation_unit; pub mod expression; @@ -12,6 +13,7 @@ pub mod string_literal; #[cfg(test)] mod name_tests { + use crate::constants_table::ConstantsTable; use crate::ir::Ir; use crate::ir::assemble_context::AssembleContext; use crate::parser::parse_compilation_unit; @@ -29,18 +31,10 @@ mod name_tests { 0 ); assert_eq!(compilation_unit.check_name_usages(&symbol_table).len(), 0); - let irs = compilation_unit.lower_to_ir(); - for ir in &irs { - println!("{:#?}", ir); - } - for ir in &irs { - match ir { - Ir::Function(ir_function) => { - let asm_function = ir_function.assemble(&mut AssembleContext::new()); - println!("{:#?}", asm_function); - } - _ => {} - } + let mut constants_table = ConstantsTable::new(); + let asm_functions = compilation_unit.assemble(&symbol_table, &mut constants_table); + for asm_function in &asm_functions { + println!("{:#?}", asm_function); } } diff --git a/dmc-lib/src/ast/statement.rs b/dmc-lib/src/ast/statement.rs index 2cef340..2196cd0 100644 --- a/dmc-lib/src/ast/statement.rs +++ b/dmc-lib/src/ast/statement.rs @@ -1,6 +1,8 @@ +use crate::ast::assemble_context::AssembleContext; use crate::ast::expression_statement::ExpressionStatement; use crate::ast::function::FunctionLoweringContext; use crate::ast::let_statement::LetStatement; +use crate::constants_table::ConstantsTable; use crate::diagnostic::Diagnostic; use crate::symbol_table::SymbolTable; @@ -47,4 +49,20 @@ impl Statement { } } } + + pub fn assemble( + &self, + context: &mut AssembleContext, + symbol_table: &SymbolTable, + constants_table: &mut ConstantsTable, + ) { + match self { + Statement::Let(let_statement) => { + let_statement.assemble(context, symbol_table, constants_table); + } + Statement::Expression(expression_statement) => { + expression_statement.assemble(context, symbol_table, constants_table); + } + } + } } diff --git a/dmc-lib/src/constants_table.rs b/dmc-lib/src/constants_table.rs new file mode 100644 index 0000000..88199f9 --- /dev/null +++ b/dmc-lib/src/constants_table.rs @@ -0,0 +1,22 @@ +use std::collections::HashMap; + +pub struct ConstantsTable { + string_counter: usize, + strings_to_names: HashMap, +} + +impl ConstantsTable { + pub fn new() -> Self { + Self { + string_counter: 0, + strings_to_names: HashMap::new(), + } + } + + pub fn insert_string(&mut self, s: &str) -> String { + let name = format!("s_{}", self.string_counter); + self.string_counter += 1; + self.strings_to_names.insert(s.into(), name.clone()); + name + } +} diff --git a/dmc-lib/src/ir/ir_function.rs b/dmc-lib/src/ir/ir_function.rs index 235641d..f006f20 100644 --- a/dmc-lib/src/ir/ir_function.rs +++ b/dmc-lib/src/ir/ir_function.rs @@ -22,7 +22,7 @@ impl IrFunction { for statement in &self.statements { instructions.append(&mut statement.assemble(context)); } - let blocks = vec![AsmBlock::new(0, instructions)]; + let blocks = vec![AsmBlock::new("oops", instructions)]; AsmFunction::new(&self.name, blocks) } } diff --git a/dmc-lib/src/lib.rs b/dmc-lib/src/lib.rs index c6674fc..c6b8fd4 100644 --- a/dmc-lib/src/lib.rs +++ b/dmc-lib/src/lib.rs @@ -1,5 +1,6 @@ mod asm; mod ast; +mod constants_table; mod diagnostic; mod ir; mod lexer; diff --git a/dmc-lib/src/scope.rs b/dmc-lib/src/scope.rs index f0f219d..8e2d68b 100644 --- a/dmc-lib/src/scope.rs +++ b/dmc-lib/src/scope.rs @@ -1,4 +1,5 @@ use crate::symbol::{FunctionSymbol, ParameterSymbol, VariableSymbol}; +use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; @@ -6,8 +7,8 @@ pub struct Scope { debug_name: String, parent_id: Option, function_symbols: HashMap, Rc>, - parameter_symbols: HashMap, Rc>, - variable_symbols: HashMap, Rc>, + parameter_symbols: HashMap, Rc>>, + variable_symbols: HashMap, Rc>>, } impl Scope { @@ -29,19 +30,19 @@ impl Scope { &mut self.function_symbols } - pub fn parameter_symbols(&self) -> &HashMap, Rc> { + pub fn parameter_symbols(&self) -> &HashMap, Rc>> { &self.parameter_symbols } - pub fn parameter_symbols_mut(&mut self) -> &mut HashMap, Rc> { + pub fn parameter_symbols_mut(&mut self) -> &mut HashMap, Rc>> { &mut self.parameter_symbols } - pub fn variable_symbols(&self) -> &HashMap, Rc> { + pub fn variable_symbols(&self) -> &HashMap, Rc>> { &self.variable_symbols } - pub fn variable_symbols_mut(&mut self) -> &mut HashMap, Rc> { + pub fn variable_symbols_mut(&mut self) -> &mut HashMap, Rc>> { &mut self.variable_symbols } diff --git a/dmc-lib/src/source_range.rs b/dmc-lib/src/source_range.rs index 3996719..9b1f68c 100644 --- a/dmc-lib/src/source_range.rs +++ b/dmc-lib/src/source_range.rs @@ -1,3 +1,4 @@ +#[derive(Debug, Clone)] pub struct SourceRange { start: usize, end: usize, diff --git a/dmc-lib/src/symbol.rs b/dmc-lib/src/symbol.rs index 1943dcb..db2365f 100644 --- a/dmc-lib/src/symbol.rs +++ b/dmc-lib/src/symbol.rs @@ -1,4 +1,5 @@ use crate::type_info::TypeInfo; +use std::cell::RefCell; use std::rc::Rc; pub struct FunctionSymbol { @@ -34,6 +35,7 @@ impl FunctionSymbol { pub struct ParameterSymbol { name: Rc, type_info: TypeInfo, + stack_frame_offset: Option, } impl ParameterSymbol { @@ -41,6 +43,7 @@ impl ParameterSymbol { Self { name: name.into(), type_info, + stack_frame_offset: None, } } @@ -55,11 +58,20 @@ impl ParameterSymbol { pub fn type_info(&self) -> &TypeInfo { &self.type_info } + + pub fn set_stack_frame_offset(&mut self, offset: usize) { + self.stack_frame_offset = Some(offset); + } + + pub fn stack_frame_offset(&self) -> usize { + self.stack_frame_offset.unwrap() + } } pub struct VariableSymbol { name: Rc, type_info: TypeInfo, + register: Option, } impl VariableSymbol { @@ -67,6 +79,7 @@ impl VariableSymbol { Self { name: name.into(), type_info, + register: None, } } @@ -81,10 +94,18 @@ impl VariableSymbol { pub fn type_info(&self) -> &TypeInfo { &self.type_info } + + pub fn set_register(&mut self, register: usize) { + self.register = Some(register); + } + + pub fn register(&self) -> usize { + self.register.unwrap() + } } pub enum ExpressibleSymbol { Function(Rc), - Parameter(Rc), - Variable(Rc), + Parameter(Rc>), + Variable(Rc>), } diff --git a/dmc-lib/src/symbol_table.rs b/dmc-lib/src/symbol_table.rs index a50af89..62bdfc1 100644 --- a/dmc-lib/src/symbol_table.rs +++ b/dmc-lib/src/symbol_table.rs @@ -1,5 +1,6 @@ use crate::scope::Scope; use crate::symbol::{ExpressibleSymbol, FunctionSymbol, ParameterSymbol, VariableSymbol}; +use std::cell::RefCell; use std::rc::Rc; pub struct SymbolTable { @@ -71,9 +72,10 @@ impl SymbolTable { parameter_symbol.name(), ))); } - self.current_scope_mut() - .parameter_symbols_mut() - .insert(parameter_symbol.name_owned(), Rc::new(parameter_symbol)); + self.current_scope_mut().parameter_symbols_mut().insert( + parameter_symbol.name_owned(), + Rc::new(RefCell::new(parameter_symbol)), + ); Ok(()) } @@ -86,9 +88,10 @@ impl SymbolTable { variable_symbol.name(), ))); } - self.current_scope_mut() - .variable_symbols_mut() - .insert(variable_symbol.name_owned(), Rc::new(variable_symbol)); + self.current_scope_mut().variable_symbols_mut().insert( + variable_symbol.name_owned(), + Rc::new(RefCell::new(variable_symbol)), + ); Ok(()) } @@ -125,6 +128,11 @@ impl SymbolTable { } None } + + pub fn get_variable_symbol(&self, scope_id: usize, name: &str) -> Rc> { + let scope = self.scopes.get(scope_id).unwrap(); + scope.variable_symbols().get(name).unwrap().clone() + } } pub enum SymbolInsertError {