Repl clean up.

This commit is contained in:
Jesse Brault 2026-08-08 13:40:28 -05:00
parent 1e9a0ec993
commit c1447444cc
3 changed files with 48 additions and 368 deletions

View File

@ -1,7 +1,7 @@
mod repl; mod repl;
mod run; mod run;
use crate::repl::repl_2; use crate::repl::repl;
use crate::run::compile_and_run_script; use crate::run::compile_and_run_script;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use std::io; use std::io;
@ -44,7 +44,12 @@ fn main() {
compile_and_run_script(script, *show_asm, *show_ir, register_count); compile_and_run_script(script, *show_asm, *show_ir, register_count);
} }
SubCommand::Repl => { 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,
);
} }
} }
} }

View File

@ -1,304 +1,23 @@
use dmc_lib::SyntheticFunctionSession; 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::constants_table::ConstantsTable;
use dmc_lib::diagnostic::Diagnostics; use dmc_lib::diagnostic::Diagnostics;
use dmc_lib::lexer::Lexer; use dmc_lib::parser::parse_statement;
use dmc_lib::parser::{parse_expression, parse_let_statement};
use dmc_lib::token::TokenKind;
use dvm_lib::vm::constant::{Constant, StringConstant}; use dvm_lib::vm::constant::{Constant, StringConstant};
use dvm_lib::vm::function::Function; use dvm_lib::vm::function::Function;
use dvm_lib::vm::operand::Operand; use dvm_lib::vm::operand::Operand;
use dvm_lib::vm::{CallStack, DvmContext, loop_instructions, prepare_for_instruction_loop}; use dvm_lib::vm::{CallStack, DvmContext, loop_instructions, prepare_for_instruction_loop};
use std::io;
use std::io::{BufRead, Write}; 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<usize> = 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<Operand> = 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>) -> 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<usize>,
// fn_local_variables: &HashMap<Rc<VariableSymbol>, Rc<RefCell<IrVariable>>>,
// offset_counter: &mut OffsetCounter,
// constants_table: &mut ConstantsTable,
// ) -> Result<Function, Vec<Diagnostic>> {
// // // 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<usize>,
// offset_counter: &mut OffsetCounter,
// local_variables: &mut HashMap<Rc<VariableSymbol>, Rc<RefCell<IrVariable>>>,
// types_table: &mut TypesTable,
// constants_table: &mut ConstantsTable,
// ) -> Result<Function, Vec<Diagnostic>> {
// // // 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 buffer = String::new();
let mut session = SyntheticFunctionSession::new("__repl"); let mut session = SyntheticFunctionSession::new("__repl");
let analysis_context = session.ctx_mut(); let analysis_context = session.ctx_mut();
analysis_context.push_scope("__repl_root_scope"); analysis_context.push_scope("__repl_root_scope");
analysis_context.push_scope("__repl_function_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<Operand> = Vec::new(); let mut repl_fn_stack_locals: Vec<Operand> = Vec::new();
'repl: loop { 'repl: loop {
print!("> "); write!(out, "> ").unwrap();
io::stdout().flush().unwrap(); out.flush().unwrap();
read.read_line(&mut buffer).unwrap(); read.read_line(&mut buffer).unwrap();
let input = buffer.trim(); let input = buffer.trim();
if input.is_empty() { if input.is_empty() {
@ -319,47 +39,8 @@ pub fn repl_2(read: &mut impl BufRead, register_count: usize) {
continue; 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 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 = let compile_result =
compile_expression_2(input, &mut session, register_count, &mut constants_table); compile_statement(input, &mut session, register_count, &mut constants_table);
match compile_result { match compile_result {
Ok(function) => { Ok(function) => {
dvm_context dvm_context
@ -368,14 +49,12 @@ pub fn repl_2(read: &mut impl BufRead, register_count: usize) {
} }
Err(diagnostics) => { Err(diagnostics) => {
for diagnostic in diagnostics { for diagnostic in diagnostics {
eprintln!("{}", diagnostic.message()); writeln!(err, "{}", diagnostic.message()).unwrap();
} }
buffer.clear(); buffer.clear();
continue 'repl; continue 'repl;
} }
} }
}
}
for (name, content) in constants_table.string_constants() { for (name, content) in constants_table.string_constants() {
dvm_context.constants_mut().insert( dvm_context.constants_mut().insert(
@ -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()); repl_fn_stack_locals = std::mem::take(call_stack.top_mut().stack_mut());
if let Some(value) = result { if let Some(value) = result {
println!("{}", value); writeln!(out, "{}", value).unwrap();
} }
buffer.clear(); buffer.clear();
} }
} }
fn compile_expression_2( fn compile_statement(
input: &str, input: &str,
session: &mut SyntheticFunctionSession, session: &mut SyntheticFunctionSession,
register_count: usize, register_count: usize,
constants_table: &mut ConstantsTable, constants_table: &mut ConstantsTable,
) -> Result<Function, Diagnostics> { ) -> Result<Function, Diagnostics> {
let (expression, parse_diagnostics) = parse_expression(input); let (maybe_statement, parse_diagnostics) = parse_statement(input);
if !parse_diagnostics.is_empty() { if !parse_diagnostics.is_empty() {
return Err(parse_diagnostics); Err(parse_diagnostics)
} } else if let Some(statement) = maybe_statement {
let statement = Statement::Expression(ExpressionStatement::new(0, expression));
session.compile_statement(&statement, register_count, constants_table) session.compile_statement(&statement, register_count, constants_table)
} } else {
panic!("Unable to unwrap statement from previous input.")
fn compile_let_statement_2(
input: &str,
session: &mut SyntheticFunctionSession,
register_count: usize,
constants_table: &mut ConstantsTable,
) -> Result<Function, Diagnostics> {
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)
} }

View File

@ -53,6 +53,15 @@ pub fn parse_compilation_unit(
(compilation_unit, diagnostics) (compilation_unit, diagnostics)
} }
pub fn parse_statement(input: &str) -> ParseResult<Option<Statement>> {
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<Expression> { pub fn parse_expression(input: &str) -> ParseResult<Expression> {
let mut parser = Parser::new(input); let mut parser = Parser::new(input);
let mut diagnostics = Vec::new(); let mut diagnostics = Vec::new();
@ -62,6 +71,7 @@ pub fn parse_expression(input: &str) -> ParseResult<Expression> {
(expression, diagnostics) (expression, diagnostics)
} }
#[deprecated]
pub fn parse_let_statement(input: &str) -> ParseResult<Option<LetStatement>> { pub fn parse_let_statement(input: &str) -> ParseResult<Option<LetStatement>> {
let mut parser = Parser::new(input); let mut parser = Parser::new(input);
let mut diagnostics = Vec::new(); let mut diagnostics = Vec::new();