1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 #![allow(unused_parens)]
13 #![feature(plugin_registrar)]
14 #![feature(rustc_private)]
15 #![plugin(proc_macro)]
17 extern crate rustc_plugin
;
18 extern crate proc_macro
;
21 use proc_macro
::prelude
::*;
23 use rustc_plugin
::Registry
;
25 use syntax
::ast
::Ident
;
26 use syntax
::codemap
::{DUMMY_SP, Span}
;
27 use syntax
::ext
::proc_macro_shim
::build_block_emitter
;
28 use syntax
::ext
::base
::{ExtCtxt, MacResult}
;
29 use syntax
::parse
::token
::{self, Token, DelimToken, keywords, str_to_ident}
;
30 use syntax
::tokenstream
::{TokenTree, TokenStream}
;
33 pub fn plugin_registrar(reg
: &mut Registry
) {
34 reg
.register_macro("cond", cond
);
37 fn cond
<'cx
>(cx
: &'cx
mut ExtCtxt
, sp
: Span
, tts
: &[TokenTree
]) -> Box
<MacResult
+ 'cx
> {
38 let output
= cond_rec(TokenStream
::from_tts(tts
.clone().to_owned()));
39 build_block_emitter(cx
, sp
, output
)
42 fn cond_rec(input
: TokenStream
) -> TokenStream
{
47 let next
= input
.slice(0..1);
48 let rest
= input
.slice_from(1..);
50 let clause
: TokenStream
= match next
.maybe_delimited() {
52 _
=> panic
!("Invalid input"),
55 // clause is ([test]) [rhs]
56 if clause
.len() < 2 { panic!("Invalid macro usage in cond: {:?}
", clause) }
58 let test: TokenStream = clause.slice(0..1);
59 let rhs: TokenStream = clause.slice_from(1..);
61 if ident_eq(&test[0], str_to_ident("else")) || rest.is_empty() {
62 qquote!({unquote(rhs)})
64 qquote!({if unquote(test) { unquote(rhs) } else { cond!(unquote(rest)) } })