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>
diff --git a/syntax/mod.rs b/syntax/mod.rs
index 4702a69..88c96e8 100644
--- a/syntax/mod.rs
+++ b/syntax/mod.rs
@@ -23,7 +23,7 @@
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::types::Types;
pub enum Api {
- Include(LitStr),
+ Include(String),
Struct(Struct),
Enum(Enum),
CxxType(ExternType),
diff --git a/syntax/parse.rs b/syntax/parse.rs
index a11a5c8..a1d31cf 100644
--- a/syntax/parse.rs
+++ b/syntax/parse.rs
@@ -5,14 +5,14 @@
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 @@
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_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),