//! rustnim — Rust -> Nim transpiler. //! //! Usage: rustnim [-o ] mod fmt; mod lower; mod ty; use std::path::PathBuf; use std::process::ExitCode; fn main() -> ExitCode { match run() { Ok(()) => ExitCode::SUCCESS, Err(e) => { eprintln!("rustnim: {e}"); // Exiting non-zero on any failure is load-bearing: the entire // point of this project is that a transpiler must never report // success for work it did not do. ExitCode::FAILURE } } } fn run() -> Result<(), String> { let mut args = std::env::args_os().skip(1); let mut input: Option = None; let mut output: Option = None; while let Some(a) = args.next() { match a.to_string_lossy().as_ref() { "-o" | "--output" => { output = Some( args.next() .ok_or("`-o` needs a path")? .into(), ); } "-h" | "--help" => { println!("usage: rustnim [-o ]"); return Ok(()); } s if s.starts_with('-') => return Err(format!("unknown flag `{s}`")), _ => { if input.is_some() { return Err("more than one input file given".into()); } input = Some(a.into()); } } } let input = input.ok_or("no input file; usage: rustnim [-o ]")?; let src = std::fs::read_to_string(&input) .map_err(|e| format!("cannot read {}: {e}", input.display()))?; let file: syn::File = syn::parse_file(&src) .map_err(|e| format!("{}: parse error: {e}", input.display()))?; let nim = lower::Lowerer::new().lower_file(&file)?; match output { Some(p) => std::fs::write(&p, nim) .map_err(|e| format!("cannot write {}: {e}", p.display()))?, None => print!("{nim}"), } Ok(()) }