Implement quote! and other proc_macro API.

This commit is contained in:
Jeffrey Seyfried 2017-03-17 23:41:09 +00:00
parent 7d41674b17
commit e42836b208
34 changed files with 1084 additions and 576 deletions

View file

@ -8,50 +8,37 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(unused_parens)]
#![feature(plugin)]
#![feature(plugin_registrar)]
#![feature(rustc_private)]
#![plugin(proc_macro_plugin)]
// no-prefer-dynamic
extern crate rustc_plugin;
extern crate syntax;
#![crate_type = "proc-macro"]
#![feature(proc_macro, proc_macro_lib)]
use rustc_plugin::Registry;
extern crate proc_macro;
use syntax::ext::base::SyntaxExtension;
use syntax::parse::token::Token;
use syntax::symbol::Symbol;
use syntax::tokenstream::{TokenTree, TokenStream};
use proc_macro::{TokenStream, TokenKind, quote};
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_syntax_extension(Symbol::intern("cond"),
SyntaxExtension::ProcMacro(Box::new(cond)));
}
fn cond(input: TokenStream) -> TokenStream {
#[proc_macro]
pub fn cond(input: TokenStream) -> TokenStream {
let mut conds = Vec::new();
let mut input = input.trees().peekable();
let mut input = input.into_iter().peekable();
while let Some(tree) = input.next() {
let mut cond = match tree {
TokenTree::Delimited(_, ref delimited) => delimited.stream(),
let cond = match tree.kind {
TokenKind::Sequence(_, cond) => cond,
_ => panic!("Invalid input"),
};
let mut trees = cond.trees();
let test = trees.next();
let rhs = trees.collect::<TokenStream>();
let mut cond_trees = cond.clone().into_iter();
let test = cond_trees.next().expect("Unexpected empty condition in `cond!`");
let rhs = cond_trees.collect::<TokenStream>();
if rhs.is_empty() {
panic!("Invalid macro usage in cond: {}", cond);
}
let is_else = match test {
Some(TokenTree::Token(_, Token::Ident(ident))) if ident.name == "else" => true,
let is_else = match test.kind {
TokenKind::Word(word) => *word == *"else",
_ => false,
};
conds.push(if is_else || input.peek().is_none() {
quote!({ $rhs })
} else {
let test = test.unwrap();
quote!(if $test { $rhs } else)
});
}

View file

@ -8,29 +8,20 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(plugin)]
#![feature(plugin_registrar)]
#![feature(rustc_private)]
#![plugin(proc_macro_plugin)]
// no-prefer-dynamic
extern crate rustc_plugin;
extern crate syntax;
#![crate_type = "proc-macro"]
#![feature(proc_macro, proc_macro_lib)]
use rustc_plugin::Registry;
use syntax::ext::base::SyntaxExtension;
use syntax::symbol::Symbol;
use syntax::tokenstream::TokenStream;
extern crate proc_macro;
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_syntax_extension(Symbol::intern("hello"),
SyntaxExtension::ProcMacro(Box::new(hello)));
}
use proc_macro::{TokenStream, quote};
// This macro is not very interesting, but it does contain delimited tokens with
// no content - `()` and `{}` - which has caused problems in the past.
// Also, it tests that we can escape `$` via `$$`.
fn hello(_: TokenStream) -> TokenStream {
#[proc_macro]
pub fn hello(_: TokenStream) -> TokenStream {
quote!({
fn hello() {}
macro_rules! m { ($$($$t:tt)*) => { $$($$t)* } }

View file

@ -8,47 +8,37 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(plugin, plugin_registrar, rustc_private)]
#![plugin(proc_macro_plugin)]
// no-prefer-dynamic
extern crate rustc_plugin;
extern crate syntax;
#![crate_type = "proc-macro"]
#![feature(proc_macro, proc_macro_lib)]
use rustc_plugin::Registry;
use syntax::ext::base::SyntaxExtension;
use syntax::tokenstream::TokenStream;
use syntax::symbol::Symbol;
extern crate proc_macro;
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_syntax_extension(Symbol::intern("attr_tru"),
SyntaxExtension::AttrProcMacro(Box::new(attr_tru)));
reg.register_syntax_extension(Symbol::intern("attr_identity"),
SyntaxExtension::AttrProcMacro(Box::new(attr_identity)));
reg.register_syntax_extension(Symbol::intern("tru"),
SyntaxExtension::ProcMacro(Box::new(tru)));
reg.register_syntax_extension(Symbol::intern("ret_tru"),
SyntaxExtension::ProcMacro(Box::new(ret_tru)));
reg.register_syntax_extension(Symbol::intern("identity"),
SyntaxExtension::ProcMacro(Box::new(identity)));
use proc_macro::{TokenStream, quote};
#[proc_macro_attribute]
pub fn attr_tru(_attr: TokenStream, item: TokenStream) -> TokenStream {
let name = item.into_iter().skip(1).next().unwrap();
quote!(fn $name() -> bool { true })
}
fn attr_tru(_attr: TokenStream, _item: TokenStream) -> TokenStream {
quote!(fn f1() -> bool { true })
}
fn attr_identity(_attr: TokenStream, item: TokenStream) -> TokenStream {
#[proc_macro_attribute]
pub fn attr_identity(_attr: TokenStream, item: TokenStream) -> TokenStream {
quote!($item)
}
fn tru(_ts: TokenStream) -> TokenStream {
#[proc_macro]
pub fn tru(_ts: TokenStream) -> TokenStream {
quote!(true)
}
fn ret_tru(_ts: TokenStream) -> TokenStream {
#[proc_macro]
pub fn ret_tru(_ts: TokenStream) -> TokenStream {
quote!(return true;)
}
fn identity(ts: TokenStream) -> TokenStream {
#[proc_macro]
pub fn identity(ts: TokenStream) -> TokenStream {
quote!($ts)
}

View file

@ -1,40 +0,0 @@
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-stage1
#![feature(plugin)]
#![feature(rustc_private)]
#![plugin(proc_macro_plugin)]
extern crate syntax;
extern crate syntax_pos;
use syntax::ast::{Ident, Name};
use syntax::parse::token::{self, Token, Lit};
use syntax::tokenstream::TokenTree;
fn main() {
let true_tok = token::Ident(Ident::from_str("true"));
assert!(quote!(true).eq_unspanned(&true_tok.into()));
// issue #35829, extended check to proc_macro.
let triple_dot_tok = Token::DotDotDot;
assert!(quote!(...).eq_unspanned(&triple_dot_tok.into()));
let byte_str_tok = Token::Literal(Lit::ByteStr(Name::intern("one")), None);
assert!(quote!(b"one").eq_unspanned(&byte_str_tok.into()));
let byte_str_raw_tok = Token::Literal(Lit::ByteStrRaw(Name::intern("#\"two\"#"), 3), None);
assert!(quote!(br###"#"two"#"###).eq_unspanned(&byte_str_raw_tok.into()));
let str_raw_tok = Token::Literal(Lit::StrRaw(Name::intern("#\"three\"#"), 2), None);
assert!(quote!(r##"#"three"#"##).eq_unspanned(&str_raw_tok.into()));
}

View file

@ -11,9 +11,11 @@
// aux-build:cond_plugin.rs
// ignore-stage1
#![feature(plugin)]
#![feature(rustc_private)]
#![plugin(cond_plugin)]
#![feature(proc_macro)]
extern crate cond_plugin;
use cond_plugin::cond;
fn fact(n : i64) -> i64 {
if n == 0 {

View file

@ -13,10 +13,10 @@
// aux-build:hello_macro.rs
// ignore-stage1
#![feature(plugin)]
#![feature(rustc_private)]
#![plugin(hello_macro)]
#![feature(proc_macro)]
extern crate hello_macro;
fn main() {
hello!();
hello_macro::hello!();
}

View file

@ -12,10 +12,11 @@
// ignore-stage1
// ignore-cross-compile
#![feature(plugin, custom_attribute)]
#![feature(type_macros)]
#![feature(proc_macro)]
#![plugin(proc_macro_def)]
extern crate proc_macro_def;
use proc_macro_def::{attr_tru, attr_identity, identity, ret_tru, tru};
#[attr_tru]
fn f1() -> bool {