Skip to content
This repository was archived by the owner on Dec 27, 2022. It is now read-only.

Commit c6cb011

Browse files
committed
Proc macro hack
0 parents  commit c6cb011

File tree

12 files changed

+367
-0
lines changed

12 files changed

+367
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
target
2+
Cargo.lock

Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "proc-macro-hack"
3+
version = "0.1.0"
4+
authors = ["David Tolnay <[email protected]>"]
5+
license = "MIT/Apache-2.0"
6+
description = "Procedural functionlike!() macros using only Macros 1.1"
7+
repository = "https://github.com/dtolnay/proc-macro-hack"

README.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
Procedural functionlike!() macros using only Macros 1.1
2+
=======================================================
3+
4+
[![Build Status](https://api.travis-ci.org/dtolnay/proc-macro-hack.svg?branch=master)](https://travis-ci.org/dtolnay/proc-macro-hack)
5+
[![Latest Version](https://img.shields.io/crates/v/proc-macro-hack.svg)](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.

demo-hack-impl/Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "demo-hack-impl"
3+
version = "0.1.0"
4+
authors = ["David Tolnay <[email protected]>"]
5+
6+
[lib]
7+
proc-macro = true
8+
9+
[dependencies]
10+
proc-macro-hack = { path = ".." }
11+
proc-macro-hack-impl = { path = "../impl" }

demo-hack-impl/src/lib.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#![feature(proc_macro, proc_macro_lib)]
2+
3+
#[macro_use] extern crate proc_macro_hack;
4+
#[macro_use] extern crate proc_macro_hack_impl;
5+
6+
proc_macro_expr_impl! {
7+
/// Add one to an expression.
8+
pub fn add_one_impl(input: &str) -> Result<String, String> {
9+
Ok(format!("1 + {}", input))
10+
}
11+
}
12+
13+
proc_macro_item_impl! {
14+
/// A function that always returns 2.
15+
pub fn two_fn_impl(input: &str) -> Result<String, String> {
16+
Ok(format!("fn {}() -> u8 {{ 2 }}", input))
17+
}
18+
}

demo-hack/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "demo-hack"
3+
version = "0.1.0"
4+
authors = ["David Tolnay <[email protected]>"]
5+
6+
[dependencies]
7+
proc-macro-hack = { path = ".." }
8+
proc-macro-hack-impl = { path = "../impl" }

demo-hack/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![feature(proc_macro)]
2+
3+
#[macro_use] extern crate proc_macro_hack;
4+
#[macro_use] extern crate proc_macro_hack_impl;
5+
6+
/// Add one to an expression.
7+
proc_macro_expr_decl!(add_one! => add_one_impl);
8+
9+
/// A function that always returns 2.
10+
proc_macro_item_decl!(two_fn! => two_fn_impl);

example/Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "example"
3+
version = "0.1.0"
4+
authors = ["David Tolnay <[email protected]>"]
5+
6+
[dependencies]
7+
demo-hack = { path = "../demo-hack" }
8+
demo-hack-impl = { path = "../demo-hack-impl" }
9+
proc-macro-hack = { path = ".." }

example/src/main.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#![feature(proc_macro)]
2+
3+
#[macro_use] extern crate demo_hack;
4+
#[macro_use] extern crate demo_hack_impl;
5+
6+
two_fn!(two);
7+
8+
fn main() {
9+
let x = two();
10+
let nine = add_one!(x) + add_one!(2 + 3);
11+
println!("nine = {}", nine);
12+
}

impl/Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "proc-macro-hack-impl"
3+
version = "0.1.0"
4+
authors = ["David Tolnay <[email protected]>"]
5+
license = "MIT/Apache-2.0"
6+
description = "Procedural functionlike!() macros using only Macros 1.1"
7+
repository = "https://github.com/dtolnay/proc-macro-hack"
8+
9+
[lib]
10+
proc-macro = true

0 commit comments

Comments
 (0)