@@ -13,7 +13,7 @@ This feature is part of "compiler plugins." It will often be used with the
13
13
------------------------
14
14
15
15
` rustc ` can load compiler plugins, which are user-provided libraries that
16
- extend the compiler's behavior with new syntax extensions, lint checks, etc.
16
+ extend the compiler's behavior with new lint checks, etc.
17
17
18
18
A plugin is a dynamic library crate with a designated * registrar* function that
19
19
registers extensions with ` rustc ` . Other crates can load these extensions using
@@ -35,134 +35,6 @@ The usual practice is to put compiler plugins in their own crate, separate from
35
35
any ` macro_rules! ` macros or ordinary Rust code meant to be used by consumers
36
36
of a library.
37
37
38
- # Syntax extensions
39
-
40
- Plugins can extend Rust's syntax in various ways. One kind of syntax extension
41
- is the procedural macro. These are invoked the same way as [ ordinary
42
- macros] ( ../../book/macros.md ) , but the expansion is performed by arbitrary Rust
43
- code that manipulates syntax trees at
44
- compile time.
45
-
46
- Let's write a plugin
47
- [ ` roman_numerals.rs ` ] ( https://github.com/rust-lang/rust/blob/master/src/test/ui-fulldeps/auxiliary/roman_numerals.rs )
48
- that implements Roman numeral integer literals.
49
-
50
- ``` rust,ignore
51
- #![crate_type="dylib"]
52
- #![feature(plugin_registrar, rustc_private)]
53
-
54
- extern crate syntax;
55
- extern crate syntax_pos;
56
- extern crate rustc;
57
- extern crate rustc_driver;
58
-
59
- use syntax::parse::token::{self, Token};
60
- use syntax::tokenstream::{TokenTree, TokenStream};
61
- use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
62
- use syntax_pos::Span;
63
- use rustc_driver::plugin::Registry;
64
-
65
- fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: TokenStream)
66
- -> Box<dyn MacResult + 'static> {
67
-
68
- static NUMERALS: &'static [(&'static str, usize)] = &[
69
- ("M", 1000), ("CM", 900), ("D", 500), ("CD", 400),
70
- ("C", 100), ("XC", 90), ("L", 50), ("XL", 40),
71
- ("X", 10), ("IX", 9), ("V", 5), ("IV", 4),
72
- ("I", 1)];
73
-
74
- if args.len() != 1 {
75
- cx.span_err(
76
- sp,
77
- &format!("argument should be a single identifier, but got {} arguments", args.len()));
78
- return DummyResult::any(sp);
79
- }
80
-
81
- let text = match args.into_trees().next().unwrap() {
82
- TokenTree::Token(Token { kind: token::Ident(s, _), .. }) => s.to_string(),
83
- _ => {
84
- cx.span_err(sp, "argument should be a single identifier");
85
- return DummyResult::any(sp);
86
- }
87
- };
88
-
89
- let mut text = &*text;
90
- let mut total = 0;
91
- while !text.is_empty() {
92
- match NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) {
93
- Some(&(rn, val)) => {
94
- total += val;
95
- text = &text[rn.len()..];
96
- }
97
- None => {
98
- cx.span_err(sp, "invalid Roman numeral");
99
- return DummyResult::any(sp);
100
- }
101
- }
102
- }
103
-
104
- MacEager::expr(cx.expr_usize(sp, total))
105
- }
106
-
107
- #[plugin_registrar]
108
- pub fn plugin_registrar(reg: &mut Registry) {
109
- reg.register_macro("rn", expand_rn);
110
- }
111
- ```
112
-
113
- Then we can use ` rn!() ` like any other macro:
114
-
115
- ``` rust,ignore
116
- #![feature(plugin)]
117
- #![plugin(roman_numerals)]
118
-
119
- fn main() {
120
- assert_eq!(rn!(MMXV), 2015);
121
- }
122
- ```
123
-
124
- The advantages over a simple ` fn(&str) -> u32 ` are:
125
-
126
- * The (arbitrarily complex) conversion is done at compile time.
127
- * Input validation is also performed at compile time.
128
- * It can be extended to allow use in patterns, which effectively gives
129
- a way to define new literal syntax for any data type.
130
-
131
- In addition to procedural macros, you can define new
132
- [ ` derive ` ] ( ../../reference/attributes/derive.md ) -like attributes and other kinds
133
- of extensions. See ` Registry::register_syntax_extension ` and the
134
- ` SyntaxExtension ` struct. For a more involved macro example, see
135
- [ ` regex_macros ` ] ( https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs ) .
136
-
137
-
138
- ## Tips and tricks
139
-
140
- You can use ` syntax::parse ` to turn token trees into
141
- higher-level syntax elements like expressions:
142
-
143
- ``` rust,ignore
144
- fn expand_foo(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
145
- -> Box<MacResult+'static> {
146
-
147
- let mut parser = cx.new_parser_from_tts(args);
148
-
149
- let expr: P<Expr> = parser.parse_expr();
150
- ```
151
-
152
- Looking through [ ` libsyntax ` parser
153
- code] ( https://github.com/rust-lang/rust/blob/master/src/libsyntax/parse/parser.rs )
154
- will give you a feel for how the parsing infrastructure works.
155
-
156
- Keep the ` Span ` s of everything you parse, for better error reporting. You can
157
- wrap ` Spanned ` around your custom data structures.
158
-
159
- Calling ` ExtCtxt::span_fatal ` will immediately abort compilation. It's better to
160
- instead call ` ExtCtxt::span_err ` and return ` DummyResult ` so that the compiler
161
- can continue and find further errors.
162
-
163
- To print syntax fragments for debugging, you can use ` span_note ` together with
164
- ` syntax::print::pprust::*_to_string ` .
165
-
166
38
# Lint plugins
167
39
168
40
Plugins can extend [ Rust's lint
0 commit comments