diff --git a/Cargo.lock b/Cargo.lock --- a/Cargo.lock +++ b/Cargo.lock @@ -160,6 +160,7 @@ "eyre", "serde", "serde_json", + "thiserror", "walkdir", ] @@ -243,6 +244,26 @@ "proc-macro2", "quote", "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] diff --git a/parakeet-lexgen/Cargo.toml b/parakeet-lexgen/Cargo.toml --- a/parakeet-lexgen/Cargo.toml +++ b/parakeet-lexgen/Cargo.toml @@ -8,4 +8,5 @@ eyre = "0.6.12" serde = { version = "1.0.217", features = ["derive"] } serde_json = "1.0.136" +thiserror = "2.0.11" walkdir = "2.5.0" diff --git a/parakeet-lexgen/src/main.rs b/parakeet-lexgen/src/main.rs --- a/parakeet-lexgen/src/main.rs +++ b/parakeet-lexgen/src/main.rs @@ -1,4 +1,5 @@ use clap::Parser; +use std::collections::BTreeMap; use walkdir::WalkDir; mod types; @@ -12,6 +13,14 @@ /// Turn off lexicon validation - this may cause Rust compilation to fail on generated types. #[clap(short, long)] no_validate: bool, +} + +#[derive(Debug, thiserror::Error)] +enum Error { + #[error("{0}")] + Serde(#[from] serde_json::Error), + #[error("{0}")] + Io(#[from] std::io::Error), } fn main() -> eyre::Result<()> { @@ -31,7 +40,50 @@ true => Some(path.to_path_buf()), false => None, } - }).collect::>(); + }) + .collect::>(); + + let (parsed, errors) = lexicon_files + .into_iter() + .map(|path| { + let filename = path.display().to_string(); + + let file = + std::fs::File::open(path).map_err(|err| (filename.clone(), Error::from(err)))?; + + let res = serde_json::from_reader::<_, types::Lexicon>(file) + .map_err(|err| (filename, Error::from(err)))?; + + Ok(res) + }) + .map(|v| match v { + Ok(v) => (Some(v), None), + Err(e) => (None, Some(e)), + }) + .unzip::<_, _, Vec<_>, Vec<_>>(); + + // report the errors + for error in errors { + if let Some((filename, error)) = error { + eprintln!("Lexicon {filename} parse failed: {error}"); + } + } + + // pull all the valid lexicon files into a big map so we can run validation + let parsed = parsed + .into_iter() + .filter_map(|maybe_lexicon| match maybe_lexicon { + Some(lexicon) => Some((lexicon.id.clone(), lexicon)), + None => None, + }) + .collect::>(); + + if !args.no_validate { + let failed = validate::validate(&parsed); + for (fail_nsid, fail_err) in failed { + eprintln!("Lexicon {fail_nsid} failed validation: {fail_err:?}"); + } + } Ok(()) }