]> git.proxmox.com Git - rustc.git/blob - src/doc/book/compiler-plugins.md
Imported Upstream version 1.6.0+dfsg1
[rustc.git] / src / doc / book / compiler-plugins.md
1 % Compiler Plugins
2
3 # Introduction
4
5 `rustc` can load compiler plugins, which are user-provided libraries that
6 extend the compiler's behavior with new syntax extensions, lint checks, etc.
7
8 A plugin is a dynamic library crate with a designated *registrar* function that
9 registers extensions with `rustc`. Other crates can load these extensions using
10 the crate attribute `#![plugin(...)]`. See the
11 [`rustc_plugin`](../rustc_plugin/index.html) documentation for more about the
12 mechanics of defining and loading a plugin.
13
14 If present, arguments passed as `#![plugin(foo(... args ...))]` are not
15 interpreted by rustc itself. They are provided to the plugin through the
16 `Registry`'s [`args` method](../rustc_plugin/registry/struct.Registry.html#method.args).
17
18 In the vast majority of cases, a plugin should *only* be used through
19 `#![plugin]` and not through an `extern crate` item. Linking a plugin would
20 pull in all of libsyntax and librustc as dependencies of your crate. This is
21 generally unwanted unless you are building another plugin. The
22 `plugin_as_library` lint checks these guidelines.
23
24 The usual practice is to put compiler plugins in their own crate, separate from
25 any `macro_rules!` macros or ordinary Rust code meant to be used by consumers
26 of a library.
27
28 # Syntax extensions
29
30 Plugins can extend Rust's syntax in various ways. One kind of syntax extension
31 is the procedural macro. These are invoked the same way as [ordinary
32 macros](macros.html), but the expansion is performed by arbitrary Rust
33 code that manipulates [syntax trees](../syntax/ast/index.html) at
34 compile time.
35
36 Let's write a plugin
37 [`roman_numerals.rs`](https://github.com/rust-lang/rust/tree/master/src/test/auxiliary/roman_numerals.rs)
38 that implements Roman numeral integer literals.
39
40 ```ignore
41 #![crate_type="dylib"]
42 #![feature(plugin_registrar, rustc_private)]
43
44 extern crate syntax;
45 extern crate rustc;
46 extern crate rustc_plugin;
47
48 use syntax::codemap::Span;
49 use syntax::parse::token;
50 use syntax::ast::TokenTree;
51 use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
52 use syntax::ext::build::AstBuilder; // trait for expr_usize
53 use rustc_plugin::Registry;
54
55 fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
56 -> Box<MacResult + 'static> {
57
58 static NUMERALS: &'static [(&'static str, usize)] = &[
59 ("M", 1000), ("CM", 900), ("D", 500), ("CD", 400),
60 ("C", 100), ("XC", 90), ("L", 50), ("XL", 40),
61 ("X", 10), ("IX", 9), ("V", 5), ("IV", 4),
62 ("I", 1)];
63
64 if args.len() != 1 {
65 cx.span_err(
66 sp,
67 &format!("argument should be a single identifier, but got {} arguments", args.len()));
68 return DummyResult::any(sp);
69 }
70
71 let text = match args[0] {
72 TokenTree::Token(_, token::Ident(s, _)) => s.to_string(),
73 _ => {
74 cx.span_err(sp, "argument should be a single identifier");
75 return DummyResult::any(sp);
76 }
77 };
78
79 let mut text = &*text;
80 let mut total = 0;
81 while !text.is_empty() {
82 match NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) {
83 Some(&(rn, val)) => {
84 total += val;
85 text = &text[rn.len()..];
86 }
87 None => {
88 cx.span_err(sp, "invalid Roman numeral");
89 return DummyResult::any(sp);
90 }
91 }
92 }
93
94 MacEager::expr(cx.expr_usize(sp, total))
95 }
96
97 #[plugin_registrar]
98 pub fn plugin_registrar(reg: &mut Registry) {
99 reg.register_macro("rn", expand_rn);
100 }
101 ```
102
103 Then we can use `rn!()` like any other macro:
104
105 ```ignore
106 #![feature(plugin)]
107 #![plugin(roman_numerals)]
108
109 fn main() {
110 assert_eq!(rn!(MMXV), 2015);
111 }
112 ```
113
114 The advantages over a simple `fn(&str) -> u32` are:
115
116 * The (arbitrarily complex) conversion is done at compile time.
117 * Input validation is also performed at compile time.
118 * It can be extended to allow use in patterns, which effectively gives
119 a way to define new literal syntax for any data type.
120
121 In addition to procedural macros, you can define new
122 [`derive`](../reference.html#derive)-like attributes and other kinds of
123 extensions. See
124 [`Registry::register_syntax_extension`](../rustc_plugin/registry/struct.Registry.html#method.register_syntax_extension)
125 and the [`SyntaxExtension`
126 enum](https://doc.rust-lang.org/syntax/ext/base/enum.SyntaxExtension.html). For
127 a more involved macro example, see
128 [`regex_macros`](https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs).
129
130
131 ## Tips and tricks
132
133 Some of the [macro debugging tips](macros.html#debugging-macro-code) are applicable.
134
135 You can use [`syntax::parse`](../syntax/parse/index.html) to turn token trees into
136 higher-level syntax elements like expressions:
137
138 ```ignore
139 fn expand_foo(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
140 -> Box<MacResult+'static> {
141
142 let mut parser = cx.new_parser_from_tts(args);
143
144 let expr: P<Expr> = parser.parse_expr();
145 ```
146
147 Looking through [`libsyntax` parser
148 code](https://github.com/rust-lang/rust/blob/master/src/libsyntax/parse/parser.rs)
149 will give you a feel for how the parsing infrastructure works.
150
151 Keep the [`Span`s](../syntax/codemap/struct.Span.html) of
152 everything you parse, for better error reporting. You can wrap
153 [`Spanned`](../syntax/codemap/struct.Spanned.html) around
154 your custom data structures.
155
156 Calling
157 [`ExtCtxt::span_fatal`](../syntax/ext/base/struct.ExtCtxt.html#method.span_fatal)
158 will immediately abort compilation. It's better to instead call
159 [`ExtCtxt::span_err`](../syntax/ext/base/struct.ExtCtxt.html#method.span_err)
160 and return
161 [`DummyResult`](../syntax/ext/base/struct.DummyResult.html),
162 so that the compiler can continue and find further errors.
163
164 To print syntax fragments for debugging, you can use
165 [`span_note`](../syntax/ext/base/struct.ExtCtxt.html#method.span_note) together
166 with
167 [`syntax::print::pprust::*_to_string`](https://doc.rust-lang.org/syntax/print/pprust/index.html#functions).
168
169 The example above produced an integer literal using
170 [`AstBuilder::expr_usize`](../syntax/ext/build/trait.AstBuilder.html#tymethod.expr_usize).
171 As an alternative to the `AstBuilder` trait, `libsyntax` provides a set of
172 [quasiquote macros](../syntax/ext/quote/index.html). They are undocumented and
173 very rough around the edges. However, the implementation may be a good
174 starting point for an improved quasiquote as an ordinary plugin library.
175
176
177 # Lint plugins
178
179 Plugins can extend [Rust's lint
180 infrastructure](../reference.html#lint-check-attributes) with additional checks for
181 code style, safety, etc. Now let's write a plugin [`lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/auxiliary/lint_plugin_test.rs)
182 that warns about any item named `lintme`.
183
184 ```ignore
185 #![feature(plugin_registrar)]
186 #![feature(box_syntax, rustc_private)]
187
188 extern crate syntax;
189
190 // Load rustc as a plugin to get macros
191 #[macro_use]
192 extern crate rustc;
193 extern crate rustc_plugin;
194
195 use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass,
196 EarlyLintPassObject, LintArray};
197 use rustc_plugin::Registry;
198 use syntax::ast;
199
200 declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
201
202 struct Pass;
203
204 impl LintPass for Pass {
205 fn get_lints(&self) -> LintArray {
206 lint_array!(TEST_LINT)
207 }
208 }
209
210 impl EarlyLintPass for Pass {
211 fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {
212 if it.ident.name.as_str() == "lintme" {
213 cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'");
214 }
215 }
216 }
217
218 #[plugin_registrar]
219 pub fn plugin_registrar(reg: &mut Registry) {
220 reg.register_early_lint_pass(box Pass as EarlyLintPassObject);
221 }
222 ```
223
224 Then code like
225
226 ```ignore
227 #![plugin(lint_plugin_test)]
228
229 fn lintme() { }
230 ```
231
232 will produce a compiler warning:
233
234 ```txt
235 foo.rs:4:1: 4:16 warning: item is named 'lintme', #[warn(test_lint)] on by default
236 foo.rs:4 fn lintme() { }
237 ^~~~~~~~~~~~~~~
238 ```
239
240 The components of a lint plugin are:
241
242 * one or more `declare_lint!` invocations, which define static
243 [`Lint`](../rustc/lint/struct.Lint.html) structs;
244
245 * a struct holding any state needed by the lint pass (here, none);
246
247 * a [`LintPass`](../rustc/lint/trait.LintPass.html)
248 implementation defining how to check each syntax element. A single
249 `LintPass` may call `span_lint` for several different `Lint`s, but should
250 register them all through the `get_lints` method.
251
252 Lint passes are syntax traversals, but they run at a late stage of compilation
253 where type information is available. `rustc`'s [built-in
254 lints](https://github.com/rust-lang/rust/blob/master/src/librustc/lint/builtin.rs)
255 mostly use the same infrastructure as lint plugins, and provide examples of how
256 to access type information.
257
258 Lints defined by plugins are controlled by the usual [attributes and compiler
259 flags](../reference.html#lint-check-attributes), e.g. `#[allow(test_lint)]` or
260 `-A test-lint`. These identifiers are derived from the first argument to
261 `declare_lint!`, with appropriate case and punctuation conversion.
262
263 You can run `rustc -W help foo.rs` to see a list of lints known to `rustc`,
264 including those provided by plugins loaded by `foo.rs`.