119 lines
4.0 KiB
Rust
119 lines
4.0 KiB
Rust
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<Operand> = 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<Function, Diagnostics> {
|
|
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,
|
|
)
|
|
}
|
|
}
|