Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unify TokResult and ResultAnyMacro #36669

Merged
merged 4 commits into from
Sep 27, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 1 addition & 142 deletions src/libsyntax/ext/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ use errors::DiagnosticBuilder;
use ext::expand::{self, Invocation, Expansion};
use ext::hygiene::Mark;
use fold::{self, Folder};
use parse;
use parse::parser::{self, Parser};
use parse::{self, parser};
use parse::token;
use parse::token::{InternedString, str_to_ident};
use ptr::P;
Expand Down Expand Up @@ -188,146 +187,6 @@ impl<F> AttrProcMacro for F
}
}

pub struct TokResult<'a> {
pub parser: Parser<'a>,
pub span: Span,
}

impl<'a> TokResult<'a> {
// There is quite a lot of overlap here with ParserAnyMacro in ext/tt/macro_rules.rs
// We could probably share more code.
// FIXME(#36641) Unify TokResult and ParserAnyMacro.
fn ensure_complete_parse(&mut self, allow_semi: bool) {
let macro_span = &self.span;
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 following", token_str);
let span = parser.span;
parser.diagnostic()
.struct_span_err(span, &msg)
.span_note(*macro_span, "caused by the macro expansion here")
.emit();
});
}
}

impl<'a> MacResult for TokResult<'a> {
fn make_items(mut self: Box<Self>) -> Option<SmallVector<P<ast::Item>>> {
if self.parser.sess.span_diagnostic.has_errors() {
return Some(SmallVector::zero());
}

let mut items = SmallVector::zero();
loop {
match self.parser.parse_item() {
Ok(Some(item)) => items.push(item),
Ok(None) => {
self.ensure_complete_parse(false);
return Some(items);
}
Err(mut e) => {
e.emit();
return Some(SmallVector::zero());
}
}
}
}

fn make_impl_items(mut self: Box<Self>) -> Option<SmallVector<ast::ImplItem>> {
let mut items = SmallVector::zero();
loop {
if self.parser.token == token::Eof {
break;
}
match self.parser.parse_impl_item() {
Ok(item) => items.push(item),
Err(mut e) => {
e.emit();
return Some(SmallVector::zero());
}
}
}
self.ensure_complete_parse(false);
Some(items)
}

fn make_trait_items(mut self: Box<Self>) -> Option<SmallVector<ast::TraitItem>> {
let mut items = SmallVector::zero();
loop {
if self.parser.token == token::Eof {
break;
}
match self.parser.parse_trait_item() {
Ok(item) => items.push(item),
Err(mut e) => {
e.emit();
return Some(SmallVector::zero());
}
}
}
self.ensure_complete_parse(false);
Some(items)
}

fn make_expr(mut self: Box<Self>) -> Option<P<ast::Expr>> {
match self.parser.parse_expr() {
Ok(e) => {
self.ensure_complete_parse(true);
Some(e)
}
Err(mut e) => {
e.emit();
Some(DummyResult::raw_expr(self.span))
}
}
}

fn make_pat(mut self: Box<Self>) -> Option<P<ast::Pat>> {
match self.parser.parse_pat() {
Ok(e) => {
self.ensure_complete_parse(false);
Some(e)
}
Err(mut e) => {
e.emit();
Some(P(DummyResult::raw_pat(self.span)))
}
}
}

fn make_stmts(mut self: Box<Self>) -> Option<SmallVector<ast::Stmt>> {
let mut stmts = SmallVector::zero();
loop {
if self.parser.token == token::Eof {
break;
}
match self.parser.parse_full_stmt(false) {
Ok(Some(stmt)) => stmts.push(stmt),
Ok(None) => { /* continue */ }
Err(mut e) => {
e.emit();
return Some(SmallVector::zero());
}
}
}
self.ensure_complete_parse(false);
Some(stmts)
}

fn make_ty(mut self: Box<Self>) -> Option<P<ast::Ty>> {
match self.parser.parse_ty() {
Ok(e) => {
self.ensure_complete_parse(false);
Some(e)
}
Err(mut e) => {
e.emit();
Some(DummyResult::raw_ty(self.span))
}
}
}
}

/// Represents a thing that maps token trees to Macro Results
pub trait TTMacroExpander {
fn expand<'cx>(&self,
Expand Down
108 changes: 86 additions & 22 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// except according to those terms.

use ast::{Block, Crate, Ident, Mac_, PatKind};
use ast::{MacStmtStyle, StmtKind, ItemKind};
use ast::{Name, MacStmtStyle, StmtKind, ItemKind};
use ast;
use ext::hygiene::Mark;
use ext::placeholders::{placeholder, PlaceholderExpander};
Expand All @@ -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};
Expand All @@ -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, )*
Expand Down Expand Up @@ -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())
})*
}
}
}

Expand Down Expand Up @@ -293,10 +299,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
};

attr::mark_used(&attr);
let name = intern(&attr.name());
self.cx.bt_push(ExpnInfo {
call_site: attr.span,
callee: NameAndSpan {
format: MacroAttribute(intern(&attr.name())),
format: MacroAttribute(name),
span: Some(attr.span),
allow_internal_unstable: false,
}
Expand All @@ -319,14 +326,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let item_toks = TokenStream::from_tts(tts_for_item(&item, &self.cx.parse_sess));

let tok_result = mac.expand(self.cx, attr.span, attr_toks, item_toks);
let parser = self.cx.new_parser_from_tts(&tok_result.to_tts());
let result = Box::new(TokResult { parser: parser, span: attr.span });

kind.make_from(result).unwrap_or_else(|| {
let msg = format!("macro could not be expanded into {} position", kind.name());
self.cx.span_err(attr.span, &msg);
kind.dummy(attr.span)
})
self.parse_expansion(tok_result, kind, name, attr.span)
}
_ => unreachable!(),
}
Expand Down Expand Up @@ -423,14 +423,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
},
});


let tok_result = expandfun.expand(self.cx,
span,
TokenStream::from_tts(marked_tts));
let parser = self.cx.new_parser_from_tts(&tok_result.to_tts());
let result = Box::new(TokResult { parser: parser, span: span });
// FIXME better span info.
kind.make_from(result).map(|i| i.fold_with(&mut ChangeSpan { span: span }))
let toks = TokenStream::from_tts(marked_tts);
let tok_result = expandfun.expand(self.cx, span, toks);
Some(self.parse_expansion(tok_result, kind, extname, span))
}
};

Expand All @@ -448,6 +443,75 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
expn_id: Some(self.cx.backtrace()),
})
}

fn parse_expansion(&mut self, toks: TokenStream, kind: ExpansionKind, name: Name, span: Span)
-> Expansion {
let mut parser = self.cx.new_parser_from_tts(&toks.to_tts());
let expansion = match parser.parse_expansion(kind, false) {
Ok(expansion) => expansion,
Err(mut err) => {
err.emit();
return kind.dummy(span);
}
};
parser.ensure_complete_parse(name, kind.name(), span);
// FIXME better span info
expansion.fold_with(&mut ChangeSpan { span: span })
}
}

impl<'a> Parser<'a> {
pub fn parse_expansion(&mut self, kind: ExpansionKind, macro_legacy_warnings: bool)
-> 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(macro_legacy_warnings)? {
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()?),
})
}

pub fn ensure_complete_parse(&mut self, macro_name: ast::Name, kind_name: &str, span: Span) {
if self.token != token::Eof {
let msg = format!("macro expansion ignores token `{}` and any following",
self.this_token_to_string());
let mut err = self.diagnostic().struct_span_err(self.span, &msg);
let msg = format!("caused by the macro expansion here; the usage \
of `{}!` is likely invalid in {} context",
macro_name, kind_name);
err.span_note(span, &msg).emit();
}
}
}

struct InvocationCollector<'a, 'b: 'a> {
Expand Down
Loading