Compare commits
3 Commits
f15ff43df8
...
ed6f15a8a9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed6f15a8a9 | ||
|
|
9b2e952bf8 | ||
|
|
c69098db71 |
303
dm/src/repl.rs
303
dm/src/repl.rs
@ -1,17 +1,18 @@
|
|||||||
use dmc_lib::ast::ir_builder::IrBuilder;
|
use dmc_lib::ast::expression_statement::ExpressionStatement;
|
||||||
|
use dmc_lib::ast::statement::Statement;
|
||||||
|
use dmc_lib::compile_statement_to_synthetic_function;
|
||||||
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::ir::ir_function::IrFunction;
|
|
||||||
use dmc_lib::ir::ir_return::IrReturn;
|
|
||||||
use dmc_lib::ir::ir_statement::IrStatement;
|
|
||||||
use dmc_lib::ir::ir_variable::IrVariable;
|
use dmc_lib::ir::ir_variable::IrVariable;
|
||||||
|
use dmc_lib::ir::variable_locations::VariableLocations;
|
||||||
use dmc_lib::lexer::Lexer;
|
use dmc_lib::lexer::Lexer;
|
||||||
use dmc_lib::offset_counter::OffsetCounter;
|
use dmc_lib::offset_counter::OffsetCounter;
|
||||||
use dmc_lib::parser::{parse_expression, parse_let_statement};
|
use dmc_lib::parser::parse_expression;
|
||||||
|
use dmc_lib::semantic_analysis::AnalysisContext;
|
||||||
|
use dmc_lib::semantic_analysis::scope::ScopeId;
|
||||||
use dmc_lib::symbol::variable_symbol::VariableSymbol;
|
use dmc_lib::symbol::variable_symbol::VariableSymbol;
|
||||||
use dmc_lib::symbol_table::SymbolTable;
|
use dmc_lib::symbol_table::SymbolTable;
|
||||||
use dmc_lib::token::TokenKind;
|
use dmc_lib::token::TokenKind;
|
||||||
use dmc_lib::type_info::TypeInfo;
|
|
||||||
use dmc_lib::types_table::TypesTable;
|
use dmc_lib::types_table::TypesTable;
|
||||||
use dvm_lib::vm::constant::{Constant, StringConstant};
|
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||||
use dvm_lib::vm::function::Function;
|
use dvm_lib::vm::function::Function;
|
||||||
@ -174,62 +175,63 @@ fn compile_expression(
|
|||||||
offset_counter: &mut OffsetCounter,
|
offset_counter: &mut OffsetCounter,
|
||||||
constants_table: &mut ConstantsTable,
|
constants_table: &mut ConstantsTable,
|
||||||
) -> Result<Function, Vec<Diagnostic>> {
|
) -> Result<Function, Vec<Diagnostic>> {
|
||||||
// parse
|
// // parse
|
||||||
let (mut expression, parse_diagnostics) = parse_expression(input);
|
// let (mut expression, parse_diagnostics) = parse_expression(input);
|
||||||
if !parse_diagnostics.is_empty() {
|
// if !parse_diagnostics.is_empty() {
|
||||||
return Err(parse_diagnostics);
|
// return Err(parse_diagnostics);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// init scopes, if necessary
|
// // init scopes, if necessary
|
||||||
let container_scope = prepare_scopes(symbol_table, fn_body_scope_id);
|
// let container_scope = prepare_scopes(symbol_table, fn_body_scope_id);
|
||||||
|
//
|
||||||
// inner scopes
|
// // inner scopes
|
||||||
expression.init_scopes(symbol_table, container_scope);
|
// expression.init_scopes(symbol_table, container_scope);
|
||||||
|
//
|
||||||
// names
|
// // names
|
||||||
let diagnostics = expression.check_static_fn_local_names(&symbol_table);
|
// let diagnostics = expression.check_static_fn_local_names(&symbol_table);
|
||||||
if !diagnostics.is_empty() {
|
// if !diagnostics.is_empty() {
|
||||||
return Err(diagnostics);
|
// return Err(diagnostics);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// type check
|
// // type check
|
||||||
expression.type_check(&symbol_table, types_table)?;
|
// expression.type_check(&symbol_table, types_table)?;
|
||||||
|
//
|
||||||
// synthesize a function
|
// // synthesize a function
|
||||||
// init ir_builder
|
// // init ir_builder
|
||||||
let mut ir_builder = IrBuilder::new();
|
// let mut ir_builder = IrBuilder::new();
|
||||||
|
//
|
||||||
// copy all previous declared variables to here so we preserve their stack offsets
|
// // copy all previous declared variables to here so we preserve their stack offsets
|
||||||
for (key, value) in fn_local_variables {
|
// for (key, value) in fn_local_variables {
|
||||||
ir_builder
|
// ir_builder
|
||||||
.local_variables_mut()
|
// .local_variables_mut()
|
||||||
.insert(key.clone(), value.clone());
|
// .insert(key.clone(), value.clone());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
let entry_block_id = ir_builder.new_block();
|
// let entry_block_id = ir_builder.new_block();
|
||||||
|
//
|
||||||
let maybe_ir_expression =
|
// let maybe_ir_expression =
|
||||||
expression.to_ir_expression(&mut ir_builder, &symbol_table, &types_table);
|
// expression.to_ir_expression(&mut ir_builder, &symbol_table, &types_table);
|
||||||
|
//
|
||||||
// if Some, return the value
|
// // if Some, return the value
|
||||||
ir_builder
|
// ir_builder
|
||||||
.current_block_mut()
|
// .current_block_mut()
|
||||||
.add_statement(IrStatement::Return(IrReturn::new(maybe_ir_expression)));
|
// .add_statement(IrStatement::Return(IrReturn::new(maybe_ir_expression)));
|
||||||
|
//
|
||||||
ir_builder.finish_block();
|
// ir_builder.finish_block();
|
||||||
let entry_block = ir_builder.get_block(entry_block_id);
|
// let entry_block = ir_builder.get_block(entry_block_id);
|
||||||
|
//
|
||||||
let mut ir_function = IrFunction::new(
|
// let mut ir_function = IrFunction::new(
|
||||||
"__repl".into(),
|
// "__repl".into(),
|
||||||
vec![],
|
// vec![],
|
||||||
expression.type_info(&symbol_table, &types_table),
|
// expression.type_info(&symbol_table, &types_table),
|
||||||
entry_block.clone(),
|
// entry_block.clone(),
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
// spilled registers are put on the stack, so we need to add it to our stack size
|
// // spilled registers are put on the stack, so we need to add it to our stack size
|
||||||
ir_function.assign_registers(register_count, offset_counter);
|
// ir_function.assign_registers(register_count, offset_counter);
|
||||||
|
//
|
||||||
Ok(ir_function.assemble(offset_counter.get_count(), constants_table))
|
// Ok(ir_function.assemble(offset_counter.get_count(), constants_table))
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_let_statement(
|
fn compile_let_statement(
|
||||||
@ -242,63 +244,130 @@ fn compile_let_statement(
|
|||||||
types_table: &mut TypesTable,
|
types_table: &mut TypesTable,
|
||||||
constants_table: &mut ConstantsTable,
|
constants_table: &mut ConstantsTable,
|
||||||
) -> Result<Function, Vec<Diagnostic>> {
|
) -> Result<Function, Vec<Diagnostic>> {
|
||||||
// parse
|
// // parse
|
||||||
let (maybe_let_statement, parse_diagnostics) = parse_let_statement(input);
|
// let (maybe_let_statement, parse_diagnostics) = parse_let_statement(input);
|
||||||
|
// if !parse_diagnostics.is_empty() {
|
||||||
|
// return Err(parse_diagnostics);
|
||||||
|
// }
|
||||||
|
// let mut let_statement = maybe_let_statement.unwrap();
|
||||||
|
//
|
||||||
|
// // names
|
||||||
|
// let container_scope_id = prepare_scopes(symbol_table, body_scope_id);
|
||||||
|
//
|
||||||
|
// let_statement.init_scopes(symbol_table, container_scope_id);
|
||||||
|
//
|
||||||
|
// let name_diagnostics = let_statement.analyze_static_fn_local_names(symbol_table);
|
||||||
|
// if !name_diagnostics.is_empty() {
|
||||||
|
// return Err(name_diagnostics);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // types
|
||||||
|
// let_statement.type_check(&symbol_table, types_table)?;
|
||||||
|
//
|
||||||
|
// // init the ir builder
|
||||||
|
// let mut ir_builder = IrBuilder::new();
|
||||||
|
//
|
||||||
|
// // put previous locals in ir_builder so expressions can find them
|
||||||
|
// for (k, v) in local_variables.iter() {
|
||||||
|
// ir_builder
|
||||||
|
// .local_variables_mut()
|
||||||
|
// .insert(k.clone(), v.clone());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // ir function
|
||||||
|
// let entry_block_id = ir_builder.new_block();
|
||||||
|
//
|
||||||
|
// let destination_ir_variable = let_statement.to_repl_ir(
|
||||||
|
// &mut ir_builder,
|
||||||
|
// symbol_table,
|
||||||
|
// types_table,
|
||||||
|
// offset_counter.next() as isize,
|
||||||
|
// ); // put it on top
|
||||||
|
//
|
||||||
|
// // Now that we've translated to ir, we can add the new local variable in the IrBuilder to our
|
||||||
|
// // record of them to be used for next loop iteration.
|
||||||
|
// let variable_symbol = let_statement.get_destination_symbol(symbol_table);
|
||||||
|
// local_variables.insert(variable_symbol, destination_ir_variable);
|
||||||
|
//
|
||||||
|
// ir_builder.finish_block();
|
||||||
|
// let entry_block = ir_builder.get_block(entry_block_id);
|
||||||
|
// let mut ir_function = IrFunction::new(
|
||||||
|
// "__repl".into(),
|
||||||
|
// vec![],
|
||||||
|
// &TypeInfo::Void,
|
||||||
|
// entry_block.clone(),
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// // By here, the variables should all be assigned to their new or existing stack slots.
|
||||||
|
// // Register allocation should only be required for temp variables.
|
||||||
|
// ir_function.assign_registers(register_count, offset_counter);
|
||||||
|
//
|
||||||
|
// Ok(ir_function.assemble(offset_counter.get_count(), constants_table))
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn repl_2(read: &mut impl BufRead, register_count: usize) {
|
||||||
|
let mut buffer = String::new();
|
||||||
|
|
||||||
|
let mut analysis_context = AnalysisContext::new();
|
||||||
|
let mut function_scope_id: Option<ScopeId> = None;
|
||||||
|
let fqn: Rc<str> = Rc::from("repl");
|
||||||
|
let mut variable_locations = VariableLocations::new();
|
||||||
|
let mut constants_table = ConstantsTable::new();
|
||||||
|
|
||||||
|
let mut dvm_context = DvmContext::new();
|
||||||
|
let mut repl_fn_stack_locals: Vec<Operand> = Vec::new();
|
||||||
|
|
||||||
|
'repl: loop {
|
||||||
|
print!("> ");
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
read.read_line(&mut buffer).unwrap();
|
||||||
|
let input = buffer.trim();
|
||||||
|
if input.is_empty() {
|
||||||
|
buffer.clear();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut lexer = Lexer::new(input);
|
||||||
|
let first_token = match lexer.next() {
|
||||||
|
None => {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Some(result) => match result {
|
||||||
|
Ok(first_token) => first_token,
|
||||||
|
Err(lexer_error) => {
|
||||||
|
eprintln!("{:?}", lexer_error);
|
||||||
|
buffer.clear();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compile_expression_2(
|
||||||
|
input: &str,
|
||||||
|
analysis_context: &mut AnalysisContext,
|
||||||
|
function_scope_id: ScopeId,
|
||||||
|
fqn: &Rc<str>,
|
||||||
|
variable_locations: &mut VariableLocations,
|
||||||
|
register_count: usize,
|
||||||
|
constants_table: &mut ConstantsTable,
|
||||||
|
) -> Result<Function, Diagnostics> {
|
||||||
|
let (expression, parse_diagnostics) = parse_expression(input);
|
||||||
if !parse_diagnostics.is_empty() {
|
if !parse_diagnostics.is_empty() {
|
||||||
return Err(parse_diagnostics);
|
return Err(parse_diagnostics);
|
||||||
}
|
}
|
||||||
let mut let_statement = maybe_let_statement.unwrap();
|
|
||||||
|
|
||||||
// names
|
let statement = Statement::Expression(ExpressionStatement::new(0, expression));
|
||||||
let container_scope_id = prepare_scopes(symbol_table, body_scope_id);
|
|
||||||
|
|
||||||
let_statement.init_scopes(symbol_table, container_scope_id);
|
compile_statement_to_synthetic_function(
|
||||||
|
&statement,
|
||||||
let name_diagnostics = let_statement.analyze_static_fn_local_names(symbol_table);
|
analysis_context,
|
||||||
if !name_diagnostics.is_empty() {
|
function_scope_id,
|
||||||
return Err(name_diagnostics);
|
fqn.clone(),
|
||||||
}
|
variable_locations,
|
||||||
|
register_count,
|
||||||
// types
|
constants_table,
|
||||||
let_statement.type_check(&symbol_table, types_table)?;
|
)
|
||||||
|
|
||||||
// init the ir builder
|
|
||||||
let mut ir_builder = IrBuilder::new();
|
|
||||||
|
|
||||||
// put previous locals in ir_builder so expressions can find them
|
|
||||||
for (k, v) in local_variables.iter() {
|
|
||||||
ir_builder
|
|
||||||
.local_variables_mut()
|
|
||||||
.insert(k.clone(), v.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// ir function
|
|
||||||
let entry_block_id = ir_builder.new_block();
|
|
||||||
|
|
||||||
let destination_ir_variable = let_statement.to_repl_ir(
|
|
||||||
&mut ir_builder,
|
|
||||||
symbol_table,
|
|
||||||
types_table,
|
|
||||||
offset_counter.next() as isize,
|
|
||||||
); // put it on top
|
|
||||||
|
|
||||||
// Now that we've translated to ir, we can add the new local variable in the IrBuilder to our
|
|
||||||
// record of them to be used for next loop iteration.
|
|
||||||
let variable_symbol = let_statement.get_destination_symbol(symbol_table);
|
|
||||||
local_variables.insert(variable_symbol, destination_ir_variable);
|
|
||||||
|
|
||||||
ir_builder.finish_block();
|
|
||||||
let entry_block = ir_builder.get_block(entry_block_id);
|
|
||||||
let mut ir_function = IrFunction::new(
|
|
||||||
"__repl".into(),
|
|
||||||
vec![],
|
|
||||||
&TypeInfo::Void,
|
|
||||||
entry_block.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// By here, the variables should all be assigned to their new or existing stack slots.
|
|
||||||
// Register allocation should only be required for temp variables.
|
|
||||||
ir_function.assign_registers(register_count, offset_counter);
|
|
||||||
|
|
||||||
Ok(ir_function.assemble(offset_counter.get_count(), constants_table))
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,18 +3,13 @@ use codespan_reporting::files::SimpleFiles;
|
|||||||
use codespan_reporting::term;
|
use codespan_reporting::term;
|
||||||
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
|
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
|
||||||
use dm_std_lib::add_all_std_core;
|
use dm_std_lib::add_all_std_core;
|
||||||
|
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::semantic_analysis::AnalysisContext;
|
||||||
use dmc_lib::offset_counter::OffsetCounter;
|
|
||||||
use dmc_lib::parser::get_compilation_unit;
|
|
||||||
use dmc_lib::symbol_table::SymbolTable;
|
|
||||||
use dmc_lib::types_table::TypesTable;
|
|
||||||
use dvm_lib::vm::constant::{Constant, StringConstant};
|
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||||
use dvm_lib::vm::function::Function;
|
|
||||||
use dvm_lib::vm::{DvmContext, call};
|
use dvm_lib::vm::{DvmContext, call};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
pub fn compile_and_run_script(
|
pub fn compile_and_run_script(
|
||||||
script: &PathBuf,
|
script: &PathBuf,
|
||||||
@ -40,65 +35,23 @@ fn run(
|
|||||||
show_ir: bool,
|
show_ir: bool,
|
||||||
show_asm: bool,
|
show_asm: bool,
|
||||||
register_count: usize,
|
register_count: usize,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
) -> Result<(), Diagnostics> {
|
||||||
let mut compilation_unit = get_compilation_unit(&input, None)?;
|
let mut analysis_context = AnalysisContext::new();
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
if show_ir {
|
|
||||||
for ir_function in &ir_functions {
|
|
||||||
println!("{}", ir_function);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut functions: Vec<Function> = vec![];
|
|
||||||
let mut constants_table = ConstantsTable::new();
|
let mut constants_table = ConstantsTable::new();
|
||||||
|
let compile_compilation_unit_result = compile_compilation_unit(
|
||||||
for ir_function in &mut ir_functions {
|
input,
|
||||||
let mut offset_counter = OffsetCounter::new();
|
&mut analysis_context,
|
||||||
ir_function.assign_registers(register_count, &mut offset_counter);
|
register_count,
|
||||||
let function = ir_function.assemble(offset_counter.get_count(), &mut constants_table);
|
&mut constants_table,
|
||||||
functions.push(function);
|
)?;
|
||||||
}
|
|
||||||
|
|
||||||
let classes = ir_classes
|
|
||||||
.iter()
|
|
||||||
.map(|ir_class| ir_class.to_vm_class())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
if show_asm {
|
|
||||||
for function in &functions {
|
|
||||||
println!("{}", function);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut dvm_context = DvmContext::new();
|
let mut dvm_context = DvmContext::new();
|
||||||
|
|
||||||
// add std::core fns
|
// add std::core fns
|
||||||
add_all_std_core(&mut dvm_context);
|
add_all_std_core(&mut dvm_context);
|
||||||
|
|
||||||
for function in functions {
|
for (name, function) in compile_compilation_unit_result.functions {
|
||||||
dvm_context
|
dvm_context.functions_mut().insert(name, function);
|
||||||
.functions_mut()
|
|
||||||
.insert(function.name_owned(), function);
|
|
||||||
}
|
|
||||||
|
|
||||||
for class in classes {
|
|
||||||
dvm_context
|
|
||||||
.classes_mut()
|
|
||||||
.insert(class.fqn().into(), Rc::new(class));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, content) in &constants_table.string_constants() {
|
for (name, content) in &constants_table.string_constants() {
|
||||||
|
|||||||
@ -9,14 +9,13 @@ use crate::ir::ir_operation::IrOperation;
|
|||||||
use crate::ir::ir_parameter::IrParameter;
|
use crate::ir::ir_parameter::IrParameter;
|
||||||
use crate::ir::ir_return::IrReturn;
|
use crate::ir::ir_return::IrReturn;
|
||||||
use crate::ir::ir_statement::IrStatement;
|
use crate::ir::ir_statement::IrStatement;
|
||||||
use crate::ir::ir_type_info::{IrTypeInfo, IrTypeInfoId};
|
use crate::ir::ir_type_info::IrTypeInfo;
|
||||||
use crate::ir::ir_variable::{IrVariable, IrVariableId};
|
use crate::ir::ir_variable::IrVariable;
|
||||||
use crate::ir::variable_locations::{VariableLocation, VariableLocations};
|
use crate::ir::variable_locations::{VariableLocation, VariableLocations};
|
||||||
use dvm_lib::instruction::{
|
use dvm_lib::instruction::{
|
||||||
AddOperand, Instruction, Location, LocationOrInteger, LocationOrNumber, MoveOperand,
|
AddOperand, Instruction, Location, LocationOrInteger, LocationOrNumber, MoveOperand,
|
||||||
MultiplyOperand, PushOperand, ReturnOperand, SubtractOperand,
|
MultiplyOperand, PushOperand, ReturnOperand, SubtractOperand,
|
||||||
};
|
};
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
struct FunctionAssemblyContext<'a> {
|
struct FunctionAssemblyContext<'a> {
|
||||||
variable_locations: &'a VariableLocations,
|
variable_locations: &'a VariableLocations,
|
||||||
@ -73,9 +72,15 @@ fn assemble_ir_assign(ir_assign: &IrAssign, ctx: &mut FunctionAssemblyContext) {
|
|||||||
.get_variable_location(&ir_assign.destination()),
|
.get_variable_location(&ir_assign.destination()),
|
||||||
);
|
);
|
||||||
match ir_assign.initializer() {
|
match ir_assign.initializer() {
|
||||||
IrOperation::GetFieldRef(_) => {}
|
IrOperation::GetFieldRef(_) => {
|
||||||
IrOperation::GetFieldRefMut(_) => {}
|
todo!()
|
||||||
IrOperation::ReadField(_) => {}
|
}
|
||||||
|
IrOperation::GetFieldRefMut(_) => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
IrOperation::ReadField(_) => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
IrOperation::Load(ir_expression) => {
|
IrOperation::Load(ir_expression) => {
|
||||||
let move_operand = to_move_operand(ir_expression, ctx);
|
let move_operand = to_move_operand(ir_expression, ctx);
|
||||||
let instruction = Instruction::Move(move_operand, destination_location);
|
let instruction = Instruction::Move(move_operand, destination_location);
|
||||||
@ -137,8 +142,11 @@ fn assemble_ir_assign(ir_assign: &IrAssign, ctx: &mut FunctionAssemblyContext) {
|
|||||||
|
|
||||||
ctx.instructions.push(instruction);
|
ctx.instructions.push(instruction);
|
||||||
}
|
}
|
||||||
IrOperation::Call(_) => {
|
IrOperation::Call(ir_call) => {
|
||||||
todo!()
|
// pop top of stack after call into destination
|
||||||
|
assemble_ir_call(ir_call, ctx);
|
||||||
|
ctx.instructions
|
||||||
|
.push(Instruction::Pop(Some(destination_location)));
|
||||||
}
|
}
|
||||||
IrOperation::Allocate(_) => {
|
IrOperation::Allocate(_) => {
|
||||||
todo!()
|
todo!()
|
||||||
@ -235,6 +243,10 @@ fn to_add_operand(ir_expression: &IrExpression, ctx: &mut FunctionAssemblyContex
|
|||||||
IrTypeInfo::Int | IrTypeInfo::Double | IrTypeInfo::String => {
|
IrTypeInfo::Int | IrTypeInfo::Double | IrTypeInfo::String => {
|
||||||
AddOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
|
AddOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
|
||||||
}
|
}
|
||||||
|
_ => panic!(
|
||||||
|
"Attempt to add with non-integer type (found {})",
|
||||||
|
ir_parameter.type_info()
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IrExpression::Variable(ir_variable_id) => {
|
IrExpression::Variable(ir_variable_id) => {
|
||||||
@ -243,6 +255,10 @@ fn to_add_operand(ir_expression: &IrExpression, ctx: &mut FunctionAssemblyContex
|
|||||||
IrTypeInfo::Int | IrTypeInfo::Double | IrTypeInfo::String => AddOperand::Location(
|
IrTypeInfo::Int | IrTypeInfo::Double | IrTypeInfo::String => AddOperand::Location(
|
||||||
to_location(ctx.variable_locations.get_variable_location(ir_variable_id)),
|
to_location(ctx.variable_locations.get_variable_location(ir_variable_id)),
|
||||||
),
|
),
|
||||||
|
_ => panic!(
|
||||||
|
"Attempt to add with non-integer type (found {})",
|
||||||
|
ir_variable.type_info()
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IrExpression::Int(i) => AddOperand::Int(*i),
|
IrExpression::Int(i) => AddOperand::Int(*i),
|
||||||
|
|||||||
@ -57,7 +57,7 @@ impl IrFunction {
|
|||||||
#[deprecated]
|
#[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();
|
||||||
}
|
}
|
||||||
if self.blocks.len() > 1 {
|
if self.blocks.len() > 1 {
|
||||||
unimplemented!("having more than one block in a function is not yet implemented.")
|
unimplemented!("having more than one block in a function is not yet implemented.")
|
||||||
|
|||||||
@ -7,6 +7,7 @@ pub enum IrTypeInfo {
|
|||||||
String,
|
String,
|
||||||
Int,
|
Int,
|
||||||
Double,
|
Double,
|
||||||
|
Void,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for IrTypeInfo {
|
impl Display for IrTypeInfo {
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
use crate::constants_table::ConstantsTable;
|
use crate::constants_table::ConstantsTable;
|
||||||
use crate::ir::assemble::assemble_ir_function;
|
use crate::ir::assemble::assemble_ir_function;
|
||||||
use crate::ir::ir_function::IrFunction;
|
use crate::ir::ir_function::IrFunction;
|
||||||
use crate::ir::register_allocation::assign_registers;
|
use crate::ir::register_allocation::{AssignRegistersResult, assign_registers};
|
||||||
|
use crate::ir::variable_locations::VariableLocations;
|
||||||
use dvm_lib::vm::function::Function;
|
use dvm_lib::vm::function::Function;
|
||||||
|
|
||||||
mod assemble;
|
mod assemble;
|
||||||
@ -27,14 +28,24 @@ pub mod ir_type_info;
|
|||||||
pub mod ir_variable;
|
pub mod ir_variable;
|
||||||
mod register_allocation;
|
mod register_allocation;
|
||||||
mod util;
|
mod util;
|
||||||
mod variable_locations;
|
pub mod variable_locations;
|
||||||
|
|
||||||
pub fn compile_dvm_function(
|
pub fn compile_dvm_function(
|
||||||
ir_function: &IrFunction,
|
ir_function: &IrFunction,
|
||||||
register_count: usize,
|
register_count: usize,
|
||||||
|
variable_locations: &mut VariableLocations,
|
||||||
constants_table: &mut ConstantsTable,
|
constants_table: &mut ConstantsTable,
|
||||||
) -> Function {
|
) -> Function {
|
||||||
let variable_locations = assign_registers(ir_function, register_count);
|
let AssignRegistersResult {
|
||||||
|
register_variables,
|
||||||
|
spilled_variables,
|
||||||
|
} = assign_registers(ir_function, register_count);
|
||||||
|
|
||||||
|
variable_locations.push_all_register_variables(®ister_variables);
|
||||||
|
for spilled_variable in spilled_variables {
|
||||||
|
variable_locations.push_stack_variable(spilled_variable);
|
||||||
|
}
|
||||||
|
|
||||||
let instructions = assemble_ir_function(ir_function, &variable_locations, constants_table);
|
let instructions = assemble_ir_function(ir_function, &variable_locations, constants_table);
|
||||||
Function::new(
|
Function::new(
|
||||||
ir_function.fqn().into(),
|
ir_function.fqn().into(),
|
||||||
|
|||||||
@ -3,17 +3,24 @@
|
|||||||
use crate::ir::ir_block::IrBlock;
|
use crate::ir::ir_block::IrBlock;
|
||||||
use crate::ir::ir_function::IrFunction;
|
use crate::ir::ir_function::IrFunction;
|
||||||
use crate::ir::ir_variable::IrVariableId;
|
use crate::ir::ir_variable::IrVariableId;
|
||||||
use crate::ir::variable_locations::VariableLocations;
|
use dvm_lib::instruction::Register;
|
||||||
use dvm_lib::instruction::{Register, StackFrameOffset};
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
pub type RegisterAssignment = Register;
|
pub type RegisterAssignment = Register;
|
||||||
pub type InterferenceGraph = HashMap<IrVariableId, HashSet<IrVariableId>>;
|
pub type InterferenceGraph = HashMap<IrVariableId, HashSet<IrVariableId>>;
|
||||||
pub type LivenessSets = Vec<HashSet<IrVariableId>>;
|
pub type LivenessSets = Vec<HashSet<IrVariableId>>;
|
||||||
|
|
||||||
pub fn assign_registers(ir_function: &IrFunction, register_count: usize) -> VariableLocations {
|
pub struct AssignRegistersResult {
|
||||||
|
pub register_variables: HashMap<IrVariableId, RegisterAssignment>,
|
||||||
|
pub spilled_variables: HashSet<IrVariableId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn assign_registers(ir_function: &IrFunction, register_count: usize) -> AssignRegistersResult {
|
||||||
if ir_function.blocks().is_empty() {
|
if ir_function.blocks().is_empty() {
|
||||||
return VariableLocations::new(HashMap::new(), HashMap::new());
|
return AssignRegistersResult {
|
||||||
|
register_variables: HashMap::new(),
|
||||||
|
spilled_variables: HashSet::new(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if ir_function.blocks().len() > 1 {
|
if ir_function.blocks().len() > 1 {
|
||||||
unimplemented!("having more than one block in a function is not yet implemented.")
|
unimplemented!("having more than one block in a function is not yet implemented.")
|
||||||
@ -32,7 +39,7 @@ fn block_live_in_live_out(ir_block: &IrBlock) -> (LivenessSets, LivenessSets) {
|
|||||||
let mut did_work = false;
|
let mut did_work = false;
|
||||||
// Go backwards for efficiency
|
// Go backwards for efficiency
|
||||||
for (statement_index, ir_statement) in ir_block.statements().iter().enumerate().rev() {
|
for (statement_index, ir_statement) in ir_block.statements().iter().enumerate().rev() {
|
||||||
// out (union of successors ins)
|
// out (union of successors' ins)
|
||||||
// for now, a statement can only have one successor
|
// for now, a statement can only have one successor
|
||||||
// this will need to be updated when we add jumps
|
// this will need to be updated when we add jumps
|
||||||
let statement_live_out = &mut live_out[statement_index];
|
let statement_live_out = &mut live_out[statement_index];
|
||||||
@ -120,7 +127,7 @@ fn block_interference_graph(
|
|||||||
graph
|
graph
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_assign_registers(ir_block: &IrBlock, register_count: usize) -> VariableLocations {
|
fn block_assign_registers(ir_block: &IrBlock, register_count: usize) -> AssignRegistersResult {
|
||||||
let mut spilled: HashSet<IrVariableId> = HashSet::new();
|
let mut spilled: HashSet<IrVariableId> = HashSet::new();
|
||||||
loop {
|
loop {
|
||||||
let mut interference_graph = block_interference_graph(ir_block, &spilled);
|
let mut interference_graph = block_interference_graph(ir_block, &spilled);
|
||||||
@ -130,14 +137,10 @@ fn block_assign_registers(ir_block: &IrBlock, register_count: usize) -> Variable
|
|||||||
spilled.extend(new_spills);
|
spilled.extend(new_spills);
|
||||||
// check if added zero spills to get to fixed point
|
// check if added zero spills to get to fixed point
|
||||||
if old_n_spilled == spilled.len() {
|
if old_n_spilled == spilled.len() {
|
||||||
let mut spills_to_stack_offsets: HashMap<IrVariableId, StackFrameOffset> =
|
return AssignRegistersResult {
|
||||||
HashMap::new();
|
register_variables: registers,
|
||||||
let mut offset_counter = 0isize;
|
spilled_variables: spilled,
|
||||||
for spill in spilled {
|
};
|
||||||
spills_to_stack_offsets.insert(spill, offset_counter);
|
|
||||||
offset_counter += 1;
|
|
||||||
}
|
|
||||||
return VariableLocations::new(registers, spills_to_stack_offsets);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,7 +185,7 @@ fn registers_and_spills(
|
|||||||
assign_register(&work_item, &mut rebuilt_graph, k, &mut register_assignments);
|
assign_register(&work_item, &mut rebuilt_graph, k, &mut register_assignments);
|
||||||
} else {
|
} else {
|
||||||
// spill
|
// spill
|
||||||
spills.insert(work_item.vr.clone());
|
spills.insert(work_item.vr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,8 +323,9 @@ fn can_optimistically_color(
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::diagnostic::Diagnostics;
|
use crate::diagnostic::Diagnostics;
|
||||||
use crate::lowering::lower_to_ir;
|
use crate::lowering::lower_to_ir_compilation_unit;
|
||||||
use crate::parser::get_compilation_unit;
|
use crate::parser::get_compilation_unit;
|
||||||
|
use crate::semantic_analysis::AnalysisContext;
|
||||||
use crate::semantic_analysis::analyze_compilation_unit;
|
use crate::semantic_analysis::analyze_compilation_unit;
|
||||||
|
|
||||||
fn line_graph() -> InterferenceGraph {
|
fn line_graph() -> InterferenceGraph {
|
||||||
@ -452,23 +456,20 @@ mod tests {
|
|||||||
None,
|
None,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let (analysis_result, diagnostics) = analyze_compilation_unit(&compilation_unit);
|
let mut analysis_context = AnalysisContext::new();
|
||||||
|
let diagnostics = analyze_compilation_unit(&compilation_unit, &mut analysis_context);
|
||||||
assert!(diagnostics.is_empty());
|
assert!(diagnostics.is_empty());
|
||||||
|
|
||||||
let lower_result = lower_to_ir(
|
let lower_result = lower_to_ir_compilation_unit(&compilation_unit, &analysis_context);
|
||||||
&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,
|
|
||||||
); // todo: make this API friendlier
|
|
||||||
|
|
||||||
assert_eq!(lower_result.functions.len(), 1);
|
assert_eq!(lower_result.functions.len(), 1);
|
||||||
let main_fn = &lower_result.functions[0];
|
let main_fn = &lower_result.functions[0];
|
||||||
|
|
||||||
let variable_locations = assign_registers(main_fn, 2);
|
let AssignRegistersResult {
|
||||||
assert_eq!(variable_locations.register_variables_count(), 4);
|
register_variables,
|
||||||
|
spilled_variables: _,
|
||||||
|
} = assign_registers(main_fn, 2);
|
||||||
|
assert_eq!(register_variables.len(), 4);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,19 +12,25 @@ pub enum VariableLocation {
|
|||||||
pub struct VariableLocations {
|
pub struct VariableLocations {
|
||||||
register_variables: HashMap<IrVariableId, RegisterAssignment>,
|
register_variables: HashMap<IrVariableId, RegisterAssignment>,
|
||||||
stack_variables: HashMap<IrVariableId, StackVariableOffset>,
|
stack_variables: HashMap<IrVariableId, StackVariableOffset>,
|
||||||
|
next_stack_variable_offset: StackVariableOffset,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VariableLocations {
|
impl VariableLocations {
|
||||||
pub fn new(
|
pub fn new() -> Self {
|
||||||
register_variables: HashMap<IrVariableId, RegisterAssignment>,
|
|
||||||
stack_variables: HashMap<IrVariableId, StackVariableOffset>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
register_variables,
|
register_variables: HashMap::new(),
|
||||||
stack_variables,
|
stack_variables: HashMap::new(),
|
||||||
|
next_stack_variable_offset: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn push_all_register_variables(
|
||||||
|
&mut self,
|
||||||
|
register_variables: &HashMap<IrVariableId, RegisterAssignment>,
|
||||||
|
) {
|
||||||
|
self.register_variables.extend(register_variables);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_variable_location(&self, id: &IrVariableId) -> VariableLocation {
|
pub fn get_variable_location(&self, id: &IrVariableId) -> VariableLocation {
|
||||||
match self.register_variables.get(id) {
|
match self.register_variables.get(id) {
|
||||||
Some(register_assignment) => VariableLocation::Register(*register_assignment),
|
Some(register_assignment) => VariableLocation::Register(*register_assignment),
|
||||||
@ -39,4 +45,18 @@ impl VariableLocations {
|
|||||||
pub fn stack_variables_count(&self) -> usize {
|
pub fn stack_variables_count(&self) -> usize {
|
||||||
self.stack_variables.len()
|
self.stack_variables.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn extend(&mut self, other: &VariableLocations) {
|
||||||
|
// todo: add logic to transpose the `other`'s stack assignments on top of the current ones.
|
||||||
|
|
||||||
|
self.register_variables
|
||||||
|
.extend(other.register_variables.clone());
|
||||||
|
self.stack_variables.extend(other.stack_variables.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_stack_variable(&mut self, ir_variable_id: IrVariableId) {
|
||||||
|
self.stack_variables
|
||||||
|
.insert(ir_variable_id, self.next_stack_variable_offset);
|
||||||
|
self.next_stack_variable_offset += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,14 @@
|
|||||||
|
use crate::ast::statement::Statement;
|
||||||
use crate::constants_table::ConstantsTable;
|
use crate::constants_table::ConstantsTable;
|
||||||
use crate::diagnostic::Diagnostics;
|
use crate::diagnostic::Diagnostics;
|
||||||
use crate::ir::compile_dvm_function;
|
use crate::ir::compile_dvm_function;
|
||||||
use crate::lowering::lower_to_ir;
|
use crate::ir::variable_locations::VariableLocations;
|
||||||
|
use crate::lowering::{lower_to_ir_compilation_unit, lower_to_ir_synthetic_function};
|
||||||
use crate::parser::parse_compilation_unit;
|
use crate::parser::parse_compilation_unit;
|
||||||
use crate::semantic_analysis::analyze_compilation_unit;
|
use crate::semantic_analysis::scope::ScopeId;
|
||||||
|
use crate::semantic_analysis::{analyze_compilation_unit, analyze_statement};
|
||||||
use dvm_lib::vm::function::Function;
|
use dvm_lib::vm::function::Function;
|
||||||
|
use semantic_analysis::AnalysisContext;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@ -39,6 +43,7 @@ pub struct CompileCompilationUnitResult {
|
|||||||
|
|
||||||
pub fn compile_compilation_unit(
|
pub fn compile_compilation_unit(
|
||||||
input: &str,
|
input: &str,
|
||||||
|
analysis_context: &mut AnalysisContext,
|
||||||
register_count: usize,
|
register_count: usize,
|
||||||
constants_table: &mut ConstantsTable,
|
constants_table: &mut ConstantsTable,
|
||||||
) -> Result<CompileCompilationUnitResult, Diagnostics> {
|
) -> Result<CompileCompilationUnitResult, Diagnostics> {
|
||||||
@ -47,24 +52,22 @@ pub fn compile_compilation_unit(
|
|||||||
return Err(diagnostics);
|
return Err(diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (analysis_result, diagnostics) = analyze_compilation_unit(&compilation_unit);
|
let diagnostics = analyze_compilation_unit(&compilation_unit, analysis_context);
|
||||||
if !diagnostics.is_empty() {
|
if !diagnostics.is_empty() {
|
||||||
return Err(diagnostics);
|
return Err(diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
let lower_to_ir_result = lower_to_ir(
|
let lower_to_ir_result = lower_to_ir_compilation_unit(&compilation_unit, analysis_context);
|
||||||
&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();
|
let mut dvm_functions = HashMap::new();
|
||||||
|
|
||||||
for ir_function in &lower_to_ir_result.functions {
|
for ir_function in &lower_to_ir_result.functions {
|
||||||
let dvm_function = compile_dvm_function(ir_function, register_count, constants_table);
|
let dvm_function = compile_dvm_function(
|
||||||
|
ir_function,
|
||||||
|
register_count,
|
||||||
|
&mut VariableLocations::new(),
|
||||||
|
constants_table,
|
||||||
|
);
|
||||||
dvm_functions.insert(dvm_function.name_owned(), dvm_function);
|
dvm_functions.insert(dvm_function.name_owned(), dvm_function);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,3 +75,25 @@ pub fn compile_compilation_unit(
|
|||||||
functions: dvm_functions,
|
functions: dvm_functions,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn compile_statement_to_synthetic_function(
|
||||||
|
statement: &Statement,
|
||||||
|
analysis_context: &mut AnalysisContext,
|
||||||
|
function_scope_id: ScopeId,
|
||||||
|
fqn: Rc<str>,
|
||||||
|
variable_locations: &mut VariableLocations,
|
||||||
|
register_count: usize,
|
||||||
|
constants_table: &mut ConstantsTable,
|
||||||
|
) -> Result<Function, Diagnostics> {
|
||||||
|
let diagnostics = analyze_statement(statement, analysis_context, function_scope_id);
|
||||||
|
if !diagnostics.is_empty() {
|
||||||
|
return Err(diagnostics);
|
||||||
|
}
|
||||||
|
let ir_function = lower_to_ir_synthetic_function(statement, analysis_context, fqn);
|
||||||
|
Ok(compile_dvm_function(
|
||||||
|
&ir_function,
|
||||||
|
register_count,
|
||||||
|
variable_locations,
|
||||||
|
constants_table,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|||||||
@ -23,10 +23,12 @@ use crate::ir::ir_statement::IrStatement;
|
|||||||
use crate::ir::ir_type_info::IrTypeInfo;
|
use crate::ir::ir_type_info::IrTypeInfo;
|
||||||
use crate::ir::ir_variable::{IrVariable, IrVariableId};
|
use crate::ir::ir_variable::{IrVariable, IrVariableId};
|
||||||
use crate::lowering::util::{return_type_info_to_ir_type_info, to_ir_type_info};
|
use crate::lowering::util::{return_type_info_to_ir_type_info, to_ir_type_info};
|
||||||
|
use crate::semantic_analysis::AnalysisContext;
|
||||||
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;
|
||||||
use std::ops::Neg;
|
use std::ops::Neg;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct LowerToIrResult {
|
pub struct LowerToIrResult {
|
||||||
pub functions: Vec<IrFunction>,
|
pub functions: Vec<IrFunction>,
|
||||||
@ -41,20 +43,16 @@ struct LowerToIrContext<'a> {
|
|||||||
ir_functions: Vec<IrFunction>,
|
ir_functions: Vec<IrFunction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lower_to_ir(
|
pub fn lower_to_ir_compilation_unit(
|
||||||
compilation_unit: &CompilationUnit,
|
compilation_unit: &CompilationUnit,
|
||||||
symbols: &[Symbol],
|
analysis_context: &AnalysisContext,
|
||||||
nodes_to_symbols: &HashMap<NodeId, SymbolId>,
|
|
||||||
type_infos: &[TypeInfo],
|
|
||||||
symbols_to_type_infos: &HashMap<SymbolId, TypeInfoId>,
|
|
||||||
nodes_to_type_infos: &HashMap<NodeId, TypeInfoId>,
|
|
||||||
) -> LowerToIrResult {
|
) -> LowerToIrResult {
|
||||||
let mut ctx = LowerToIrContext {
|
let mut ctx = LowerToIrContext {
|
||||||
symbols,
|
symbols: analysis_context.symbols(),
|
||||||
nodes_to_symbols,
|
nodes_to_symbols: analysis_context.nodes_to_symbols(),
|
||||||
type_infos,
|
type_infos: analysis_context.type_infos(),
|
||||||
symbols_to_type_infos,
|
symbols_to_type_infos: analysis_context.symbols_to_type_infos(),
|
||||||
nodes_to_type_infos,
|
nodes_to_type_infos: analysis_context.nodes_to_type_infos(),
|
||||||
ir_functions: Vec::new(),
|
ir_functions: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -67,6 +65,45 @@ pub fn lower_to_ir(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn lower_to_ir_synthetic_function(
|
||||||
|
statement: &Statement,
|
||||||
|
analysis_ctx: &AnalysisContext,
|
||||||
|
fqn: Rc<str>,
|
||||||
|
) -> IrFunction {
|
||||||
|
let mut ctx = LowerToIrContext {
|
||||||
|
symbols: analysis_ctx.symbols(),
|
||||||
|
nodes_to_symbols: analysis_ctx.nodes_to_symbols(),
|
||||||
|
type_infos: analysis_ctx.type_infos(),
|
||||||
|
symbols_to_type_infos: analysis_ctx.symbols_to_type_infos(),
|
||||||
|
nodes_to_type_infos: analysis_ctx.nodes_to_type_infos(),
|
||||||
|
ir_functions: Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut fn_ctx = LowerToIrFunctionContext::new();
|
||||||
|
|
||||||
|
lower_to_ir_statement(statement, &mut ctx, &mut fn_ctx, true);
|
||||||
|
fn_ctx.finish_block();
|
||||||
|
|
||||||
|
// infer return type from statement
|
||||||
|
let maybe_return_ir_type_info = match statement {
|
||||||
|
Statement::Let(_) | Statement::Assign(_) => None,
|
||||||
|
Statement::Expression(expression_statement) => {
|
||||||
|
let type_info_id =
|
||||||
|
ctx.nodes_to_type_infos[&expression_statement.expression().node_id()];
|
||||||
|
let type_info = &ctx.type_infos[type_info_id];
|
||||||
|
return_type_info_to_ir_type_info(type_info)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
IrFunction::new(
|
||||||
|
fqn,
|
||||||
|
fn_ctx.ir_parameters,
|
||||||
|
fn_ctx.ir_variables,
|
||||||
|
maybe_return_ir_type_info,
|
||||||
|
fn_ctx.blocks,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
struct LowerToIrFunctionContext {
|
struct LowerToIrFunctionContext {
|
||||||
blocks: Vec<IrBlock>,
|
blocks: Vec<IrBlock>,
|
||||||
ir_variables: Vec<IrVariable>,
|
ir_variables: Vec<IrVariable>,
|
||||||
@ -145,26 +182,30 @@ fn lower_to_ir_function(function: &Function, ctx: &mut LowerToIrContext) {
|
|||||||
|
|
||||||
lower_to_ir_parameters(function, ctx, &mut fn_ctx);
|
lower_to_ir_parameters(function, ctx, &mut fn_ctx);
|
||||||
|
|
||||||
let n_statements = function.statements().len();
|
// get various function info
|
||||||
for (i, statement) in function.statements().iter().enumerate() {
|
|
||||||
let can_return_value = i == n_statements - 1;
|
|
||||||
lower_to_ir_statement(statement, ctx, &mut fn_ctx, can_return_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn_ctx.finish_block();
|
|
||||||
|
|
||||||
let function_symbol_id = ctx.nodes_to_symbols[&function.node_id()];
|
let function_symbol_id = ctx.nodes_to_symbols[&function.node_id()];
|
||||||
let function_symbol = match &ctx.symbols[function_symbol_id] {
|
let function_symbol = match &ctx.symbols[function_symbol_id] {
|
||||||
Symbol::Function(function_symbol) => function_symbol,
|
Symbol::Function(function_symbol) => function_symbol,
|
||||||
_ => panic!("Expected function symbol"),
|
_ => panic!("Expected FunctionSymbol"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let function_type_info_id = ctx.symbols_to_type_infos[&function_symbol_id];
|
let function_type_info_id = ctx.symbols_to_type_infos[&function_symbol_id];
|
||||||
let function_type_info = match &ctx.type_infos[function_type_info_id] {
|
let function_type_info = match &ctx.type_infos[function_type_info_id] {
|
||||||
TypeInfo::Function(function_type_info) => function_type_info,
|
TypeInfo::Function(function_type_info) => function_type_info,
|
||||||
_ => panic!("Expected FunctionTypeInfo"),
|
_ => panic!("Expected FunctionTypeInfo"),
|
||||||
};
|
};
|
||||||
let return_type_info = &ctx.type_infos[function_type_info.return_type_id()];
|
let return_type_info = &ctx.type_infos[function_type_info.return_type_id()];
|
||||||
|
let is_void_function = match return_type_info {
|
||||||
|
TypeInfo::Void => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// lower function body
|
||||||
|
let n_statements = function.statements().len();
|
||||||
|
for (i, statement) in function.statements().iter().enumerate() {
|
||||||
|
let can_return_value = i == n_statements - 1 && !is_void_function;
|
||||||
|
lower_to_ir_statement(statement, ctx, &mut fn_ctx, can_return_value);
|
||||||
|
}
|
||||||
|
fn_ctx.finish_block();
|
||||||
|
|
||||||
let ir_function = IrFunction::new(
|
let ir_function = IrFunction::new(
|
||||||
function_symbol.fqn_owned(),
|
function_symbol.fqn_owned(),
|
||||||
@ -265,10 +306,8 @@ fn lower_to_ir_expression_statement(
|
|||||||
let ir_statement = IrStatement::Return(IrReturn::new(Some(ir_expression)));
|
let ir_statement = IrStatement::Return(IrReturn::new(Some(ir_expression)));
|
||||||
fn_ctx.current_block_statements.push(ir_statement);
|
fn_ctx.current_block_statements.push(ir_statement);
|
||||||
} else {
|
} else {
|
||||||
// we could try to filter out useless code, but it's not guaranteed that there aren't
|
// This block executes when the expression has side effects. For now, we just throw the
|
||||||
// intended side effects from the lowering, so, for now, let's throw the result in a t_var.
|
// result away in a temporary variable.
|
||||||
// in the future we may want to somehow enforce with the type system a way that we can't
|
|
||||||
// create useless, dead ir code
|
|
||||||
let ir_operation =
|
let ir_operation =
|
||||||
lower_expression_to_ir_operation(expression_statement.expression(), ctx, fn_ctx);
|
lower_expression_to_ir_operation(expression_statement.expression(), ctx, fn_ctx);
|
||||||
|
|
||||||
|
|||||||
@ -6,8 +6,9 @@ pub fn to_ir_type_info(sa_type_info: &TypeInfo) -> IrTypeInfo {
|
|||||||
TypeInfo::String => IrTypeInfo::String,
|
TypeInfo::String => IrTypeInfo::String,
|
||||||
TypeInfo::Int => IrTypeInfo::Int,
|
TypeInfo::Int => IrTypeInfo::Int,
|
||||||
TypeInfo::Double => IrTypeInfo::Double,
|
TypeInfo::Double => IrTypeInfo::Double,
|
||||||
|
TypeInfo::Void => IrTypeInfo::Void,
|
||||||
_ => {
|
_ => {
|
||||||
panic!()
|
panic!("BUG! Unknown sa_type_info: {}", sa_type_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,34 +14,37 @@ use crate::ast::statement::Statement;
|
|||||||
use crate::semantic_analysis::scope::{Scope, ScopeId};
|
use crate::semantic_analysis::scope::{Scope, ScopeId};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct ScopeCollectionResult {
|
struct ScopeCollectionContext<'a> {
|
||||||
pub scopes: Vec<Scope>,
|
scopes: &'a mut Vec<Scope>,
|
||||||
pub nodes_to_scopes: HashMap<NodeId, ScopeId>,
|
nodes_to_scopes: &'a mut HashMap<NodeId, ScopeId>,
|
||||||
}
|
|
||||||
|
|
||||||
struct ScopeCollectionContext {
|
|
||||||
scopes: Vec<Scope>,
|
|
||||||
current_scope_id: Option<ScopeId>,
|
current_scope_id: Option<ScopeId>,
|
||||||
nodes_to_scopes: HashMap<NodeId, ScopeId>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScopeCollectionContext {
|
impl<'a> ScopeCollectionContext<'a> {
|
||||||
pub fn new() -> Self {
|
pub fn new(
|
||||||
|
scopes: &'a mut Vec<Scope>,
|
||||||
|
nodes_to_scopes: &'a mut HashMap<NodeId, ScopeId>,
|
||||||
|
current_scope_id: ScopeId,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
scopes: Vec::new(),
|
scopes,
|
||||||
current_scope_id: None,
|
nodes_to_scopes,
|
||||||
nodes_to_scopes: HashMap::new(),
|
current_scope_id: Some(current_scope_id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_scope(&mut self, scope: Scope) -> ScopeId {
|
pub fn down_scope(&mut self) -> ScopeId {
|
||||||
|
let scope = Scope::new(self.current_scope_id); // current is parent before push
|
||||||
self.scopes.push(scope);
|
self.scopes.push(scope);
|
||||||
self.current_scope_id = Some(self.scopes.len() - 1);
|
self.current_scope_id = Some(self.scopes.len() - 1);
|
||||||
self.current_scope_id.unwrap() // guaranteed because we just set it
|
self.current_scope_id.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pop_scope(&mut self) {
|
pub fn up_scope(&mut self) {
|
||||||
self.current_scope_id = self.scopes[self.current_scope_id.unwrap()].parent_id();
|
let current_scope_id = self
|
||||||
|
.current_scope_id
|
||||||
|
.expect("Cannot up_scope() when there is no current_scope");
|
||||||
|
self.current_scope_id = self.scopes[current_scope_id].parent_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn current_scope_id(&self) -> Option<ScopeId> {
|
pub fn current_scope_id(&self) -> Option<ScopeId> {
|
||||||
@ -53,20 +56,35 @@ impl ScopeCollectionContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect_scopes(compilation_unit: &CompilationUnit) -> ScopeCollectionResult {
|
/// N.b.: the parent_scope_id refers to the **parent** of the compilation unit scope, and must
|
||||||
let mut ctx = ScopeCollectionContext::new();
|
/// be a valid (non-panicking) index of `scopes`.
|
||||||
ctx.push_scope(Scope::new(None));
|
pub fn collect_scopes_in_compilation_unit(
|
||||||
|
compilation_unit: &CompilationUnit,
|
||||||
|
scopes: &mut Vec<Scope>,
|
||||||
|
nodes_to_scopes: &mut HashMap<NodeId, ScopeId>,
|
||||||
|
parent_scope_id: ScopeId,
|
||||||
|
) {
|
||||||
|
let mut ctx = ScopeCollectionContext::new(scopes, nodes_to_scopes, parent_scope_id);
|
||||||
|
ctx.down_scope(); // compilation unit scope
|
||||||
for function in compilation_unit.functions() {
|
for function in compilation_unit.functions() {
|
||||||
collect_scopes_function(function, &mut ctx);
|
collect_scopes_function(function, &mut ctx);
|
||||||
}
|
}
|
||||||
for extern_function in compilation_unit.extern_functions() {
|
for extern_function in compilation_unit.extern_functions() {
|
||||||
collect_scopes_extern_function(extern_function, &mut ctx);
|
collect_scopes_extern_function(extern_function, &mut ctx);
|
||||||
}
|
}
|
||||||
ctx.pop_scope();
|
ctx.up_scope(); // compilation unit scope
|
||||||
ScopeCollectionResult {
|
}
|
||||||
scopes: ctx.scopes,
|
|
||||||
nodes_to_scopes: ctx.nodes_to_scopes,
|
/// N.b. the parent_scope_id refers to the scope of the statement and must be a valid
|
||||||
}
|
/// (non-panicking) index of `scopes`.
|
||||||
|
pub fn collect_scopes_in_statement(
|
||||||
|
statement: &Statement,
|
||||||
|
scopes: &mut Vec<Scope>,
|
||||||
|
nodes_to_scopes: &mut HashMap<NodeId, ScopeId>,
|
||||||
|
parent_scope_id: ScopeId,
|
||||||
|
) {
|
||||||
|
let mut ctx = ScopeCollectionContext::new(scopes, nodes_to_scopes, parent_scope_id);
|
||||||
|
collect_scopes_statement(statement, &mut ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_scopes_function(function: &Function, ctx: &mut ScopeCollectionContext) {
|
fn collect_scopes_function(function: &Function, ctx: &mut ScopeCollectionContext) {
|
||||||
@ -78,8 +96,7 @@ fn collect_scopes_function(function: &Function, ctx: &mut ScopeCollectionContext
|
|||||||
.insert(function.node_id(), containing_scope_id);
|
.insert(function.node_id(), containing_scope_id);
|
||||||
|
|
||||||
// push function scope
|
// push function scope
|
||||||
let function_scope = Scope::new(Some(containing_scope_id));
|
let function_scope_id = ctx.down_scope();
|
||||||
let function_scope_id = ctx.push_scope(function_scope);
|
|
||||||
|
|
||||||
// save return-type and parameters' scope id
|
// save return-type and parameters' scope id
|
||||||
for parameter in function.parameters() {
|
for parameter in function.parameters() {
|
||||||
@ -97,15 +114,14 @@ fn collect_scopes_function(function: &Function, ctx: &mut ScopeCollectionContext
|
|||||||
}
|
}
|
||||||
|
|
||||||
// push block scope for body
|
// push block scope for body
|
||||||
let block_scope = Scope::new(Some(function_scope_id));
|
ctx.down_scope();
|
||||||
ctx.push_scope(block_scope);
|
|
||||||
|
|
||||||
for statement in function.statements() {
|
for statement in function.statements() {
|
||||||
collect_scopes_statement(statement, ctx);
|
collect_scopes_statement(statement, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.pop_scope(); // block
|
ctx.up_scope(); // block
|
||||||
ctx.pop_scope(); // function
|
ctx.up_scope(); // function
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_scopes_extern_function(
|
fn collect_scopes_extern_function(
|
||||||
@ -117,8 +133,7 @@ fn collect_scopes_extern_function(
|
|||||||
ctx.nodes_to_scopes_mut()
|
ctx.nodes_to_scopes_mut()
|
||||||
.insert(extern_function.node_id(), containing_scope_id);
|
.insert(extern_function.node_id(), containing_scope_id);
|
||||||
|
|
||||||
let function_scope = Scope::new(Some(containing_scope_id));
|
let function_scope_id = ctx.down_scope();
|
||||||
let function_scope_id = ctx.push_scope(function_scope);
|
|
||||||
|
|
||||||
for parameter in extern_function.parameters() {
|
for parameter in extern_function.parameters() {
|
||||||
ctx.nodes_to_scopes_mut()
|
ctx.nodes_to_scopes_mut()
|
||||||
@ -127,7 +142,7 @@ fn collect_scopes_extern_function(
|
|||||||
ctx.nodes_to_scopes_mut()
|
ctx.nodes_to_scopes_mut()
|
||||||
.insert(extern_function.return_type().node_id(), function_scope_id);
|
.insert(extern_function.return_type().node_id(), function_scope_id);
|
||||||
|
|
||||||
ctx.pop_scope();
|
ctx.up_scope();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_scopes_statement(statement: &Statement, ctx: &mut ScopeCollectionContext) {
|
fn collect_scopes_statement(statement: &Statement, ctx: &mut ScopeCollectionContext) {
|
||||||
|
|||||||
@ -3,6 +3,7 @@ use crate::ast::compilation_unit::CompilationUnit;
|
|||||||
use crate::ast::extern_function::ExternFunction;
|
use crate::ast::extern_function::ExternFunction;
|
||||||
use crate::ast::function::Function;
|
use crate::ast::function::Function;
|
||||||
use crate::ast::parameter::Parameter;
|
use crate::ast::parameter::Parameter;
|
||||||
|
use crate::ast::statement::Statement;
|
||||||
use crate::diagnostic::Diagnostics;
|
use crate::diagnostic::Diagnostics;
|
||||||
use crate::semantic_analysis::diagnostic_helpers::symbol_already_declared;
|
use crate::semantic_analysis::diagnostic_helpers::symbol_already_declared;
|
||||||
use crate::semantic_analysis::scope::{Scope, ScopeId};
|
use crate::semantic_analysis::scope::{Scope, ScopeId};
|
||||||
@ -10,26 +11,27 @@ use crate::semantic_analysis::symbol::{FunctionSymbol, ParameterSymbol, Symbol};
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct SymbolCollectionResult {
|
pub struct SymbolCollectionResult(pub Diagnostics);
|
||||||
pub symbols: Vec<Symbol>,
|
|
||||||
pub diagnostics: Diagnostics,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SymbolCollectionContext<'a> {
|
struct SymbolCollectionContext<'a> {
|
||||||
scopes: &'a mut Vec<Scope>,
|
scopes: &'a mut Vec<Scope>,
|
||||||
nodes_to_scopes: &'a HashMap<NodeId, ScopeId>,
|
nodes_to_scopes: &'a HashMap<NodeId, ScopeId>,
|
||||||
|
symbols: &'a mut Vec<Symbol>,
|
||||||
fqn_context: Vec<Rc<str>>,
|
fqn_context: Vec<Rc<str>>,
|
||||||
symbols: Vec<Symbol>,
|
|
||||||
diagnostics: Diagnostics,
|
diagnostics: Diagnostics,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SymbolCollectionContext<'a> {
|
impl<'a> SymbolCollectionContext<'a> {
|
||||||
pub fn new(scopes: &'a mut Vec<Scope>, nodes_to_scopes: &'a HashMap<NodeId, ScopeId>) -> Self {
|
pub fn new(
|
||||||
|
scopes: &'a mut Vec<Scope>,
|
||||||
|
nodes_to_scopes: &'a HashMap<NodeId, ScopeId>,
|
||||||
|
symbols: &'a mut Vec<Symbol>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
scopes,
|
scopes,
|
||||||
nodes_to_scopes,
|
nodes_to_scopes,
|
||||||
|
symbols,
|
||||||
fqn_context: Vec::new(),
|
fqn_context: Vec::new(),
|
||||||
symbols: Vec::new(),
|
|
||||||
diagnostics: Diagnostics::new(),
|
diagnostics: Diagnostics::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,12 +81,13 @@ impl<'a> SymbolCollectionContext<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect_symbols(
|
pub fn collect_symbols_in_compilation_unit(
|
||||||
compilation_unit: &CompilationUnit,
|
compilation_unit: &CompilationUnit,
|
||||||
scopes: &mut Vec<Scope>,
|
scopes: &mut Vec<Scope>,
|
||||||
nodes_to_scopes: &HashMap<NodeId, ScopeId>,
|
nodes_to_scopes: &HashMap<NodeId, ScopeId>,
|
||||||
|
symbols: &mut Vec<Symbol>,
|
||||||
) -> SymbolCollectionResult {
|
) -> SymbolCollectionResult {
|
||||||
let mut ctx = SymbolCollectionContext::new(scopes, nodes_to_scopes);
|
let mut ctx = SymbolCollectionContext::new(scopes, nodes_to_scopes, symbols);
|
||||||
|
|
||||||
for function in compilation_unit.functions() {
|
for function in compilation_unit.functions() {
|
||||||
collect_symbols_function(function, &mut ctx);
|
collect_symbols_function(function, &mut ctx);
|
||||||
@ -94,10 +97,7 @@ pub fn collect_symbols(
|
|||||||
collect_symbols_extern_function(extern_function, &mut ctx);
|
collect_symbols_extern_function(extern_function, &mut ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolCollectionResult {
|
SymbolCollectionResult(ctx.diagnostics)
|
||||||
symbols: ctx.symbols,
|
|
||||||
diagnostics: ctx.diagnostics,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_symbols_function(function: &Function, ctx: &mut SymbolCollectionContext) {
|
fn collect_symbols_function(function: &Function, ctx: &mut SymbolCollectionContext) {
|
||||||
|
|||||||
@ -7,23 +7,22 @@ use crate::semantic_analysis::symbol::SymbolId;
|
|||||||
use crate::semantic_analysis::type_info::{FunctionTypeInfo, TypeInfo, TypeInfoId};
|
use crate::semantic_analysis::type_info::{FunctionTypeInfo, TypeInfo, TypeInfoId};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct CollectTypesResult {
|
|
||||||
pub type_infos: Vec<TypeInfo>,
|
|
||||||
pub symbols_to_type_infos: HashMap<SymbolId, TypeInfoId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CollectTypesContext<'a> {
|
struct CollectTypesContext<'a> {
|
||||||
nodes_to_symbols: &'a HashMap<NodeId, SymbolId>,
|
nodes_to_symbols: &'a HashMap<NodeId, SymbolId>,
|
||||||
type_infos: Vec<TypeInfo>,
|
type_infos: &'a mut Vec<TypeInfo>,
|
||||||
symbols_to_type_infos: HashMap<SymbolId, TypeInfoId>,
|
symbols_to_type_infos: &'a mut HashMap<SymbolId, TypeInfoId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CollectTypesContext<'a> {
|
impl<'a> CollectTypesContext<'a> {
|
||||||
pub fn new(nodes_to_symbols: &'a HashMap<NodeId, SymbolId>) -> Self {
|
pub fn new(
|
||||||
|
nodes_to_symbols: &'a HashMap<NodeId, SymbolId>,
|
||||||
|
type_infos: &'a mut Vec<TypeInfo>,
|
||||||
|
symbols_to_type_infos: &'a mut HashMap<SymbolId, TypeInfoId>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
nodes_to_symbols,
|
nodes_to_symbols,
|
||||||
type_infos: Vec::new(),
|
type_infos,
|
||||||
symbols_to_type_infos: HashMap::new(),
|
symbols_to_type_infos,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,8 +35,10 @@ impl<'a> CollectTypesContext<'a> {
|
|||||||
pub fn collect_types(
|
pub fn collect_types(
|
||||||
compilation_unit: &CompilationUnit,
|
compilation_unit: &CompilationUnit,
|
||||||
nodes_to_symbols: &HashMap<NodeId, SymbolId>,
|
nodes_to_symbols: &HashMap<NodeId, SymbolId>,
|
||||||
) -> CollectTypesResult {
|
type_infos: &mut Vec<TypeInfo>,
|
||||||
let mut ctx = CollectTypesContext::new(nodes_to_symbols);
|
symbols_to_type_infos: &mut HashMap<SymbolId, TypeInfoId>,
|
||||||
|
) {
|
||||||
|
let mut ctx = CollectTypesContext::new(nodes_to_symbols, type_infos, symbols_to_type_infos);
|
||||||
for function in compilation_unit.functions() {
|
for function in compilation_unit.functions() {
|
||||||
collect_types_function(function, &mut ctx);
|
collect_types_function(function, &mut ctx);
|
||||||
}
|
}
|
||||||
@ -45,11 +46,6 @@ pub fn collect_types(
|
|||||||
for extern_function in compilation_unit.extern_functions() {
|
for extern_function in compilation_unit.extern_functions() {
|
||||||
collect_types_extern_function(extern_function, &mut ctx);
|
collect_types_extern_function(extern_function, &mut ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
CollectTypesResult {
|
|
||||||
type_infos: ctx.type_infos,
|
|
||||||
symbols_to_type_infos: ctx.symbols_to_type_infos,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_types_function(function: &Function, ctx: &mut CollectTypesContext) {
|
fn collect_types_function(function: &Function, ctx: &mut CollectTypesContext) {
|
||||||
|
|||||||
@ -1,11 +1,21 @@
|
|||||||
use crate::ast::NodeId;
|
use crate::ast::NodeId;
|
||||||
use crate::ast::compilation_unit::CompilationUnit;
|
use crate::ast::compilation_unit::CompilationUnit;
|
||||||
|
use crate::ast::statement::Statement;
|
||||||
use crate::diagnostic::Diagnostics;
|
use crate::diagnostic::Diagnostics;
|
||||||
use crate::semantic_analysis::collect_scopes::collect_scopes;
|
use crate::semantic_analysis::collect_scopes::{
|
||||||
use crate::semantic_analysis::collect_symbols::collect_symbols;
|
collect_scopes_in_compilation_unit, collect_scopes_in_statement,
|
||||||
|
};
|
||||||
|
use crate::semantic_analysis::collect_symbols::{
|
||||||
|
SymbolCollectionResult, collect_symbols_in_compilation_unit,
|
||||||
|
};
|
||||||
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::{
|
||||||
use crate::semantic_analysis::resolve_types::resolve_types;
|
NameResolutionResult, resolve_names_in_compilation_unit, resolve_names_in_statement,
|
||||||
|
};
|
||||||
|
use crate::semantic_analysis::resolve_types::{
|
||||||
|
ResolveTypesResult, resolve_types_in_compilation_unit, resolve_types_in_statement,
|
||||||
|
};
|
||||||
|
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;
|
||||||
@ -16,59 +26,141 @@ mod collect_types;
|
|||||||
mod diagnostic_helpers;
|
mod diagnostic_helpers;
|
||||||
mod resolve_names;
|
mod resolve_names;
|
||||||
mod resolve_types;
|
mod resolve_types;
|
||||||
mod scope;
|
pub mod scope;
|
||||||
mod semantic_context;
|
|
||||||
pub mod symbol;
|
pub mod symbol;
|
||||||
pub mod type_info;
|
pub mod type_info;
|
||||||
|
|
||||||
pub struct AnalysisResult {
|
pub struct AnalysisContext {
|
||||||
pub symbols: Vec<Symbol>,
|
root_scope_id: ScopeId,
|
||||||
pub nodes_to_symbols: HashMap<NodeId, SymbolId>,
|
scopes: Vec<Scope>,
|
||||||
pub type_infos: Vec<TypeInfo>,
|
nodes_to_scopes: HashMap<NodeId, ScopeId>,
|
||||||
pub symbols_to_type_infos: HashMap<SymbolId, TypeInfoId>,
|
symbols: Vec<Symbol>,
|
||||||
pub nodes_to_type_infos: HashMap<NodeId, TypeInfoId>,
|
nodes_to_symbols: HashMap<NodeId, SymbolId>,
|
||||||
|
type_infos: Vec<TypeInfo>,
|
||||||
|
symbols_to_type_infos: HashMap<SymbolId, TypeInfoId>,
|
||||||
|
nodes_to_type_infos: HashMap<NodeId, TypeInfoId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnalysisContext {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
scopes: vec![Scope::new(None)],
|
||||||
|
nodes_to_scopes: HashMap::new(),
|
||||||
|
root_scope_id: 0, // already pushed in vec! above
|
||||||
|
symbols: Vec::new(),
|
||||||
|
nodes_to_symbols: HashMap::new(),
|
||||||
|
type_infos: Vec::new(),
|
||||||
|
symbols_to_type_infos: HashMap::new(),
|
||||||
|
nodes_to_type_infos: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn symbols(&self) -> &[Symbol] {
|
||||||
|
&self.symbols
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nodes_to_symbols(&self) -> &HashMap<NodeId, SymbolId> {
|
||||||
|
&self.nodes_to_symbols
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_infos(&self) -> &[TypeInfo] {
|
||||||
|
&self.type_infos
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn symbols_to_type_infos(&self) -> &HashMap<SymbolId, TypeInfoId> {
|
||||||
|
&self.symbols_to_type_infos
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nodes_to_type_infos(&self) -> &HashMap<NodeId, TypeInfoId> {
|
||||||
|
&self.nodes_to_type_infos
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn analyze_compilation_unit(
|
pub fn analyze_compilation_unit(
|
||||||
compilation_unit: &CompilationUnit,
|
compilation_unit: &CompilationUnit,
|
||||||
) -> (AnalysisResult, Diagnostics) {
|
ctx: &mut AnalysisContext,
|
||||||
|
) -> Diagnostics {
|
||||||
let mut diagnostics = Diagnostics::new();
|
let mut diagnostics = Diagnostics::new();
|
||||||
|
|
||||||
let mut scopes_result = collect_scopes(compilation_unit);
|
collect_scopes_in_compilation_unit(
|
||||||
|
|
||||||
let mut symbols_result = collect_symbols(
|
|
||||||
compilation_unit,
|
compilation_unit,
|
||||||
&mut scopes_result.scopes,
|
&mut ctx.scopes,
|
||||||
&scopes_result.nodes_to_scopes,
|
&mut ctx.nodes_to_scopes,
|
||||||
|
ctx.root_scope_id,
|
||||||
);
|
);
|
||||||
diagnostics.append(&mut symbols_result.diagnostics);
|
|
||||||
|
|
||||||
let mut names_result = resolve_names(
|
let SymbolCollectionResult(mut collect_symbols_diagnostics) =
|
||||||
|
collect_symbols_in_compilation_unit(
|
||||||
|
compilation_unit,
|
||||||
|
&mut ctx.scopes,
|
||||||
|
&ctx.nodes_to_scopes,
|
||||||
|
&mut ctx.symbols,
|
||||||
|
);
|
||||||
|
diagnostics.append(&mut collect_symbols_diagnostics);
|
||||||
|
|
||||||
|
let NameResolutionResult(mut resolve_names_diagnostics) = resolve_names_in_compilation_unit(
|
||||||
compilation_unit,
|
compilation_unit,
|
||||||
&mut scopes_result.scopes,
|
&mut ctx.scopes,
|
||||||
&mut symbols_result.symbols,
|
&mut ctx.symbols,
|
||||||
&scopes_result.nodes_to_scopes,
|
&mut ctx.nodes_to_scopes,
|
||||||
|
&mut ctx.nodes_to_symbols,
|
||||||
);
|
);
|
||||||
diagnostics.append(&mut names_result.diagnostics);
|
diagnostics.append(&mut resolve_names_diagnostics);
|
||||||
|
|
||||||
let mut collect_types_result = collect_types(compilation_unit, &names_result.nodes_to_symbols);
|
collect_types(
|
||||||
|
|
||||||
let mut resolve_types_result = resolve_types(
|
|
||||||
compilation_unit,
|
compilation_unit,
|
||||||
&names_result.nodes_to_symbols,
|
&ctx.nodes_to_symbols,
|
||||||
&mut collect_types_result.type_infos,
|
&mut ctx.type_infos,
|
||||||
&mut collect_types_result.symbols_to_type_infos,
|
&mut ctx.symbols_to_type_infos,
|
||||||
);
|
);
|
||||||
diagnostics.append(&mut resolve_types_result.diagnostics);
|
|
||||||
|
|
||||||
(
|
let ResolveTypesResult(mut resolve_types_diagnostics) = resolve_types_in_compilation_unit(
|
||||||
AnalysisResult {
|
compilation_unit,
|
||||||
symbols: symbols_result.symbols,
|
&ctx.nodes_to_symbols,
|
||||||
nodes_to_symbols: names_result.nodes_to_symbols,
|
&mut ctx.type_infos,
|
||||||
type_infos: collect_types_result.type_infos,
|
&mut ctx.symbols_to_type_infos,
|
||||||
symbols_to_type_infos: collect_types_result.symbols_to_type_infos,
|
&mut ctx.nodes_to_type_infos,
|
||||||
nodes_to_type_infos: resolve_types_result.nodes_to_type_infos,
|
);
|
||||||
},
|
diagnostics.append(&mut resolve_types_diagnostics);
|
||||||
diagnostics,
|
|
||||||
)
|
diagnostics
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn analyze_statement(
|
||||||
|
statement: &Statement,
|
||||||
|
ctx: &mut AnalysisContext,
|
||||||
|
function_scope_id: ScopeId,
|
||||||
|
) -> Diagnostics {
|
||||||
|
let mut diagnostics = Diagnostics::new();
|
||||||
|
|
||||||
|
collect_scopes_in_statement(
|
||||||
|
statement,
|
||||||
|
&mut ctx.scopes,
|
||||||
|
&mut ctx.nodes_to_scopes,
|
||||||
|
function_scope_id,
|
||||||
|
);
|
||||||
|
|
||||||
|
// collect symbols for a statement is currently a no-op, so not needed here
|
||||||
|
|
||||||
|
let NameResolutionResult(mut resolve_names_diagnostics) = resolve_names_in_statement(
|
||||||
|
statement,
|
||||||
|
&mut ctx.scopes,
|
||||||
|
&mut ctx.symbols,
|
||||||
|
&mut ctx.nodes_to_scopes,
|
||||||
|
&mut ctx.nodes_to_symbols,
|
||||||
|
);
|
||||||
|
diagnostics.append(&mut resolve_names_diagnostics);
|
||||||
|
|
||||||
|
// collect types for a statement is currently a no-op, so not needed here
|
||||||
|
|
||||||
|
let ResolveTypesResult(mut resolve_types_diagnostics) = resolve_types_in_statement(
|
||||||
|
statement,
|
||||||
|
&ctx.nodes_to_symbols,
|
||||||
|
&mut ctx.type_infos,
|
||||||
|
&mut ctx.symbols_to_type_infos,
|
||||||
|
&mut ctx.nodes_to_type_infos,
|
||||||
|
);
|
||||||
|
diagnostics.append(&mut resolve_types_diagnostics);
|
||||||
|
|
||||||
|
diagnostics
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,32 +1,30 @@
|
|||||||
|
use crate::ast::NodeId;
|
||||||
use crate::ast::assign_statement::AssignStatement;
|
use crate::ast::assign_statement::AssignStatement;
|
||||||
use crate::ast::binary_expression::BinaryExpression;
|
use crate::ast::binary_expression::BinaryExpression;
|
||||||
use crate::ast::call::Call;
|
use crate::ast::call::Call;
|
||||||
use crate::ast::compilation_unit::CompilationUnit;
|
use crate::ast::compilation_unit::CompilationUnit;
|
||||||
use crate::ast::expression::Expression;
|
use crate::ast::expression::Expression;
|
||||||
use crate::ast::expression_statement::ExpressionStatement;
|
use crate::ast::expression_statement::ExpressionStatement;
|
||||||
|
use crate::ast::extern_function::ExternFunction;
|
||||||
use crate::ast::function::Function;
|
use crate::ast::function::Function;
|
||||||
use crate::ast::identifier::Identifier;
|
use crate::ast::identifier::Identifier;
|
||||||
use crate::ast::let_statement::LetStatement;
|
use crate::ast::let_statement::LetStatement;
|
||||||
use crate::ast::negative_expression::NegativeExpression;
|
use crate::ast::negative_expression::NegativeExpression;
|
||||||
use crate::ast::parameter::Parameter;
|
use crate::ast::parameter::Parameter;
|
||||||
use crate::ast::statement::Statement;
|
use crate::ast::statement::Statement;
|
||||||
use crate::ast::NodeId;
|
|
||||||
use crate::diagnostic::Diagnostics;
|
use crate::diagnostic::Diagnostics;
|
||||||
use crate::diagnostic_factories::symbol_not_found;
|
use crate::diagnostic_factories::symbol_not_found;
|
||||||
use crate::semantic_analysis::scope::{Scope, ScopeId};
|
use crate::semantic_analysis::scope::{Scope, ScopeId};
|
||||||
use crate::semantic_analysis::symbol::{Symbol, SymbolId, VariableSymbol};
|
use crate::semantic_analysis::symbol::{Symbol, SymbolId, VariableSymbol};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct NameResolutionResult {
|
pub struct NameResolutionResult(pub Diagnostics);
|
||||||
pub nodes_to_symbols: HashMap<NodeId, SymbolId>,
|
|
||||||
pub diagnostics: Diagnostics,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct NameResolutionContext<'a> {
|
struct NameResolutionContext<'a> {
|
||||||
scopes: &'a mut Vec<Scope>,
|
scopes: &'a mut Vec<Scope>,
|
||||||
symbols: &'a mut Vec<Symbol>,
|
symbols: &'a mut Vec<Symbol>,
|
||||||
nodes_to_scopes: &'a HashMap<NodeId, ScopeId>,
|
nodes_to_scopes: &'a HashMap<NodeId, ScopeId>,
|
||||||
nodes_to_symbols: HashMap<NodeId, SymbolId>,
|
nodes_to_symbols: &'a mut HashMap<NodeId, SymbolId>,
|
||||||
diagnostics: Diagnostics,
|
diagnostics: Diagnostics,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,12 +33,13 @@ impl<'a> NameResolutionContext<'a> {
|
|||||||
scopes: &'a mut Vec<Scope>,
|
scopes: &'a mut Vec<Scope>,
|
||||||
symbols: &'a mut Vec<Symbol>,
|
symbols: &'a mut Vec<Symbol>,
|
||||||
nodes_to_scopes: &'a HashMap<NodeId, ScopeId>,
|
nodes_to_scopes: &'a HashMap<NodeId, ScopeId>,
|
||||||
|
nodes_to_symbols: &'a mut HashMap<NodeId, SymbolId>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
scopes,
|
scopes,
|
||||||
symbols,
|
symbols,
|
||||||
nodes_to_scopes,
|
nodes_to_scopes,
|
||||||
nodes_to_symbols: HashMap::new(),
|
nodes_to_symbols,
|
||||||
diagnostics: Diagnostics::new(),
|
diagnostics: Diagnostics::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,22 +86,36 @@ enum ExpressionResolutionPhase {
|
|||||||
Static,
|
Static,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_names(
|
pub fn resolve_names_in_compilation_unit(
|
||||||
compilation_unit: &CompilationUnit,
|
compilation_unit: &CompilationUnit,
|
||||||
scopes: &mut Vec<Scope>,
|
scopes: &mut Vec<Scope>,
|
||||||
symbols: &mut Vec<Symbol>,
|
symbols: &mut Vec<Symbol>,
|
||||||
nodes_to_scopes: &HashMap<NodeId, ScopeId>,
|
nodes_to_scopes: &HashMap<NodeId, ScopeId>,
|
||||||
|
nodes_to_symbols: &mut HashMap<NodeId, SymbolId>,
|
||||||
) -> NameResolutionResult {
|
) -> NameResolutionResult {
|
||||||
let mut ctx = NameResolutionContext::new(scopes, symbols, nodes_to_scopes);
|
let mut ctx = NameResolutionContext::new(scopes, symbols, nodes_to_scopes, nodes_to_symbols);
|
||||||
|
|
||||||
for function in compilation_unit.functions() {
|
for function in compilation_unit.functions() {
|
||||||
resolve_names_function(function, &mut ctx);
|
resolve_names_function(function, &mut ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
NameResolutionResult {
|
for extern_function in compilation_unit.extern_functions() {
|
||||||
nodes_to_symbols: ctx.nodes_to_symbols,
|
resolve_names_extern_function(extern_function, &mut ctx);
|
||||||
diagnostics: ctx.diagnostics,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NameResolutionResult(ctx.diagnostics)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolve_names_in_statement(
|
||||||
|
statement: &Statement,
|
||||||
|
scopes: &mut Vec<Scope>,
|
||||||
|
symbols: &mut Vec<Symbol>,
|
||||||
|
nodes_to_scopes: &HashMap<NodeId, ScopeId>,
|
||||||
|
nodes_to_symbols: &mut HashMap<NodeId, SymbolId>,
|
||||||
|
) -> NameResolutionResult {
|
||||||
|
let mut ctx = NameResolutionContext::new(scopes, symbols, nodes_to_scopes, nodes_to_symbols);
|
||||||
|
resolve_names_statement(statement, &mut ctx, StatementResolutionPhase::Static);
|
||||||
|
NameResolutionResult(ctx.diagnostics)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_names_function(function: &Function, ctx: &mut NameResolutionContext) {
|
fn resolve_names_function(function: &Function, ctx: &mut NameResolutionContext) {
|
||||||
@ -121,6 +134,22 @@ fn resolve_names_function(function: &Function, ctx: &mut NameResolutionContext)
|
|||||||
ctx.nodes_to_symbols.insert(function.node_id(), symbol_id);
|
ctx.nodes_to_symbols.insert(function.node_id(), symbol_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolve_names_extern_function(
|
||||||
|
extern_function: &ExternFunction,
|
||||||
|
ctx: &mut NameResolutionContext,
|
||||||
|
) {
|
||||||
|
for parameter in extern_function.parameters() {
|
||||||
|
resolve_names_parameter(parameter, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// point this extern function's node_id to the symbol_id for this function symbol
|
||||||
|
let scope_id = ctx.nodes_to_scopes[&extern_function.node_id()];
|
||||||
|
let scope = &ctx.scopes[scope_id];
|
||||||
|
let symbol_id = scope.symbols()[extern_function.declared_name()];
|
||||||
|
ctx.nodes_to_symbols
|
||||||
|
.insert(extern_function.node_id(), symbol_id);
|
||||||
|
}
|
||||||
|
|
||||||
fn resolve_names_parameter(parameter: &Parameter, ctx: &mut NameResolutionContext) {
|
fn resolve_names_parameter(parameter: &Parameter, ctx: &mut NameResolutionContext) {
|
||||||
// point this parameter's node_id to the symbol_id for the parameter symbol
|
// point this parameter's node_id to the symbol_id for the parameter symbol
|
||||||
let scope_id = ctx.nodes_to_scopes[¶meter.node_id()];
|
let scope_id = ctx.nodes_to_scopes[¶meter.node_id()];
|
||||||
|
|||||||
@ -21,16 +21,13 @@ use crate::semantic_analysis::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;
|
||||||
|
|
||||||
pub struct ResolveTypesResult {
|
pub struct ResolveTypesResult(pub Diagnostics);
|
||||||
pub nodes_to_type_infos: HashMap<NodeId, TypeInfoId>,
|
|
||||||
pub diagnostics: Diagnostics,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ResolveTypesContext<'a> {
|
struct ResolveTypesContext<'a> {
|
||||||
nodes_to_symbols: &'a HashMap<NodeId, SymbolId>,
|
nodes_to_symbols: &'a HashMap<NodeId, SymbolId>,
|
||||||
type_infos: &'a mut Vec<TypeInfo>,
|
type_infos: &'a mut Vec<TypeInfo>,
|
||||||
symbols_to_type_infos: &'a mut HashMap<SymbolId, TypeInfoId>,
|
symbols_to_type_infos: &'a mut HashMap<SymbolId, TypeInfoId>,
|
||||||
nodes_to_type_infos: HashMap<NodeId, TypeInfoId>,
|
nodes_to_type_infos: &'a mut HashMap<NodeId, TypeInfoId>,
|
||||||
diagnostics: Diagnostics,
|
diagnostics: Diagnostics,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,32 +36,54 @@ impl<'a> ResolveTypesContext<'a> {
|
|||||||
nodes_to_symbols: &'a HashMap<NodeId, SymbolId>,
|
nodes_to_symbols: &'a HashMap<NodeId, SymbolId>,
|
||||||
type_infos: &'a mut Vec<TypeInfo>,
|
type_infos: &'a mut Vec<TypeInfo>,
|
||||||
symbols_to_type_infos: &'a mut HashMap<SymbolId, TypeInfoId>,
|
symbols_to_type_infos: &'a mut HashMap<SymbolId, TypeInfoId>,
|
||||||
|
nodes_to_type_infos: &'a mut HashMap<NodeId, TypeInfoId>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
nodes_to_symbols,
|
nodes_to_symbols,
|
||||||
type_infos,
|
type_infos,
|
||||||
symbols_to_type_infos,
|
symbols_to_type_infos,
|
||||||
nodes_to_type_infos: HashMap::new(),
|
nodes_to_type_infos,
|
||||||
diagnostics: Diagnostics::new(),
|
diagnostics: Diagnostics::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_types(
|
pub fn resolve_types_in_compilation_unit(
|
||||||
compilation_unit: &CompilationUnit,
|
compilation_unit: &CompilationUnit,
|
||||||
nodes_to_symbols: &HashMap<NodeId, SymbolId>,
|
nodes_to_symbols: &HashMap<NodeId, SymbolId>,
|
||||||
type_infos: &mut Vec<TypeInfo>,
|
type_infos: &mut Vec<TypeInfo>,
|
||||||
symbols_to_type_infos: &mut HashMap<SymbolId, TypeInfoId>,
|
symbols_to_type_infos: &mut HashMap<SymbolId, TypeInfoId>,
|
||||||
|
nodes_to_type_infos: &mut HashMap<NodeId, TypeInfoId>,
|
||||||
) -> ResolveTypesResult {
|
) -> ResolveTypesResult {
|
||||||
let mut ctx = ResolveTypesContext::new(nodes_to_symbols, type_infos, symbols_to_type_infos);
|
let mut ctx = ResolveTypesContext::new(
|
||||||
|
nodes_to_symbols,
|
||||||
|
type_infos,
|
||||||
|
symbols_to_type_infos,
|
||||||
|
nodes_to_type_infos,
|
||||||
|
);
|
||||||
|
|
||||||
for function in compilation_unit.functions() {
|
for function in compilation_unit.functions() {
|
||||||
resolve_types_function(function, &mut ctx);
|
resolve_types_function(function, &mut ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolveTypesResult {
|
ResolveTypesResult(ctx.diagnostics)
|
||||||
nodes_to_type_infos: ctx.nodes_to_type_infos,
|
}
|
||||||
diagnostics: ctx.diagnostics,
|
|
||||||
}
|
pub fn resolve_types_in_statement(
|
||||||
|
statement: &Statement,
|
||||||
|
nodes_to_symbols: &HashMap<NodeId, SymbolId>,
|
||||||
|
type_infos: &mut Vec<TypeInfo>,
|
||||||
|
symbols_to_type_infos: &mut HashMap<SymbolId, TypeInfoId>,
|
||||||
|
nodes_to_type_infos: &mut HashMap<NodeId, TypeInfoId>,
|
||||||
|
) -> ResolveTypesResult {
|
||||||
|
let mut ctx = ResolveTypesContext::new(
|
||||||
|
nodes_to_symbols,
|
||||||
|
type_infos,
|
||||||
|
symbols_to_type_infos,
|
||||||
|
nodes_to_type_infos,
|
||||||
|
);
|
||||||
|
resolve_types_statement(statement, &mut ctx);
|
||||||
|
ResolveTypesResult(ctx.diagnostics)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_types_function(function: &Function, ctx: &mut ResolveTypesContext) {
|
fn resolve_types_function(function: &Function, ctx: &mut ResolveTypesContext) {
|
||||||
@ -266,6 +285,11 @@ fn resolve_types_negative_expression(
|
|||||||
fn resolve_types_call(call: &Call, ctx: &mut ResolveTypesContext) {
|
fn resolve_types_call(call: &Call, ctx: &mut ResolveTypesContext) {
|
||||||
resolve_types_expression(call.callee(), ctx);
|
resolve_types_expression(call.callee(), ctx);
|
||||||
|
|
||||||
|
// get types of arguments
|
||||||
|
for argument in call.arguments() {
|
||||||
|
resolve_types_expression(argument, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
let callee_type_info_id = ctx.nodes_to_type_infos[&call.callee().node_id()];
|
let callee_type_info_id = ctx.nodes_to_type_infos[&call.callee().node_id()];
|
||||||
let callee_type_info = &ctx.type_infos[callee_type_info_id];
|
let callee_type_info = &ctx.type_infos[callee_type_info_id];
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +0,0 @@
|
|||||||
use crate::ast::NodeId;
|
|
||||||
use crate::semantic_analysis::scope::{Scope, ScopeId};
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
pub struct SemanticContext {
|
|
||||||
scopes: Vec<Scope>,
|
|
||||||
node_scopes: HashMap<NodeId, ScopeId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SemanticContext {}
|
|
||||||
@ -3,6 +3,7 @@ mod e2e_tests {
|
|||||||
use dmc_lib::compile_compilation_unit;
|
use dmc_lib::compile_compilation_unit;
|
||||||
use dmc_lib::constants_table::ConstantsTable;
|
use dmc_lib::constants_table::ConstantsTable;
|
||||||
use dmc_lib::diagnostic::{Diagnostic, Diagnostics};
|
use dmc_lib::diagnostic::{Diagnostic, Diagnostics};
|
||||||
|
use dmc_lib::semantic_analysis::AnalysisContext;
|
||||||
use dvm_lib::vm::constant::{Constant, StringConstant};
|
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||||
use dvm_lib::vm::value::Value;
|
use dvm_lib::vm::value::Value;
|
||||||
use dvm_lib::vm::{DvmContext, call};
|
use dvm_lib::vm::{DvmContext, call};
|
||||||
@ -23,10 +24,11 @@ mod e2e_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_context(input: &str) -> Result<DvmContext, Diagnostics> {
|
fn prepare_context(input: &str) -> Result<DvmContext, Diagnostics> {
|
||||||
|
let mut ctx = AnalysisContext::new();
|
||||||
let mut constants_table = ConstantsTable::new();
|
let mut constants_table = ConstantsTable::new();
|
||||||
|
|
||||||
let compile_compilation_unit_result =
|
let compile_compilation_unit_result =
|
||||||
compile_compilation_unit(input, REGISTER_COUNT, &mut constants_table);
|
compile_compilation_unit(input, &mut ctx, REGISTER_COUNT, &mut constants_table);
|
||||||
|
|
||||||
let mut dvm_context = DvmContext::new();
|
let mut dvm_context = DvmContext::new();
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user