| Add the differential test runner, and a lowering to measure with it 8ac32af nandithebull 19h ago | 1 | //! rustnim — Rust -> Nim transpiler. |
| 2 | //! |
| 3 | //! Usage: rustnim <input.rs> [-o <output.nim>] |
| 4 | |
| 5 | mod fmt; |
| 6 | mod lower; |
| Settle signed-shr and unsigned-wrap semantics against both compilers 87c9cc8 nandi 20h ago | 7 | mod ty; |
| Add the differential test runner, and a lowering to measure with it 8ac32af nandithebull 19h ago | 8 | |
| 9 | use std::path::PathBuf; |
| 10 | use std::process::ExitCode; |
| 11 | |
| 12 | fn main() -> ExitCode { |
| 13 | match run() { |
| 14 | Ok(()) => ExitCode::SUCCESS, |
| 15 | Err(e) => { |
| 16 | eprintln!("rustnim: {e}"); |
| 17 | // Exiting non-zero on any failure is load-bearing: the entire |
| 18 | // point of this project is that a transpiler must never report |
| 19 | // success for work it did not do. |
| 20 | ExitCode::FAILURE |
| 21 | } |
| 22 | } |
| 23 | } |
| 24 | |
| 25 | fn run() -> Result<(), String> { |
| 26 | let mut args = std::env::args_os().skip(1); |
| 27 | let mut input: Option<PathBuf> = None; |
| 28 | let mut output: Option<PathBuf> = None; |
| 29 | |
| 30 | while let Some(a) = args.next() { |
| 31 | match a.to_string_lossy().as_ref() { |
| 32 | "-o" | "--output" => { |
| 33 | output = Some( |
| 34 | args.next() |
| 35 | .ok_or("`-o` needs a path")? |
| 36 | .into(), |
| 37 | ); |
| 38 | } |
| 39 | "-h" | "--help" => { |
| 40 | println!("usage: rustnim <input.rs> [-o <output.nim>]"); |
| 41 | return Ok(()); |
| 42 | } |
| 43 | s if s.starts_with('-') => return Err(format!("unknown flag `{s}`")), |
| 44 | _ => { |
| 45 | if input.is_some() { |
| 46 | return Err("more than one input file given".into()); |
| 47 | } |
| 48 | input = Some(a.into()); |
| 49 | } |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | let input = input.ok_or("no input file; usage: rustnim <input.rs> [-o <output.nim>]")?; |
| 54 | let src = std::fs::read_to_string(&input) |
| 55 | .map_err(|e| format!("cannot read {}: {e}", input.display()))?; |
| 56 | |
| 57 | let file: syn::File = syn::parse_file(&src) |
| 58 | .map_err(|e| format!("{}: parse error: {e}", input.display()))?; |
| 59 | |
| 60 | let nim = lower::Lowerer::new().lower_file(&file)?; |
| 61 | |
| 62 | match output { |
| 63 | Some(p) => std::fs::write(&p, nim) |
| 64 | .map_err(|e| format!("cannot write {}: {e}", p.display()))?, |
| 65 | None => print!("{nim}"), |
| 66 | } |
| 67 | Ok(()) |
| 68 | } |