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::diagnostic::Diagnostics; use dmc_lib::ir::variable_locations::VariableLocations; use dmc_lib::lexer::Lexer; use dmc_lib::parser::{parse_expression, parse_let_statement}; use dmc_lib::semantic_analysis::analysis_context::AnalysisContext; 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::io; use std::io::{BufRead, Write}; use std::rc::Rc; // // pub fn repl(read: &mut impl BufRead, register_count: usize) { // let mut buffer = String::new(); // // let mut symbol_table = SymbolTable::new(); // let mut types_table = TypesTable::new(); // // let mut repl_fn_body_scope_id: Option = None; // let mut repl_fn_offset_counter = OffsetCounter::new(); // let mut repl_fn_local_variables = HashMap::new(); // // let mut constants_table = ConstantsTable::new(); // let mut context = DvmContext::new(); // // let mut repl_fn_stack_locals: Vec = vec![]; // // '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; // } // }, // }; // // match first_token.kind() { // TokenKind::Fn => { // todo!("Parse functions in repl") // } // TokenKind::Let => { // match compile_let_statement( // input, // register_count, // &mut symbol_table, // &mut repl_fn_body_scope_id, // &mut repl_fn_offset_counter, // &mut repl_fn_local_variables, // &mut types_table, // &mut constants_table, // ) { // Ok(function) => { // context // .functions_mut() // .insert(function.name_owned(), function); // } // Err(diagnostics) => { // for diagnostic in diagnostics { // eprintln!("{}", diagnostic.message()); // } // buffer.clear(); // continue 'repl; // } // } // } // _ => match compile_expression( // input, // register_count, // &mut symbol_table, // &mut types_table, // &mut repl_fn_body_scope_id, // &mut repl_fn_local_variables, // &mut repl_fn_offset_counter, // &mut constants_table, // ) { // Ok(function) => { // context // .functions_mut() // .insert(function.name_owned(), function); // } // Err(diagnostics) => { // for diagnostic in &diagnostics { // eprintln!("{}", diagnostic.message()); // } // buffer.clear(); // continue 'repl; // } // }, // } // // for (name, content) in constants_table.string_constants() { // context.constants_mut().insert( // name.clone(), // Constant::String(StringConstant::new(name, content)), // ); // } // // let mut call_stack = CallStack::new(); // prepare_for_instruction_loop(&context, "__repl", &mut call_stack, &[]); // // // copy all old locals to current call frame's stack // // this has to be done with indexing because the preparation above creates space for them // for (i, operand) in repl_fn_stack_locals.iter().enumerate() { // let target_index = call_stack.top().fp() + i; // call_stack.top_mut().stack_mut()[target_index] = operand.clone(); // } // // let result = loop_instructions( // &context, // &mut vec![Operand::Null; register_count], // &mut call_stack, // ); // // // copy the top frame's stack locals back to OUR stack locals for next iteration // repl_fn_stack_locals = std::mem::take(call_stack.top_mut().stack_mut()); // // if let Some(value) = result { // println!("{}", value); // } // // buffer.clear(); // } // } // // fn prepare_scopes(symbol_table: &mut SymbolTable, fn_body_scope_id: &mut Option) -> usize { // if let Some(scope_id) = fn_body_scope_id { // symbol_table.change_scope(*scope_id); // *scope_id // } else { // symbol_table.push_module_scope("__repl_module"); // symbol_table.push_function_scope("__repl_fn"); // let container_scope_id = symbol_table.push_block_scope("__repl_fn_body"); // fn_body_scope_id.replace(container_scope_id); // container_scope_id // } // } // // fn compile_expression( // input: &str, // register_count: usize, // symbol_table: &mut SymbolTable, // types_table: &mut TypesTable, // fn_body_scope_id: &mut Option, // fn_local_variables: &HashMap, Rc>>, // offset_counter: &mut OffsetCounter, // constants_table: &mut ConstantsTable, // ) -> Result> { // // // parse // // let (mut expression, parse_diagnostics) = parse_expression(input); // // if !parse_diagnostics.is_empty() { // // return Err(parse_diagnostics); // // } // // // // // init scopes, if necessary // // let container_scope = prepare_scopes(symbol_table, fn_body_scope_id); // // // // // inner scopes // // expression.init_scopes(symbol_table, container_scope); // // // // // names // // let diagnostics = expression.check_static_fn_local_names(&symbol_table); // // if !diagnostics.is_empty() { // // return Err(diagnostics); // // } // // // // // type check // // expression.type_check(&symbol_table, types_table)?; // // // // // synthesize a function // // // init ir_builder // // let mut ir_builder = IrBuilder::new(); // // // // // copy all previous declared variables to here so we preserve their stack offsets // // for (key, value) in fn_local_variables { // // ir_builder // // .local_variables_mut() // // .insert(key.clone(), value.clone()); // // } // // // // let entry_block_id = ir_builder.new_block(); // // // // let maybe_ir_expression = // // expression.to_ir_expression(&mut ir_builder, &symbol_table, &types_table); // // // // // if Some, return the value // // ir_builder // // .current_block_mut() // // .add_statement(IrStatement::Return(IrReturn::new(maybe_ir_expression))); // // // // ir_builder.finish_block(); // // let entry_block = ir_builder.get_block(entry_block_id); // // // // let mut ir_function = IrFunction::new( // // "__repl".into(), // // vec![], // // expression.type_info(&symbol_table, &types_table), // // entry_block.clone(), // // ); // // // // // 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); // // // // Ok(ir_function.assemble(offset_counter.get_count(), constants_table)) // todo!() // } // // fn compile_let_statement( // input: &str, // register_count: usize, // symbol_table: &mut SymbolTable, // body_scope_id: &mut Option, // offset_counter: &mut OffsetCounter, // local_variables: &mut HashMap, Rc>>, // types_table: &mut TypesTable, // constants_table: &mut ConstantsTable, // ) -> Result> { // // // parse // // 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(); analysis_context.push_scope("__repl_root_scope"); analysis_context.push_scope("__repl_function_scope"); analysis_context.push_scope("__repl_body_scope"); let fqn: Rc = 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 = 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; } }, }; match first_token.kind() { TokenKind::Let => { let compile_result = compile_let_statement_2( input, &mut analysis_context, &fqn, &mut variable_locations, register_count, &mut constants_table, ); match compile_result { Ok(function) => { dvm_context .functions_mut() .insert(function.name_owned(), function); } Err(diagnostics) => { for diagnostic in diagnostics { eprintln!("{}", diagnostic.message()); } buffer.clear(); continue 'repl; } } } _ => { let compile_result = compile_expression_2( input, &mut analysis_context, &fqn, &mut variable_locations, register_count, &mut constants_table, ); match compile_result { Ok(function) => { dvm_context .functions_mut() .insert(function.name_owned(), function); } Err(diagnostics) => { for diagnostic in diagnostics { eprintln!("{}", diagnostic.message()); } buffer.clear(); continue 'repl; } } } } for (name, content) in constants_table.string_constants() { dvm_context.constants_mut().insert( name.clone(), Constant::String(StringConstant::new(name, content)), ); } let mut call_stack = CallStack::new(); prepare_for_instruction_loop(&dvm_context, "__repl", &mut call_stack, &[]); // copy all old locals to current call frame's stack // this has to be done with indexing because the preparation above creates space for them for (i, operand) in repl_fn_stack_locals.iter().enumerate() { let target_index = call_stack.top().fp() + i; call_stack.top_mut().stack_mut()[target_index] = operand.clone(); } let result = loop_instructions( &dvm_context, &mut vec![Operand::Null; register_count], &mut call_stack, ); // copy the top frame's stack locals back to OUR stack locals for next iteration repl_fn_stack_locals = std::mem::take(call_stack.top_mut().stack_mut()); if let Some(value) = result { println!("{}", value); } buffer.clear(); } } fn compile_expression_2( input: &str, analysis_context: &mut AnalysisContext, fqn: &Rc, variable_locations: &mut VariableLocations, register_count: usize, constants_table: &mut ConstantsTable, ) -> Result { let (expression, parse_diagnostics) = parse_expression(input); if !parse_diagnostics.is_empty() { return Err(parse_diagnostics); } let statement = Statement::Expression(ExpressionStatement::new(0, expression)); compile_statement_to_synthetic_function( &statement, analysis_context, fqn.clone(), variable_locations, register_count, constants_table, ) } fn compile_let_statement_2( input: &str, analysis_context: &mut AnalysisContext, fqn: &Rc, variable_locations: &mut VariableLocations, register_count: usize, constants_table: &mut ConstantsTable, ) -> Result { let (maybe_let_statement, parse_diagnostics) = parse_let_statement(input); if !parse_diagnostics.is_empty() { return Err(parse_diagnostics); } compile_statement_to_synthetic_function( &Statement::Let(maybe_let_statement.unwrap()), analysis_context, fqn.clone(), variable_locations, register_count, constants_table, ) }