mirror of
https://gitee.com/openharmony/third_party_rust_cxx
synced 2024-11-24 07:40:19 +00:00
Parse full file using the new Module parser
This commit is contained in:
parent
17c3230d08
commit
3c64a4e144
@ -16,7 +16,6 @@ pub(super) type Result<T, E = Error> = std::result::Result<T, E>;
|
||||
#[derive(Debug)]
|
||||
pub(super) enum Error {
|
||||
NoBridgeMod,
|
||||
OutOfLineMod,
|
||||
Io(io::Error),
|
||||
Syn(syn::Error),
|
||||
}
|
||||
@ -25,7 +24,6 @@ impl Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Error::NoBridgeMod => write!(f, "no #[cxx::bridge] module found"),
|
||||
Error::OutOfLineMod => write!(f, "#[cxx::bridge] module must have inline contents"),
|
||||
Error::Io(err) => err.fmt(f),
|
||||
Error::Syn(err) => err.fmt(f),
|
||||
}
|
||||
|
@ -1,20 +1,71 @@
|
||||
use syn::parse::{Parse, ParseStream, Result};
|
||||
use syn::{Attribute, Item};
|
||||
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 attrs: Vec<Attribute>,
|
||||
pub items: Vec<Item>,
|
||||
pub modules: Vec<Module>,
|
||||
}
|
||||
|
||||
impl Parse for File {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let attrs = input.call(Attribute::parse_inner)?;
|
||||
|
||||
let mut items = Vec::new();
|
||||
while !input.is_empty() {
|
||||
items.push(input.parse()?);
|
||||
}
|
||||
|
||||
Ok(File { attrs, items })
|
||||
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 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;
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
@ -1,47 +0,0 @@
|
||||
use crate::gen::{Error, File, Input, Result};
|
||||
use crate::syntax::namespace::Namespace;
|
||||
use syn::{Attribute, Item};
|
||||
|
||||
pub(super) fn find_bridge_mod(syntax: File) -> Result<Input> {
|
||||
match scan(syntax.items)? {
|
||||
Some(input) => Ok(input),
|
||||
None => Err(Error::NoBridgeMod),
|
||||
}
|
||||
}
|
||||
|
||||
fn scan(items: Vec<Item>) -> Result<Option<Input>> {
|
||||
for item in items {
|
||||
if let Item::Mod(item) = item {
|
||||
for attr in &item.attrs {
|
||||
let path = &attr.path.segments;
|
||||
if path.len() == 2 && path[0].ident == "cxx" && path[1].ident == "bridge" {
|
||||
let module = match item.content {
|
||||
Some(module) => module.1,
|
||||
None => {
|
||||
return Err(Error::Syn(syn::Error::new_spanned(
|
||||
item,
|
||||
Error::OutOfLineMod,
|
||||
)));
|
||||
}
|
||||
};
|
||||
let namespace = parse_args(attr)?;
|
||||
return Ok(Some(Input { namespace, module }));
|
||||
}
|
||||
}
|
||||
if let Some(module) = item.content {
|
||||
if let Some(input) = scan(module.1)? {
|
||||
return Ok(Some(input));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn parse_args(attr: &Attribute) -> syn::Result<Namespace> {
|
||||
if attr.tokens.is_empty() {
|
||||
Ok(Namespace::none())
|
||||
} else {
|
||||
attr.parse_args()
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@
|
||||
|
||||
mod error;
|
||||
mod file;
|
||||
mod find;
|
||||
pub(super) mod include;
|
||||
pub(super) mod out;
|
||||
mod write;
|
||||
@ -13,17 +12,10 @@ mod tests;
|
||||
|
||||
use self::error::{format_err, Error, Result};
|
||||
use self::file::File;
|
||||
use crate::syntax::namespace::Namespace;
|
||||
use crate::syntax::report::Errors;
|
||||
use crate::syntax::{self, check, Types};
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use syn::Item;
|
||||
|
||||
struct Input {
|
||||
namespace: Namespace,
|
||||
module: Vec<Item>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(super) struct Opt {
|
||||
@ -64,9 +56,13 @@ fn generate(source: &str, opt: Opt, header: bool) -> Result<Vec<u8>> {
|
||||
proc_macro2::fallback::force();
|
||||
let ref mut errors = Errors::new();
|
||||
let syntax: File = syn::parse_str(source)?;
|
||||
let bridge = find::find_bridge_mod(syntax)?;
|
||||
let bridge = syntax
|
||||
.modules
|
||||
.into_iter()
|
||||
.next()
|
||||
.ok_or(Error::NoBridgeMod)?;
|
||||
let ref namespace = bridge.namespace;
|
||||
let ref apis = syntax::parse_items(errors, bridge.module);
|
||||
let ref apis = syntax::parse_items(errors, bridge.content);
|
||||
let ref types = Types::collect(errors, apis);
|
||||
errors.propagate()?;
|
||||
check::typecheck(errors, namespace, apis, types);
|
||||
|
@ -11,21 +11,23 @@ use quote::{format_ident, quote, quote_spanned, ToTokens};
|
||||
use std::mem;
|
||||
use syn::{parse_quote, Result, Token};
|
||||
|
||||
pub fn bridge(namespace: &Namespace, mut ffi: Module) -> Result<TokenStream> {
|
||||
pub fn bridge(mut ffi: Module) -> Result<TokenStream> {
|
||||
let ref mut errors = Errors::new();
|
||||
let content = mem::take(&mut ffi.content);
|
||||
let ref apis = syntax::parse_items(errors, content);
|
||||
let ref types = Types::collect(errors, apis);
|
||||
errors.propagate()?;
|
||||
let namespace = &ffi.namespace;
|
||||
check::typecheck(errors, namespace, apis, types);
|
||||
errors.propagate()?;
|
||||
|
||||
Ok(expand(namespace, ffi, apis, types))
|
||||
Ok(expand(ffi, apis, types))
|
||||
}
|
||||
|
||||
fn expand(namespace: &Namespace, ffi: Module, apis: &[Api], types: &Types) -> TokenStream {
|
||||
fn expand(ffi: Module, apis: &[Api], types: &Types) -> TokenStream {
|
||||
let mut expanded = TokenStream::new();
|
||||
let mut hidden = TokenStream::new();
|
||||
let namespace = &ffi.namespace;
|
||||
|
||||
for api in apis {
|
||||
if let Api::RustType(ety) = api {
|
||||
|
@ -40,9 +40,10 @@ pub fn bridge(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let _ = syntax::error::ERRORS;
|
||||
|
||||
let namespace = parse_macro_input!(args as Namespace);
|
||||
let ffi = parse_macro_input!(input as Module);
|
||||
let mut ffi = parse_macro_input!(input as Module);
|
||||
ffi.namespace = namespace;
|
||||
|
||||
expand::bridge(&namespace, ffi)
|
||||
expand::bridge(ffi)
|
||||
.unwrap_or_else(|err| err.to_compile_error())
|
||||
.into()
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
use proc_macro2::Span;
|
||||
use crate::syntax::namespace::Namespace;
|
||||
use quote::quote;
|
||||
use syn::parse::{Error, Parse, ParseStream, Result};
|
||||
use syn::{braced, token, Attribute, Ident, Item, Token, Visibility};
|
||||
|
||||
pub struct Module {
|
||||
pub namespace: Namespace,
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub vis: Visibility,
|
||||
// TODO: unsafety
|
||||
@ -14,14 +16,17 @@ pub struct Module {
|
||||
|
||||
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 mod_token: Token![mod] = input.parse()?;
|
||||
let ident: Ident = input.parse()?;
|
||||
|
||||
if input.peek(Token![;]) {
|
||||
return Err(Error::new(
|
||||
Span::call_site(),
|
||||
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",
|
||||
))?;
|
||||
}
|
||||
@ -36,6 +41,7 @@ impl Parse for Module {
|
||||
}
|
||||
|
||||
Ok(Module {
|
||||
namespace,
|
||||
attrs,
|
||||
vis,
|
||||
mod_token,
|
||||
|
Loading…
Reference in New Issue
Block a user