use std::process; use yansi::Paint as _; // ── Help ─────────────────────────────────────────────────────────────────────── pub fn print_help() { println!( "{} {} — the Flux language compiler\n", "fluxc".bold(), env!("CARGO_PKG_VERSION").dim(), ); println!("{}", "USAGE:".bold().yellow()); println!(" fluxc [OPTIONS] [ ...]\n"); println!("{}", "OPTIONS:".bold().yellow()); println!( " {}, {} Print this help message", "-h".bold(), "--help".bold(), ); println!( " {}, {} Print version information", "-V".bold(), "--version".bold(), ); println!( " {} Compile to object file (no `main` required, no linking)", "-c".bold(), ); println!( " {} Emit LLVM IR and stop (implies `-c`)", "-S".bold(), ); println!( " {} {} Write output to ", "-o".bold(), "".bold(), ); println!(); println!("{}", "ARGS:".bold().yellow()); println!( " {} One or more Flux source files to compile", "".bold(), ); } pub fn print_version() { println!("fluxc {}", env!("CARGO_PKG_VERSION")); } // ── Error helpers ───────────────────────────────────────────────────────────── pub fn fatal(msg: &str) -> ! { eprintln!("{}: {}", "error".bold().red(), msg.bold()); eprintln!(" {} fluxc --help", "hint:".bold().cyan()); process::exit(1); } pub fn io_error(path: &str, err: std::io::Error) -> ! { eprintln!( "{}: cannot read {}: {}", "error".bold().red(), path.bold(), err, ); process::exit(1); } // ── Argument parsing ────────────────────────────────────────────────────────── pub struct Opts { pub files: Vec, /// `-c`: compile to object file without requiring a `main` entry point. pub no_main: bool, /// `-S`: emit LLVM IR text and stop (implies `-c`). pub emit_ir: bool, /// `-o `: write final output to this path. pub output: Option, } pub fn parse_args() -> Opts { let mut files = Vec::new(); let mut no_main = false; let mut emit_ir = false; let mut output: Option = None; let mut args = std::env::args().skip(1).peekable(); while let Some(arg) = args.next() { match arg.as_str() { "-h" | "--help" => { print_help(); process::exit(0); } "-V" | "--version" => { print_version(); process::exit(0); } "-c" => no_main = true, "-S" => { emit_ir = true; no_main = true; } "-o" => match args.next() { Some(path) => output = Some(path), None => fatal("option `-o` requires an argument"), }, flag if flag.starts_with('-') => { fatal(&format!("unknown option `{flag}`")); } path => files.push(path.to_owned()), } } if files.is_empty() { fatal("no input files — at least one source file is required"); } Opts { files, no_main, emit_ir, output } }