From 78e841d8b10e05b5bbad4b02a9d5f0e9611100c7 Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Fri, 2 Jan 2015 20:05:30 -0800 Subject: [PATCH] Update docs --- src/doc/guide-macros.md | 155 +++++++++++++++++++++++++--------------- src/doc/guide-plugin.md | 14 ++-- src/doc/reference.md | 64 +++++++++-------- 3 files changed, 140 insertions(+), 93 deletions(-) diff --git a/src/doc/guide-macros.md b/src/doc/guide-macros.md index 58af5917407..dc6d281307a 100644 --- a/src/doc/guide-macros.md +++ b/src/doc/guide-macros.md @@ -1,14 +1,5 @@ % The Rust Macros Guide -
-Warning: There are currently various problems with invoking macros, how -they interact with their environment, and how they are used outside of the -location in which they are defined. Macro definitions are likely to change -slightly in the future. For this reason, they are hidden behind the -macro_rules feature -attribute. -
- # Introduction Functions are the primary tool that programmers can use to build abstractions. @@ -46,19 +37,18 @@ lightweight custom syntax extensions, themselves defined using the the pattern in the above code: ~~~~ -# #![feature(macro_rules)] # enum T { SpecialA(uint), SpecialB(uint) } # fn f() -> uint { # let input_1 = T::SpecialA(0); # let input_2 = T::SpecialA(0); -macro_rules! early_return( +macro_rules! early_return { ($inp:expr $sp:path) => ( // invoke it like `(input_5 SpecialE)` match $inp { $sp(x) => { return x; } _ => {} } ); -); +} // ... early_return!(input_1 T::SpecialA); // ... @@ -109,10 +99,10 @@ that could be invoked like: `my_macro!(i->(( 2+2 )))`. ## Invocation location -A macro invocation may take the place of (and therefore expand to) -an expression, an item, or a statement. -The Rust parser will parse the macro invocation as a "placeholder" -for whichever of those three nonterminals is appropriate for the location. +A macro invocation may take the place of (and therefore expand to) an +expression, item, statement, or pattern. The Rust parser will parse the macro +invocation as a "placeholder" for whichever syntactic form is appropriate for +the location. At expansion time, the output of the macro will be parsed as whichever of the three nonterminals it stands in for. This means that a single macro might, @@ -166,12 +156,11 @@ separator token (a comma-separated list could be written `$(...),*`), and `+` instead of `*` to mean "at least one". ~~~~ -# #![feature(macro_rules)] # enum T { SpecialA(uint),SpecialB(uint),SpecialC(uint),SpecialD(uint)} # fn f() -> uint { # let input_1 = T::SpecialA(0); # let input_2 = T::SpecialA(0); -macro_rules! early_return( +macro_rules! early_return { ($inp:expr, [ $($sp:path)|+ ]) => ( match $inp { $( @@ -180,7 +169,7 @@ macro_rules! early_return( _ => {} } ) -); +} // ... early_return!(input_1, [T::SpecialA|T::SpecialC|T::SpecialD]); // ... @@ -228,7 +217,6 @@ solves the problem. Now consider code like the following: ~~~~ -# #![feature(macro_rules)] # enum T1 { Good1(T2, uint), Bad1} # struct T2 { body: T3 } # enum T3 { Good2(uint), Bad2} @@ -255,8 +243,7 @@ a match, but with a syntax that suits the problem better. The following macro can solve the problem: ~~~~ -# #![feature(macro_rules)] -macro_rules! biased_match ( +macro_rules! biased_match { // special case: `let (x) = ...` is illegal, so use `let x = ...` instead ( ($e:expr) ~ ($p:pat) else $err:stmt ; binds $bind_res:ident @@ -275,7 +262,7 @@ macro_rules! biased_match ( _ => { $err } }; ) -); +} # enum T1 { Good1(T2, uint), Bad1} # struct T2 { body: T3 } @@ -297,13 +284,12 @@ like this, we might prefer to write a single macro invocation. The input pattern we want is clear: ~~~~ -# #![feature(macro_rules)] # fn main() {} -# macro_rules! b( +# macro_rules! b { ( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )* binds $( $bind_res:ident ),* ) -# => (0)); +# => (0) } ~~~~ However, it's not possible to directly expand to nested match statements. But @@ -320,24 +306,22 @@ process the semicolon-terminated lines, one-by-one. So, we want the following input patterns: ~~~~ -# #![feature(macro_rules)] -# macro_rules! b( +# macro_rules! b { ( binds $( $bind_res:ident ),* ) -# => (0)); +# => (0) } # fn main() {} ~~~~ ...and: ~~~~ -# #![feature(macro_rules)] # fn main() {} -# macro_rules! b( +# macro_rules! b { ( ($e :expr) ~ ($p :pat) else $err :stmt ; $( ($e_rest:expr) ~ ($p_rest:pat) else $err_rest:stmt ; )* binds $( $bind_res:ident ),* ) -# => (0)); +# => (0) } ~~~~ The resulting macro looks like this. Note that the separation into @@ -345,10 +329,9 @@ The resulting macro looks like this. Note that the separation into piece of syntax (the `let`) which we only want to transcribe once. ~~~~ -# #![feature(macro_rules)] # fn main() { -macro_rules! biased_match_rec ( +macro_rules! biased_match_rec { // Handle the first layer ( ($e :expr) ~ ($p :pat) else $err :stmt ; $( ($e_rest:expr) ~ ($p_rest:pat) else $err_rest:stmt ; )* @@ -366,10 +349,10 @@ macro_rules! biased_match_rec ( ); // Produce the requested values ( binds $( $bind_res:ident ),* ) => ( ($( $bind_res ),*) ) -); +} // Wrap the whole thing in a `let`. -macro_rules! biased_match ( +macro_rules! biased_match { // special case: `let (x) = ...` is illegal, so use `let x = ...` instead ( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )* binds $bind_res:ident @@ -388,7 +371,7 @@ macro_rules! biased_match ( binds $( $bind_res ),* ); ) -); +} # enum T1 { Good1(T2, uint), Bad1} @@ -434,9 +417,7 @@ As an example, `loop` and `for-loop` labels (discussed in the lifetimes guide) will not clash. The following code will print "Hello!" only once: ~~~ -#![feature(macro_rules)] - -macro_rules! loop_x ( +macro_rules! loop_x { ($e: expr) => ( // $e will not interact with this 'x 'x: loop { @@ -444,7 +425,7 @@ macro_rules! loop_x ( $e } ); -); +} fn main() { 'x: loop { @@ -467,22 +448,30 @@ lexical-order traversal of a crate's source. So a macro defined at module scope is visible to any subsequent code in the same module, which includes the body of any subsequent child `mod` items. -If a module has the `macro_escape` attribute, its macros are also visible in -its parent module after the child's `mod` item. If the parent also has -`macro_escape` then the macros will be visible in the grandparent after the -parent's `mod` item, and so forth. +If a module has the `macro_use` attribute, its macros are also visible in its +parent module after the child's `mod` item. If the parent also has `macro_use` +then the macros will be visible in the grandparent after the parent's `mod` +item, and so forth. -Independent of `macro_escape`, the `macro_export` attribute controls visibility -between crates. Any `macro_rules!` definition with the `macro_export` -attribute will be visible to other crates that have loaded this crate with -`phase(plugin)`. There is currently no way for the importing crate to control -which macros are imported. +The `macro_use` attribute can also appear on `extern crate`. In this context +it controls which macros are loaded from the external crate, e.g. + +```rust,ignore +#[macro_use(foo, bar)] +extern crate baz; +``` + +If the attribute is given simply as `#[macro_use]`, all macros are loaded. If +there is no `#[macro_use]` attribute then no macros are loaded. Only macros +defined with the `#[macro_export]` attribute may be loaded. + +To load a crate's macros *without* linking it into the output, use `#[no_link]` +as well. An example: ```rust -# #![feature(macro_rules)] -macro_rules! m1 (() => (())); +macro_rules! m1 { () => (()) } // visible here: m1 @@ -490,22 +479,22 @@ mod foo { // visible here: m1 #[macro_export] - macro_rules! m2 (() => (())); + macro_rules! m2 { () => (()) } // visible here: m1, m2 } // visible here: m1 -macro_rules! m3 (() => (())); +macro_rules! m3 { () => (()) } // visible here: m1, m3 -#[macro_escape] +#[macro_use] mod bar { // visible here: m1, m3 - macro_rules! m4 (() => (())); + macro_rules! m4 { () => (()) } // visible here: m1, m3, m4 } @@ -514,8 +503,58 @@ mod bar { # fn main() { } ``` -When this library is loaded with `#[phase(plugin)] extern crate`, only `m2` -will be imported. +When this library is loaded with `#[use_macros] extern crate`, only `m2` will +be imported. + +The Rust Reference has a [listing of macro-related +attributes](reference.html#macro--and-plugin-related-attributes). + +# The variable `$crate` + +A further difficulty occurs when a macro is used in multiple crates. Say that +`mylib` defines + +```rust +pub fn increment(x: uint) -> uint { + x + 1 +} + +#[macro_export] +macro_rules! inc_a { + ($x:expr) => ( ::increment($x) ) +} + +#[macro_export] +macro_rules! inc_b { + ($x:expr) => ( ::mylib::increment($x) ) +} +# fn main() { } +``` + +`inc_a` only works within `mylib`, while `inc_b` only works outside the +library. Furthermore, `inc_b` will break if the user imports `mylib` under +another name. + +Rust does not (yet) have a hygiene system for crate references, but it does +provide a simple workaround for this problem. Within a macro imported from a +crate named `foo`, the special macro variable `$crate` will expand to `::foo`. +By contrast, when a macro is defined and then used in the same crate, `$crate` +will expand to nothing. This means we can write + +```rust +#[macro_export] +macro_rules! inc { + ($x:expr) => ( $crate::increment($x) ) +} +# fn main() { } +``` + +to define a single macro that works both inside and outside our library. The +function name will expand to either `::increment` or `::mylib::increment`. + +To keep this system simple and correct, `#[macro_use] extern crate ...` may +only appear at the root of your crate, not inside `mod`. This ensures that +`$crate` is a single identifier. # A final note diff --git a/src/doc/guide-plugin.md b/src/doc/guide-plugin.md index eb3e4ce75c4..025f0cced63 100644 --- a/src/doc/guide-plugin.md +++ b/src/doc/guide-plugin.md @@ -31,10 +31,14 @@ extend the compiler's behavior with new syntax extensions, lint checks, etc. A plugin is a dynamic library crate with a designated "registrar" function that registers extensions with `rustc`. Other crates can use these extensions by -loading the plugin crate with `#[phase(plugin)] extern crate`. See the +loading the plugin crate with `#[plugin] extern crate`. See the [`rustc::plugin`](rustc/plugin/index.html) documentation for more about the mechanics of defining and loading a plugin. +Arguments passed as `#[plugin=...]` or `#[plugin(...)]` are not interpreted by +rustc itself. They are provided to the plugin through the `Registry`'s [`args` +method](rustc/plugin/registry/struct.Registry.html#method.args). + # Syntax extensions Plugins can extend Rust's syntax in various ways. One kind of syntax extension @@ -105,10 +109,9 @@ pub fn plugin_registrar(reg: &mut Registry) { Then we can use `rn!()` like any other macro: ```ignore -#![feature(phase)] +#![feature(plugin)] -#[phase(plugin)] -extern crate roman_numerals; +#[plugin] extern crate roman_numerals; fn main() { assert_eq!(rn!(MMXV), 2015); @@ -217,8 +220,7 @@ pub fn plugin_registrar(reg: &mut Registry) { Then code like ```ignore -#[phase(plugin)] -extern crate lint_plugin_test; +#[plugin] extern crate lint_plugin_test; fn lintme() { } ``` diff --git a/src/doc/reference.md b/src/doc/reference.md index e2134cdebef..829c0e67514 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -668,9 +668,11 @@ transcriber : '(' transcriber * ')' | '[' transcriber * ']' | non_special_token ; ``` -User-defined syntax extensions are called "macros", and the `macro_rules` -syntax extension defines them. Currently, user-defined macros can expand to -expressions, statements, items, or patterns. +`macro_rules` allows users to define syntax extension in a declarative way. We +call such extensions "macros by example" or simply "macros" — to be distinguished +from the "procedural macros" defined in [compiler plugins][plugin]. + +Currently, macros can expand to expressions, statements, items, or patterns. (A `sep_token` is any token other than `*` and `+`. A `non_special_token` is any token other than a delimiter or `$`.) @@ -2002,8 +2004,6 @@ type int8_t = i8; ### Module-only attributes -- `macro_escape` - macros defined in this module will be visible in the - module's parent, after this module has been included. - `no_implicit_prelude` - disable injecting `use std::prelude::*` in this module. - `path` - specifies the file to load the module from. `#[path="foo.rs"] mod @@ -2066,23 +2066,43 @@ On `struct`s: remove any padding between fields (note that this is very fragile and may break platforms which require aligned access). +### Macro- and plugin-related attributes + +- `macro_use` on a `mod` — macros defined in this module will be visible in the + module's parent, after this module has been included. + +- `macro_use` on an `extern crate` — load macros from this crate. An optional + list of names `#[macro_use(foo, bar)]` restricts the import to just those + macros named. The `extern crate` must appear at the crate root, not inside + `mod`, which ensures proper function of the [`$crate` macro + variable](guide-macros.html#the-variable-$crate). + +- `macro_reexport` on an `extern crate` — re-export the named macros. + +- `macro_export` - export a macro for cross-crate usage. + +- `plugin` on an `extern crate` — load this crate as a [compiler + plugin][plugin]. The `plugin` feature gate is required. Any arguments to + the attribute, e.g. `#[plugin=...]` or `#[plugin(...)]`, are provided to the + plugin. + +- `no_link` on an `extern crate` — even if we load this crate for macros or + compiler plugins, don't link it into the output. + +See the [macros guide](guide-macros.html#scoping-and-macro-import/export) for +more information on macro scope. + + ### Miscellaneous attributes - `export_name` - on statics and functions, this determines the name of the exported symbol. - `link_section` - on statics and functions, this specifies the section of the object file that this item's contents will be placed into. -- `macro_export` - export a macro for cross-crate usage. - `no_mangle` - on any item, do not apply the standard name mangling. Set the symbol for this item to its identifier. - `packed` - on structs or enums, eliminate any padding that would be used to align fields. -- `phase` - on `extern crate` statements, allows specifying which "phase" of - compilation the crate should be loaded for. Currently, there are two - choices: `link` and `plugin`. `link` is the default. `plugin` will [load the - crate at compile-time][plugin] and use any syntax extensions or lints that the crate - defines. They can both be specified, `#[phase(link, plugin)]` to use a crate - both at runtime and compiletime. - `simd` - on certain tuple structs, derive the arithmetic operators, which lower to the target's SIMD instructions, if any; the `simd` feature gate is necessary to use this attribute. @@ -2569,15 +2589,6 @@ The currently implemented features of the reference compiler are: * `log_syntax` - Allows use of the `log_syntax` macro attribute, which is a nasty hack that will certainly be removed. -* `macro_rules` - The definition of new macros. This does not encompass - macro-invocation, that is always enabled by default, this - only covers the definition of new macros. There are currently - various problems with invoking macros, how they interact with - their environment, and possibly how they are used outside of - location in which they are defined. Macro definitions are - likely to change slightly in the future, so they are - currently hidden behind this feature. - * `non_ascii_idents` - The compiler supports the use of non-ascii identifiers, but the implementation is a little rough around the edges, so this can be seen as an experimental feature @@ -2588,15 +2599,10 @@ The currently implemented features of the reference compiler are: closure as `once` is unlikely to be supported going forward. So they are hidden behind this feature until they are to be removed. -* `phase` - Usage of the `#[phase]` attribute allows loading compiler plugins - for custom lints or syntax extensions. The implementation is - considered unwholesome and in need of overhaul, and it is not clear - what they will look like moving forward. +* `plugin` - Usage of [compiler plugins][plugin] for custom lints or syntax extensions. + These depend on compiler internals and are subject to change. -* `plugin_registrar` - Indicates that a crate has [compiler plugins][plugin] that it - wants to load. As with `phase`, the implementation is - in need of an overhaul, and it is not clear that plugins - defined using this will continue to work. +* `plugin_registrar` - Indicates that a crate provides [compiler plugins][plugin]. * `quote` - Allows use of the `quote_*!` family of macros, which are implemented very poorly and will likely change significantly