Add a codegen error type to avoid unwraps
diff --git a/codegen/src/error.rs b/codegen/src/error.rs
new file mode 100644
index 0000000..0b3f191
--- /dev/null
+++ b/codegen/src/error.rs
@@ -0,0 +1,59 @@
+use std::fmt::{self, Display};
+use std::io;
+
+pub type Result<T> = std::result::Result<T, Error>;
+
+#[derive(Debug)]
+pub enum Error {
+ Io(io::Error),
+ Json(serde_json::Error),
+ Rustfmt(rustfmt::ErrorKind),
+ Syn(syn::Error),
+ Toml(toml::de::Error),
+}
+
+impl Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use self::Error::*;
+
+ match self {
+ Io(e) => write!(f, "{}", e),
+ Json(e) => write!(f, "{}", e),
+ Rustfmt(e) => write!(f, "{}", e),
+ Syn(e) => write!(f, "{}", e),
+ Toml(e) => write!(f, "{}", e),
+ }
+ }
+}
+
+impl std::error::Error for Error {}
+
+impl From<io::Error> for Error {
+ fn from(e: io::Error) -> Self {
+ Error::Io(e)
+ }
+}
+
+impl From<rustfmt::ErrorKind> for Error {
+ fn from(e: rustfmt::ErrorKind) -> Self {
+ Error::Rustfmt(e)
+ }
+}
+
+impl From<serde_json::Error> for Error {
+ fn from(e: serde_json::Error) -> Self {
+ Error::Json(e)
+ }
+}
+
+impl From<syn::Error> for Error {
+ fn from(e: syn::Error) -> Self {
+ Error::Syn(e)
+ }
+}
+
+impl From<toml::de::Error> for Error {
+ fn from(e: toml::de::Error) -> Self {
+ Error::Toml(e)
+ }
+}
diff --git a/codegen/src/file.rs b/codegen/src/file.rs
index c525938..c28f2d9 100644
--- a/codegen/src/file.rs
+++ b/codegen/src/file.rs
@@ -1,22 +1,21 @@
+use crate::error::Result;
use proc_macro2::TokenStream;
use std::fs::File;
use std::io::Write;
use std::path::Path;
-pub fn write<P: AsRef<Path>>(path: P, content: TokenStream) {
- let mut file = File::create(path).unwrap();
+pub fn write<P: AsRef<Path>>(path: P, content: TokenStream) -> Result<()> {
+ let mut file = File::create(path)?;
write!(
file,
"// THIS FILE IS AUTOMATICALLY GENERATED; DO NOT EDIT\n\n"
- )
- .unwrap();
+ )?;
let mut config = rustfmt::Config::default();
config.set().emit_mode(rustfmt::EmitMode::Stdout);
config.set().verbose(rustfmt::Verbosity::Quiet);
config.set().format_macro_matchers(true);
config.set().normalize_doc_attributes(true);
let mut session = rustfmt::Session::new(config, Some(&mut file));
- session
- .format(rustfmt::Input::Text(content.to_string()))
- .unwrap();
+ session.format(rustfmt::Input::Text(content.to_string()))?;
+ Ok(())
}
diff --git a/codegen/src/fold.rs b/codegen/src/fold.rs
index 7cadf20..b9f31bb 100644
--- a/codegen/src/fold.rs
+++ b/codegen/src/fold.rs
@@ -1,3 +1,4 @@
+use crate::error::Result;
use crate::{file, full, gen};
use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;
@@ -225,7 +226,7 @@
});
}
-pub fn generate(defs: &Definitions) {
+pub fn generate(defs: &Definitions) -> Result<()> {
let (traits, impls) = gen::traverse(defs, node);
let full_macro = full::get_macro();
file::write(
@@ -256,5 +257,6 @@
#impls
},
- );
+ )?;
+ Ok(())
}
diff --git a/codegen/src/gen.rs b/codegen/src/gen.rs
index db033f9..ba86fbf 100644
--- a/codegen/src/gen.rs
+++ b/codegen/src/gen.rs
@@ -1,7 +1,7 @@
use inflections::Inflect;
use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;
-use syn_codegen::{Data, Features, Definitions, Node};
+use syn_codegen::{Data, Definitions, Features, Node};
pub const TERMINAL_TYPES: &[&str] = &["Span", "Ident"];
diff --git a/codegen/src/json.rs b/codegen/src/json.rs
index 8e45308..e202bbe 100644
--- a/codegen/src/json.rs
+++ b/codegen/src/json.rs
@@ -1,16 +1,18 @@
-use syn_codegen::Definitions;
-
+use crate::error::Result;
use std::fs;
use std::path::Path;
+use syn_codegen::Definitions;
-pub fn generate(defs: &Definitions) {
- let mut j = serde_json::to_string_pretty(&defs).unwrap();
+pub fn generate(defs: &Definitions) -> Result<()> {
+ let mut j = serde_json::to_string_pretty(&defs)?;
j.push('\n');
- let check: Definitions = serde_json::from_str(&j).unwrap();
+ let check: Definitions = serde_json::from_str(&j)?;
assert_eq!(*defs, check);
let codegen_root = Path::new(env!("CARGO_MANIFEST_DIR"));
let json_path = codegen_root.join("../syn.json");
- fs::write(json_path, j).unwrap();
+ fs::write(json_path, j)?;
+
+ Ok(())
}
diff --git a/codegen/src/main.rs b/codegen/src/main.rs
index cc48ddd..3e27e1e 100644
--- a/codegen/src/main.rs
+++ b/codegen/src/main.rs
@@ -12,6 +12,7 @@
#![recursion_limit = "128"]
#![allow(clippy::needless_pass_by_value)]
+mod error;
mod file;
mod fold;
mod full;
@@ -23,10 +24,21 @@
mod visit;
mod visit_mut;
+use crate::error::Result;
+use std::process;
+
fn main() {
- let defs = parse::parse();
- json::generate(&defs);
- fold::generate(&defs);
- visit::generate(&defs);
- visit_mut::generate(&defs);
+ if let Err(err) = do_main() {
+ let _ = eprintln!("error: {}", err);
+ process::exit(1);
+ }
+}
+
+fn do_main() -> Result<()> {
+ let defs = parse::parse()?;
+ json::generate(&defs)?;
+ fold::generate(&defs)?;
+ visit::generate(&defs)?;
+ visit_mut::generate(&defs)?;
+ Ok(())
}
diff --git a/codegen/src/parse.rs b/codegen/src/parse.rs
index c6335b7..ba4bc5d 100644
--- a/codegen/src/parse.rs
+++ b/codegen/src/parse.rs
@@ -1,3 +1,4 @@
+use crate::error::Result;
use crate::version;
use indexmap::IndexMap;
@@ -21,13 +22,13 @@
type TokenLookup = BTreeMap<String, String>;
/// Parse the contents of `src` and return a list of AST types.
-pub fn parse() -> types::Definitions {
+pub fn parse() -> Result<types::Definitions> {
let mut item_lookup = BTreeMap::new();
- load_file(SYN_CRATE_ROOT, &[], &mut item_lookup).unwrap();
+ load_file(SYN_CRATE_ROOT, &[], &mut item_lookup)?;
- let token_lookup = load_token_file(TOKEN_SRC).unwrap();
+ let token_lookup = load_token_file(TOKEN_SRC)?;
- let version = version::get();
+ let version = version::get()?;
let types = item_lookup
.values()
@@ -39,11 +40,11 @@
.map(|(name, ty)| (ty, name))
.collect();
- types::Definitions {
+ Ok(types::Definitions {
version,
types,
tokens,
- }
+ })
}
/// Data extracted from syn source
@@ -501,15 +502,13 @@
ret
}
-type Error = Box<::std::error::Error>;
-
fn load_file<P: AsRef<Path>>(
name: P,
features: &[syn::Attribute],
lookup: &mut ItemLookup,
-) -> Result<(), Error> {
+) -> Result<()> {
let name = name.as_ref();
- let parent = name.parent().ok_or("no parent path")?;
+ let parent = name.parent().expect("no parent path");
let mut f = File::open(name)?;
let mut src = String::new();
@@ -602,7 +601,7 @@
Ok(())
}
-fn load_token_file<P: AsRef<Path>>(name: P) -> Result<TokenLookup, Error> {
+fn load_token_file<P: AsRef<Path>>(name: P) -> Result<TokenLookup> {
let name = name.as_ref();
let mut f = File::open(name)?;
let mut src = String::new();
@@ -623,5 +622,5 @@
}
}
- Err("failed to parse Token macro".into())
+ panic!("failed to parse Token macro")
}
diff --git a/codegen/src/version.rs b/codegen/src/version.rs
index fab7907..7ccca60 100644
--- a/codegen/src/version.rs
+++ b/codegen/src/version.rs
@@ -1,15 +1,16 @@
+use crate::error::Result;
use semver::Version;
use serde::Deserialize;
use std::fs;
use std::path::Path;
-pub fn get() -> Version {
+pub fn get() -> Result<Version> {
let codegen_root = Path::new(env!("CARGO_MANIFEST_DIR"));
let syn_cargo_toml = codegen_root.join("../Cargo.toml");
- let manifest = fs::read_to_string(syn_cargo_toml).unwrap();
- let parsed: Manifest = toml::from_str(&manifest).unwrap();
- parsed.package.version
+ let manifest = fs::read_to_string(syn_cargo_toml)?;
+ let parsed: Manifest = toml::from_str(&manifest)?;
+ Ok(parsed.package.version)
}
#[derive(Debug, Deserialize)]
diff --git a/codegen/src/visit.rs b/codegen/src/visit.rs
index 988045d..122d57e 100644
--- a/codegen/src/visit.rs
+++ b/codegen/src/visit.rs
@@ -1,3 +1,4 @@
+use crate::error::Result;
use crate::operand::{Borrowed, Operand, Owned};
use crate::{file, full, gen};
use proc_macro2::{Ident, Span, TokenStream};
@@ -195,7 +196,7 @@
});
}
-pub fn generate(defs: &Definitions) {
+pub fn generate(defs: &Definitions) -> Result<()> {
let (traits, impls) = gen::traverse(defs, node);
let full_macro = full::get_macro();
file::write(
@@ -230,5 +231,6 @@
#impls
},
- );
+ )?;
+ Ok(())
}
diff --git a/codegen/src/visit_mut.rs b/codegen/src/visit_mut.rs
index 2202aad..2ec2961 100644
--- a/codegen/src/visit_mut.rs
+++ b/codegen/src/visit_mut.rs
@@ -1,3 +1,4 @@
+use crate::error::Result;
use crate::operand::{Borrowed, Operand, Owned};
use crate::{file, full, gen};
use proc_macro2::{Ident, Span, TokenStream};
@@ -195,7 +196,7 @@
});
}
-pub fn generate(defs: &Definitions) {
+pub fn generate(defs: &Definitions) -> Result<()> {
let (traits, impls) = gen::traverse(defs, node);
let full_macro = full::get_macro();
file::write(
@@ -229,5 +230,6 @@
#impls
},
- );
+ )?;
+ Ok(())
}