diff --git a/dm/src/main.rs b/dm/src/main.rs index e5fadc9..c58a42b 100644 --- a/dm/src/main.rs +++ b/dm/src/main.rs @@ -1,5 +1,7 @@ +mod repl; mod run; +use crate::repl::repl; use crate::run::run; use clap::{Parser, Subcommand}; use std::path::PathBuf; @@ -25,6 +27,10 @@ enum SubCommand { #[arg(long, default_value = "8")] register_count: usize, }, + Repl { + #[arg(long, default_value = "8")] + register_count: usize, + }, } fn main() { @@ -38,5 +44,8 @@ fn main() { } => { run(script, *show_asm, *show_ir, *register_count); } + SubCommand::Repl { register_count } => { + repl(*register_count); + } } } diff --git a/dm/src/repl.rs b/dm/src/repl.rs new file mode 100644 index 0000000..a162179 --- /dev/null +++ b/dm/src/repl.rs @@ -0,0 +1,140 @@ +use dmc_lib::ast::ir_builder::IrBuilder; +use dmc_lib::constants_table::ConstantsTable; +use dmc_lib::diagnostic::Diagnostic; +use dmc_lib::ir::ir_function::IrFunction; +use dmc_lib::ir::ir_return::IrReturn; +use dmc_lib::ir::ir_statement::IrStatement; +use dmc_lib::lexer::Lexer; +use dmc_lib::parser::parse_expression; +use dmc_lib::symbol::FunctionSymbol; +use dmc_lib::symbol_table::SymbolTable; +use dmc_lib::token::TokenKind; +use dvm_lib::vm::constant::{Constant, StringConstant}; +use dvm_lib::vm::function::Function; +use dvm_lib::vm::value::Value; +use dvm_lib::vm::{CallStack, DvmContext, call}; +use std::cell::RefCell; +use std::io; +use std::io::Write; +use std::rc::Rc; + +pub fn repl(register_count: usize) { + let mut buffer = String::new(); + + let mut constants_table = ConstantsTable::new(); + let mut context = DvmContext::new(); + + 'repl: loop { + print!("> "); + io::stdout().flush().unwrap(); + io::stdin().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 => { + todo!("Parse let statements in repl") + } + _ => match compile_expression(input, register_count, &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 registers = vec![Value::Null; register_count]; + let mut call_stack = CallStack::new(); + + let result = call(&context, &mut registers, &mut call_stack, "__repl", &[]); + if let Some(value) = result { + println!("{}", value); + } + + buffer.clear(); + } +} + +fn compile_expression( + input: &str, + register_count: usize, + constants_table: &mut ConstantsTable, +) -> Result> { + let parse_result = parse_expression(input); + let mut expression = parse_result?; + + let mut symbol_table = SymbolTable::new(); + // "fake" scope + symbol_table.push_scope("__repl_enter"); + expression.gather_declared_names(&mut symbol_table)?; + symbol_table.pop_scope(); + + expression.check_name_usages(&symbol_table)?; + expression.type_check(&symbol_table)?; + + // synthesize a function + let mut ir_builder = IrBuilder::new(); + let entry_block_id = ir_builder.new_block(); + + let maybe_ir_expression = expression.to_ir(&mut ir_builder, &symbol_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); + + // synthesize symbol + let fake_function_symbol = Rc::new(RefCell::new(FunctionSymbol::new( + "__repl", + false, + expression.type_info().clone(), // dubious + ))); + let mut ir_function = IrFunction::new( + fake_function_symbol, + &[], + expression.type_info(), + entry_block.clone(), + ); + + let (_, stack_size) = ir_function.assign_registers(register_count); + Ok(ir_function.assemble(stack_size, constants_table)) +}