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}; use std::path::PathBuf; #[derive(Debug, Parser)] #[command(name = "dm", about = "Deimos", version = "0.1.0", long_about = None)] struct Cli { script: PathBuf, #[arg(long)] show_asm: bool, #[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!(); } }; let mut symbol_table = SymbolTable::new(); let gather_names_diagnostics = compilation_unit.gather_declared_names(&mut symbol_table); check_and_report_diagnostics(&files, script_file_id, &gather_names_diagnostics); let name_usages_diagnostics = compilation_unit.check_name_usages(&symbol_table); check_and_report_diagnostics(&files, script_file_id, &name_usages_diagnostics); let type_check_diagnostics = compilation_unit.type_check(&symbol_table); check_and_report_diagnostics(&files, script_file_id, &type_check_diagnostics); 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 = 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 = 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() { 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); } }