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);
}