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` 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.
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 at
37 [`roman_numerals.rs`](https://github.com/rust-lang/rust/blob/master/src/test/run-pass-fulldeps/auxiliary/roman_numerals.rs)
38 that implements Roman numeral integer literals.
41 #![crate_type="dylib"]
42 #![feature(plugin_registrar, rustc_private)]
46 extern crate rustc_plugin;
48 use syntax::parse::token;
49 use syntax::ast::TokenTree;
50 use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
51 use syntax::ext::build::AstBuilder; // trait for expr_usize
53 use rustc_plugin::Registry;
55 fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
56 -> Box<MacResult + 'static> {
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),
67 &format!("argument should be a single identifier, but got {} arguments", args.len()));
68 return DummyResult::any(sp);
71 let text = match args[0] {
72 TokenTree::Token(_, token::Ident(s, _)) => s.to_string(),
74 cx.span_err(sp, "argument should be a single identifier");
75 return DummyResult::any(sp);
79 let mut text = &*text;
81 while !text.is_empty() {
82 match NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) {
85 text = &text[rn.len()..];
88 cx.span_err(sp, "invalid Roman numeral");
89 return DummyResult::any(sp);
94 MacEager::expr(cx.expr_usize(sp, total))
98 pub fn plugin_registrar(reg: &mut Registry) {
99 reg.register_macro("rn", expand_rn);
103 Then we can use `rn!()` like any other macro:
107 #![plugin(roman_numerals)]
110 assert_eq!(rn!(MMXV), 2015);
114 The advantages over a simple `fn(&str) -> u32` are:
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.
121 In addition to procedural macros, you can define new
122 [`derive`](../reference.html#derive)-like attributes and other kinds of
123 extensions. See `Registry::register_syntax_extension` and the `SyntaxExtension`
124 enum. For a more involved macro example, see
125 [`regex_macros`](https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs).
130 Some of the [macro debugging tips](macros.html#debugging-macro-code) are applicable.
132 You can use `syntax::parse` to turn token trees into
133 higher-level syntax elements like expressions:
136 fn expand_foo(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
137 -> Box<MacResult+'static> {
139 let mut parser = cx.new_parser_from_tts(args);
141 let expr: P<Expr> = parser.parse_expr();
144 Looking through [`libsyntax` parser
145 code](https://github.com/rust-lang/rust/blob/master/src/libsyntax/parse/parser.rs)
146 will give you a feel for how the parsing infrastructure works.
148 Keep the `Span`s of everything you parse, for better error reporting. You can
149 wrap `Spanned` around your custom data structures.
151 Calling `ExtCtxt::span_fatal` will immediately abort compilation. It's better to
152 instead call `ExtCtxt::span_err` and return `DummyResult` so that the compiler
153 can continue and find further errors.
155 To print syntax fragments for debugging, you can use `span_note` together with
156 `syntax::print::pprust::*_to_string`.
158 The example above produced an integer literal using `AstBuilder::expr_usize`.
159 As an alternative to the `AstBuilder` trait, `libsyntax` provides a set of
160 quasiquote macros. They are undocumented and very rough around the edges.
161 However, the implementation may be a good starting point for an improved
162 quasiquote as an ordinary plugin library.
167 Plugins can extend [Rust's lint
168 infrastructure](../reference.html#lint-check-attributes) with additional checks for
169 code style, safety, etc. Now let's write a plugin
170 [`lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/run-pass-fulldeps/auxiliary/lint_plugin_test.rs)
171 that warns about any item named `lintme`.
174 #![feature(plugin_registrar)]
175 #![feature(box_syntax, rustc_private)]
179 // Load rustc as a plugin to get macros
182 extern crate rustc_plugin;
184 use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass,
185 EarlyLintPassObject, LintArray};
186 use rustc_plugin::Registry;
189 declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
193 impl LintPass for Pass {
194 fn get_lints(&self) -> LintArray {
195 lint_array!(TEST_LINT)
199 impl EarlyLintPass for Pass {
200 fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {
201 if it.ident.name.as_str() == "lintme" {
202 cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'");
208 pub fn plugin_registrar(reg: &mut Registry) {
209 reg.register_early_lint_pass(box Pass as EarlyLintPassObject);
216 #![plugin(lint_plugin_test)]
221 will produce a compiler warning:
224 foo.rs:4:1: 4:16 warning: item is named 'lintme', #[warn(test_lint)] on by default
225 foo.rs:4 fn lintme() { }
229 The components of a lint plugin are:
231 * one or more `declare_lint!` invocations, which define static `Lint` structs;
233 * a struct holding any state needed by the lint pass (here, none);
236 implementation defining how to check each syntax element. A single
237 `LintPass` may call `span_lint` for several different `Lint`s, but should
238 register them all through the `get_lints` method.
240 Lint passes are syntax traversals, but they run at a late stage of compilation
241 where type information is available. `rustc`'s [built-in
242 lints](https://github.com/rust-lang/rust/blob/master/src/librustc/lint/builtin.rs)
243 mostly use the same infrastructure as lint plugins, and provide examples of how
244 to access type information.
246 Lints defined by plugins are controlled by the usual [attributes and compiler
247 flags](../reference.html#lint-check-attributes), e.g. `#[allow(test_lint)]` or
248 `-A test-lint`. These identifiers are derived from the first argument to
249 `declare_lint!`, with appropriate case and punctuation conversion.
251 You can run `rustc -W help foo.rs` to see a list of lints known to `rustc`,
252 including those provided by plugins loaded by `foo.rs`.