rust - Is there a way to count with macros? -


i want create macro prints "hello" specified number of times. it's used like:

many_greetings!(3);  // expands 3 `println!("hello");` statements 

the naive way create macro is:

macro_rules! many_greetings {     ($times:expr) => {{         println!("hello");         many_greetings!($times - 1);     }};     (0) => (); } 

however, doesn't work because compiler not evaluate expressions; $times - 1 isn't calculated, fed new expression macro.

while ordinary macro system not enable repeat macro expansion many times, there no problem using loop in macro:

macro_rules! many_greetings {     ($times:expr) => {{         _ in 0..$times {             println!("hello");         }     }}; } 

if need repeat macro, have procedural macros/compiler plugins (which of 1.4 unstable, , bit harder write).

edit: there better ways of implementing this, i've spent long enough on today, here goes. repeat!, macro duplicates block of code number of times:

main.rs

#![feature(plugin)] #![plugin(repeat)]  fn main() {     let mut n = 0;     repeat!{ 4 {         println!("hello {}", n);         n += 1;     }}; } 

lib.rs

#![feature(plugin_registrar, rustc_private)]  extern crate syntax; extern crate rustc;  use syntax::codemap::span; use syntax::ast::tokentree; use syntax::ext::base::{extctxt, macresult, maceager, dummyresult}; use rustc::plugin::registry; use syntax::util::small_vector::smallvector; use syntax::ast::lit_; use std::error::error;  fn expand_repeat(cx: &mut extctxt, sp: span, tts: &[tokentree]) -> box<macresult + 'static> {     let mut parser = cx.new_parser_from_tts(tts);     let times = match parser.parse_lit() {         ok(lit) => match lit.node {             lit_::litint(n, _) => n,             _ => {                 cx.span_err(lit.span, "expected literal integer");                 return dummyresult::any(sp);             }         },         err(e) => {             cx.span_err(sp, e.description());             return dummyresult::any(sp);         }     };     let res = parser.parse_block();      match res {         ok(block) => {             let mut stmts = smallvector::many(block.stmts.clone());             _ in 1..times {                 let rep_stmts = smallvector::many(block.stmts.clone());                 stmts.push_all(rep_stmts);             }             maceager::stmts(stmts)         }         err(e) => {             cx.span_err(sp, e.description());             dummyresult::any(sp)         }     } }  #[plugin_registrar] pub fn plugin_registrar(reg: &mut registry) {     reg.register_macro("repeat", expand_repeat); } 

added cargo.toml

[lib] name = "repeat" plugin = true 

note if don't want looping, expanding @ compile-time, have things requiring literal numbers. after all, not able evaluate variables , function calls reference other parts of program @ compile time.


Comments

Popular posts from this blog

php - Vagrant up error - Uncaught Reflection Exception: Class DOMDocument does not exist -

vue.js - Create hooks for automated testing -

Add new key value to json node in java -