1 // Copyright 2015 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_plugin)]
17 extern crate rustc_plugin
;
18 extern crate proc_macro_tokens
;
21 use proc_macro_tokens
::build
::ident_eq
;
23 use syntax
::ext
::base
::{ExtCtxt, MacResult}
;
24 use syntax
::ext
::proc_macro_shim
::build_block_emitter
;
25 use syntax
::tokenstream
::{TokenTree, TokenStream}
;
26 use syntax
::parse
::token
::str_to_ident
;
27 use syntax
::codemap
::Span
;
29 use rustc_plugin
::Registry
;
32 pub fn plugin_registrar(reg
: &mut Registry
) {
33 reg
.register_macro("cond", cond
);
36 fn cond
<'cx
>(cx
: &'cx
mut ExtCtxt
, sp
: Span
, tts
: &[TokenTree
]) -> Box
<MacResult
+ 'cx
> {
37 let output
= cond_rec(TokenStream
::from_tts(tts
.clone().to_owned()));
38 build_block_emitter(cx
, sp
, output
)
41 fn cond_rec(input
: TokenStream
) -> TokenStream
{
46 let next
= input
.slice(0..1);
47 let rest
= input
.slice_from(1..);
49 let clause
: TokenStream
= match next
.maybe_delimited() {
51 _
=> panic
!("Invalid input"),
54 // clause is ([test]) [rhs]
55 if clause
.len() < 2 { panic!("Invalid macro usage in cond: {:?}
", clause) }
57 let test: TokenStream = clause.slice(0..1);
58 let rhs: TokenStream = clause.slice_from(1..);
60 if ident_eq(&test[0], str_to_ident("else")) || rest.is_empty() {
61 qquote!({unquote(rhs)})
63 qquote!({if unquote(test) { unquote(rhs) } else { cond!(unquote(rest)) } })