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