111 lines
3.1 KiB
Rust
111 lines
3.1 KiB
Rust
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<String>,
|
|
|
|
/// 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);
|
|
}
|
|
}
|