use crate::common::to_csr_diagnostic; use codespan_reporting::files::SimpleFiles; use codespan_reporting::term::{Config, WriteStyle, emit_to_write_style}; use dmc_lib::SyntheticFunctionSession; use dmc_lib::constants_table::ConstantsTable; use dmc_lib::diagnostic::Diagnostics; 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::{BufRead, Write}; pub fn repl( read: &mut impl BufRead, out: &mut impl Write, err: &mut impl WriteStyle, register_count: usize, ) { let diagnostics_config = Config::default(); let mut files: SimpleFiles<&str, String> = SimpleFiles::new(); let mut current_file_id; 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"); analysis_context.push_scope("__repl_body_scope"); let mut constants_table = ConstantsTable::new(); let mut dvm_context = DvmContext::new(); let mut repl_fn_stack_locals: Vec = Vec::new(); 'repl: loop { write!(out, "> ").unwrap(); out.flush().unwrap(); read.read_line(&mut buffer).unwrap(); let input = buffer.trim(); if input.is_empty() { buffer.clear(); 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); } Err(diagnostics) => { current_file_id = files.add("input", String::from(input)); for diagnostic in diagnostics { let csr_diagnostic = to_csr_diagnostic(current_file_id, &diagnostic); emit_to_write_style(err, &diagnostics_config, &files, &csr_diagnostic).unwrap(); } 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 { writeln!(out, "{}", value).unwrap(); } buffer.clear(); } } fn compile_statement( input: &str, session: &mut SyntheticFunctionSession, register_count: usize, constants_table: &mut ConstantsTable, ) -> Result { let maybe_statement = parse_statement(input); if !maybe_statement.is_ok() { Err(maybe_statement.into_diagnostics()) } else { session.compile_statement( &maybe_statement.into_inner(), register_count, constants_table, ) } }