#![forbid(unsafe_code)]
use std::process::ExitCode;
use comp_cat_rs::effect::io::Io;
use cslint_core::diagnostic::Diagnostic;
use cslint_core::pipeline::analyze;
fn main() -> ExitCode {
let pipeline = args_io()
.flat_map(|path| {
Io::suspend(move || {
cslint_noir::load::load_and_lower(&path).map_err(CliError::Lower)
})
})
.map(|graph| analyze(&graph))
.map(|diags| render(&diags));
match pipeline.run() {
Ok(has_errors) => {
if has_errors {
ExitCode::from(1)
} else {
ExitCode::SUCCESS
}
}
Err(e) => {
eprintln!("error: {e}");
ExitCode::from(2)
}
}
}
fn args_io() -> Io<CliError, String> {
Io::suspend(|| {
std::env::args()
.nth(1)
.ok_or_else(|| CliError::Usage("usage: cslint <file.acir>".into()))
})
}
#[allow(clippy::needless_for_each)]
fn render(diags: &[Diagnostic]) -> bool {
diags.iter().for_each(|d| {
eprintln!("{d}");
});
!diags.is_empty()
}
#[derive(Debug)]
enum CliError {
Usage(String),
Lower(cslint_noir::error::Error),
}
impl std::fmt::Display for CliError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Usage(msg) => write!(f, "{msg}"),
Self::Lower(e) => write!(f, "lowering failed: {e}"),
}
}
}
impl std::error::Error for CliError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Lower(e) => Some(e),
Self::Usage(_) => None,
}
}
}