mirror of
https://github.com/topjohnwu/cxx.git
synced 2024-11-27 13:50:24 +00:00
Batch errors from the parser
This commit is contained in:
parent
cbf3f03ff2
commit
5275978d13
@ -47,8 +47,9 @@ fn generate(path: &Path, opt: Opt, header: bool) -> Vec<u8> {
|
||||
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);
|
||||
|
@ -15,8 +15,9 @@ pub fn bridge(namespace: &Namespace, mut ffi: ItemMod) -> Result<TokenStream> {
|
||||
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()?;
|
||||
|
||||
|
@ -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<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_variant(variant: RustVariant) -> Result<Variant> {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ fn parse_foreign_mod(foreign_mod: ItemForeignMod) -> Result<Vec<Api>> {
|
||||
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<Vec<Api>> {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(items)
|
||||
out.extend(items);
|
||||
}
|
||||
|
||||
fn parse_lang(abi: Abi) -> Result<Lang> {
|
||||
|
@ -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() {
|
||||
|
@ -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<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 @@ 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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user