Make run subcommand.

This commit is contained in:
Jesse Brault 2026-03-09 20:22:27 -05:00
parent ebca87ddb9
commit b88b230495
2 changed files with 173 additions and 148 deletions

View File

@ -1,163 +1,42 @@
use clap::Parser;
use codespan_reporting::diagnostic::Label;
use codespan_reporting::files::SimpleFiles;
use codespan_reporting::term;
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
use dm_std_lib::add_all_std_core;
use dmc_lib::constants_table::ConstantsTable;
use dmc_lib::diagnostic::Diagnostic;
use dmc_lib::parser::parse_compilation_unit;
use dmc_lib::symbol_table::SymbolTable;
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};
mod run;
use crate::run::run;
use clap::{Parser, Subcommand};
use std::path::PathBuf;
#[derive(Debug, Parser)]
#[command(name = "dm", about = "Deimos", version = "0.1.0", long_about = None)]
struct Cli {
script: PathBuf,
#[command(subcommand)]
sub_command: SubCommand,
}
#[arg(long)]
show_asm: bool,
#[derive(Debug, Subcommand)]
enum SubCommand {
Run {
script: PathBuf,
#[arg(long)]
show_ir: bool,
#[arg(long)]
show_asm: bool,
#[arg(long, default_value = "8")]
register_count: usize,
#[arg(long)]
show_ir: bool,
#[arg(long, default_value = "8")]
register_count: usize,
},
}
fn main() {
let args = Cli::parse();
let input = std::fs::read_to_string(&args.script).unwrap();
let mut files: SimpleFiles<&str, &str> = SimpleFiles::new();
let script_file_id = files.add(args.script.to_str().unwrap(), &input);
let parse_result = parse_compilation_unit(&input);
let mut compilation_unit = match parse_result {
Ok(compilation_unit) => compilation_unit,
Err(diagnostics) => {
check_and_report_diagnostics(&files, script_file_id, &diagnostics);
unreachable!();
match &args.sub_command {
SubCommand::Run {
script,
show_asm,
show_ir,
register_count,
} => {
run(script, *show_asm, *show_ir, *register_count);
}
};
let mut symbol_table = SymbolTable::new();
match compilation_unit.gather_declared_names(&mut symbol_table) {
Ok(_) => {}
Err(diagnostics) => {
report_and_exit(&diagnostics, script_file_id, &files);
}
}
match compilation_unit.check_name_usages(&symbol_table) {
Ok(_) => {}
Err(diagnostics) => {
report_and_exit(&diagnostics, script_file_id, &files);
}
}
match compilation_unit.type_check(&symbol_table) {
Ok(_) => {}
Err(diagnostics) => {
report_and_exit(&diagnostics, script_file_id, &files);
}
}
let mut ir_functions = compilation_unit.to_ir(&symbol_table);
if args.show_ir {
for ir_function in &ir_functions {
println!("{}", ir_function);
}
}
let mut functions: Vec<Function> = vec![];
let mut constants_table = ConstantsTable::new();
for ir_function in &mut ir_functions {
let (_, stack_size) = ir_function.assign_registers(args.register_count);
let function = ir_function.assemble(stack_size, &mut constants_table);
functions.push(function);
}
if args.show_asm {
for function in &functions {
println!("{}", function);
}
}
let mut dvm_context = DvmContext::new();
// add std::core fns
add_all_std_core(&mut dvm_context);
for function in functions {
dvm_context
.functions_mut()
.insert(function.name_owned(), function);
}
for (name, content) in &constants_table.string_constants() {
dvm_context.constants_mut().insert(
name.clone(),
Constant::String(StringConstant::new(name.clone(), content.clone())),
);
}
let mut registers: Vec<Value> = vec![Value::Null; args.register_count];
let mut call_stack = CallStack::new();
let result = call(
&dvm_context,
&mut registers,
&mut call_stack,
"main",
&vec![],
);
if let Some(value) = result {
println!("{}", value);
}
}
fn check_and_report_diagnostics(
files: &SimpleFiles<&str, &str>,
script_file_id: usize,
diagnostics: &[Diagnostic],
) {
if !diagnostics.is_empty() {
report_and_exit(diagnostics, script_file_id, files);
}
}
fn report_and_exit(
diagnostics: &[Diagnostic],
script_file_id: usize,
files: &SimpleFiles<&str, &str>,
) -> ! {
let writer = StandardStream::stderr(ColorChoice::Always);
let config = term::Config::default();
for diagnostic in diagnostics {
let csr_diagnostic = codespan_reporting::diagnostic::Diagnostic::error()
.with_message(diagnostic.message())
.with_label(Label::primary(
script_file_id,
diagnostic.start()..diagnostic.end(),
));
term::emit_to_write_style(&mut writer.lock(), &config, files, &csr_diagnostic).unwrap();
}
if diagnostics.len() == 1 {
eprintln!("There was 1 diagnostic. See above for more information.");
} else {
eprintln!(
"There were {} diagnostics. See above for more information.",
diagnostics.len()
);
}
std::process::exit(1);
}

146
dm/src/run.rs Normal file
View File

@ -0,0 +1,146 @@
use codespan_reporting::diagnostic::Label;
use codespan_reporting::files::SimpleFiles;
use codespan_reporting::term;
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
use dm_std_lib::add_all_std_core;
use dmc_lib::constants_table::ConstantsTable;
use dmc_lib::diagnostic::Diagnostic;
use dmc_lib::parser::parse_compilation_unit;
use dmc_lib::symbol_table::SymbolTable;
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::path::PathBuf;
pub fn run(script: &PathBuf, show_ir: bool, show_asm: bool, register_count: usize) {
let input = std::fs::read_to_string(script).unwrap();
let mut files: SimpleFiles<&str, &str> = SimpleFiles::new();
let script_file_id = files.add(script.to_str().unwrap(), &input);
let parse_result = parse_compilation_unit(&input);
let mut compilation_unit = match parse_result {
Ok(compilation_unit) => compilation_unit,
Err(diagnostics) => {
check_and_report_diagnostics(&files, script_file_id, &diagnostics);
unreachable!();
}
};
let mut symbol_table = SymbolTable::new();
match compilation_unit.gather_declared_names(&mut symbol_table) {
Ok(_) => {}
Err(diagnostics) => {
report_and_exit(&diagnostics, script_file_id, &files);
}
}
match compilation_unit.check_name_usages(&symbol_table) {
Ok(_) => {}
Err(diagnostics) => {
report_and_exit(&diagnostics, script_file_id, &files);
}
}
match compilation_unit.type_check(&symbol_table) {
Ok(_) => {}
Err(diagnostics) => {
report_and_exit(&diagnostics, script_file_id, &files);
}
}
let mut ir_functions = compilation_unit.to_ir(&symbol_table);
if show_ir {
for ir_function in &ir_functions {
println!("{}", ir_function);
}
}
let mut functions: Vec<Function> = vec![];
let mut constants_table = ConstantsTable::new();
for ir_function in &mut ir_functions {
let (_, stack_size) = ir_function.assign_registers(register_count);
let function = ir_function.assemble(stack_size, &mut constants_table);
functions.push(function);
}
if show_asm {
for function in &functions {
println!("{}", function);
}
}
let mut dvm_context = DvmContext::new();
// add std::core fns
add_all_std_core(&mut dvm_context);
for function in functions {
dvm_context
.functions_mut()
.insert(function.name_owned(), function);
}
for (name, content) in &constants_table.string_constants() {
dvm_context.constants_mut().insert(
name.clone(),
Constant::String(StringConstant::new(name.clone(), content.clone())),
);
}
let mut registers: Vec<Value> = vec![Value::Null; register_count];
let mut call_stack = CallStack::new();
let result = call(
&dvm_context,
&mut registers,
&mut call_stack,
"main",
&vec![],
);
if let Some(value) = result {
println!("{}", value);
}
}
fn check_and_report_diagnostics(
files: &SimpleFiles<&str, &str>,
script_file_id: usize,
diagnostics: &[Diagnostic],
) {
if !diagnostics.is_empty() {
report_and_exit(diagnostics, script_file_id, files);
}
}
fn report_and_exit(
diagnostics: &[Diagnostic],
script_file_id: usize,
files: &SimpleFiles<&str, &str>,
) -> ! {
let writer = StandardStream::stderr(ColorChoice::Always);
let config = term::Config::default();
for diagnostic in diagnostics {
let csr_diagnostic = codespan_reporting::diagnostic::Diagnostic::error()
.with_message(diagnostic.message())
.with_label(Label::primary(
script_file_id,
diagnostic.start()..diagnostic.end(),
));
term::emit_to_write_style(&mut writer.lock(), &config, files, &csr_diagnostic).unwrap();
}
if diagnostics.len() == 1 {
eprintln!("There was 1 diagnostic. See above for more information.");
} else {
eprintln!(
"There were {} diagnostics. See above for more information.",
diagnostics.len()
);
}
std::process::exit(1);
}