diff --git a/dm/src/repl.rs b/dm/src/repl.rs index 2469aa9..d7919c1 100644 --- a/dm/src/repl.rs +++ b/dm/src/repl.rs @@ -3,15 +3,20 @@ use dmc_lib::ast::statement::Statement; use dmc_lib::compile_statement_to_synthetic_function; use dmc_lib::constants_table::ConstantsTable; use dmc_lib::diagnostic::Diagnostics; +use dmc_lib::ir::ir_parameter::{IrParameter, IrParameterId}; +use dmc_lib::ir::ir_variable::{IrVariable, IrVariableId}; use dmc_lib::ir::variable_locations::VariableLocations; use dmc_lib::lexer::Lexer; +use dmc_lib::lowering::SyntheticFunctionLoweringContext; use dmc_lib::parser::{parse_expression, parse_let_statement}; use dmc_lib::semantic_analysis::analysis_context::AnalysisContext; +use dmc_lib::semantic_analysis::symbol::SymbolId; use dmc_lib::token::TokenKind; use dvm_lib::vm::constant::{Constant, StringConstant}; use dvm_lib::vm::function::Function; use dvm_lib::vm::operand::Operand; use dvm_lib::vm::{CallStack, DvmContext, loop_instructions, prepare_for_instruction_loop}; +use std::collections::HashMap; use std::io; use std::io::{BufRead, Write}; use std::rc::Rc; @@ -308,6 +313,12 @@ pub fn repl_2(read: &mut impl BufRead, register_count: usize) { analysis_context.push_scope("__repl_body_scope"); let fqn: Rc = Rc::from("__repl"); + + let mut ir_variables: Vec = Vec::new(); + let mut ir_parameters: Vec = Vec::new(); + let mut symbols_to_variables: HashMap = HashMap::new(); + let mut symbols_to_parameters: HashMap = HashMap::new(); + let mut variable_locations = VariableLocations::new(); let mut constants_table = ConstantsTable::new(); @@ -345,6 +356,12 @@ pub fn repl_2(read: &mut impl BufRead, register_count: usize) { input, &mut analysis_context, &fqn, + SyntheticFunctionLoweringContext { + ir_variables: &mut ir_variables, + symbols_to_variables: &mut symbols_to_variables, + ir_parameters: &mut ir_parameters, + symbols_to_parameters: &mut symbols_to_parameters, + }, &mut variable_locations, register_count, &mut constants_table, @@ -369,6 +386,12 @@ pub fn repl_2(read: &mut impl BufRead, register_count: usize) { input, &mut analysis_context, &fqn, + SyntheticFunctionLoweringContext { + ir_variables: &mut ir_variables, + symbols_to_variables: &mut symbols_to_variables, + ir_parameters: &mut ir_parameters, + symbols_to_parameters: &mut symbols_to_parameters, + }, &mut variable_locations, register_count, &mut constants_table, @@ -428,6 +451,7 @@ fn compile_expression_2( input: &str, analysis_context: &mut AnalysisContext, fqn: &Rc, + synthetic_function_lowering_context: SyntheticFunctionLoweringContext, variable_locations: &mut VariableLocations, register_count: usize, constants_table: &mut ConstantsTable, @@ -443,6 +467,7 @@ fn compile_expression_2( &statement, analysis_context, fqn.clone(), + synthetic_function_lowering_context, variable_locations, register_count, constants_table, @@ -453,6 +478,7 @@ fn compile_let_statement_2( input: &str, analysis_context: &mut AnalysisContext, fqn: &Rc, + synthetic_function_lowering_context: SyntheticFunctionLoweringContext, variable_locations: &mut VariableLocations, register_count: usize, constants_table: &mut ConstantsTable, @@ -465,6 +491,7 @@ fn compile_let_statement_2( &Statement::Let(maybe_let_statement.unwrap()), analysis_context, fqn.clone(), + synthetic_function_lowering_context, variable_locations, register_count, constants_table, diff --git a/dmc-lib/src/ir/ir_parameter.rs b/dmc-lib/src/ir/ir_parameter.rs index 4298682..98f2191 100644 --- a/dmc-lib/src/ir/ir_parameter.rs +++ b/dmc-lib/src/ir/ir_parameter.rs @@ -5,7 +5,7 @@ use std::rc::Rc; pub type IrParameterId = usize; -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct IrParameter { name: Rc, type_info: IrTypeInfo, diff --git a/dmc-lib/src/ir/ir_type_info.rs b/dmc-lib/src/ir/ir_type_info.rs index 01d4089..35123d5 100644 --- a/dmc-lib/src/ir/ir_type_info.rs +++ b/dmc-lib/src/ir/ir_type_info.rs @@ -2,7 +2,7 @@ use std::fmt::{Display, Formatter}; pub type IrTypeInfoId = usize; -#[derive(Debug)] +#[derive(Clone, Debug)] pub enum IrTypeInfo { String, Int, diff --git a/dmc-lib/src/ir/ir_variable.rs b/dmc-lib/src/ir/ir_variable.rs index ec042b3..0ee3627 100644 --- a/dmc-lib/src/ir/ir_variable.rs +++ b/dmc-lib/src/ir/ir_variable.rs @@ -4,7 +4,7 @@ use std::rc::Rc; pub type IrVariableId = usize; -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct IrVariable { name: Rc, type_info: IrTypeInfo, diff --git a/dmc-lib/src/lib.rs b/dmc-lib/src/lib.rs index d4acd1d..f59cdf1 100644 --- a/dmc-lib/src/lib.rs +++ b/dmc-lib/src/lib.rs @@ -3,7 +3,9 @@ use crate::constants_table::ConstantsTable; use crate::diagnostic::Diagnostics; use crate::ir::compile_dvm_function; use crate::ir::variable_locations::VariableLocations; -use crate::lowering::{lower_to_ir_compilation_unit, lower_to_ir_synthetic_function}; +use crate::lowering::{ + SyntheticFunctionLoweringContext, lower_to_ir_compilation_unit, lower_to_ir_synthetic_function, +}; use crate::parser::parse_compilation_unit; use crate::semantic_analysis::{analyze_compilation_unit, analyze_statement}; use dvm_lib::vm::function::Function; @@ -79,6 +81,7 @@ pub fn compile_statement_to_synthetic_function( statement: &Statement, analysis_context: &mut AnalysisContext, fqn: Rc, + synthetic_function_lowering_context: SyntheticFunctionLoweringContext, variable_locations: &mut VariableLocations, register_count: usize, constants_table: &mut ConstantsTable, @@ -87,7 +90,12 @@ pub fn compile_statement_to_synthetic_function( if !diagnostics.is_empty() { return Err(diagnostics); } - let ir_function = lower_to_ir_synthetic_function(statement, analysis_context, fqn); + let ir_function = lower_to_ir_synthetic_function( + statement, + analysis_context, + fqn, + synthetic_function_lowering_context, + ); Ok(compile_dvm_function( &ir_function, register_count, diff --git a/dmc-lib/src/lowering/mod.rs b/dmc-lib/src/lowering/mod.rs index c3af53c..f8de81c 100644 --- a/dmc-lib/src/lowering/mod.rs +++ b/dmc-lib/src/lowering/mod.rs @@ -1,6 +1,5 @@ mod util; -use crate::ast::NodeId; use crate::ast::assign_statement::AssignStatement; use crate::ast::binary_expression::BinaryOperation; use crate::ast::call::Call; @@ -25,7 +24,7 @@ use crate::ir::ir_variable::{IrVariable, IrVariableId}; use crate::lowering::util::{return_type_info_to_ir_type_info, to_ir_type_info}; use crate::semantic_analysis::analysis_context::AnalysisContext; use crate::semantic_analysis::symbol::{Symbol, SymbolId}; -use crate::semantic_analysis::type_info::{TypeInfo, TypeInfoId}; +use crate::semantic_analysis::type_info::TypeInfo; use std::collections::HashMap; use std::ops::Neg; use std::rc::Rc; @@ -34,55 +33,40 @@ pub struct LowerToIrResult { pub functions: Vec, } -#[derive(Debug)] -struct LowerToIrContext<'a> { - symbols: &'a [Symbol], - nodes_to_symbols: &'a HashMap, - type_infos: &'a [TypeInfo], - symbols_to_type_infos: &'a HashMap, - nodes_to_type_infos: &'a HashMap, - ir_functions: Vec, -} - pub fn lower_to_ir_compilation_unit( compilation_unit: &CompilationUnit, analysis_context: &AnalysisContext, ) -> LowerToIrResult { - let mut ctx = LowerToIrContext { - symbols: analysis_context.symbols(), - nodes_to_symbols: analysis_context.nodes_to_symbols(), - type_infos: analysis_context.type_infos(), - symbols_to_type_infos: analysis_context.symbols_to_type_infos(), - nodes_to_type_infos: analysis_context.nodes_to_type_infos(), - ir_functions: Vec::new(), - }; - - for function in compilation_unit.functions() { - lower_to_ir_function(function, &mut ctx); - } - LowerToIrResult { - functions: ctx.ir_functions, + functions: compilation_unit + .functions() + .iter() + .map(|function| lower_to_ir_function(function, analysis_context)) + .collect(), } } +pub struct SyntheticFunctionLoweringContext<'a> { + pub ir_variables: &'a mut Vec, + pub symbols_to_variables: &'a mut HashMap, + pub ir_parameters: &'a mut Vec, + pub symbols_to_parameters: &'a mut HashMap, +} + pub fn lower_to_ir_synthetic_function( statement: &Statement, analysis_ctx: &AnalysisContext, fqn: Rc, + synthetic_function_lowering_context: SyntheticFunctionLoweringContext, ) -> 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::with_variables_and_parameters( + synthetic_function_lowering_context.ir_variables, + synthetic_function_lowering_context.symbols_to_variables, + synthetic_function_lowering_context.ir_parameters, + synthetic_function_lowering_context.symbols_to_parameters, + ); - let mut fn_ctx = LowerToIrFunctionContext::new(); - - lower_to_ir_statement(statement, &mut ctx, &mut fn_ctx, true); + lower_to_ir_statement(statement, analysis_ctx, &mut fn_ctx, true); fn_ctx.finish_block(); // infer return type from statement @@ -90,40 +74,45 @@ pub fn lower_to_ir_synthetic_function( 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]; + analysis_ctx.nodes_to_type_infos()[&expression_statement.expression().node_id()]; + let type_info = &analysis_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, + fn_ctx.ir_parameters.clone(), // provide just a snapshot of those + fn_ctx.ir_variables.clone(), maybe_return_ir_type_info, fn_ctx.blocks, ) } #[derive(Debug)] -struct LowerToIrFunctionContext { +struct LowerToIrFunctionContext<'a> { + ir_variables: &'a mut Vec, + symbols_to_variables: &'a mut HashMap, + ir_parameters: &'a mut Vec, + symbols_to_parameters: &'a mut HashMap, blocks: Vec, - ir_variables: Vec, - symbols_to_variables: HashMap, - ir_parameters: Vec, - symbols_to_parameters: HashMap, current_block_statements: Vec, t_var_counter: usize, } -impl LowerToIrFunctionContext { - fn new() -> Self { +impl<'a> LowerToIrFunctionContext<'a> { + fn with_variables_and_parameters( + ir_variables: &'a mut Vec, + symbols_to_variables: &'a mut HashMap, + ir_parameters: &'a mut Vec, + symbols_to_parameters: &'a mut HashMap, + ) -> Self { Self { + ir_variables, + symbols_to_variables, + ir_parameters, + symbols_to_parameters, blocks: Vec::new(), - ir_variables: Vec::new(), - symbols_to_variables: HashMap::new(), - ir_parameters: Vec::new(), - symbols_to_parameters: HashMap::new(), current_block_statements: Vec::new(), t_var_counter: 0, } @@ -179,23 +168,33 @@ impl LowerToIrFunctionContext { } } -fn lower_to_ir_function(function: &Function, ctx: &mut LowerToIrContext) { - let mut fn_ctx = LowerToIrFunctionContext::new(); +fn lower_to_ir_function(function: &Function, ctx: &AnalysisContext) -> IrFunction { + let mut ir_variables = Vec::new(); + let mut symbols_to_variables = HashMap::new(); + let mut ir_parameters = Vec::new(); + let mut symbols_to_parameters = HashMap::new(); + + let mut fn_ctx = LowerToIrFunctionContext::with_variables_and_parameters( + &mut ir_variables, + &mut symbols_to_variables, + &mut ir_parameters, + &mut symbols_to_parameters, + ); lower_to_ir_parameters(function, ctx, &mut fn_ctx); // get various function info - let function_symbol_id = ctx.nodes_to_symbols[&function.node_id()]; - let function_symbol = match &ctx.symbols[function_symbol_id] { + let function_symbol_id = ctx.nodes_to_symbols()[&function.node_id()]; + let function_symbol = match &ctx.symbols()[function_symbol_id] { Symbol::Function(function_symbol) => function_symbol, _ => panic!("Expected FunctionSymbol"), }; - 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_id = ctx.symbols_to_type_infos()[&function_symbol_id]; + let function_type_info = match &ctx.type_infos()[function_type_info_id] { TypeInfo::Function(function_type_info) => function_type_info, _ => 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, @@ -209,26 +208,25 @@ fn lower_to_ir_function(function: &Function, ctx: &mut LowerToIrContext) { } fn_ctx.finish_block(); - let ir_function = IrFunction::new( + let blocks = fn_ctx.blocks; // must move it out beforehand to satisfy borrow checker + IrFunction::new( function_symbol.fqn_owned(), - fn_ctx.ir_parameters, - fn_ctx.ir_variables, + ir_parameters, + ir_variables, return_type_info_to_ir_type_info(return_type_info), - fn_ctx.blocks, - ); - - ctx.ir_functions.push(ir_function); + blocks, + ) } fn lower_to_ir_parameters( function: &Function, - ctx: &LowerToIrContext, + ctx: &AnalysisContext, fn_ctx: &mut LowerToIrFunctionContext, ) { let n_parameters = function.parameters().len() as isize; for (i, parameter) in function.parameters().iter().enumerate() { - let parameter_type_info_id = ctx.nodes_to_type_infos[¶meter.node_id()]; - let parameter_type_info = &ctx.type_infos[parameter_type_info_id]; + let parameter_type_info_id = ctx.nodes_to_type_infos()[¶meter.node_id()]; + let parameter_type_info = &ctx.type_infos()[parameter_type_info_id]; let ir_parameter = IrParameter::new( parameter.declared_name(), to_ir_type_info(parameter_type_info), @@ -236,14 +234,14 @@ fn lower_to_ir_parameters( ); fn_ctx.insert_ir_parameter( ir_parameter, - Some(ctx.nodes_to_symbols[¶meter.node_id()]), + Some(ctx.nodes_to_symbols()[¶meter.node_id()]), ); } } fn lower_to_ir_statement( statement: &Statement, - ctx: &LowerToIrContext, + ctx: &AnalysisContext, fn_ctx: &mut LowerToIrFunctionContext, can_return_value: bool, ) { @@ -277,13 +275,13 @@ fn lower_binary_operator(binary_operation: &BinaryOperation) -> IrBinaryOperator fn lower_to_ir_let_statement( let_statement: &LetStatement, - ctx: &LowerToIrContext, + ctx: &AnalysisContext, fn_ctx: &mut LowerToIrFunctionContext, ) { - let symbol_id = ctx.nodes_to_symbols[&let_statement.node_id()]; + let symbol_id = ctx.nodes_to_symbols()[&let_statement.node_id()]; - let type_info_id = ctx.nodes_to_type_infos[&let_statement.node_id()]; - let type_info = &ctx.type_infos[type_info_id]; + let type_info_id = ctx.nodes_to_type_infos()[&let_statement.node_id()]; + let type_info = &ctx.type_infos()[type_info_id]; let ir_variable = IrVariable::new(let_statement.declared_name(), to_ir_type_info(type_info)); let ir_variable_id = fn_ctx.insert_ir_variable(ir_variable, Some(symbol_id)); @@ -298,7 +296,7 @@ fn lower_to_ir_let_statement( fn lower_to_ir_expression_statement( expression_statement: &ExpressionStatement, - ctx: &LowerToIrContext, + ctx: &AnalysisContext, fn_ctx: &mut LowerToIrFunctionContext, returns_value: bool, ) { @@ -314,8 +312,8 @@ fn lower_to_ir_expression_statement( lower_expression_to_ir_operation(expression_statement.expression(), ctx, fn_ctx); let result_type_info_id = - ctx.nodes_to_type_infos[&expression_statement.expression().node_id()]; - let result_type_info = &ctx.type_infos[result_type_info_id]; + ctx.nodes_to_type_infos()[&expression_statement.expression().node_id()]; + let result_type_info = &ctx.type_infos()[result_type_info_id]; let t_var_ir_variable_id = fn_ctx.make_t_var(to_ir_type_info(result_type_info)); let ir_statement = IrStatement::Assign(IrAssign::new(t_var_ir_variable_id, ir_operation)); @@ -325,12 +323,12 @@ fn lower_to_ir_expression_statement( fn lower_to_ir_assign_statement( assign_statement: &AssignStatement, - ctx: &LowerToIrContext, + ctx: &AnalysisContext, fn_ctx: &mut LowerToIrFunctionContext, ) { match assign_statement.destination() { Expression::Identifier(identifier) => { - let destination_symbol_id = ctx.nodes_to_symbols[&identifier.node_id()]; + let destination_symbol_id = ctx.nodes_to_symbols()[&identifier.node_id()]; let destination_ir_variable_id = fn_ctx.symbols_to_variables[&destination_symbol_id]; let ir_operation = @@ -345,7 +343,7 @@ fn lower_to_ir_assign_statement( fn lower_expression_to_ir_operation( expression: &Expression, - ctx: &LowerToIrContext, + ctx: &AnalysisContext, fn_ctx: &mut LowerToIrFunctionContext, ) -> IrOperation { match expression { @@ -369,7 +367,7 @@ fn lower_expression_to_ir_operation( } Expression::Call(call) => IrOperation::Call(lower_to_ir_call(call, ctx, fn_ctx)), Expression::Identifier(identifier) => { - let identifier_symbol_id = ctx.nodes_to_symbols[&identifier.node_id()]; + let identifier_symbol_id = ctx.nodes_to_symbols()[&identifier.node_id()]; let identifier_ir_variable_id = fn_ctx.symbols_to_variables[&identifier_symbol_id]; let ir_expression = IrExpression::Variable(identifier_ir_variable_id); IrOperation::Load(ir_expression) @@ -388,7 +386,7 @@ fn lower_expression_to_ir_operation( fn lower_expression_to_ir_expression( expression: &Expression, - ctx: &LowerToIrContext, + ctx: &AnalysisContext, fn_ctx: &mut LowerToIrFunctionContext, ) -> IrExpression { match expression { @@ -403,8 +401,8 @@ fn lower_expression_to_ir_expression( )); // make destination temp var - let result_type_info_id = ctx.nodes_to_type_infos[&binary_expression.node_id()]; - let result_type_info = &ctx.type_infos[result_type_info_id]; + let result_type_info_id = ctx.nodes_to_type_infos()[&binary_expression.node_id()]; + let result_type_info = &ctx.type_infos()[result_type_info_id]; let destination_ir_variable_id = fn_ctx.make_t_var(to_ir_type_info(result_type_info)); // make assign statement to destination temp var @@ -425,8 +423,8 @@ fn lower_expression_to_ir_expression( negative_one, IrBinaryOperator::Multiply, )); - let result_type_info_id = ctx.nodes_to_type_infos[&negative_expression.node_id()]; - let result_type_info = &ctx.type_infos[result_type_info_id]; + let result_type_info_id = ctx.nodes_to_type_infos()[&negative_expression.node_id()]; + let result_type_info = &ctx.type_infos()[result_type_info_id]; let destination_ir_variable_id = fn_ctx.make_t_var(to_ir_type_info(result_type_info)); let ir_assign = IrAssign::new(destination_ir_variable_id, ir_operation); @@ -441,8 +439,8 @@ fn lower_expression_to_ir_expression( let ir_call = lower_to_ir_call(call, ctx, fn_ctx); // make temp var - let return_type_info_id = ctx.nodes_to_type_infos[&call.node_id()]; - let return_type_info = &ctx.type_infos[return_type_info_id]; + let return_type_info_id = ctx.nodes_to_type_infos()[&call.node_id()]; + let return_type_info = &ctx.type_infos()[return_type_info_id]; let return_ir_type_info = to_ir_type_info(return_type_info); let t_var_ir_variable_id = fn_ctx.make_t_var(return_ir_type_info); @@ -457,7 +455,7 @@ fn lower_expression_to_ir_expression( IrExpression::Variable(t_var_ir_variable_id) } Expression::Identifier(identifier) => { - let rhs_symbol_id = ctx.nodes_to_symbols[&identifier.node_id()]; + let rhs_symbol_id = ctx.nodes_to_symbols()[&identifier.node_id()]; if let Some(rhs_ir_variable_id) = fn_ctx.symbols_to_variables.get(&rhs_symbol_id) { IrExpression::Variable(*rhs_ir_variable_id) } else if let Some(rhs_ir_parameter_id) = @@ -465,7 +463,6 @@ fn lower_expression_to_ir_expression( { IrExpression::Parameter(*rhs_ir_parameter_id) } else { - println!("Dump:\n{:#?}\n{:#?}", ctx, fn_ctx); panic!( "Could not find parameter or variable for symbol_id {}", rhs_symbol_id @@ -480,11 +477,11 @@ fn lower_expression_to_ir_expression( fn lower_to_ir_call( call: &Call, - ctx: &LowerToIrContext, + ctx: &AnalysisContext, fn_ctx: &mut LowerToIrFunctionContext, ) -> IrCall { - let callee_symbol_id = ctx.nodes_to_symbols[&call.callee().node_id()]; - let callee_symbol = &ctx.symbols[callee_symbol_id]; + let callee_symbol_id = ctx.nodes_to_symbols()[&call.callee().node_id()]; + let callee_symbol = &ctx.symbols()[callee_symbol_id]; match callee_symbol { Symbol::Function(function_symbol) => { let arguments = call diff --git a/dvm-lib/src/vm/mod.rs b/dvm-lib/src/vm/mod.rs index 54124fc..7898d95 100644 --- a/dvm-lib/src/vm/mod.rs +++ b/dvm-lib/src/vm/mod.rs @@ -252,6 +252,12 @@ pub fn loop_instructions<'a>( { let instruction = &call_stack.top().instructions()[call_stack.top().ip()]; if debug { + if let Some(top) = call_stack.maybe_top() { + println!("-- before instruction --"); + println!(" stack: {:?}", top.stack()); + println!(" registers: {:?}", registers); + println!(" rv: {:?}", top.return_value()); + } println!("{}", instruction); } @@ -717,6 +723,7 @@ pub fn loop_instructions<'a>( if debug { if let Some(top) = call_stack.maybe_top() { + println!("-- after instruction -- "); println!(" stack: {:?}", top.stack()); println!(" registers: {:?}", registers); println!(" rv: {:?}", top.return_value());