1 % The Rust Compiler Plugins Guide
3 <div class="unstable-feature">
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
15 For defining new syntax it is often much easier to use Rust's <a
16 href="macros.html">built-in macro system</a>.
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
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.
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.
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).
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
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.
55 #![crate_type="dylib"]
56 #![feature(plugin_registrar)]
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;
68 fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
69 -> Box<MacResult + 'static> {
71 static NUMERALS: &'static [(&'static str, uint)] = &[
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),
77 let text = match args {
78 [TtToken(_, token::Ident(s, _))] => token::get_ident(s).to_string(),
80 cx.span_err(sp, "argument should be a single identifier");
81 return DummyResult::any(sp);
85 let mut text = text.as_slice();
87 while !text.is_empty() {
88 match NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) {
91 text = text.slice_from(rn.len());
94 cx.span_err(sp, "invalid Roman numeral");
95 return DummyResult::any(sp);
100 MacExpr::new(cx.expr_uint(sp, total))
104 pub fn plugin_registrar(reg: &mut Registry) {
105 reg.register_macro("rn", expand_rn);
109 Then we can use `rn!()` like any other macro:
114 #[plugin] extern crate roman_numerals;
117 assert_eq!(rn!(MMXV), 2015);
121 The advantages over a simple `fn(&str) -> uint` are:
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.
128 In addition to procedural macros, you can define new
129 [`deriving`](../reference.html#deriving)-like attributes and other kinds of
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).
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.
149 You can use [`syntax::parse`](../syntax/parse/index.html) to turn token trees into
150 higher-level syntax elements like expressions:
153 fn expand_foo(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
154 -> Box<MacResult+'static> {
156 let mut parser = cx.new_parser_from_tts(args);
158 let expr: P<Expr> = parser.parse_expr();
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.
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.
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)
175 [`DummyResult`](../syntax/ext/base/struct.DummyResult.html),
176 so that the compiler can continue and find further errors.
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.
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:
195 declare_lint!(TEST_LINT, Warn,
196 "Warn about items named 'lintme'")
200 impl LintPass for Pass {
201 fn get_lints(&self) -> LintArray {
202 lint_array!(TEST_LINT)
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'");
214 pub fn plugin_registrar(reg: &mut Registry) {
215 reg.register_lint_pass(box Pass as LintPassObject);
222 #[plugin] extern crate lint_plugin_test;
227 will produce a compiler warning:
230 foo.rs:4:1: 4:16 warning: item is named 'lintme', #[warn(test_lint)] on by default
231 foo.rs:4 fn lintme() { }
235 The components of a lint plugin are:
237 * one or more `declare_lint!` invocations, which define static
238 [`Lint`](../rustc/lint/struct.Lint.html) structs;
240 * a struct holding any state needed by the lint pass (here, none);
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.
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.
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.
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`.