Revamp serde_codegen_internals error handling

This commit is contained in:
David Tolnay
2016-09-27 00:11:37 -07:00
parent 4ad6c4fd56
commit 0c18c151e2
5 changed files with 54 additions and 27 deletions
+4 -3
View File
@@ -5,11 +5,12 @@ use bound;
use internals::ast::{Body, Field, Item, Style, Variant}; use internals::ast::{Body, Field, Item, Style, Variant};
use internals::{self, attr}; use internals::{self, attr};
pub fn expand_derive_deserialize(item: &syn::MacroInput) -> Tokens { pub fn expand_derive_deserialize(item: &syn::MacroInput) -> Result<Tokens, String> {
let item = { let item = {
let ctxt = internals::Ctxt::new(); let ctxt = internals::Ctxt::new();
let item = Item::from_ast(&ctxt, item); let item = Item::from_ast(&ctxt, item);
check_no_str(&ctxt, &item); check_no_str(&ctxt, &item);
try!(ctxt.check());
item item
}; };
@@ -27,7 +28,7 @@ pub fn expand_derive_deserialize(item: &syn::MacroInput) -> Tokens {
let dummy_const = aster::id(format!("_IMPL_DESERIALIZE_FOR_{}", item.ident)); let dummy_const = aster::id(format!("_IMPL_DESERIALIZE_FOR_{}", item.ident));
quote! { Ok(quote! {
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const #dummy_const: () = { const #dummy_const: () = {
extern crate serde as _serde; extern crate serde as _serde;
@@ -40,7 +41,7 @@ pub fn expand_derive_deserialize(item: &syn::MacroInput) -> Tokens {
} }
} }
}; };
} })
} }
// All the generics in the input, plus a bound `T: Deserialize` for each generic // All the generics in the input, plus a bound `T: Deserialize` for each generic
+12 -6
View File
@@ -123,7 +123,7 @@ macro_rules! shim {
($name:ident $pkg:ident :: $func:ident) => { ($name:ident $pkg:ident :: $func:ident) => {
fn $func( fn $func(
cx: &mut ::syntax::ext::base::ExtCtxt, cx: &mut ::syntax::ext::base::ExtCtxt,
_span: ::syntax::codemap::Span, span: ::syntax::codemap::Span,
meta_item: &::syntax::ast::MetaItem, meta_item: &::syntax::ast::MetaItem,
annotatable: &::syntax::ext::base::Annotatable, annotatable: &::syntax::ext::base::Annotatable,
push: &mut FnMut(::syntax::ext::base::Annotatable) push: &mut FnMut(::syntax::ext::base::Annotatable)
@@ -158,7 +158,13 @@ macro_rules! shim {
let s = pprust::item_to_string(item); let s = pprust::item_to_string(item);
let syn_item = syn::parse_macro_input(&s).unwrap(); let syn_item = syn::parse_macro_input(&s).unwrap();
let expanded = $pkg::$func(&syn_item).to_string(); let expanded = match $pkg::$func(&syn_item) {
Ok(expanded) => expanded.to_string(),
Err(msg) => {
cx.span_err(span, &msg);
return;
}
};
use syntax::parse; use syntax::parse;
let name = stringify!($name).to_string(); let name = stringify!($name).to_string();
@@ -174,21 +180,21 @@ shim!(Serialize ser::expand_derive_serialize);
shim!(Deserialize de::expand_derive_deserialize); shim!(Deserialize de::expand_derive_deserialize);
#[cfg(feature = "with-syn")] #[cfg(feature = "with-syn")]
pub fn expand_single_item(item: &str) -> String { pub fn expand_single_item(item: &str) -> Result<String, String> {
let syn_item = syn::parse_macro_input(item).unwrap(); let syn_item = syn::parse_macro_input(item).unwrap();
let (ser, de, syn_item) = strip_serde_derives(syn_item); let (ser, de, syn_item) = strip_serde_derives(syn_item);
let expanded_ser = if ser { let expanded_ser = if ser {
Some(ser::expand_derive_serialize(&syn_item)) Some(try!(ser::expand_derive_serialize(&syn_item)))
} else { } else {
None None
}; };
let expanded_de = if de { let expanded_de = if de {
Some(de::expand_derive_deserialize(&syn_item)) Some(try!(de::expand_derive_deserialize(&syn_item)))
} else { } else {
None::<quote::Tokens> None::<quote::Tokens>
}; };
let syn_item = strip_serde_attrs(syn_item); let syn_item = strip_serde_attrs(syn_item);
return quote!(#expanded_ser #expanded_de #syn_item).to_string(); return Ok(quote!(#expanded_ser #expanded_de #syn_item).to_string());
fn strip_serde_derives(item: syn::MacroInput) -> (bool, bool, syn::MacroInput) { fn strip_serde_derives(item: syn::MacroInput) -> (bool, bool, syn::MacroInput) {
let mut ser = false; let mut ser = false;
+6 -4
View File
@@ -5,8 +5,10 @@ use bound;
use internals::ast::{Body, Field, Item, Style, Variant}; use internals::ast::{Body, Field, Item, Style, Variant};
use internals::{self, attr}; use internals::{self, attr};
pub fn expand_derive_serialize(item: &syn::MacroInput) -> Tokens { pub fn expand_derive_serialize(item: &syn::MacroInput) -> Result<Tokens, String> {
let item = Item::from_ast(&internals::Ctxt::new(), item); let ctxt = internals::Ctxt::new();
let item = Item::from_ast(&ctxt, item);
try!(ctxt.check());
let impl_generics = build_impl_generics(&item); let impl_generics = build_impl_generics(&item);
@@ -22,7 +24,7 @@ pub fn expand_derive_serialize(item: &syn::MacroInput) -> Tokens {
let dummy_const = aster::id(format!("_IMPL_SERIALIZE_FOR_{}", item.ident)); let dummy_const = aster::id(format!("_IMPL_SERIALIZE_FOR_{}", item.ident));
quote! { Ok(quote! {
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const #dummy_const: () = { const #dummy_const: () = {
extern crate serde as _serde; extern crate serde as _serde;
@@ -35,7 +37,7 @@ pub fn expand_derive_serialize(item: &syn::MacroInput) -> Tokens {
} }
} }
}; };
} })
} }
// All the generics in the input, plus a bound `T: Serialize` for each generic // All the generics in the input, plus a bound `T: Serialize` for each generic
+24 -10
View File
@@ -1,29 +1,43 @@
use std::fmt::Display; use std::fmt::Display;
use std::cell::Cell; use std::cell::RefCell;
#[derive(Default)] #[derive(Default)]
pub struct Ctxt { pub struct Ctxt {
err_count: Cell<usize>, errors: RefCell<Option<Vec<String>>>,
} }
impl Ctxt { impl Ctxt {
pub fn new() -> Self { pub fn new() -> Self {
Default::default() Ctxt {
errors: RefCell::new(Some(Vec::new())),
}
} }
pub fn error<T: Display>(&self, msg: T) { pub fn error<T: Display>(&self, msg: T) {
println!("{}", msg); self.errors.borrow_mut().as_mut().unwrap().push(msg.to_string());
self.err_count.set(self.err_count.get() + 1); }
pub fn check(self) -> Result<(), String> {
let mut errors = self.errors.borrow_mut().take().unwrap();
match errors.len() {
0 => Ok(()),
1 => Err(errors.pop().unwrap()),
n => {
let mut msg = format!("{} errors:", n);
for err in errors {
msg += "\n\t# ";
msg += &err;
}
Err(msg)
}
}
} }
} }
impl Drop for Ctxt { impl Drop for Ctxt {
fn drop(&mut self) { fn drop(&mut self) {
let err_count = self.err_count.get(); if self.errors.borrow().is_some() {
if err_count == 1 { panic!("forgot to check for errors");
panic!("1 error");
} else if err_count > 1 {
panic!("{} errors", err_count);
} }
} }
} }
+8 -4
View File
@@ -9,13 +9,17 @@ use rustc_macro::TokenStream;
#[rustc_macro_derive(Serialize)] #[rustc_macro_derive(Serialize)]
pub fn derive_serialize(input: TokenStream) -> TokenStream { pub fn derive_serialize(input: TokenStream) -> TokenStream {
let item = format!("#[derive(Serialize)]\n{}", input); let item = format!("#[derive(Serialize)]\n{}", input);
let expanded = serde_codegen::expand_single_item(&item); match serde_codegen::expand_single_item(&item) {
expanded.parse().unwrap() Ok(expanded) => expanded.parse().unwrap(),
Err(msg) => panic!(msg),
}
} }
#[rustc_macro_derive(Deserialize)] #[rustc_macro_derive(Deserialize)]
pub fn derive_deserialize(input: TokenStream) -> TokenStream { pub fn derive_deserialize(input: TokenStream) -> TokenStream {
let item = format!("#[derive(Deserialize)]\n{}", input); let item = format!("#[derive(Deserialize)]\n{}", input);
let expanded = serde_codegen::expand_single_item(&item); match serde_codegen::expand_single_item(&item) {
expanded.parse().unwrap() Ok(expanded) => expanded.parse().unwrap(),
Err(msg) => panic!(msg),
}
} }