From 5275978d1390846b3b346b0dc0a2d668ffa44e23 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 3 May 2020 23:59:40 -0700 Subject: [PATCH] Batch errors from the parser --- gen/src/mod.rs | 5 ++-- macro/src/expand.rs | 5 ++-- syntax/parse.rs | 63 ++++++++++++++++++++++++--------------------- syntax/report.rs | 4 +++ syntax/types.rs | 32 ++++++++++++----------- 5 files changed, 60 insertions(+), 49 deletions(-) diff --git a/gen/src/mod.rs b/gen/src/mod.rs index 0cfdc59e..6663e4b9 100644 --- a/gen/src/mod.rs +++ b/gen/src/mod.rs @@ -47,8 +47,9 @@ fn generate(path: &Path, opt: Opt, header: bool) -> Vec { let syntax = syn::parse_file(&source)?; let bridge = find_bridge_mod(syntax)?; let ref namespace = bridge.namespace; - let ref apis = syntax::parse_items(bridge.module)?; - let ref types = Types::collect(apis)?; + let ref apis = syntax::parse_items(errors, bridge.module); + let ref types = Types::collect(errors, apis); + errors.propagate()?; check::typecheck(errors, namespace, apis, types); errors.propagate()?; let out = write::gen(namespace, apis, types, opt, header); diff --git a/macro/src/expand.rs b/macro/src/expand.rs index d1af2cfa..e67902b3 100644 --- a/macro/src/expand.rs +++ b/macro/src/expand.rs @@ -15,8 +15,9 @@ pub fn bridge(namespace: &Namespace, mut ffi: ItemMod) -> Result { Span::call_site(), "#[cxx::bridge] module must have inline contents", ))?; - let ref apis = syntax::parse_items(content.1)?; - let ref types = Types::collect(apis)?; + let ref apis = syntax::parse_items(errors, content.1); + let ref types = Types::collect(errors, apis); + errors.propagate()?; check::typecheck(errors, namespace, apis, types); errors.propagate()?; diff --git a/syntax/parse.rs b/syntax/parse.rs index a0dddbd1..8bf0a4ae 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 @@ pub mod kw { syn::custom_keyword!(Result); } -pub fn parse_items(items: Vec) -> Result> { +pub fn parse_items(cx: &mut Errors, items: Vec) -> Vec { 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 { @@ -151,8 +149,11 @@ fn parse_variant(variant: RustVariant) -> Result { } } -fn parse_foreign_mod(foreign_mod: ItemForeignMod) -> Result> { - let lang = parse_lang(foreign_mod.abi)?; +fn parse_foreign_mod(cx: &mut Errors, foreign_mod: ItemForeignMod, out: &mut Vec) { + 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 @@ fn parse_foreign_mod(foreign_mod: ItemForeignMod) -> Result> { 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 @@ fn parse_foreign_mod(foreign_mod: ItemForeignMod) -> Result> { } } - Ok(items) + out.extend(items); } fn parse_lang(abi: Abi) -> Result { diff --git a/syntax/report.rs b/syntax/report.rs index 04f21d8f..d1d8bc9b 100644 --- a/syntax/report.rs +++ b/syntax/report.rs @@ -15,6 +15,10 @@ impl Errors { 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 4842507c..02249e2e 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 @@ pub struct Types<'a> { } impl<'a> Types<'a> { - pub fn collect(apis: &'a [Api]) -> Result { + 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 @@ impl<'a> Types<'a> { 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 @@ impl<'a> Types<'a> { } } - Ok(Types { + Types { all, structs, enums, cxx, rust, - }) + } } pub fn needs_indirect_abi(&self, ty: &Type) -> bool { @@ -135,7 +137,7 @@ impl<'t, 'a> IntoIterator for &'t Types<'a> { } } -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); }