Skip to content

Commit

Permalink
refactor: encapsulate cfg_if parsing within parse mod
Browse files Browse the repository at this point in the history
  • Loading branch information
calebcartwright committed Dec 21, 2021
1 parent 6298756 commit 97c3e48
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 83 deletions.
4 changes: 2 additions & 2 deletions src/modules/visitor.rs
Expand Up @@ -3,7 +3,7 @@ use rustc_ast::visit::Visitor;
use rustc_span::Symbol;

use crate::attr::MetaVisitor;
use crate::parse::parser::Parser;
use crate::parse::macros::cfg_if::parse_cfg_if;
use crate::parse::session::ParseSess;

pub(crate) struct ModItem {
Expand Down Expand Up @@ -62,7 +62,7 @@ impl<'a, 'ast: 'a> CfgIfVisitor<'a> {
}
};

let items = Parser::parse_cfg_if(self.parse_sess, mac)?;
let items = parse_cfg_if(self.parse_sess, mac)?;
self.mods
.append(&mut items.into_iter().map(|item| ModItem { item }).collect());

Expand Down
89 changes: 89 additions & 0 deletions src/parse/macros/cfg_if.rs
@@ -0,0 +1,89 @@
use std::panic::{catch_unwind, AssertUnwindSafe};

use rustc_ast::ast;
use rustc_ast::token::{DelimToken, TokenKind};
use rustc_parse::parser::ForceCollect;
use rustc_span::symbol::kw;

use crate::parse::macros::build_stream_parser;
use crate::parse::session::ParseSess;

pub(crate) fn parse_cfg_if<'a>(
sess: &'a ParseSess,
mac: &'a ast::MacCall,
) -> Result<Vec<ast::Item>, &'static str> {
match catch_unwind(AssertUnwindSafe(|| parse_cfg_if_inner(sess, mac))) {
Ok(Ok(items)) => Ok(items),
Ok(err @ Err(_)) => err,
Err(..) => Err("failed to parse cfg_if!"),
}
}

fn parse_cfg_if_inner<'a>(
sess: &'a ParseSess,
mac: &'a ast::MacCall,
) -> Result<Vec<ast::Item>, &'static str> {
let ts = mac.args.inner_tokens();
let mut parser = build_stream_parser(sess.inner(), ts);

let mut items = vec![];
let mut process_if_cfg = true;

while parser.token.kind != TokenKind::Eof {
if process_if_cfg {
if !parser.eat_keyword(kw::If) {
return Err("Expected `if`");
}
// Inner attributes are not actually syntactically permitted here, but we don't
// care about inner vs outer attributes in this position. Our purpose with this
// special case parsing of cfg_if macros is to ensure we can correctly resolve
// imported modules that may have a custom `path` defined.
//
// As such, we just need to advance the parser past the attribute and up to
// to the opening brace.
// See also https://github.com/rust-lang/rust/pull/79433
parser
.parse_attribute(rustc_parse::parser::attr::InnerAttrPolicy::Permitted)
.map_err(|_| "Failed to parse attributes")?;
}

if !parser.eat(&TokenKind::OpenDelim(DelimToken::Brace)) {
return Err("Expected an opening brace");
}

while parser.token != TokenKind::CloseDelim(DelimToken::Brace)
&& parser.token.kind != TokenKind::Eof
{
let item = match parser.parse_item(ForceCollect::No) {
Ok(Some(item_ptr)) => item_ptr.into_inner(),
Ok(None) => continue,
Err(mut err) => {
err.cancel();
parser.sess.span_diagnostic.reset_err_count();
return Err(
"Expected item inside cfg_if block, but failed to parse it as an item",
);
}
};
if let ast::ItemKind::Mod(..) = item.kind {
items.push(item);
}
}

if !parser.eat(&TokenKind::CloseDelim(DelimToken::Brace)) {
return Err("Expected a closing brace");
}

if parser.eat(&TokenKind::Eof) {
break;
}

if !parser.eat_keyword(kw::Else) {
return Err("Expected `else`");
}

process_if_cfg = parser.token.is_keyword(kw::If);
}

Ok(items)
}
8 changes: 7 additions & 1 deletion src/parse/macros/mod.rs
Expand Up @@ -3,6 +3,7 @@ use rustc_ast::tokenstream::{Cursor, Spacing, TokenStream, TokenTree};
use rustc_ast::{ast, ptr};
use rustc_parse::parser::{ForceCollect, Parser};
use rustc_parse::{stream_to_parser, MACRO_ARGUMENTS};
use rustc_session::parse::ParseSess;
use rustc_span::{
symbol::{self, kw},
BytePos, Span, Symbol, DUMMY_SP,
Expand All @@ -11,10 +12,15 @@ use rustc_span::{
use crate::macros::MacroArg;
use crate::rewrite::{Rewrite, RewriteContext};

pub(crate) mod cfg_if;
pub(crate) mod lazy_static;

fn build_stream_parser<'a>(sess: &'a ParseSess, tokens: TokenStream) -> Parser<'a> {
stream_to_parser(sess, tokens, MACRO_ARGUMENTS)
}

fn build_parser<'a>(context: &RewriteContext<'a>, tokens: TokenStream) -> Parser<'a> {
stream_to_parser(context.parse_sess.inner(), tokens, MACRO_ARGUMENTS)
build_stream_parser(context.parse_sess.inner(), tokens)
}

fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
Expand Down
80 changes: 0 additions & 80 deletions src/parse/parser.rs
Expand Up @@ -175,84 +175,4 @@ impl<'a> Parser<'a> {
Err(_) => Err(ParserError::ParsePanicError),
}
}

pub(crate) fn parse_cfg_if(
sess: &'a ParseSess,
mac: &'a ast::MacCall,
) -> Result<Vec<ast::Item>, &'static str> {
match catch_unwind(AssertUnwindSafe(|| Parser::parse_cfg_if_inner(sess, mac))) {
Ok(Ok(items)) => Ok(items),
Ok(err @ Err(_)) => err,
Err(..) => Err("failed to parse cfg_if!"),
}
}

fn parse_cfg_if_inner(
sess: &'a ParseSess,
mac: &'a ast::MacCall,
) -> Result<Vec<ast::Item>, &'static str> {
let token_stream = mac.args.inner_tokens();
let mut parser = rustc_parse::stream_to_parser(sess.inner(), token_stream, Some(""));

let mut items = vec![];
let mut process_if_cfg = true;

while parser.token.kind != TokenKind::Eof {
if process_if_cfg {
if !parser.eat_keyword(kw::If) {
return Err("Expected `if`");
}
// Inner attributes are not actually syntactically permitted here, but we don't
// care about inner vs outer attributes in this position. Our purpose with this
// special case parsing of cfg_if macros is to ensure we can correctly resolve
// imported modules that may have a custom `path` defined.
//
// As such, we just need to advance the parser past the attribute and up to
// to the opening brace.
// See also https://github.com/rust-lang/rust/pull/79433
parser
.parse_attribute(rustc_parse::parser::attr::InnerAttrPolicy::Permitted)
.map_err(|_| "Failed to parse attributes")?;
}

if !parser.eat(&TokenKind::OpenDelim(DelimToken::Brace)) {
return Err("Expected an opening brace");
}

while parser.token != TokenKind::CloseDelim(DelimToken::Brace)
&& parser.token.kind != TokenKind::Eof
{
let item = match parser.parse_item(ForceCollect::No) {
Ok(Some(item_ptr)) => item_ptr.into_inner(),
Ok(None) => continue,
Err(mut err) => {
err.cancel();
parser.sess.span_diagnostic.reset_err_count();
return Err(
"Expected item inside cfg_if block, but failed to parse it as an item",
);
}
};
if let ast::ItemKind::Mod(..) = item.kind {
items.push(item);
}
}

if !parser.eat(&TokenKind::CloseDelim(DelimToken::Brace)) {
return Err("Expected a closing brace");
}

if parser.eat(&TokenKind::Eof) {
break;
}

if !parser.eat_keyword(kw::Else) {
return Err("Expected `else`");
}

process_if_cfg = parser.token.is_keyword(kw::If);
}

Ok(items)
}
}

0 comments on commit 97c3e48

Please sign in to comment.