1use std::fs::File;
12use std::path::PathBuf;
13use std::process::ExitCode;
14
15use llvmkit_asmparser::ll_lexer::{LexError, Lexer};
16use llvmkit_asmparser::read_to_owned;
17use llvmkit_support::SourceMap;
18
19fn main() -> ExitCode {
20 let Some(path) = std::env::args_os().nth(1).map(PathBuf::from) else {
21 eprintln!("usage: lex_file <path/to/file.ll>");
22 return ExitCode::from(2);
23 };
24
25 let bytes = match File::open(&path).and_then(read_to_owned) {
27 Ok(b) => b,
28 Err(e) => {
29 eprintln!("error: cannot read {}: {e}", path.display());
30 return ExitCode::from(1);
31 }
32 };
33
34 let source_map = SourceMap::new(&bytes);
35 let mut lexer = Lexer::new(&bytes);
36 let mut count = 0usize;
37
38 loop {
39 match lexer.next_token() {
40 Ok(spanned) => {
41 let (l, c) = source_map.line_col(spanned.span.start);
42 println!(
43 "{path}:{l}:{c} ({s_start}..{s_end}) {tok:?}",
44 path = path.display(),
45 l = l,
46 c = c,
47 s_start = spanned.span.start,
48 s_end = spanned.span.end,
49 tok = spanned.value,
50 );
51 if matches!(spanned.value, llvmkit_asmparser::ll_token::Token::Eof) {
52 break;
53 }
54 count += 1;
55 }
56 Err(err) => {
57 report_error(&path, &source_map, &err);
58 return ExitCode::from(1);
59 }
60 }
61 }
62
63 eprintln!("{count} token(s) lexed");
64 ExitCode::SUCCESS
65}
66
67fn report_error(path: &std::path::Path, sm: &SourceMap<'_>, err: &LexError) {
68 let span = err.span();
69 let (l, c) = sm.line_col(span.start);
70 eprintln!("{path}:{l}:{c}: {err}", path = path.display());
71 if let Some(line) = sm.line_text(l) {
72 eprintln!(" | {}", String::from_utf8_lossy(line));
73 let underline_len = (span.end.saturating_sub(span.start) as usize).max(1);
74 eprintln!(
75 " | {pad}{caret}",
76 pad = " ".repeat((c - 1) as usize),
77 caret = "^".repeat(underline_len)
78 );
79 }
80}