use std::{fs::read_to_string, path::PathBuf, process::exit}; use codespan_reporting::diagnostic::{Diagnostic, Label}; use codespan_reporting::files::SimpleFile; use codespan_reporting::term; use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; use crate::frontend::parser::Parser; use crate::frontend::sema::Sema; use crate::middle::builder::MirBuilder; use crate::middle::dce::eliminate_dead_code; use crate::middle::fold::fold_constants; use clap::Parser as ClapParser; pub mod backend; pub mod frontend; pub mod middle; use crate::backend::cranelift::CraneliftBackend; #[derive(ClapParser)] #[command(version, about, long_about = None)] struct Cli { /// The input source file to compile input: String, /// The output file path #[arg(short, long)] output: Option, /// Emit Cranelift IR instead of an object file #[arg(long)] emit_ir: bool, } fn main() { let cli = Cli::parse(); let content = read_to_string(&cli.input).unwrap_or_else(|err| { eprintln!("error: failed to read source file ({:?})", err); exit(1); }); let writer = StandardStream::stderr(ColorChoice::Always); let config = term::Config::default(); let file = SimpleFile::new(&cli.input, &content); let mut parser = Parser::new(&content); let module = parser.parse_module(); if let Some(errors) = parser.errors() { for error in errors { let diagnostic = Diagnostic::error() .with_message(error.message) .with_label(Label::primary((), error.span)); term::emit_to_write_style(&mut writer.lock(), &config, &file, &diagnostic).unwrap(); } exit(1); } let mut sema = Sema::new(); let typed_module = sema.analyze_module(&module); if let Some(errors) = sema.errors() { for error in errors { let diagnostic = Diagnostic::error() .with_message(error.message) .with_label(Label::primary((), error.span)); term::emit_to_write_style(&mut writer.lock(), &config, &file, &diagnostic).unwrap(); } exit(1); } let mut mir_module = MirBuilder::build(&typed_module); fold_constants(&mut mir_module); let warnings = eliminate_dead_code(&mut mir_module); for warning in warnings { let diagnostic = Diagnostic::warning() .with_message(warning.message) .with_label(Label::primary((), warning.span)); term::emit_to_write_style(&mut writer.lock(), &config, &file, &diagnostic).unwrap(); } let backend = CraneliftBackend::new(); let (ir, obj_bytes) = backend.compile_module(&mir_module); if cli.emit_ir { println!("{}", ir); } else { let output_path = cli.output.unwrap_or_else(|| { PathBuf::from(&cli.input) .with_extension("o") .to_string_lossy() .into_owned() }); std::fs::write(&output_path, obj_bytes).unwrap_or_else(|err| { eprintln!("error: failed to write object file: {:?}", err); exit(1); }); println!("Generated object file: {}", output_path); } }