diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index e100b7705d817..e0753b2f6f6ee 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -28,8 +28,7 @@ pub mod rt { use ast; use codemap::Spanned; use ext::base::ExtCtxt; - use parse::token; - use parse; + use parse::{self, token, classify}; use ptr::P; use std::rc::Rc; @@ -94,6 +93,18 @@ pub mod rt { } } + impl ToTokens for ast::Generics { + fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { + vec![ast::TtToken(DUMMY_SP, token::Interpolated(token::NtGenerics(self.clone())))] + } + } + + impl ToTokens for ast::WhereClause { + fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { + vec![ast::TtToken(DUMMY_SP, token::Interpolated(token::NtWhereClause(self.clone())))] + } + } + impl ToTokens for P { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { vec![ast::TtToken(self.span, token::Interpolated(token::NtItem(self.clone())))] @@ -114,7 +125,16 @@ pub mod rt { impl ToTokens for P { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![ast::TtToken(self.span, token::Interpolated(token::NtStmt(self.clone())))] + let mut tts = vec![ + ast::TtToken(self.span, token::Interpolated(token::NtStmt(self.clone()))) + ]; + + // Some statements require a trailing semicolon. + if classify::stmt_ends_with_semi(&self.node) { + tts.push(ast::TtToken(self.span, token::Semi)); + } + + tts } } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index adfda988b23b7..4bf15f509a048 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -689,6 +689,9 @@ pub fn noop_fold_interpolated(nt: token::Nonterminal, fld: &mut T) token::NtTraitItem(arm) => token::NtTraitItem(fld.fold_trait_item(arm) .expect_one("expected fold to produce exactly one item")), + token::NtGenerics(generics) => token::NtGenerics(fld.fold_generics(generics)), + token::NtWhereClause(where_clause) => + token::NtWhereClause(fld.fold_where_clause(where_clause)), } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 541ec16b415d4..9bf6fa88ba553 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3808,6 +3808,8 @@ impl<'a> Parser<'a> { /// | ( < lifetimes , typaramseq ( , )? > ) /// where typaramseq = ( typaram ) | ( typaram , typaramseq ) pub fn parse_generics(&mut self) -> PResult { + maybe_whole!(self, NtGenerics); + if try!(self.eat(&token::Lt) ){ let lifetime_defs = try!(self.parse_lifetime_defs()); let mut seen_default = false; @@ -3928,6 +3930,8 @@ impl<'a> Parser<'a> { /// where T : Trait + 'b, 'a : 'b /// ``` pub fn parse_where_clause(&mut self) -> PResult { + maybe_whole!(self, NtWhereClause); + let mut where_clause = WhereClause { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 53ed4f351d356..832fec40199b8 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -385,6 +385,8 @@ pub enum Nonterminal { NtArm(ast::Arm), NtImplItem(P), NtTraitItem(P), + NtGenerics(ast::Generics), + NtWhereClause(ast::WhereClause), } impl fmt::Debug for Nonterminal { @@ -403,6 +405,8 @@ impl fmt::Debug for Nonterminal { NtArm(..) => f.pad("NtArm(..)"), NtImplItem(..) => f.pad("NtImplItem(..)"), NtTraitItem(..) => f.pad("NtTraitItem(..)"), + NtGenerics(..) => f.pad("NtGenerics(..)"), + NtWhereClause(..) => f.pad("NtWhereClause(..)"), } } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 5a002dd790fee..b71d65a8fb0c5 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -287,19 +287,21 @@ pub fn token_to_string(tok: &Token) -> String { token::SpecialVarNt(var) => format!("${}", var.as_str()), token::Interpolated(ref nt) => match *nt { - token::NtExpr(ref e) => expr_to_string(&**e), - token::NtMeta(ref e) => meta_item_to_string(&**e), - token::NtTy(ref e) => ty_to_string(&**e), - token::NtPath(ref e) => path_to_string(&**e), - token::NtItem(..) => "an interpolated item".to_string(), - token::NtBlock(..) => "an interpolated block".to_string(), - token::NtStmt(..) => "an interpolated statement".to_string(), - token::NtPat(..) => "an interpolated pattern".to_string(), - token::NtIdent(..) => "an interpolated identifier".to_string(), - token::NtTT(..) => "an interpolated tt".to_string(), - token::NtArm(..) => "an interpolated arm".to_string(), - token::NtImplItem(..) => "an interpolated impl item".to_string(), - token::NtTraitItem(..) => "an interpolated trait item".to_string(), + token::NtExpr(ref e) => expr_to_string(&**e), + token::NtMeta(ref e) => meta_item_to_string(&**e), + token::NtTy(ref e) => ty_to_string(&**e), + token::NtPath(ref e) => path_to_string(&**e), + token::NtItem(ref e) => item_to_string(&**e), + token::NtBlock(ref e) => block_to_string(&**e), + token::NtStmt(ref e) => stmt_to_string(&**e), + token::NtPat(ref e) => pat_to_string(&**e), + token::NtIdent(ref e, _) => ident_to_string(&**e), + token::NtTT(ref e) => tt_to_string(&**e), + token::NtArm(ref e) => arm_to_string(&*e), + token::NtImplItem(ref e) => impl_item_to_string(&**e), + token::NtTraitItem(ref e) => trait_item_to_string(&**e), + token::NtGenerics(ref e) => generics_to_string(&*e), + token::NtWhereClause(ref e) => where_clause_to_string(&*e), } } } diff --git a/src/test/run-pass-fulldeps/quote-tokens.rs b/src/test/run-pass-fulldeps/quote-tokens.rs index 64061eb093247..5182f274255ae 100644 --- a/src/test/run-pass-fulldeps/quote-tokens.rs +++ b/src/test/run-pass-fulldeps/quote-tokens.rs @@ -43,6 +43,12 @@ fn syntax_extension(cx: &ExtCtxt) { let _n: syntax::ast::Attribute = quote_attr!(cx, #![cfg(foo, bar = "baz")]); let _o: Option> = quote_item!(cx, fn foo() {}); + + let stmts = vec![ + quote_stmt!(cx, let x = 1;).unwrap(), + quote_stmt!(cx, let y = 2;).unwrap(), + ]; + let expr: P = quote_expr!(cx, x + y); } fn main() {