-
Notifications
You must be signed in to change notification settings - Fork 339
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #270 from dtolnay/parse
Parse unsafe modules and unsafe extern blocks
- Loading branch information
Showing
9 changed files
with
215 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
use crate::syntax::file::Module; | ||
use crate::syntax::namespace::Namespace; | ||
use syn::parse::discouraged::Speculative; | ||
use syn::parse::{Error, Parse, ParseStream, Result}; | ||
use syn::{braced, Attribute, Ident, Item, Token, Visibility}; | ||
|
||
pub struct File { | ||
pub modules: Vec<Module>, | ||
} | ||
|
||
impl Parse for File { | ||
fn parse(input: ParseStream) -> Result<Self> { | ||
let mut modules = Vec::new(); | ||
input.call(Attribute::parse_inner)?; | ||
parse(input, &mut modules)?; | ||
Ok(File { modules }) | ||
} | ||
} | ||
|
||
fn parse(input: ParseStream, modules: &mut Vec<Module>) -> Result<()> { | ||
while !input.is_empty() { | ||
let mut cxx_bridge = false; | ||
let mut namespace = Namespace::none(); | ||
let mut attrs = input.call(Attribute::parse_outer)?; | ||
for attr in &attrs { | ||
let path = &attr.path.segments; | ||
if path.len() == 2 && path[0].ident == "cxx" && path[1].ident == "bridge" { | ||
cxx_bridge = true; | ||
namespace = parse_args(attr)?; | ||
break; | ||
} | ||
} | ||
|
||
let ahead = input.fork(); | ||
ahead.parse::<Visibility>()?; | ||
ahead.parse::<Option<Token![unsafe]>>()?; | ||
if !ahead.peek(Token![mod]) { | ||
let item: Item = input.parse()?; | ||
if cxx_bridge { | ||
return Err(Error::new_spanned(item, "expected a module")); | ||
} | ||
continue; | ||
} | ||
|
||
if cxx_bridge { | ||
let mut module: Module = input.parse()?; | ||
module.namespace = namespace; | ||
attrs.extend(module.attrs); | ||
module.attrs = attrs; | ||
modules.push(module); | ||
} else { | ||
input.advance_to(&ahead); | ||
input.parse::<Token![mod]>()?; | ||
input.parse::<Ident>()?; | ||
let semi: Option<Token![;]> = input.parse()?; | ||
if semi.is_none() { | ||
let content; | ||
braced!(content in input); | ||
parse(&content, modules)?; | ||
} | ||
} | ||
} | ||
Ok(()) | ||
} | ||
|
||
fn parse_args(attr: &Attribute) -> Result<Namespace> { | ||
if attr.tokens.is_empty() { | ||
Ok(Namespace::none()) | ||
} else { | ||
attr.parse_args() | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
use crate::syntax::namespace::Namespace; | ||
use quote::quote; | ||
use syn::parse::{Error, Parse, ParseStream, Result}; | ||
use syn::{ | ||
braced, token, Abi, Attribute, ForeignItem, Ident, Item as RustItem, ItemEnum, ItemStruct, | ||
ItemUse, LitStr, Token, Visibility, | ||
}; | ||
|
||
pub struct Module { | ||
pub namespace: Namespace, | ||
pub attrs: Vec<Attribute>, | ||
pub vis: Visibility, | ||
pub unsafety: Option<Token![unsafe]>, | ||
pub mod_token: Token![mod], | ||
pub ident: Ident, | ||
pub brace_token: token::Brace, | ||
pub content: Vec<Item>, | ||
} | ||
|
||
pub enum Item { | ||
Struct(ItemStruct), | ||
Enum(ItemEnum), | ||
ForeignMod(ItemForeignMod), | ||
Use(ItemUse), | ||
Other(RustItem), | ||
} | ||
|
||
pub struct ItemForeignMod { | ||
pub attrs: Vec<Attribute>, | ||
pub unsafety: Option<Token![unsafe]>, | ||
pub abi: Abi, | ||
pub brace_token: token::Brace, | ||
pub items: Vec<ForeignItem>, | ||
} | ||
|
||
impl Parse for Module { | ||
fn parse(input: ParseStream) -> Result<Self> { | ||
let namespace = Namespace::none(); | ||
let mut attrs = input.call(Attribute::parse_outer)?; | ||
let vis: Visibility = input.parse()?; | ||
let unsafety: Option<Token![unsafe]> = input.parse()?; | ||
let mod_token: Token![mod] = input.parse()?; | ||
let ident: Ident = input.parse()?; | ||
|
||
let semi: Option<Token![;]> = input.parse()?; | ||
if let Some(semi) = semi { | ||
let span = quote!(#vis #mod_token #semi); | ||
return Err(Error::new_spanned( | ||
span, | ||
"#[cxx::bridge] module must have inline contents", | ||
))?; | ||
} | ||
|
||
let content; | ||
let brace_token = braced!(content in input); | ||
attrs.extend(content.call(Attribute::parse_inner)?); | ||
|
||
let mut items = Vec::new(); | ||
while !content.is_empty() { | ||
items.push(content.parse()?); | ||
} | ||
|
||
Ok(Module { | ||
namespace, | ||
attrs, | ||
vis, | ||
unsafety, | ||
mod_token, | ||
ident, | ||
brace_token, | ||
content: items, | ||
}) | ||
} | ||
} | ||
|
||
impl Parse for Item { | ||
fn parse(input: ParseStream) -> Result<Self> { | ||
let attrs = input.call(Attribute::parse_outer)?; | ||
|
||
let ahead = input.fork(); | ||
let unsafety = if ahead.parse::<Option<Token![unsafe]>>()?.is_some() | ||
&& ahead.parse::<Option<Token![extern]>>()?.is_some() | ||
&& ahead.parse::<Option<LitStr>>().is_ok() | ||
&& ahead.peek(token::Brace) | ||
{ | ||
Some(input.parse()?) | ||
} else { | ||
None | ||
}; | ||
|
||
let item = input.parse()?; | ||
match item { | ||
RustItem::Struct(item) => Ok(Item::Struct(ItemStruct { attrs, ..item })), | ||
RustItem::Enum(item) => Ok(Item::Enum(ItemEnum { attrs, ..item })), | ||
RustItem::ForeignMod(item) => Ok(Item::ForeignMod(ItemForeignMod { | ||
attrs: item.attrs, | ||
unsafety, | ||
abi: item.abi, | ||
brace_token: item.brace_token, | ||
items: item.items, | ||
})), | ||
RustItem::Use(item) => Ok(Item::Use(ItemUse { attrs, ..item })), | ||
other => Ok(Item::Other(other)), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.