use std::fs;
use std::path::{Path, PathBuf};
use std::process::exit;
use masl_compiler::{CompileError, compile};
use crate::diagnostics::print_diagnostics;
pub fn compile_file(file: &Path, output: Option<&Path>) -> Result<(), ()> {
let source = match fs::read_to_string(file) {
Ok(s) => s,
Err(e) => {
eprintln!("Error reading file {}: {}", file.display(), e);
return Err(());
}
};
match compile(&source) {
Ok(bytes) => {
let out_path = resolve_output_path(file, output);
if let Err(e) = fs::write(&out_path, bytes) {
eprintln!("Error writing output {}: {}", out_path.display(), e);
return Err(());
}
println!(
"Successfully compiled {} to {}",
file.display(),
out_path.display()
);
Ok(())
}
Err(e) => {
let diags = extract_diagnostics(e);
print_diagnostics(&diags, &source, file.to_str().unwrap_or(""));
Err(())
}
}
}
fn resolve_output_path(file: &Path, output: Option<&Path>) -> PathBuf {
if let Some(out) = output {
if out.is_dir() {
let mut p = out.to_path_buf();
p.push(file.file_name().unwrap_or_default());
p.set_extension("mdkc");
p
} else {
out.to_path_buf()
}
} else {
let mut p = file.to_path_buf();
p.set_extension("mdkc");
p
}
}
fn extract_diagnostics(e: CompileError) -> Vec<masl_diagnostics::diagnostic::Diagnostic> {
match e {
CompileError::ParseFailed(d) => d,
CompileError::AnalysisFailed(d) => d,
CompileError::ValidationFailed(d) => d,
CompileError::LoweringFailed(d) => d,
CompileError::BytecodeFailed(d) => d,
}
}
pub fn run(path: PathBuf, output: Option<PathBuf>) {
if path.is_dir() {
if let Some(ref out) = output {
let _ = fs::create_dir_all(out);
}
let mut success = true;
let read_dir = match fs::read_dir(&path) {
Ok(rd) => rd,
Err(e) => {
eprintln!("Error reading directory {}: {}", path.display(), e);
exit(1);
}
};
for entry in read_dir {
let file_path = entry.unwrap().path();
if file_path.is_file()
&& file_path.extension().is_some_and(|ext| ext == "mdk")
&& compile_file(&file_path, output.as_deref()).is_err()
{
success = false;
}
}
if !success {
exit(1);
}
} else if compile_file(&path, output.as_deref()).is_err() {
exit(1);
}
}