|
| 1 | +Procedural functionlike!() macros using only Macros 1.1 |
| 2 | +======================================================= |
| 3 | + |
| 4 | +[](https://travis-ci.org/dtolnay/proc-macro-hack) |
| 5 | +[](https://crates.io/crates/proc-macro-hack) |
| 6 | + |
| 7 | +Did you think Macros 1.1 was only for custom derives? Think again. |
| 8 | + |
| 9 | +## Defining procedural macros |
| 10 | + |
| 11 | +Two crates are required to define a macro. |
| 12 | + |
| 13 | +### The declaration crate |
| 14 | + |
| 15 | +This crate is allowed to contain other public things if you need, for example |
| 16 | +traits or functions or ordinary macros. |
| 17 | + |
| 18 | +https://github.com/dtolnay/proc-macro-hack/tree/master/demo-hack |
| 19 | + |
| 20 | +```rust |
| 21 | +#![feature(proc_macro)] |
| 22 | + |
| 23 | +#[macro_use] extern crate proc_macro_hack; |
| 24 | +#[macro_use] extern crate proc_macro_hack_impl; |
| 25 | + |
| 26 | +/// Add one to an expression. |
| 27 | +proc_macro_expr_decl!(add_one! => add_one_impl); |
| 28 | + |
| 29 | +/// A function that always returns 2. |
| 30 | +proc_macro_item_decl!(two_fn! => two_fn_impl); |
| 31 | +``` |
| 32 | + |
| 33 | +### The implementation crate |
| 34 | + |
| 35 | +This crate must contain nothing but procedural macros. Private helper functions |
| 36 | +and private modules are fine but nothing can be public. |
| 37 | + |
| 38 | +https://github.com/dtolnay/proc-macro-hack/tree/master/demo-hack-impl |
| 39 | + |
| 40 | +```rust |
| 41 | +#![feature(proc_macro, proc_macro_lib)] |
| 42 | + |
| 43 | +#[macro_use] extern crate proc_macro_hack; |
| 44 | +#[macro_use] extern crate proc_macro_hack_impl; |
| 45 | + |
| 46 | +proc_macro_expr_impl! { |
| 47 | + /// Add one to an expression. |
| 48 | + pub fn add_one_impl(input: &str) -> Result<String, String> { |
| 49 | + Ok(format!("1 + {}", input)) |
| 50 | + } |
| 51 | +} |
| 52 | + |
| 53 | +proc_macro_item_impl! { |
| 54 | + /// A function that always returns 2. |
| 55 | + pub fn two_fn_impl(input: &str) -> Result<String, String> { |
| 56 | + Ok(format!("fn {}() -> u8 {{ 2 }}", input)) |
| 57 | + } |
| 58 | +} |
| 59 | +``` |
| 60 | + |
| 61 | +Both crates depend on `proc-macro-hack` which itself has a declaration crate and |
| 62 | +implementation crate: |
| 63 | + |
| 64 | +```toml |
| 65 | +[dependencies] |
| 66 | +proc-macro-hack = "0.1" |
| 67 | +proc-macro-hack-impl = "0.1" |
| 68 | +``` |
| 69 | + |
| 70 | +Additionally, your implementation crate (but not your declaration crate) is a |
| 71 | +proc macro: |
| 72 | + |
| 73 | +```toml |
| 74 | +[lib] |
| 75 | +proc-macro = true |
| 76 | +``` |
| 77 | + |
| 78 | +## Using procedural macros |
| 79 | + |
| 80 | +Users of your crate depend on your declaration crate and implementation crate, |
| 81 | +then use your procedural macros as though it were magic. They even get |
| 82 | +reasonable error messages if your procedural macro returns an error. |
| 83 | + |
| 84 | +https://github.com/dtolnay/proc-macro-hack/tree/master/example |
| 85 | + |
| 86 | +```rust |
| 87 | +#![feature(proc_macro)] |
| 88 | + |
| 89 | +#[macro_use] extern crate demo_hack; |
| 90 | +#[macro_use] extern crate demo_hack_impl; |
| 91 | + |
| 92 | +two_fn!(two); |
| 93 | + |
| 94 | +fn main() { |
| 95 | + let x = two(); |
| 96 | + let nine = add_one!(x) + add_one!(2 + 3); |
| 97 | + println!("nine = {}", nine); |
| 98 | +} |
| 99 | +``` |
| 100 | + |
| 101 | +## Limitations |
| 102 | + |
| 103 | +- The input to your macro cannot contain dollar signs. |
| 104 | +- Users of your macro need to `#[macro_use] extern crate` two different crates, |
| 105 | + not just one. |
| 106 | +- Your macro must expand to either an expression or zero-or-more items, cannot |
| 107 | + sometimes be one or the other depending on input. |
| 108 | + |
| 109 | +## License |
| 110 | + |
| 111 | +Licensed under either of |
| 112 | + |
| 113 | + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) |
| 114 | + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) |
| 115 | + |
| 116 | +at your option. |
| 117 | + |
| 118 | +### Contribution |
| 119 | + |
| 120 | +Unless you explicitly state otherwise, any contribution intentionally submitted |
| 121 | +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall |
| 122 | +be dual licensed as above, without any additional terms or conditions. |
0 commit comments