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