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::intrinsics::{insert_intrinsic_symbols, insert_intrinsic_types}; use dmc_lib::offset_counter::OffsetCounter; use dmc_lib::parser::get_compilation_unit; use dmc_lib::symbol_table::SymbolTable; use dmc_lib::types_table::TypesTable; use dvm_lib::vm::constant::{Constant, StringConstant}; use dvm_lib::vm::function::Function; use dvm_lib::vm::{DvmContext, call}; use std::path::PathBuf; use std::rc::Rc; pub fn compile_and_run_script( 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); match run(&input, show_ir, show_asm, register_count) { Ok(_) => {} Err(diagnostics) => { check_and_report_diagnostics(&files, script_file_id, &diagnostics); } } } fn run( input: &str, show_ir: bool, show_asm: bool, register_count: usize, ) -> Result<(), Vec> { let mut compilation_unit = get_compilation_unit(&input, None)?; let mut symbol_table = SymbolTable::new(); symbol_table.push_module_scope("global scope"); insert_intrinsic_symbols(&mut symbol_table); let mut types_table = TypesTable::new(); insert_intrinsic_types(&symbol_table, &mut types_table); compilation_unit.init_scopes(&mut symbol_table); compilation_unit.gather_symbols_into(&mut symbol_table)?; compilation_unit.check_names(&mut symbol_table)?; compilation_unit.gather_types_into(&symbol_table, &mut types_table)?; compilation_unit.type_check(&symbol_table, &mut types_table)?; let (ir_classes, mut ir_functions) = compilation_unit.to_ir(&symbol_table, &types_table); if 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 mut offset_counter = OffsetCounter::new(); ir_function.assign_registers(register_count, &mut offset_counter); let function = ir_function.assemble(offset_counter.get_count(), &mut constants_table); functions.push(function); } let classes = ir_classes .iter() .map(|ir_class| ir_class.to_vm_class()) .collect::>(); 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 class in classes { dvm_context .classes_mut() .insert(class.fqn().into(), Rc::new(class)); } for (name, content) in &constants_table.string_constants() { dvm_context.constants_mut().insert( name.clone(), Constant::String(StringConstant::new(name.clone(), content.clone())), ); } let result = call(&dvm_context, "main", &vec![], register_count); if let Some(value) = result { println!("{}", value); } Ok(()) } 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 mut primary_label = Label::primary(script_file_id, diagnostic.start()..diagnostic.end()); if let Some(primary_label_message) = diagnostic.primary_label_message() { primary_label = primary_label.with_message(primary_label_message); } let secondary_labels: Vec> = diagnostic .secondary_labels() .iter() .map(|secondary_label| { let mut label = Label::secondary( script_file_id, secondary_label.start()..secondary_label.end(), ); if let Some(message) = secondary_label.message() { label = label.with_message(message); } label }) .collect(); let mut csr_diagnostic = codespan_reporting::diagnostic::Diagnostic::error() .with_message(diagnostic.message()) .with_label(primary_label) .with_labels(secondary_labels); if let Some(error_code) = diagnostic.error_code() { csr_diagnostic = csr_diagnostic.with_code(format!("E{:04}", error_code)); } if let Some((reporter_file, reporter_line)) = diagnostic.reporter() { csr_diagnostic = csr_diagnostic.with_note(format!( "Reported by (Rust) source: {}, line {}", reporter_file, reporter_line )); } 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); }