187 lines
5.9 KiB
Rust
187 lines
5.9 KiB
Rust
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<Diagnostic>> {
|
|
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<Function> = 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::<Vec<_>>();
|
|
|
|
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<Label<usize>> = 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);
|
|
}
|