nandi/rustnimpublic Fork 0
main
Commits
Clone
git clone https://git.rickub.com/nandi/rustnim.git
git clone ssh://git@rickub.com/nandi/rustnim.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

main.rs · 107 lines · 3.9 KBRust Blame HistoryRaw
Add the differential test runner, and a lowering to measure with it 8ac32af nandithebull 5h ago1//! rustnim — Rust -> Nim transpiler.
2//!
3//! Usage: rustnim <input.rs> [-o <output.nim>]
4
5mod fmt;
Lower `bitflags!` directly, checked against the real crate af6e50f nandithebull 1h ago6mod macros;
Expand `macro_rules!` rather than translating it to a Nim template 04eb29f nandithebull 52m ago7mod mrules;
Add the differential test runner, and a lowering to measure with it 8ac32af nandithebull 5h ago8mod lower;
Settle signed-shr and unsigned-wrap semantics against both compilers 87c9cc8 nandi 5h ago9mod ty;
Add the differential test runner, and a lowering to measure with it 8ac32af nandithebull 5h ago10
11use std::path::PathBuf;
12use std::process::ExitCode;
13
14fn main() -> ExitCode {
15 match run() {
16 Ok(()) => ExitCode::SUCCESS,
17 Err(e) => {
18 eprintln!("rustnim: {e}");
19 // Exiting non-zero on any failure is load-bearing: the entire
20 // point of this project is that a transpiler must never report
21 // success for work it did not do.
22 ExitCode::FAILURE
23 }
24 }
25}
26
27fn run() -> Result<(), String> {
28 let mut args = std::env::args_os().skip(1);
Add enums, Option/Result, `?`, and the machinery base16ct needs around them b0ccd80 nandithebull 4h ago29 let mut inputs: Vec<PathBuf> = Vec::new();
Add the differential test runner, and a lowering to measure with it 8ac32af nandithebull 5h ago30 let mut output: Option<PathBuf> = None;
Add enums, Option/Result, `?`, and the machinery base16ct needs around them b0ccd80 nandithebull 4h ago31 let mut features: Vec<String> = Vec::new();
Add the differential test runner, and a lowering to measure with it 8ac32af nandithebull 5h ago32
33 while let Some(a) = args.next() {
34 match a.to_string_lossy().as_ref() {
35 "-o" | "--output" => {
36 output = Some(
37 args.next()
38 .ok_or("`-o` needs a path")?
39 .into(),
40 );
41 }
Add enums, Option/Result, `?`, and the machinery base16ct needs around them b0ccd80 nandithebull 4h ago42 "--cfg" => {
43 let v = args.next().ok_or("`--cfg` needs an argument")?;
44 let v = v.to_string_lossy().into_owned();
45 let f = v
46 .strip_prefix("feature=")
47 .ok_or("only `--cfg feature=<name>` is supported")?;
48 features.push(f.trim_matches('"').to_string());
49 }
Add the differential test runner, and a lowering to measure with it 8ac32af nandithebull 5h ago50 "-h" | "--help" => {
Add enums, Option/Result, `?`, and the machinery base16ct needs around them b0ccd80 nandithebull 4h ago51 println!("usage: rustnim <input.rs>... [--cfg feature=<name>]... [-o <output.nim>]");
52 println!();
53 println!("Several inputs are concatenated into one Nim module, in the");
54 println!("order given. That is how a multi-file crate is handled: Nim");
55 println!("has no equivalent of Rust's per-file `mod`, so the items are");
56 println!("flattened. Names must not collide across the files.");
Add the differential test runner, and a lowering to measure with it 8ac32af nandithebull 5h ago57 return Ok(());
58 }
59 s if s.starts_with('-') => return Err(format!("unknown flag `{s}`")),
Add enums, Option/Result, `?`, and the machinery base16ct needs around them b0ccd80 nandithebull 4h ago60 _ => inputs.push(a.into()),
Add the differential test runner, and a lowering to measure with it 8ac32af nandithebull 5h ago61 }
62 }
63
Add enums, Option/Result, `?`, and the machinery base16ct needs around them b0ccd80 nandithebull 4h ago64 if inputs.is_empty() {
65 return Err("no input file; usage: rustnim <input.rs>... [-o <output.nim>]".into());
66 }
Add the differential test runner, and a lowering to measure with it 8ac32af nandithebull 5h ago67
Add enums, Option/Result, `?`, and the machinery base16ct needs around them b0ccd80 nandithebull 4h ago68 // Several files become one Nim module: Rust's `mod` has no Nim analogue
69 // inside a single output file, so the items are flattened in argument
70 // order. A name collision between two files is a Nim compile error, which
71 // is a loud failure rather than a silently shadowed definition.
Add closures and unsafe; base16ct's lower.rs and upper.rs go through 0a375d8 nandithebull 3h ago72 // The first input is the crate root; each later one is a module named by
73 // its file stem. That is what keeps `lower::decode` and `mixed::decode`
74 // apart once everything is flattened into a single Nim module.
75 let mut files = Vec::new();
76 for (i, input) in inputs.iter().enumerate() {
Add enums, Option/Result, `?`, and the machinery base16ct needs around them b0ccd80 nandithebull 4h ago77 let src = std::fs::read_to_string(input)
78 .map_err(|e| format!("cannot read {}: {e}", input.display()))?;
79 let parsed: syn::File = syn::parse_file(&src)
80 .map_err(|e| format!("{}: parse error: {e}", input.display()))?;
Add closures and unsafe; base16ct's lower.rs and upper.rs go through 0a375d8 nandithebull 3h ago81 let module = if i == 0 {
82 String::new()
83 } else {
84 input
85 .file_stem()
86 .map(|s| s.to_string_lossy().into_owned())
87 .unwrap_or_default()
88 };
89 files.push((module, parsed));
Add enums, Option/Result, `?`, and the machinery base16ct needs around them b0ccd80 nandithebull 4h ago90 }
Add the differential test runner, and a lowering to measure with it 8ac32af nandithebull 5h ago91
Add enums, Option/Result, `?`, and the machinery base16ct needs around them b0ccd80 nandithebull 4h ago92 let mut lowerer = lower::Lowerer::new();
93 lowerer.features = features;
Add trait impls and slice iterators; base16ct's decoder now goes through ae9f986 nandithebull 4h ago94 // A `mod x;` is satisfied when x.rs is one of the inputs.
95 lowerer.modules = inputs
96 .iter()
97 .filter_map(|p| p.file_stem().map(|s| s.to_string_lossy().into_owned()))
98 .collect();
Add closures and unsafe; base16ct's lower.rs and upper.rs go through 0a375d8 nandithebull 3h ago99 let nim = lowerer.lower_file(&files)?;
Add the differential test runner, and a lowering to measure with it 8ac32af nandithebull 5h ago100
101 match output {
102 Some(p) => std::fs::write(&p, nim)
103 .map_err(|e| format!("cannot write {}: {e}", p.display()))?,
104 None => print!("{nim}"),
105 }
106 Ok(())
107}