Skip to content

libsyntax: Add more quasiquoting macros #29780

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

Merged
merged 1 commit into from
Nov 12, 2015
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
12 changes: 12 additions & 0 deletions src/libsyntax/ext/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,18 @@ fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>)
syntax_expanders.insert(intern("quote_attr"),
builtin_normal_expander(
ext::quote::expand_quote_attr));
syntax_expanders.insert(intern("quote_arg"),
builtin_normal_expander(
ext::quote::expand_quote_arg));
syntax_expanders.insert(intern("quote_block"),
builtin_normal_expander(
ext::quote::expand_quote_block));
syntax_expanders.insert(intern("quote_meta_item"),
builtin_normal_expander(
ext::quote::expand_quote_meta_item));
syntax_expanders.insert(intern("quote_path"),
builtin_normal_expander(
ext::quote::expand_quote_path));
}

syntax_expanders.insert(intern("line"),
Expand Down
51 changes: 51 additions & 0 deletions src/libsyntax/ext/quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,18 @@ pub mod rt {
}
}

impl ToTokens for ast::Arg {
fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtArg(self.clone())))]
}
}

impl ToTokens for P<ast::Block> {
fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtBlock(self.clone())))]
}
}

macro_rules! impl_to_tokens_slice {
($t: ty, $sep: expr) => {
impl ToTokens for [$t] {
Expand All @@ -177,6 +189,7 @@ pub mod rt {

impl_to_tokens_slice! { ast::Ty, [TokenTree::Token(DUMMY_SP, token::Comma)] }
impl_to_tokens_slice! { P<ast::Item>, [] }
impl_to_tokens_slice! { ast::Arg, [TokenTree::Token(DUMMY_SP, token::Comma)] }

impl ToTokens for P<ast::MetaItem> {
fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
Expand Down Expand Up @@ -383,6 +396,39 @@ pub fn expand_quote_attr(cx: &mut ExtCtxt,
base::MacEager::expr(expanded)
}

pub fn expand_quote_arg(cx: &mut ExtCtxt,
sp: Span,
tts: &[TokenTree])
-> Box<base::MacResult+'static> {
let expanded = expand_parse_call(cx, sp, "parse_arg_panic", vec!(), tts);
base::MacEager::expr(expanded)
}

pub fn expand_quote_block(cx: &mut ExtCtxt,
sp: Span,
tts: &[TokenTree])
-> Box<base::MacResult+'static> {
let expanded = expand_parse_call(cx, sp, "parse_block_panic", vec!(), tts);
base::MacEager::expr(expanded)
}

pub fn expand_quote_meta_item(cx: &mut ExtCtxt,
sp: Span,
tts: &[TokenTree])
-> Box<base::MacResult+'static> {
let expanded = expand_parse_call(cx, sp, "parse_meta_item_panic", vec!(), tts);
base::MacEager::expr(expanded)
}

pub fn expand_quote_path(cx: &mut ExtCtxt,
sp: Span,
tts: &[TokenTree])
-> Box<base::MacResult+'static> {
let mode = mk_parser_path(cx, sp, "LifetimeAndTypesWithoutColons");
let expanded = expand_parse_call(cx, sp, "parse_path_panic", vec!(mode), tts);
base::MacEager::expr(expanded)
}

pub fn expand_quote_matcher(cx: &mut ExtCtxt,
sp: Span,
tts: &[TokenTree])
Expand Down Expand Up @@ -440,6 +486,11 @@ fn mk_token_path(cx: &ExtCtxt, sp: Span, name: &str) -> P<ast::Expr> {
cx.expr_path(cx.path_global(sp, idents))
}

fn mk_parser_path(cx: &ExtCtxt, sp: Span, name: &str) -> P<ast::Expr> {
let idents = vec!(id_ext("syntax"), id_ext("parse"), id_ext("parser"), id_ext(name));
cx.expr_path(cx.path_global(sp, idents))
}

fn mk_binop(cx: &ExtCtxt, sp: Span, bop: token::BinOpToken) -> P<ast::Expr> {
let name = match bop {
token::Plus => "Plus",
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,7 @@ pub fn noop_fold_interpolated<T: Folder>(nt: token::Nonterminal, fld: &mut T)
token::NtGenerics(generics) => token::NtGenerics(fld.fold_generics(generics)),
token::NtWhereClause(where_clause) =>
token::NtWhereClause(fld.fold_where_clause(where_clause)),
token::NtArg(arg) => token::NtArg(fld.fold_arg(arg)),
}
}

Expand Down
18 changes: 18 additions & 0 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,22 @@ impl<'a> Parser<'a> {
panictry!(self.parse_attribute(permit_inner))
}

pub fn parse_arg_panic(&mut self) -> Arg {
panictry!(self.parse_arg())
}

pub fn parse_block_panic(&mut self) -> P<Block> {
panictry!(self.parse_block())
}

pub fn parse_meta_item_panic(&mut self) -> P<ast::MetaItem> {
panictry!(self.parse_meta_item())
}

pub fn parse_path_panic(&mut self, mode: PathParsingMode) -> ast::Path {
panictry!(self.parse_path(mode))
}

/// Convert a token to a string using self's reader
pub fn token_to_string(token: &token::Token) -> String {
pprust::token_to_string(token)
Expand Down Expand Up @@ -1455,6 +1471,8 @@ impl<'a> Parser<'a> {
/// This version of parse arg doesn't necessarily require
/// identifier names.
pub fn parse_arg_general(&mut self, require_name: bool) -> PResult<Arg> {
maybe_whole!(no_clone self, NtArg);

let pat = if require_name || self.is_named_argument() {
debug!("parse_arg_general parse_pat (require_name:{})",
require_name);
Expand Down
4 changes: 3 additions & 1 deletion src/libsyntax/parse/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,12 +381,13 @@ pub enum Nonterminal {
NtMeta(P<ast::MetaItem>),
NtPath(Box<ast::Path>),
NtTT(P<ast::TokenTree>), // needs P'ed to break a circularity
// These is not exposed to macros, but is used by quasiquote.
// These are not exposed to macros, but are used by quasiquote.
NtArm(ast::Arm),
NtImplItem(P<ast::ImplItem>),
NtTraitItem(P<ast::TraitItem>),
NtGenerics(ast::Generics),
NtWhereClause(ast::WhereClause),
NtArg(ast::Arg),
}

impl fmt::Debug for Nonterminal {
Expand All @@ -407,6 +408,7 @@ impl fmt::Debug for Nonterminal {
NtTraitItem(..) => f.pad("NtTraitItem(..)"),
NtGenerics(..) => f.pad("NtGenerics(..)"),
NtWhereClause(..) => f.pad("NtWhereClause(..)"),
NtArg(..) => f.pad("NtArg(..)"),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax/print/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ pub fn token_to_string(tok: &Token) -> String {
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),
token::NtArg(ref e) => arg_to_string(&*e),
}
}
}
Expand Down
24 changes: 14 additions & 10 deletions src/test/compile-fail-fulldeps/gated-quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,18 @@ impl ParseSess {

pub fn main() {
let ecx = &ParseSess;
let x = quote_tokens!(ecx, 3); //~ ERROR macro undefined: 'quote_tokens!'
let x = quote_expr!(ecx, 3); //~ ERROR macro undefined: 'quote_expr!'
let x = quote_ty!(ecx, 3); //~ ERROR macro undefined: 'quote_ty!'
let x = quote_method!(ecx, 3); //~ ERROR macro undefined: 'quote_method!'
let x = quote_item!(ecx, 3); //~ ERROR macro undefined: 'quote_item!'
let x = quote_pat!(ecx, 3); //~ ERROR macro undefined: 'quote_pat!'
let x = quote_arm!(ecx, 3); //~ ERROR macro undefined: 'quote_arm!'
let x = quote_stmt!(ecx, 3); //~ ERROR macro undefined: 'quote_stmt!'
let x = quote_matcher!(ecx, 3); //~ ERROR macro undefined: 'quote_matcher!'
let x = quote_attr!(ecx, 3); //~ ERROR macro undefined: 'quote_attr!'
let x = quote_tokens!(ecx, 3); //~ ERROR macro undefined: 'quote_tokens!'
let x = quote_expr!(ecx, 3); //~ ERROR macro undefined: 'quote_expr!'
let x = quote_ty!(ecx, 3); //~ ERROR macro undefined: 'quote_ty!'
let x = quote_method!(ecx, 3); //~ ERROR macro undefined: 'quote_method!'
let x = quote_item!(ecx, 3); //~ ERROR macro undefined: 'quote_item!'
let x = quote_pat!(ecx, 3); //~ ERROR macro undefined: 'quote_pat!'
let x = quote_arm!(ecx, 3); //~ ERROR macro undefined: 'quote_arm!'
let x = quote_stmt!(ecx, 3); //~ ERROR macro undefined: 'quote_stmt!'
let x = quote_matcher!(ecx, 3); //~ ERROR macro undefined: 'quote_matcher!'
let x = quote_attr!(ecx, 3); //~ ERROR macro undefined: 'quote_attr!'
let x = quote_arg!(ecx, 3); //~ ERROR macro undefined: 'quote_arg!'
let x = quote_block!(ecx, 3); //~ ERROR macro undefined: 'quote_block!'
let x = quote_meta_item!(ecx, 3); //~ ERROR macro undefined: 'quote_meta_item!'
let x = quote_path!(ecx, 3); //~ ERROR macro undefined: 'quote_path!'
}
37 changes: 37 additions & 0 deletions src/test/run-pass-fulldeps/qquote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,41 @@ fn main() {

let attr = quote_attr!(cx, #![cfg(foo = "bar")]);
check!(attribute_to_string, attr, quote_attr!(cx, $attr); r#"#![cfg(foo = "bar")]"#);

// quote_arg!

let arg = quote_arg!(cx, foo: i32);
check!(arg_to_string, arg, quote_arg!(cx, $arg); "foo: i32");

let function = quote_item!(cx, fn f($arg) { }).unwrap();
check!(item_to_string, function; "fn f(foo: i32) { }");

let args = vec![arg, quote_arg!(cx, bar: u32)];
let args = &args[..];
let function = quote_item!(cx, fn f($args) { }).unwrap();
check!(item_to_string, function; "fn f(foo: i32, bar: u32) { }");

// quote_block!

let block = quote_block!(cx, { $stmt let y = 40u32; });
check!(block_to_string, block, *quote_block!(cx, $block); "{ let x = 20u16; let y = 40u32; }");

let function = quote_item!(cx, fn f() $block).unwrap();
check!(item_to_string, function; "fn f() { let x = 20u16; let y = 40u32; }");

// quote_path!

let path = quote_path!(cx, ::syntax::ptr::P<MetaItem>);
check!(path_to_string, path, quote_path!(cx, $path); "::syntax::ptr::P<MetaItem>");

let ty = quote_ty!(cx, $path);
check!(ty_to_string, ty; "::syntax::ptr::P<MetaItem>");

// quote_meta_item!

let meta = quote_meta_item!(cx, cfg(foo = "bar"));
check!(meta_item_to_string, meta, *quote_meta_item!(cx, $meta); r#"cfg(foo = "bar")"#);

let attr = quote_attr!(cx, #![$meta]);
check!(attribute_to_string, attr; r#"#![cfg(foo = "bar")]"#);
}