]> git.proxmox.com Git - rustc.git/blob - src/doc/trpl/compiler-plugins.md
Imported Upstream version 1.3.0+dfsg1
[rustc.git] / src / doc / trpl / 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
47 use syntax::codemap::Span;
48 use syntax::parse::token;
49 use syntax::ast::{TokenTree, TtToken};
50 use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
51 use syntax::ext::build::AstBuilder; // trait for expr_usize
52 use rustc::plugin::Registry;
53
54 fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
55 -> Box<MacResult + 'static> {
56
57 static NUMERALS: &'static [(&'static str, u32)] = &[
58 ("M", 1000), ("CM", 900), ("D", 500), ("CD", 400),
59 ("C", 100), ("XC", 90), ("L", 50), ("XL", 40),
60 ("X", 10), ("IX", 9), ("V", 5), ("IV", 4),
61 ("I", 1)];
62
63 let text = match args {
64 [TtToken(_, token::Ident(s, _))] => s.to_string(),
65 _ => {
66 cx.span_err(sp, "argument should be a single identifier");
67 return DummyResult::any(sp);
68 }
69 };
70
71 let mut text = &*text;
72 let mut total = 0;
73 while !text.is_empty() {
74 match NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) {
75 Some(&(rn, val)) => {
76 total += val;
77 text = &text[rn.len()..];
78 }
79 None => {
80 cx.span_err(sp, "invalid Roman numeral");
81 return DummyResult::any(sp);
82 }
83 }
84 }
85
86 MacEager::expr(cx.expr_u32(sp, total))
87 }
88
89 #[plugin_registrar]
90 pub fn plugin_registrar(reg: &mut Registry) {
91 reg.register_macro("rn", expand_rn);
92 }
93 ```
94
95 Then we can use `rn!()` like any other macro:
96
97 ```ignore
98 #![feature(plugin)]
99 #![plugin(roman_numerals)]
100
101 fn main() {
102 assert_eq!(rn!(MMXV), 2015);
103 }
104 ```
105
106 The advantages over a simple `fn(&str) -> u32` are:
107
108 * The (arbitrarily complex) conversion is done at compile time.
109 * Input validation is also performed at compile time.
110 * It can be extended to allow use in patterns, which effectively gives
111 a way to define new literal syntax for any data type.
112
113 In addition to procedural macros, you can define new
114 [`derive`](../reference.html#derive)-like attributes and other kinds of
115 extensions. See
116 [`Registry::register_syntax_extension`](../rustc/plugin/registry/struct.Registry.html#method.register_syntax_extension)
117 and the [`SyntaxExtension`
118 enum](http://doc.rust-lang.org/syntax/ext/base/enum.SyntaxExtension.html). For
119 a more involved macro example, see
120 [`regex_macros`](https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs).
121
122
123 ## Tips and tricks
124
125 Some of the [macro debugging tips](macros.html#debugging-macro-code) are applicable.
126
127 You can use [`syntax::parse`](../syntax/parse/index.html) to turn token trees into
128 higher-level syntax elements like expressions:
129
130 ```ignore
131 fn expand_foo(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
132 -> Box<MacResult+'static> {
133
134 let mut parser = cx.new_parser_from_tts(args);
135
136 let expr: P<Expr> = parser.parse_expr();
137 ```
138
139 Looking through [`libsyntax` parser
140 code](https://github.com/rust-lang/rust/blob/master/src/libsyntax/parse/parser.rs)
141 will give you a feel for how the parsing infrastructure works.
142
143 Keep the [`Span`s](../syntax/codemap/struct.Span.html) of
144 everything you parse, for better error reporting. You can wrap
145 [`Spanned`](../syntax/codemap/struct.Spanned.html) around
146 your custom data structures.
147
148 Calling
149 [`ExtCtxt::span_fatal`](../syntax/ext/base/struct.ExtCtxt.html#method.span_fatal)
150 will immediately abort compilation. It's better to instead call
151 [`ExtCtxt::span_err`](../syntax/ext/base/struct.ExtCtxt.html#method.span_err)
152 and return
153 [`DummyResult`](../syntax/ext/base/struct.DummyResult.html),
154 so that the compiler can continue and find further errors.
155
156 To print syntax fragments for debugging, you can use
157 [`span_note`](../syntax/ext/base/struct.ExtCtxt.html#method.span_note) together
158 with
159 [`syntax::print::pprust::*_to_string`](http://doc.rust-lang.org/syntax/print/pprust/index.html#functions).
160
161 The example above produced an integer literal using
162 [`AstBuilder::expr_usize`](../syntax/ext/build/trait.AstBuilder.html#tymethod.expr_usize).
163 As an alternative to the `AstBuilder` trait, `libsyntax` provides a set of
164 [quasiquote macros](../syntax/ext/quote/index.html). They are undocumented and
165 very rough around the edges. However, the implementation may be a good
166 starting point for an improved quasiquote as an ordinary plugin library.
167
168
169 # Lint plugins
170
171 Plugins can extend [Rust's lint
172 infrastructure](../reference.html#lint-check-attributes) with additional checks for
173 code style, safety, etc. You can see
174 [`src/test/auxiliary/lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/auxiliary/lint_plugin_test.rs)
175 for a full example, the core of which is reproduced here:
176
177 ```ignore
178 declare_lint!(TEST_LINT, Warn,
179 "Warn about items named 'lintme'");
180
181 struct Pass;
182
183 impl LintPass for Pass {
184 fn get_lints(&self) -> LintArray {
185 lint_array!(TEST_LINT)
186 }
187
188 fn check_item(&mut self, cx: &Context, it: &ast::Item) {
189 if it.ident.name == "lintme" {
190 cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'");
191 }
192 }
193 }
194
195 #[plugin_registrar]
196 pub fn plugin_registrar(reg: &mut Registry) {
197 reg.register_lint_pass(box Pass as LintPassObject);
198 }
199 ```
200
201 Then code like
202
203 ```ignore
204 #![plugin(lint_plugin_test)]
205
206 fn lintme() { }
207 ```
208
209 will produce a compiler warning:
210
211 ```txt
212 foo.rs:4:1: 4:16 warning: item is named 'lintme', #[warn(test_lint)] on by default
213 foo.rs:4 fn lintme() { }
214 ^~~~~~~~~~~~~~~
215 ```
216
217 The components of a lint plugin are:
218
219 * one or more `declare_lint!` invocations, which define static
220 [`Lint`](../rustc/lint/struct.Lint.html) structs;
221
222 * a struct holding any state needed by the lint pass (here, none);
223
224 * a [`LintPass`](../rustc/lint/trait.LintPass.html)
225 implementation defining how to check each syntax element. A single
226 `LintPass` may call `span_lint` for several different `Lint`s, but should
227 register them all through the `get_lints` method.
228
229 Lint passes are syntax traversals, but they run at a late stage of compilation
230 where type information is available. `rustc`'s [built-in
231 lints](https://github.com/rust-lang/rust/blob/master/src/librustc/lint/builtin.rs)
232 mostly use the same infrastructure as lint plugins, and provide examples of how
233 to access type information.
234
235 Lints defined by plugins are controlled by the usual [attributes and compiler
236 flags](../reference.html#lint-check-attributes), e.g. `#[allow(test_lint)]` or
237 `-A test-lint`. These identifiers are derived from the first argument to
238 `declare_lint!`, with appropriate case and punctuation conversion.
239
240 You can run `rustc -W help foo.rs` to see a list of lints known to `rustc`,
241 including those provided by plugins loaded by `foo.rs`.