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.
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.
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).
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.
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
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
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.
41 #![crate_type="dylib"]
42 #![feature(plugin_registrar, rustc_private)]
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;
54 fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
55 -> Box<MacResult + 'static> {
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),
63 let text = match args {
64 [TtToken(_, token::Ident(s, _))] => s.to_string(),
66 cx.span_err(sp, "argument should be a single identifier");
67 return DummyResult::any(sp);
71 let mut text = &*text;
73 while !text.is_empty() {
74 match NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) {
77 text = &text[rn.len()..];
80 cx.span_err(sp, "invalid Roman numeral");
81 return DummyResult::any(sp);
86 MacEager::expr(cx.expr_u32(sp, total))
90 pub fn plugin_registrar(reg: &mut Registry) {
91 reg.register_macro("rn", expand_rn);
95 Then we can use `rn!()` like any other macro:
99 #![plugin(roman_numerals)]
102 assert_eq!(rn!(MMXV), 2015);
106 The advantages over a simple `fn(&str) -> u32` are:
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.
113 In addition to procedural macros, you can define new
114 [`derive`](../reference.html#derive)-like attributes and other kinds of
116 [`Registry::register_syntax_extension`](../rustc/plugin/registry/struct.Registry.html#method.register_syntax_extension)
117 and the [`SyntaxExtension`
118 enum](https://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).
125 Some of the [macro debugging tips](macros.html#debugging-macro-code) are applicable.
127 You can use [`syntax::parse`](../syntax/parse/index.html) to turn token trees into
128 higher-level syntax elements like expressions:
131 fn expand_foo(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
132 -> Box<MacResult+'static> {
134 let mut parser = cx.new_parser_from_tts(args);
136 let expr: P<Expr> = parser.parse_expr();
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.
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.
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)
153 [`DummyResult`](../syntax/ext/base/struct.DummyResult.html),
154 so that the compiler can continue and find further errors.
156 To print syntax fragments for debugging, you can use
157 [`span_note`](../syntax/ext/base/struct.ExtCtxt.html#method.span_note) together
159 [`syntax::print::pprust::*_to_string`](https://doc.rust-lang.org/syntax/print/pprust/index.html#functions).
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.
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:
178 declare_lint!(TEST_LINT, Warn,
179 "Warn about items named 'lintme'");
183 impl LintPass for Pass {
184 fn get_lints(&self) -> LintArray {
185 lint_array!(TEST_LINT)
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'");
196 pub fn plugin_registrar(reg: &mut Registry) {
197 reg.register_lint_pass(box Pass as LintPassObject);
204 #![plugin(lint_plugin_test)]
209 will produce a compiler warning:
212 foo.rs:4:1: 4:16 warning: item is named 'lintme', #[warn(test_lint)] on by default
213 foo.rs:4 fn lintme() { }
217 The components of a lint plugin are:
219 * one or more `declare_lint!` invocations, which define static
220 [`Lint`](../rustc/lint/struct.Lint.html) structs;
222 * a struct holding any state needed by the lint pass (here, none);
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.
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.
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.
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`.