@@ -13,7 +13,7 @@ This feature is part of "compiler plugins." It will often be used with the
1313------------------------
1414
1515` rustc ` can load compiler plugins, which are user-provided libraries that
16- extend the compiler's behavior with new syntax extensions, lint checks, etc.
16+ extend the compiler's behavior with new lint checks, etc.
1717
1818A plugin is a dynamic library crate with a designated * registrar* function that
1919registers extensions with ` rustc ` . Other crates can load these extensions using
@@ -35,134 +35,6 @@ The usual practice is to put compiler plugins in their own crate, separate from
3535any ` macro_rules! ` macros or ordinary Rust code meant to be used by consumers
3636of a library.
3737
38- # Syntax extensions
39-
40- Plugins can extend Rust's syntax in various ways. One kind of syntax extension
41- is the procedural macro. These are invoked the same way as [ ordinary
42- macros] ( ../../book/macros.md ) , but the expansion is performed by arbitrary Rust
43- code that manipulates syntax trees at
44- compile time.
45-
46- Let's write a plugin
47- [ ` roman_numerals.rs ` ] ( https://github.com/rust-lang/rust/blob/master/src/test/ui-fulldeps/auxiliary/roman_numerals.rs )
48- that implements Roman numeral integer literals.
49-
50- ``` rust,ignore
51- #![crate_type="dylib"]
52- #![feature(plugin_registrar, rustc_private)]
53-
54- extern crate syntax;
55- extern crate syntax_pos;
56- extern crate rustc;
57- extern crate rustc_driver;
58-
59- use syntax::parse::token::{self, Token};
60- use syntax::tokenstream::{TokenTree, TokenStream};
61- use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
62- use syntax_pos::Span;
63- use rustc_driver::plugin::Registry;
64-
65- fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: TokenStream)
66- -> Box<dyn MacResult + 'static> {
67-
68- static NUMERALS: &'static [(&'static str, usize)] = &[
69- ("M", 1000), ("CM", 900), ("D", 500), ("CD", 400),
70- ("C", 100), ("XC", 90), ("L", 50), ("XL", 40),
71- ("X", 10), ("IX", 9), ("V", 5), ("IV", 4),
72- ("I", 1)];
73-
74- if args.len() != 1 {
75- cx.span_err(
76- sp,
77- &format!("argument should be a single identifier, but got {} arguments", args.len()));
78- return DummyResult::any(sp);
79- }
80-
81- let text = match args.into_trees().next().unwrap() {
82- TokenTree::Token(Token { kind: token::Ident(s, _), .. }) => s.to_string(),
83- _ => {
84- cx.span_err(sp, "argument should be a single identifier");
85- return DummyResult::any(sp);
86- }
87- };
88-
89- let mut text = &*text;
90- let mut total = 0;
91- while !text.is_empty() {
92- match NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) {
93- Some(&(rn, val)) => {
94- total += val;
95- text = &text[rn.len()..];
96- }
97- None => {
98- cx.span_err(sp, "invalid Roman numeral");
99- return DummyResult::any(sp);
100- }
101- }
102- }
103-
104- MacEager::expr(cx.expr_usize(sp, total))
105- }
106-
107- #[plugin_registrar]
108- pub fn plugin_registrar(reg: &mut Registry) {
109- reg.register_macro("rn", expand_rn);
110- }
111- ```
112-
113- Then we can use ` rn!() ` like any other macro:
114-
115- ``` rust,ignore
116- #![feature(plugin)]
117- #![plugin(roman_numerals)]
118-
119- fn main() {
120- assert_eq!(rn!(MMXV), 2015);
121- }
122- ```
123-
124- The advantages over a simple ` fn(&str) -> u32 ` are:
125-
126- * The (arbitrarily complex) conversion is done at compile time.
127- * Input validation is also performed at compile time.
128- * It can be extended to allow use in patterns, which effectively gives
129- a way to define new literal syntax for any data type.
130-
131- In addition to procedural macros, you can define new
132- [ ` derive ` ] ( ../../reference/attributes/derive.md ) -like attributes and other kinds
133- of extensions. See ` Registry::register_syntax_extension ` and the
134- ` SyntaxExtension ` struct. For a more involved macro example, see
135- [ ` regex_macros ` ] ( https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs ) .
136-
137-
138- ## Tips and tricks
139-
140- You can use ` syntax::parse ` to turn token trees into
141- higher-level syntax elements like expressions:
142-
143- ``` rust,ignore
144- fn expand_foo(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
145- -> Box<MacResult+'static> {
146-
147- let mut parser = cx.new_parser_from_tts(args);
148-
149- let expr: P<Expr> = parser.parse_expr();
150- ```
151-
152- Looking through [ ` libsyntax ` parser
153- code] ( https://github.com/rust-lang/rust/blob/master/src/libsyntax/parse/parser.rs )
154- will give you a feel for how the parsing infrastructure works.
155-
156- Keep the ` Span ` s of everything you parse, for better error reporting. You can
157- wrap ` Spanned ` around your custom data structures.
158-
159- Calling ` ExtCtxt::span_fatal ` will immediately abort compilation. It's better to
160- instead call ` ExtCtxt::span_err ` and return ` DummyResult ` so that the compiler
161- can continue and find further errors.
162-
163- To print syntax fragments for debugging, you can use ` span_note ` together with
164- ` syntax::print::pprust::*_to_string ` .
165-
16638# Lint plugins
16739
16840Plugins can extend [ Rust's lint
0 commit comments