Parse include!(<path/to/bracketed>)

For example:

    #[cxx::bridge]
    mod ffi {
        extern "C" {
            include!("path/to/quoted");
            include!(<path/to/bracketed>);

            ...
        }
    }

Emitted as:

    #include "path/to/quoted"
    #include <path/to/bracketed>
This commit is contained in:
David Tolnay 2020-05-11 19:10:23 -07:00
parent 8918451412
commit 91e87fa51e
No known key found for this signature in database
GPG Key ID: F9BA143B95FF6D82
4 changed files with 41 additions and 9 deletions

View File

@ -47,8 +47,8 @@ impl Includes {
Includes::default()
}
pub fn insert(&mut self, include: String) {
self.custom.push(include);
pub fn insert(&mut self, include: impl AsRef<str>) {
self.custom.push(include.as_ref().to_owned());
}
}

View File

@ -24,7 +24,7 @@ pub(super) fn gen(
out.include.extend(opt.include);
for api in apis {
if let Api::Include(include) = api {
out.include.insert(include.value());
out.include.insert(include);
}
}

View File

@ -23,7 +23,7 @@ use self::parse::kw;
use proc_macro2::{Ident, Span};
use syn::punctuated::Punctuated;
use syn::token::{Brace, Bracket, Paren};
use syn::{Expr, Lifetime, LitStr, Token, Type as RustType};
use syn::{Expr, Lifetime, Token, Type as RustType};
pub use self::atom::Atom;
pub use self::derive::Derive;
@ -32,7 +32,7 @@ pub use self::parse::parse_items;
pub use self::types::Types;
pub enum Api {
Include(LitStr),
Include(String),
Struct(Struct),
Enum(Enum),
CxxType(ExternType),

View File

@ -5,14 +5,14 @@ use crate::syntax::{
attrs, error, Api, Doc, Enum, ExternFn, ExternType, Lang, Receiver, Ref, Signature, Slice,
Struct, Ty1, Type, TypeAlias, Var, Variant,
};
use proc_macro2::TokenStream;
use proc_macro2::{TokenStream, TokenTree};
use quote::{format_ident, quote, quote_spanned};
use syn::parse::{ParseStream, Parser};
use syn::punctuated::Punctuated;
use syn::{
Abi, Attribute, Error, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType,
GenericArgument, Ident, Item, ItemEnum, ItemForeignMod, ItemStruct, Pat, PathArguments, Result,
ReturnType, Token, Type as RustType, TypeBareFn, TypePath, TypeReference, TypeSlice,
GenericArgument, Ident, Item, ItemEnum, ItemForeignMod, ItemStruct, LitStr, Pat, PathArguments,
Result, ReturnType, Token, Type as RustType, TypeBareFn, TypePath, TypeReference, TypeSlice,
};
pub mod kw {
@ -187,7 +187,7 @@ fn parse_foreign_mod(cx: &mut Errors, foreign_mod: ItemForeignMod, out: &mut Vec
Err(err) => cx.push(err),
},
ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
match foreign.mac.parse_body() {
match foreign.mac.parse_body_with(parse_include) {
Ok(include) => items.push(Api::Include(include)),
Err(err) => cx.push(err),
}
@ -389,6 +389,38 @@ fn parse_extern_verbatim(cx: &mut Errors, tokens: &TokenStream, lang: Lang) -> R
}
}
fn parse_include(input: ParseStream) -> Result<String> {
if input.peek(LitStr) {
return Ok(input.parse::<LitStr>()?.value());
}
if input.peek(Token![<]) {
let mut path = String::new();
input.parse::<Token![<]>()?;
path.push('<');
while !input.is_empty() && !input.peek(Token![>]) {
let token: TokenTree = input.parse()?;
match token {
TokenTree::Ident(token) => path += &token.to_string(),
TokenTree::Literal(token)
if token
.to_string()
.starts_with(|ch: char| ch.is_ascii_digit()) =>
{
path += &token.to_string();
}
TokenTree::Punct(token) => path.push(token.as_char()),
_ => return Err(Error::new(token.span(), "unexpected token in include path")),
}
}
input.parse::<Token![>]>()?;
path.push('>');
return Ok(path);
}
Err(input.error("expected \"quoted/path/to\" or <bracketed/path/to>"))
}
fn parse_type(ty: &RustType) -> Result<Type> {
match ty {
RustType::Reference(ty) => parse_type_reference(ty),