Complete sketch of interface between dmc-lib compile functions and other modules.

This commit is contained in:
Jesse Brault 2026-06-25 14:49:32 -05:00
parent 85e29367a8
commit 01df9a708f
6 changed files with 144 additions and 131 deletions

View File

@ -19,7 +19,7 @@ use dvm_lib::instruction::{
use std::collections::HashMap; use std::collections::HashMap;
struct FunctionAssemblyContext<'a> { struct FunctionAssemblyContext<'a> {
type_infos: &'a Vec<IrTypeInfo>, type_infos: &'a [IrTypeInfo],
variables_to_type_infos: &'a HashMap<IrVariableId, IrTypeInfoId>, variables_to_type_infos: &'a HashMap<IrVariableId, IrTypeInfoId>,
variable_locations: &'a VariableLocations, variable_locations: &'a VariableLocations,
parameters: &'a [IrParameter], parameters: &'a [IrParameter],
@ -29,7 +29,7 @@ struct FunctionAssemblyContext<'a> {
pub fn assemble_ir_function( pub fn assemble_ir_function(
ir_function: &IrFunction, ir_function: &IrFunction,
type_infos: &Vec<IrTypeInfo>, type_infos: &[IrTypeInfo],
variables_to_type_infos: &HashMap<IrVariableId, IrTypeInfoId>, variables_to_type_infos: &HashMap<IrVariableId, IrTypeInfoId>,
variable_locations: &VariableLocations, variable_locations: &VariableLocations,
constants_table: &mut ConstantsTable, constants_table: &mut ConstantsTable,

View File

@ -55,6 +55,7 @@ impl IrFunction {
self.return_type_info.as_ref() self.return_type_info.as_ref()
} }
#[deprecated]
pub fn assign_registers(&self, register_count: usize) -> VariableLocations { pub fn assign_registers(&self, register_count: usize) -> VariableLocations {
if self.blocks.is_empty() { if self.blocks.is_empty() {
return VariableLocations::new(HashMap::new(), HashMap::new()); return VariableLocations::new(HashMap::new(), HashMap::new());
@ -66,6 +67,7 @@ impl IrFunction {
block_assign_registers(block, register_count) block_assign_registers(block, register_count)
} }
#[deprecated]
pub fn assemble( pub fn assemble(
&self, &self,
type_infos: &Vec<IrTypeInfo>, type_infos: &Vec<IrTypeInfo>,

View File

@ -1,3 +1,13 @@
use crate::constants_table::ConstantsTable;
use crate::ir::assemble::assemble_ir_function;
use crate::ir::ir_function::IrFunction;
use crate::ir::ir_type_info::{IrTypeInfo, IrTypeInfoId};
use crate::ir::ir_variable::IrVariableId;
use crate::ir::register_allocation::block_assign_registers;
use crate::ir::variable_locations::VariableLocations;
use dvm_lib::vm::function::Function;
use std::collections::HashMap;
mod assemble; mod assemble;
mod debug_print; mod debug_print;
pub mod ir_allocate; pub mod ir_allocate;
@ -22,3 +32,36 @@ pub mod ir_variable;
mod register_allocation; mod register_allocation;
mod util; mod util;
mod variable_locations; mod variable_locations;
pub fn compile_dvm_function(
ir_function: &IrFunction,
ir_type_infos: &[IrTypeInfo],
ir_variables_to_ir_type_infos: &HashMap<IrVariableId, IrTypeInfoId>,
constants_table: &mut ConstantsTable,
) -> Function {
let variable_locations = assign_registers(ir_function);
let instructions = assemble_ir_function(
ir_function,
ir_type_infos,
ir_variables_to_ir_type_infos,
&variable_locations,
constants_table,
);
Function::new(
ir_function.fqn().into(),
ir_function.parameters().len(),
variable_locations.stack_size(),
instructions,
)
}
fn assign_registers(ir_function: &IrFunction) -> VariableLocations {
if ir_function.blocks().is_empty() {
return VariableLocations::new(HashMap::new(), HashMap::new());
}
if ir_function.blocks().len() > 1 {
unimplemented!("having more than one block in a function is not yet implemented.")
}
let block = &ir_function.blocks()[0];
block_assign_registers(block, 16) // TODO: make this configurable
}

View File

@ -1,3 +1,13 @@
use crate::constants_table::ConstantsTable;
use crate::diagnostic::Diagnostics;
use crate::ir::compile_dvm_function;
use crate::lowering::lower_to_ir;
use crate::parser::parse_compilation_unit;
use crate::semantic_analysis::analyze_compilation_unit;
use dvm_lib::vm::function::Function;
use std::collections::HashMap;
use std::rc::Rc;
pub mod ast; pub mod ast;
pub mod compile_pipeline; pub mod compile_pipeline;
pub mod constants_table; pub mod constants_table;
@ -19,3 +29,45 @@ pub mod token;
pub mod type_info; pub mod type_info;
pub mod types_table; pub mod types_table;
mod util; mod util;
pub type Filename = Rc<str>;
pub type FileId = usize;
pub struct CompileCompilationUnitResult {
pub functions: HashMap<Rc<str>, Function>,
}
pub fn compile_compilation_unit(
input: &str,
constants_table: &mut ConstantsTable,
) -> Result<CompileCompilationUnitResult, Diagnostics> {
let (compilation_unit, diagnostics) = parse_compilation_unit(input, None);
if !diagnostics.is_empty() {
return Err(diagnostics);
}
let (analysis_result, diagnostics) = analyze_compilation_unit(&compilation_unit);
if !diagnostics.is_empty() {
return Err(diagnostics);
}
let lower_to_ir_result = lower_to_ir(
&compilation_unit,
&analysis_result.symbols,
&analysis_result.nodes_to_symbols,
&analysis_result.type_infos,
&analysis_result.symbols_to_type_infos,
&analysis_result.nodes_to_type_infos,
);
let mut dvm_functions = HashMap::new();
for ir_function in &lower_to_ir_result.functions {
let dvm_function = compile_dvm_function(ir_function, todo!(), todo!(), constants_table);
dvm_functions.insert(dvm_function.name_owned(), dvm_function);
}
Ok(CompileCompilationUnitResult {
functions: dvm_functions,
})
}

View File

@ -1,13 +1,11 @@
use crate::ast::NodeId; use crate::ast::NodeId;
use crate::ast::compilation_unit::CompilationUnit; use crate::ast::compilation_unit::CompilationUnit;
use crate::compile_pipeline::FileId;
use crate::diagnostic::Diagnostics; use crate::diagnostic::Diagnostics;
use crate::semantic_analysis::collect_scopes::collect_scopes; use crate::semantic_analysis::collect_scopes::collect_scopes;
use crate::semantic_analysis::collect_symbols::collect_symbols; use crate::semantic_analysis::collect_symbols::collect_symbols;
use crate::semantic_analysis::collect_types::collect_types; use crate::semantic_analysis::collect_types::collect_types;
use crate::semantic_analysis::resolve_names::resolve_names; use crate::semantic_analysis::resolve_names::resolve_names;
use crate::semantic_analysis::resolve_types::resolve_types; use crate::semantic_analysis::resolve_types::resolve_types;
use crate::semantic_analysis::scope::{Scope, ScopeId};
use crate::semantic_analysis::symbol::{Symbol, SymbolId}; use crate::semantic_analysis::symbol::{Symbol, SymbolId};
use crate::semantic_analysis::type_info::{TypeInfo, TypeInfoId}; use crate::semantic_analysis::type_info::{TypeInfo, TypeInfoId};
use std::collections::HashMap; use std::collections::HashMap;
@ -24,89 +22,53 @@ pub mod symbol;
pub mod type_info; pub mod type_info;
pub struct AnalysisResult { pub struct AnalysisResult {
pub symbols: Vec<Symbol>,
pub nodes_to_symbols: HashMap<NodeId, SymbolId>,
pub type_infos: Vec<TypeInfo>, pub type_infos: Vec<TypeInfo>,
pub symbols_to_type_infos: HashMap<SymbolId, TypeInfoId>,
pub nodes_to_type_infos: HashMap<NodeId, TypeInfoId>, pub nodes_to_type_infos: HashMap<NodeId, TypeInfoId>,
} }
pub fn analyze( pub fn analyze_compilation_unit(
compilation_units: &HashMap<FileId, CompilationUnit>, compilation_unit: &CompilationUnit,
) -> HashMap<FileId, AnalysisResult> { ) -> (AnalysisResult, Diagnostics) {
let mut diagnostics = Diagnostics::new(); let mut diagnostics = Diagnostics::new();
let mut files_to_scopes: HashMap<FileId, Vec<Scope>> = HashMap::new(); let mut scopes_result = collect_scopes(compilation_unit);
let mut files_to_nodes_to_scopes: HashMap<FileId, HashMap<NodeId, ScopeId>> = HashMap::new();
for (file_id, compilation_unit) in compilation_units { let mut symbols_result = collect_symbols(
let result = collect_scopes(compilation_unit); compilation_unit,
files_to_scopes.insert(*file_id, result.scopes); &mut scopes_result.scopes,
files_to_nodes_to_scopes.insert(*file_id, result.nodes_to_scopes); &scopes_result.nodes_to_scopes,
} );
diagnostics.append(&mut symbols_result.diagnostics);
let mut files_to_symbols: HashMap<FileId, Vec<Symbol>> = HashMap::new(); let mut names_result = resolve_names(
compilation_unit,
&mut scopes_result.scopes,
&mut symbols_result.symbols,
&scopes_result.nodes_to_scopes,
);
diagnostics.append(&mut names_result.diagnostics);
for (file_id, compilation_unit) in compilation_units { let mut collect_types_result = collect_types(compilation_unit, &names_result.nodes_to_symbols);
let scopes = files_to_scopes.get_mut(file_id).unwrap();
let nodes_to_scopes = files_to_nodes_to_scopes.get(file_id).unwrap();
let mut result = collect_symbols(compilation_unit, scopes, nodes_to_scopes);
files_to_symbols.insert(*file_id, result.symbols);
diagnostics.append(&mut result.diagnostics);
}
let mut files_to_nodes_to_symbols: HashMap<FileId, HashMap<NodeId, SymbolId>> = HashMap::new(); let mut resolve_types_result = resolve_types(
compilation_unit,
&names_result.nodes_to_symbols,
&mut collect_types_result.type_infos,
&mut collect_types_result.symbols_to_type_infos,
);
diagnostics.append(&mut resolve_types_result.diagnostics);
for (file_id, compilation_unit) in compilation_units { (
let scopes = files_to_scopes.get_mut(file_id).unwrap(); AnalysisResult {
let symbols = files_to_symbols.get_mut(file_id).unwrap(); symbols: symbols_result.symbols,
let nodes_to_scopes = files_to_nodes_to_scopes.get(file_id).unwrap(); nodes_to_symbols: names_result.nodes_to_symbols,
type_infos: collect_types_result.type_infos,
let mut result = resolve_names(compilation_unit, scopes, symbols, nodes_to_scopes); symbols_to_type_infos: collect_types_result.symbols_to_type_infos,
nodes_to_type_infos: resolve_types_result.nodes_to_type_infos,
files_to_nodes_to_symbols.insert(*file_id, result.nodes_to_symbols); },
diagnostics.append(&mut result.diagnostics); diagnostics,
} )
let mut files_to_type_infos: HashMap<FileId, Vec<TypeInfo>> = HashMap::new();
let mut files_to_symbols_to_type_infos: HashMap<FileId, HashMap<SymbolId, TypeInfoId>> =
HashMap::new();
for (file_id, compilation_unit) in compilation_units {
let nodes_to_symbols = files_to_nodes_to_symbols.get(&file_id).unwrap();
let result = collect_types(compilation_unit, nodes_to_symbols);
files_to_type_infos.insert(*file_id, result.type_infos);
files_to_symbols_to_type_infos.insert(*file_id, result.symbols_to_type_infos);
}
let mut files_to_nodes_to_type_infos: HashMap<FileId, HashMap<NodeId, TypeInfoId>> =
HashMap::new();
for (file_id, compilation_unit) in compilation_units {
let nodes_to_symbols = files_to_nodes_to_symbols.get_mut(file_id).unwrap();
let type_infos = files_to_type_infos.get_mut(file_id).unwrap();
let symbols_to_type_infos = files_to_symbols_to_type_infos.get_mut(file_id).unwrap();
let mut result = resolve_types(
compilation_unit,
nodes_to_symbols,
type_infos,
symbols_to_type_infos,
);
files_to_nodes_to_type_infos.insert(*file_id, result.nodes_to_type_infos);
diagnostics.append(&mut result.diagnostics);
}
let mut files_to_results: HashMap<FileId, AnalysisResult> = HashMap::new();
for (file_id, _) in compilation_units {
let type_infos = files_to_type_infos.remove(file_id).unwrap();
let nodes_to_type_infos = files_to_nodes_to_type_infos.remove(file_id).unwrap();
let analysis_result = AnalysisResult {
type_infos,
nodes_to_type_infos,
};
files_to_results.insert(*file_id, analysis_result);
}
files_to_results
} }

View File

@ -1,20 +1,14 @@
#[cfg(test)] #[cfg(test)]
mod e2e_tests { mod e2e_tests {
use dmc_lib::compile_compilation_unit;
use dmc_lib::constants_table::ConstantsTable; use dmc_lib::constants_table::ConstantsTable;
use dmc_lib::diagnostic::Diagnostic; use dmc_lib::diagnostic::{Diagnostic, Diagnostics};
use dmc_lib::intrinsics::{insert_intrinsic_symbols, insert_intrinsic_types};
use dmc_lib::offset_counter::OffsetCounter;
use dmc_lib::parser::parse_compilation_unit;
use dmc_lib::symbol_table::SymbolTable;
use dmc_lib::types_table::TypesTable;
use dvm_lib::vm::class::Class;
use dvm_lib::vm::constant::{Constant, StringConstant}; use dvm_lib::vm::constant::{Constant, StringConstant};
use dvm_lib::vm::function::Function;
use dvm_lib::vm::value::Value; use dvm_lib::vm::value::Value;
use dvm_lib::vm::{DvmContext, call}; use dvm_lib::vm::{DvmContext, call};
use std::rc::Rc; use std::rc::Rc;
const REGISTER_COUNT: usize = 8; const REGISTER_COUNT: usize = 16;
fn report_diagnostics(diagnostics: &[Diagnostic]) -> ! { fn report_diagnostics(diagnostics: &[Diagnostic]) -> ! {
eprintln!( eprintln!(
@ -28,55 +22,15 @@ mod e2e_tests {
panic!("There were diagnostics."); panic!("There were diagnostics.");
} }
fn prepare_context(input: &str) -> Result<DvmContext, Vec<Diagnostic>> { fn prepare_context(input: &str) -> Result<DvmContext, Diagnostics> {
let (mut compilation_unit, diagnostics) = parse_compilation_unit(input, None);
if !diagnostics.is_empty() {
return Err(diagnostics);
}
let mut symbol_table = SymbolTable::new();
symbol_table.push_module_scope("global_scope");
insert_intrinsic_symbols(&mut symbol_table);
let mut types_table = TypesTable::new();
insert_intrinsic_types(&symbol_table, &mut types_table);
compilation_unit.init_scopes(&mut symbol_table);
compilation_unit.gather_symbols_into(&mut symbol_table)?;
compilation_unit.check_names(&mut symbol_table)?;
compilation_unit.gather_types_into(&symbol_table, &mut types_table)?;
compilation_unit.type_check(&symbol_table, &mut types_table)?;
let (ir_classes, mut ir_functions) = compilation_unit.to_ir(&symbol_table, &types_table);
let mut functions: Vec<Function> = vec![];
let mut constants_table = ConstantsTable::new(); let mut constants_table = ConstantsTable::new();
for ir_function in &mut ir_functions { let compile_compilation_unit_result = compile_compilation_unit(input, &mut constants_table);
let mut offset_counter = OffsetCounter::new();
ir_function.assign_registers(REGISTER_COUNT, &mut offset_counter);
let stack_size = offset_counter.get_count();
let function = ir_function.assemble(stack_size, &mut constants_table);
functions.push(function);
}
let mut classes: Vec<Class> = vec![];
for ir_class in &ir_classes {
classes.push(ir_class.to_vm_class());
}
let mut dvm_context = DvmContext::new(); let mut dvm_context = DvmContext::new();
for class in classes { for (name, function) in compile_compilation_unit_result?.functions {
dvm_context dvm_context.functions_mut().insert(name, function);
.classes_mut()
.insert(class.fqn().into(), Rc::new(class));
}
for function in functions {
dvm_context
.functions_mut()
.insert(function.name_owned(), function);
} }
for (name, content) in &constants_table.string_constants() { for (name, content) in &constants_table.string_constants() {