From c1447444cca405fdc411420c7f3bf5b9587e6e43 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Sat, 8 Aug 2026 13:40:28 -0500 Subject: [PATCH] Repl clean up. --- dm/src/main.rs | 9 +- dm/src/repl.rs | 397 ++++-------------------------------------- dmc-lib/src/parser.rs | 10 ++ 3 files changed, 48 insertions(+), 368 deletions(-) diff --git a/dm/src/main.rs b/dm/src/main.rs index ef67dd6..51a233e 100644 --- a/dm/src/main.rs +++ b/dm/src/main.rs @@ -1,7 +1,7 @@ mod repl; mod run; -use crate::repl::repl_2; +use crate::repl::repl; use crate::run::compile_and_run_script; use clap::{Parser, Subcommand}; use std::io; @@ -44,7 +44,12 @@ fn main() { compile_and_run_script(script, *show_asm, *show_ir, register_count); } SubCommand::Repl => { - repl_2(&mut io::stdin().lock(), register_count); + repl( + &mut io::stdin().lock(), + &mut io::stdout().lock(), + &mut io::stderr().lock(), + register_count, + ); } } } diff --git a/dm/src/repl.rs b/dm/src/repl.rs index c0525ac..dda915b 100644 --- a/dm/src/repl.rs +++ b/dm/src/repl.rs @@ -1,304 +1,23 @@ use dmc_lib::SyntheticFunctionSession; -use dmc_lib::ast::expression_statement::ExpressionStatement; -use dmc_lib::ast::statement::Statement; use dmc_lib::constants_table::ConstantsTable; use dmc_lib::diagnostic::Diagnostics; -use dmc_lib::lexer::Lexer; -use dmc_lib::parser::{parse_expression, parse_let_statement}; -use dmc_lib::token::TokenKind; +use dmc_lib::parser::parse_statement; 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}; -// -// 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) { +pub fn repl( + read: &mut impl BufRead, + out: &mut impl Write, + err: &mut impl Write, + register_count: usize, +) { let mut buffer = String::new(); let mut session = SyntheticFunctionSession::new("__repl"); + let analysis_context = session.ctx_mut(); analysis_context.push_scope("__repl_root_scope"); analysis_context.push_scope("__repl_function_scope"); @@ -310,8 +29,9 @@ pub fn repl_2(read: &mut impl BufRead, register_count: usize) { let mut repl_fn_stack_locals: Vec = Vec::new(); 'repl: loop { - print!("> "); - io::stdout().flush().unwrap(); + write!(out, "> ").unwrap(); + out.flush().unwrap(); + read.read_line(&mut buffer).unwrap(); let input = buffer.trim(); if input.is_empty() { @@ -319,61 +39,20 @@ pub fn repl_2(read: &mut impl BufRead, register_count: usize) { continue; } - let mut lexer = Lexer::new(input); - let first_token = match lexer.next() { - None => { - continue; + let compile_result = + compile_statement(input, &mut session, register_count, &mut constants_table); + match compile_result { + Ok(function) => { + dvm_context + .functions_mut() + .insert(function.name_owned(), function); } - 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 session, - 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 session, 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; - } + Err(diagnostics) => { + for diagnostic in diagnostics { + writeln!(err, "{}", diagnostic.message()).unwrap(); } + buffer.clear(); + continue 'repl; } } @@ -404,39 +83,25 @@ pub fn repl_2(read: &mut impl BufRead, register_count: usize) { repl_fn_stack_locals = std::mem::take(call_stack.top_mut().stack_mut()); if let Some(value) = result { - println!("{}", value); + writeln!(out, "{}", value).unwrap(); } buffer.clear(); } } -fn compile_expression_2( +fn compile_statement( input: &str, session: &mut SyntheticFunctionSession, register_count: usize, constants_table: &mut ConstantsTable, ) -> Result { - let (expression, parse_diagnostics) = parse_expression(input); + let (maybe_statement, parse_diagnostics) = parse_statement(input); if !parse_diagnostics.is_empty() { - return Err(parse_diagnostics); + Err(parse_diagnostics) + } else if let Some(statement) = maybe_statement { + session.compile_statement(&statement, register_count, constants_table) + } else { + panic!("Unable to unwrap statement from previous input.") } - - let statement = Statement::Expression(ExpressionStatement::new(0, expression)); - - session.compile_statement(&statement, register_count, constants_table) -} - -fn compile_let_statement_2( - input: &str, - session: &mut SyntheticFunctionSession, - 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); - } - let statement = Statement::Let(maybe_let_statement.unwrap()); - session.compile_statement(&statement, register_count, constants_table) } diff --git a/dmc-lib/src/parser.rs b/dmc-lib/src/parser.rs index d10fd6c..1beb902 100644 --- a/dmc-lib/src/parser.rs +++ b/dmc-lib/src/parser.rs @@ -53,6 +53,15 @@ pub fn parse_compilation_unit( (compilation_unit, diagnostics) } +pub fn parse_statement(input: &str) -> ParseResult> { + let mut parser = Parser::new(input); + let mut diagnostics = Diagnostics::new(); + diagnostics.append(&mut parser.advance()); + let (statement, mut ds) = parser.statement(); + diagnostics.append(&mut ds); + (statement, diagnostics) +} + pub fn parse_expression(input: &str) -> ParseResult { let mut parser = Parser::new(input); let mut diagnostics = Vec::new(); @@ -62,6 +71,7 @@ pub fn parse_expression(input: &str) -> ParseResult { (expression, diagnostics) } +#[deprecated] pub fn parse_let_statement(input: &str) -> ParseResult> { let mut parser = Parser::new(input); let mut diagnostics = Vec::new();