1use std::fs::File;
16use std::path::{Path, PathBuf};
17use std::process::ExitCode;
18
19use llvmkit_asmparser::ll_parser::Parser;
20use llvmkit_asmparser::parse_error::ParseError;
21use llvmkit_asmparser::read_to_owned;
22use llvmkit_ir::Module;
23use llvmkit_support::{SourceMap, Span};
24
25fn main() -> ExitCode {
26 let Some(path) = std::env::args_os().nth(1).map(PathBuf::from) else {
27 eprintln!("usage: parse_file <path/to/file.ll>");
28 return ExitCode::from(2);
29 };
30
31 let bytes = match File::open(&path).and_then(read_to_owned) {
34 Ok(b) => b,
35 Err(e) => {
36 eprintln!("error: cannot read {}: {e}", path.display());
37 return ExitCode::from(1);
38 }
39 };
40
41 let module_name = path.file_stem().and_then(|s| s.to_str()).unwrap_or("input");
44 Module::with_new::<_, _, _>(module_name, |module| {
45 let parser = match Parser::new(&bytes, &module) {
46 Ok(p) => p,
47 Err(err) => {
48 report_error(&path, &bytes, &err);
49 return ExitCode::from(1);
50 }
51 };
52
53 match parser.parse_module() {
54 Ok(_parsed) => {
55 print!("{module}");
59 ExitCode::SUCCESS
60 }
61 Err(err) => {
62 report_error(&path, &bytes, &err);
63 ExitCode::from(1)
64 }
65 }
66 })
67}
68
69fn report_error(path: &Path, src: &[u8], err: &ParseError) {
70 let sm = SourceMap::new(src);
71 let span = err.loc().map(|l| l.span).unwrap_or(Span::new(0, 0));
72 let (line, col) = sm.line_col(span.start);
73 eprintln!("{path}:{line}:{col}: {err}", path = path.display());
74 if let Some(line_bytes) = sm.line_text(line) {
75 eprintln!(" | {}", String::from_utf8_lossy(line_bytes));
76 let underline_len = (span.end.saturating_sub(span.start) as usize).max(1);
77 eprintln!(
78 " | {pad}{caret}",
79 pad = " ".repeat((col - 1) as usize),
80 caret = "^".repeat(underline_len)
81 );
82 }
83}