Refactor parse_expansion out of ResultAnyMacro.

This commit is contained in:
Jeffrey Seyfried 2016-09-23 09:32:58 +00:00
parent 5fc14c1a6f
commit 8b40eaddf1
2 changed files with 63 additions and 92 deletions

View file

@ -21,9 +21,9 @@ use ext::base::*;
use feature_gate::{self, Features};
use fold;
use fold::*;
use parse::{ParseSess, lexer};
use parse::{ParseSess, PResult, lexer};
use parse::parser::Parser;
use parse::token::{intern, keywords};
use parse::token::{self, intern, keywords};
use print::pprust;
use ptr::P;
use tokenstream::{TokenTree, TokenStream};
@ -38,12 +38,12 @@ macro_rules! expansions {
($($kind:ident: $ty:ty [$($vec:ident, $ty_elt:ty)*], $kind_name:expr, .$make:ident,
$(.$fold:ident)* $(lift .$fold_elt:ident)*,
$(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => {
#[derive(Copy, Clone)]
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum ExpansionKind { OptExpr, $( $kind, )* }
pub enum Expansion { OptExpr(Option<P<ast::Expr>>), $( $kind($ty), )* }
impl ExpansionKind {
fn name(self) -> &'static str {
pub fn name(self) -> &'static str {
match self {
ExpansionKind::OptExpr => "expression",
$( ExpansionKind::$kind => $kind_name, )*
@ -106,6 +106,12 @@ macro_rules! expansions {
self.expand(Expansion::$kind(SmallVector::one(node))).$make()
})*)*
}
impl<'a> MacResult for ::ext::tt::macro_rules::ParserAnyMacro<'a> {
$(fn $make(self: Box<::ext::tt::macro_rules::ParserAnyMacro<'a>>) -> Option<$ty> {
Some(self.make(ExpansionKind::$kind).$make())
})*
}
}
}
@ -450,6 +456,47 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
}
impl<'a> Parser<'a> {
pub fn parse_expansion(&mut self, kind: ExpansionKind) -> PResult<'a, Expansion> {
Ok(match kind {
ExpansionKind::Items => {
let mut items = SmallVector::zero();
while let Some(item) = self.parse_item()? {
items.push(item);
}
Expansion::Items(items)
}
ExpansionKind::TraitItems => {
let mut items = SmallVector::zero();
while self.token != token::Eof {
items.push(self.parse_trait_item()?);
}
Expansion::TraitItems(items)
}
ExpansionKind::ImplItems => {
let mut items = SmallVector::zero();
while self.token != token::Eof {
items.push(self.parse_impl_item()?);
}
Expansion::ImplItems(items)
}
ExpansionKind::Stmts => {
let mut stmts = SmallVector::zero();
while self.token != token::Eof {
if let Some(stmt) = self.parse_full_stmt(true)? {
stmts.push(stmt);
}
}
Expansion::Stmts(stmts)
}
ExpansionKind::Expr => Expansion::Expr(self.parse_expr()?),
ExpansionKind::OptExpr => Expansion::OptExpr(Some(self.parse_expr()?)),
ExpansionKind::Ty => Expansion::Ty(self.parse_ty()?),
ExpansionKind::Pat => Expansion::Pat(self.parse_pat()?),
})
}
}
struct InvocationCollector<'a, 'b: 'a> {
cx: &'a mut ExtCtxt<'b>,
cfg: StripUnconfigured<'a>,

View file

@ -12,6 +12,7 @@ use {ast, attr};
use syntax_pos::{Span, DUMMY_SP};
use ext::base::{DummyResult, ExtCtxt, MacEager, MacResult, SyntaxExtension};
use ext::base::{IdentMacroExpander, NormalTT, TTMacroExpander};
use ext::expand::{Expansion, ExpansionKind};
use ext::placeholders;
use ext::tt::macro_parser::{Success, Error, Failure};
use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
@ -22,18 +23,14 @@ use parse::parser::{Parser, Restrictions};
use parse::token::{self, gensym_ident, NtTT, Token};
use parse::token::Token::*;
use print;
use ptr::P;
use tokenstream::{self, TokenTree};
use util::small_vector::SmallVector;
use std::cell::RefCell;
use std::collections::{HashMap};
use std::collections::hash_map::{Entry};
use std::rc::Rc;
struct ParserAnyMacro<'a> {
parser: RefCell<Parser<'a>>,
pub struct ParserAnyMacro<'a> {
parser: Parser<'a>,
/// Span of the expansion site of the macro this parser is for
site_span: Span,
@ -48,8 +45,8 @@ impl<'a> ParserAnyMacro<'a> {
/// about e.g. the semicolon in `macro_rules! kapow { () => {
/// panic!(); } }` doesn't get picked up by .parse_expr(), but it's
/// allowed to be there.
fn ensure_complete_parse(&self, allow_semi: bool, context: &str) {
let mut parser = self.parser.borrow_mut();
fn ensure_complete_parse(&mut self, allow_semi: bool, context: &str) {
let ParserAnyMacro { site_span, macro_ident, ref mut parser } = *self;
parser.ensure_complete_parse(allow_semi, |parser| {
let token_str = parser.this_token_to_string();
let msg = format!("macro expansion ignores token `{}` and any \
@ -59,89 +56,16 @@ impl<'a> ParserAnyMacro<'a> {
let mut err = parser.diagnostic().struct_span_err(span, &msg);
let msg = format!("caused by the macro expansion here; the usage \
of `{}!` is likely invalid in {} context",
self.macro_ident, context);
err.span_note(self.site_span, &msg)
macro_ident, context);
err.span_note(site_span, &msg)
.emit();
});
}
}
impl<'a> MacResult for ParserAnyMacro<'a> {
fn make_expr(self: Box<ParserAnyMacro<'a>>) -> Option<P<ast::Expr>> {
let ret = panictry!(self.parser.borrow_mut().parse_expr());
self.ensure_complete_parse(true, "expression");
Some(ret)
}
fn make_pat(self: Box<ParserAnyMacro<'a>>) -> Option<P<ast::Pat>> {
let ret = panictry!(self.parser.borrow_mut().parse_pat());
self.ensure_complete_parse(false, "pattern");
Some(ret)
}
fn make_items(self: Box<ParserAnyMacro<'a>>) -> Option<SmallVector<P<ast::Item>>> {
let mut ret = SmallVector::zero();
while let Some(item) = panictry!(self.parser.borrow_mut().parse_item()) {
ret.push(item);
}
self.ensure_complete_parse(false, "item");
Some(ret)
}
fn make_impl_items(self: Box<ParserAnyMacro<'a>>)
-> Option<SmallVector<ast::ImplItem>> {
let mut ret = SmallVector::zero();
loop {
let mut parser = self.parser.borrow_mut();
match parser.token {
token::Eof => break,
_ => ret.push(panictry!(parser.parse_impl_item()))
}
}
self.ensure_complete_parse(false, "item");
Some(ret)
}
fn make_trait_items(self: Box<ParserAnyMacro<'a>>)
-> Option<SmallVector<ast::TraitItem>> {
let mut ret = SmallVector::zero();
loop {
let mut parser = self.parser.borrow_mut();
match parser.token {
token::Eof => break,
_ => ret.push(panictry!(parser.parse_trait_item()))
}
}
self.ensure_complete_parse(false, "item");
Some(ret)
}
fn make_stmts(self: Box<ParserAnyMacro<'a>>)
-> Option<SmallVector<ast::Stmt>> {
let mut ret = SmallVector::zero();
loop {
let mut parser = self.parser.borrow_mut();
match parser.token {
token::Eof => break,
_ => match parser.parse_full_stmt(true) {
Ok(maybe_stmt) => match maybe_stmt {
Some(stmt) => ret.push(stmt),
None => (),
},
Err(mut e) => {
e.emit();
break;
}
}
}
}
self.ensure_complete_parse(false, "statement");
Some(ret)
}
fn make_ty(self: Box<ParserAnyMacro<'a>>) -> Option<P<ast::Ty>> {
let ret = panictry!(self.parser.borrow_mut().parse_ty());
self.ensure_complete_parse(false, "type");
Some(ret)
pub fn make(mut self: Box<ParserAnyMacro<'a>>, kind: ExpansionKind) -> Expansion {
let expansion = panictry!(self.parser.parse_expansion(kind));
self.ensure_complete_parse(kind == ExpansionKind::Expr, kind.name());
expansion
}
}
@ -219,7 +143,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
// Let the context choose how to interpret the result.
// Weird, but useful for X-macros.
return Box::new(ParserAnyMacro {
parser: RefCell::new(p),
parser: p,
// Pass along the original expansion site and the name of the macro
// so we can print a useful error message if the parse of the expanded