Add repl subcommand with expressions only.

This commit is contained in:
Jesse Brault 2026-03-09 21:11:09 -05:00
parent b88b230495
commit 705436ba61
2 changed files with 149 additions and 0 deletions

View File

@ -1,5 +1,7 @@
mod repl;
mod run; mod run;
use crate::repl::repl;
use crate::run::run; use crate::run::run;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use std::path::PathBuf; use std::path::PathBuf;
@ -25,6 +27,10 @@ enum SubCommand {
#[arg(long, default_value = "8")] #[arg(long, default_value = "8")]
register_count: usize, register_count: usize,
}, },
Repl {
#[arg(long, default_value = "8")]
register_count: usize,
},
} }
fn main() { fn main() {
@ -38,5 +44,8 @@ fn main() {
} => { } => {
run(script, *show_asm, *show_ir, *register_count); run(script, *show_asm, *show_ir, *register_count);
} }
SubCommand::Repl { register_count } => {
repl(*register_count);
}
} }
} }

140
dm/src/repl.rs Normal file
View File

@ -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<Function, Vec<Diagnostic>> {
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))
}