Batch errors from the parser
diff --git a/syntax/parse.rs b/syntax/parse.rs
index a0dddbd..8bf0a4a 100644
--- a/syntax/parse.rs
+++ b/syntax/parse.rs
@@ -1,3 +1,4 @@
+use crate::syntax::report::Errors;
 use crate::syntax::Atom::*;
 use crate::syntax::{
     attrs, error, Api, Doc, Enum, ExternFn, ExternType, Lang, Receiver, Ref, Signature, Slice,
@@ -16,27 +17,24 @@
     syn::custom_keyword!(Result);
 }
 
-pub fn parse_items(items: Vec<Item>) -> Result<Vec<Api>> {
+pub fn parse_items(cx: &mut Errors, items: Vec<Item>) -> Vec<Api> {
     let mut apis = Vec::new();
     for item in items {
         match item {
-            Item::Struct(item) => {
-                let strct = parse_struct(item)?;
-                apis.push(strct);
-            }
-            Item::Enum(item) => {
-                let enm = parse_enum(item)?;
-                apis.push(enm);
-            }
-            Item::ForeignMod(foreign_mod) => {
-                let functions = parse_foreign_mod(foreign_mod)?;
-                apis.extend(functions);
-            }
-            Item::Use(item) => return Err(Error::new_spanned(item, error::USE_NOT_ALLOWED)),
-            _ => return Err(Error::new_spanned(item, "unsupported item")),
+            Item::Struct(item) => match parse_struct(item) {
+                Ok(strct) => apis.push(strct),
+                Err(err) => cx.push(err),
+            },
+            Item::Enum(item) => match parse_enum(item) {
+                Ok(enm) => apis.push(enm),
+                Err(err) => cx.push(err),
+            },
+            Item::ForeignMod(foreign_mod) => parse_foreign_mod(cx, foreign_mod, &mut apis),
+            Item::Use(item) => cx.error(item, error::USE_NOT_ALLOWED),
+            _ => cx.error(item, "unsupported item"),
         }
     }
-    Ok(apis)
+    apis
 }
 
 fn parse_struct(item: ItemStruct) -> Result<Api> {
@@ -151,8 +149,11 @@
     }
 }
 
-fn parse_foreign_mod(foreign_mod: ItemForeignMod) -> Result<Vec<Api>> {
-    let lang = parse_lang(foreign_mod.abi)?;
+fn parse_foreign_mod(cx: &mut Errors, foreign_mod: ItemForeignMod, out: &mut Vec<Api>) {
+    let lang = match parse_lang(foreign_mod.abi) {
+        Ok(lang) => lang,
+        Err(err) => return cx.push(err),
+    };
     let api_type = match lang {
         Lang::Cxx => Api::CxxType,
         Lang::Rust => Api::RustType,
@@ -165,19 +166,21 @@
     let mut items = Vec::new();
     for foreign in &foreign_mod.items {
         match foreign {
-            ForeignItem::Type(foreign) => {
-                let ety = parse_extern_type(foreign)?;
-                items.push(api_type(ety));
-            }
-            ForeignItem::Fn(foreign) => {
-                let efn = parse_extern_fn(foreign, lang)?;
-                items.push(api_function(efn));
-            }
+            ForeignItem::Type(foreign) => match parse_extern_type(foreign) {
+                Ok(ety) => items.push(api_type(ety)),
+                Err(err) => cx.push(err),
+            },
+            ForeignItem::Fn(foreign) => match parse_extern_fn(foreign, lang) {
+                Ok(efn) => items.push(api_function(efn)),
+                Err(err) => cx.push(err),
+            },
             ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
-                let include = foreign.mac.parse_body()?;
-                items.push(Api::Include(include));
+                match foreign.mac.parse_body() {
+                    Ok(include) => items.push(Api::Include(include)),
+                    Err(err) => cx.push(err),
+                }
             }
-            _ => return Err(Error::new_spanned(foreign, "unsupported foreign item")),
+            _ => cx.error(foreign, "unsupported foreign item"),
         }
     }
 
@@ -198,7 +201,7 @@
         }
     }
 
-    Ok(items)
+    out.extend(items);
 }
 
 fn parse_lang(abi: Abi) -> Result<Lang> {
diff --git a/syntax/report.rs b/syntax/report.rs
index 04f21d8..d1d8bc9 100644
--- a/syntax/report.rs
+++ b/syntax/report.rs
@@ -15,6 +15,10 @@
         self.errors.push(Error::new_spanned(sp, msg));
     }
 
+    pub fn push(&mut self, error: Error) {
+        self.errors.push(error);
+    }
+
     pub fn propagate(&mut self) -> Result<()> {
         let mut iter = self.errors.drain(..);
         let mut all_errors = match iter.next() {
diff --git a/syntax/types.rs b/syntax/types.rs
index 4842507..02249e2 100644
--- a/syntax/types.rs
+++ b/syntax/types.rs
@@ -1,10 +1,10 @@
 use crate::syntax::atom::Atom::{self, *};
+use crate::syntax::report::Errors;
 use crate::syntax::set::OrderedSet as Set;
 use crate::syntax::{Api, Derive, Enum, Struct, Type};
 use proc_macro2::Ident;
 use quote::ToTokens;
 use std::collections::{BTreeMap as Map, HashSet as UnorderedSet};
-use syn::{Error, Result};
 
 pub struct Types<'a> {
     pub all: Set<'a, Type>,
@@ -15,7 +15,7 @@
 }
 
 impl<'a> Types<'a> {
-    pub fn collect(apis: &'a [Api]) -> Result<Self> {
+    pub fn collect(cx: &mut Errors, apis: &'a [Api]) -> Self {
         let mut all = Set::new();
         let mut structs = Map::new();
         let mut enums = Map::new();
@@ -50,39 +50,41 @@
                 Api::Include(_) => {}
                 Api::Struct(strct) => {
                     let ident = &strct.ident;
-                    if !type_names.insert(ident) {
-                        return Err(duplicate_name(strct, ident));
+                    if type_names.insert(ident) {
+                        structs.insert(ident.clone(), strct);
+                    } else {
+                        duplicate_name(cx, strct, ident);
                     }
-                    structs.insert(ident.clone(), strct);
                     for field in &strct.fields {
                         visit(&mut all, &field.ty);
                     }
                 }
                 Api::Enum(enm) => {
                     let ident = &enm.ident;
-                    if !type_names.insert(ident) {
-                        return Err(duplicate_name(enm, ident));
+                    if type_names.insert(ident) {
+                        enums.insert(ident.clone(), enm);
+                    } else {
+                        duplicate_name(cx, enm, ident);
                     }
-                    enums.insert(ident.clone(), enm);
                 }
                 Api::CxxType(ety) => {
                     let ident = &ety.ident;
                     if !type_names.insert(ident) {
-                        return Err(duplicate_name(ety, ident));
+                        duplicate_name(cx, ety, ident);
                     }
                     cxx.insert(ident);
                 }
                 Api::RustType(ety) => {
                     let ident = &ety.ident;
                     if !type_names.insert(ident) {
-                        return Err(duplicate_name(ety, ident));
+                        duplicate_name(cx, ety, ident);
                     }
                     rust.insert(ident);
                 }
                 Api::CxxFunction(efn) | Api::RustFunction(efn) => {
                     let ident = &efn.ident;
                     if !function_names.insert((&efn.receiver, ident)) {
-                        return Err(duplicate_name(efn, ident));
+                        duplicate_name(cx, efn, ident);
                     }
                     for arg in &efn.args {
                         visit(&mut all, &arg.ty);
@@ -94,13 +96,13 @@
             }
         }
 
-        Ok(Types {
+        Types {
             all,
             structs,
             enums,
             cxx,
             rust,
-        })
+        }
     }
 
     pub fn needs_indirect_abi(&self, ty: &Type) -> bool {
@@ -135,7 +137,7 @@
     }
 }
 
-fn duplicate_name(sp: impl ToTokens, ident: &Ident) -> Error {
+fn duplicate_name(cx: &mut Errors, sp: impl ToTokens, ident: &Ident) {
     let msg = format!("the name `{}` is defined multiple times", ident);
-    Error::new_spanned(sp, msg)
+    cx.error(sp, msg);
 }