diff options
| author | bors <bors@rust-lang.org> | 2015-02-25 20:32:58 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2015-02-25 20:32:58 +0000 |
| commit | 4db0b32467535d718d6474de7ae8d1007d900818 (patch) | |
| tree | 85c3f0131e2347eb2c0b2931a6c41284a52aaa1b /src/doc | |
| parent | 880fb89bde126aa43fc348d0b93839d3d18a1f51 (diff) | |
| parent | 357b41bfcfcfd902d842a20f2c5858b8e196495d (diff) | |
| download | rust-4db0b32467535d718d6474de7ae8d1007d900818.tar.gz rust-4db0b32467535d718d6474de7ae8d1007d900818.zip | |
Auto merge of #22796 - Manishearth:rollup, r=Manishearth
Diffstat (limited to 'src/doc')
| -rw-r--r-- | src/doc/index.md | 2 | ||||
| -rw-r--r-- | src/doc/reference.md | 17 | ||||
| -rw-r--r-- | src/doc/trpl/advanced-macros.md | 57 | ||||
| -rw-r--r-- | src/doc/trpl/error-handling.md | 72 | ||||
| -rw-r--r-- | src/doc/trpl/macros.md | 89 | ||||
| -rw-r--r-- | src/doc/trpl/plugins.md | 14 |
6 files changed, 217 insertions, 34 deletions
diff --git a/src/doc/index.md b/src/doc/index.md index a4f79412220..f6b0a18824a 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -68,7 +68,7 @@ There are questions that are asked quite often, and so we've made FAQs for them: * [Language Design FAQ](complement-design-faq.html) * [Language FAQ](complement-lang-faq.html) * [Project FAQ](complement-project-faq.html) -* [How to submit a bug report](complement-bugreport.html) +* [How to submit a bug report](https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports) # The standard library diff --git a/src/doc/reference.md b/src/doc/reference.md index 31524579df7..781b40be768 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -731,15 +731,20 @@ Rust syntax is restricted in two ways: pairs when they occur at the beginning of, or immediately after, a `$(...)*`; requiring a distinctive token in front can solve the problem. -## Syntax extensions useful for the macro author +## Syntax extensions useful in macros -* `log_syntax!` : print out the arguments at compile time -* `trace_macros!` : supply `true` or `false` to enable or disable macro expansion logging * `stringify!` : turn the identifier argument into a string literal * `concat!` : concatenates a comma-separated list of literals -* `concat_idents!` : create a new identifier by concatenating the arguments -The following attributes are used for quasiquoting in procedural macros: +## Syntax extensions for macro debugging + +* `log_syntax!` : print out the arguments at compile time +* `trace_macros!` : supply `true` or `false` to enable or disable macro expansion logging + +## Quasiquoting + +The following syntax extensions are used for quasiquoting Rust syntax trees, +usually in [procedural macros](book/plugins.html#syntax-extensions): * `quote_expr!` * `quote_item!` @@ -748,6 +753,8 @@ The following attributes are used for quasiquoting in procedural macros: * `quote_tokens!` * `quote_ty!` +Documentation is very limited at the moment. + # Crates and source files Rust is a *compiled* language. Its semantics obey a *phase distinction* diff --git a/src/doc/trpl/advanced-macros.md b/src/doc/trpl/advanced-macros.md index aff365051a4..a226e4d0bf9 100644 --- a/src/doc/trpl/advanced-macros.md +++ b/src/doc/trpl/advanced-macros.md @@ -192,19 +192,58 @@ 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 +# The deep end -Macros, as currently implemented, are not for the faint of heart. Even -ordinary syntax errors can be more difficult to debug when they occur inside a -macro, and errors caused by parse problems in generated code can be very -tricky. Invoking the `log_syntax!` macro can help elucidate intermediate -states, invoking `trace_macros!(true)` will automatically print those -intermediate states out, and passing the flag `--pretty expanded` as a -command-line argument to the compiler will show the result of expansion. +The introductory chapter mentioned recursive macros, but it did not give the +full story. Recursive macros are useful for another reason: Each recursive +invocation gives you another opportunity to pattern-match the macro's +arguments. + +As an extreme example, it is possible, though hardly advisable, to implement +the [Bitwise Cyclic Tag](http://esolangs.org/wiki/Bitwise_Cyclic_Tag) automaton +within Rust's macro system. + +```rust +#![feature(trace_macros)] + +macro_rules! bct { + // cmd 0: d ... => ... + (0, $($ps:tt),* ; $_d:tt) + => (bct!($($ps),*, 0 ; )); + (0, $($ps:tt),* ; $_d:tt, $($ds:tt),*) + => (bct!($($ps),*, 0 ; $($ds),*)); + + // cmd 1p: 1 ... => 1 ... p + (1, $p:tt, $($ps:tt),* ; 1) + => (bct!($($ps),*, 1, $p ; 1, $p)); + (1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*) + => (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p)); + + // cmd 1p: 0 ... => 0 ... + (1, $p:tt, $($ps:tt),* ; $($ds:tt),*) + => (bct!($($ps),*, 1, $p ; $($ds),*)); + + // halt on empty data string + ( $($ps:tt),* ; ) + => (()); +} + +fn main() { + trace_macros!(true); +# /* just check the definition + bct!(0, 0, 1, 1, 1 ; 1, 0, 1); +# */ +} +``` + +Exercise: use macros to reduce duplication in the above definition of the +`bct!` macro. + +# Procedural macros If Rust's macro system can't do what you need, you may want to write a [compiler plugin](plugins.html) instead. Compared to `macro_rules!` macros, this is significantly more work, the interfaces are much less stable, -and the warnings about debugging apply ten-fold. In exchange you get the +and bugs can be much harder to track down. In exchange you get the flexibility of running arbitrary Rust code within the compiler. Syntax extension plugins are sometimes called *procedural macros* for this reason. diff --git a/src/doc/trpl/error-handling.md b/src/doc/trpl/error-handling.md index 68b36e7a4b7..cf60bd88c54 100644 --- a/src/doc/trpl/error-handling.md +++ b/src/doc/trpl/error-handling.md @@ -223,6 +223,78 @@ let input = io::stdin().read_line() .ok() .expect("Failed to read line"); ``` + `ok()` converts the `IoResult` into an `Option`, and `expect()` does the same thing as `unwrap()`, but takes a message. This message is passed along to the underlying `panic!`, providing a better error message if the code errors. + +# Using `try!` + +When writing code that calls many functions that return the `Result` type, the +error handling can be tedious. The `try!` macro hides some of the boilerplate +of propagating errors up the call stack. + +It replaces this: + +```rust +use std::fs::File; +use std::io; +use std::io::prelude::*; + +struct Info { + name: String, + age: i32, + rating: i32, +} + +fn write_info(info: &Info) -> io::Result<()> { + let mut file = File::open("my_best_friends.txt").unwrap(); + + if let Err(e) = writeln!(&mut file, "name: {}", info.name) { + return Err(e) + } + if let Err(e) = writeln!(&mut file, "age: {}", info.age) { + return Err(e) + } + if let Err(e) = writeln!(&mut file, "rating: {}", info.rating) { + return Err(e) + } + + return Ok(()); +} +``` + +With this: + +```rust +use std::fs::File; +use std::io; +use std::io::prelude::*; + +struct Info { + name: String, + age: i32, + rating: i32, +} + +fn write_info(info: &Info) -> io::Result<()> { + let mut file = try!(File::open("my_best_friends.txt")); + + try!(writeln!(&mut file, "name: {}", info.name)); + try!(writeln!(&mut file, "age: {}", info.age)); + try!(writeln!(&mut file, "rating: {}", info.rating)); + + return Ok(()); +} +``` + +Wrapping an expression in `try!` will result in the unwrapped success (`Ok`) +value, unless the result is `Err`, in which case `Err` is returned early from +the enclosing function. + +It's worth noting that you can only use `try!` from a function that returns a +`Result`, which means that you cannot use `try!` inside of `main()`, because +`main()` doesn't return anything. + +`try!` makes use of [`FromError`](../std/error/#the-fromerror-trait) to determine +what to return in the error case. diff --git a/src/doc/trpl/macros.md b/src/doc/trpl/macros.md index ce6fa3ce949..7da36043f6c 100644 --- a/src/doc/trpl/macros.md +++ b/src/doc/trpl/macros.md @@ -73,7 +73,7 @@ macro_rules! vec { }; } # fn main() { -# assert_eq!(&[1,2,3], &vec![1,2,3]); +# assert_eq!([1,2,3], vec![1,2,3]); # } ``` @@ -189,14 +189,12 @@ shorthand for a data type could be valid as either an expression or a pattern. ## Repetition -The repetition behavior can seem somewhat magical, especially when multiple -names are bound at multiple nested levels of repetition. The two rules to keep -in mind are: +The repetition operator follows two principal rules: -1. the behavior of `$(...)*` is to walk through one "layer" of repetitions, for -all of the `$name`s it contains, in lockstep, and +1. `$(...)*` walks through one "layer" of repetitions, for all of the `$name`s + it contains, in lockstep, and 2. each `$name` must be under at least as many `$(...)*`s as it was matched -against. If it is under more, it'll be duplicated, as appropriate. + against. If it is under more, it'll be duplicated, as appropriate. This baroque macro illustrates the duplication of variables from outer repetition levels. @@ -226,6 +224,10 @@ That's most of the matcher syntax. These examples use `$(...)*`, which is a more" match. Both forms optionally include a separator, which can be any token except `+` or `*`. +This system is based on +"[Macro-by-Example](http://www.cs.indiana.edu/ftp/techreports/TR206.pdf)" +(PDF link). + # Hygiene Some languages implement macros using simple text substitution, which leads to @@ -273,19 +275,26 @@ macro, using [a GNU C extension] to emulate Rust's expression blocks. }) ``` -This looks reasonable, but watch what happens in this example: +Here's a simple use case that goes terribly wrong: ```text const char *state = "reticulating splines"; -LOG(state); +LOG(state) ``` -The program will likely segfault, after it tries to execute +This expands to ```text -printf("log(%d): %s\n", state, state); +const char *state = "reticulating splines"; +int state = get_log_state(); +if (state > 0) { + printf("log(%d): %s\n", state, state); +} ``` +The second variable named `state` shadows the first one. This is a problem +because the print statement should refer to both of them. + The equivalent Rust macro has the desired behavior. ```rust @@ -357,6 +366,64 @@ fn main() { [items]: ../reference.html#items +# Recursive macros + +A macro's expansion can include more macro invocations, including invocations +of the very same macro being expanded. These recursive macros are useful for +processing tree-structured input, as illustrated by this (simplistic) HTML +shorthand: + +```rust +# #![allow(unused_must_use)] +macro_rules! write_html { + ($w:expr, ) => (()); + + ($w:expr, $e:tt) => (write!($w, "{}", $e)); + + ($w:expr, $tag:ident [ $($inner:tt)* ] $($rest:tt)*) => {{ + write!($w, "<{}>", stringify!($tag)); + write_html!($w, $($inner)*); + write!($w, "</{}>", stringify!($tag)); + write_html!($w, $($rest)*); + }}; +} + +fn main() { +# // FIXME(#21826) + use std::fmt::Write; + let mut out = String::new(); + + write_html!(&mut out, + html[ + head[title["Macros guide"]] + body[h1["Macros are the best!"]] + ]); + + assert_eq!(out, + "<html><head><title>Macros guide</title></head>\ + <body><h1>Macros are the best!</h1></body></html>"); +} +``` + +# Debugging macro code + +To see the results of expanding macros, run `rustc --pretty expanded`. The +output represents a whole crate, so you can also feed it back in to `rustc`, +which will sometimes produce better error messages than the original +compilation. Note that the `--pretty expanded` output may have a different +meaning if multiple variables of the same name (but different syntax contexts) +are in play in the same scope. In this case `--pretty expanded,hygiene` will +tell you about the syntax contexts. + +`rustc` provides two syntax extensions that help with macro debugging. For now, +they are unstable and require feature gates. + +* `log_syntax!(...)` will print its arguments to standard output, at compile + time, and "expand" to nothing. + +* `trace_macros!(true)` will enable a compiler message every time a macro is + expanded. Use `trace_macros!(false)` later in expansion to turn it off. + # Further reading The [advanced macros chapter][] goes into more detail about macro syntax. It diff --git a/src/doc/trpl/plugins.md b/src/doc/trpl/plugins.md index 79502f3cd17..f609a0a918a 100644 --- a/src/doc/trpl/plugins.md +++ b/src/doc/trpl/plugins.md @@ -146,14 +146,7 @@ a more involved macro example, see ## Tips and tricks -To see the results of expanding syntax extensions, run -`rustc --pretty expanded`. The output represents a whole crate, so you -can also feed it back in to `rustc`, which will sometimes produce better -error messages than the original compilation. Note that the -`--pretty expanded` output may have a different meaning if multiple -variables of the same name (but different syntax contexts) are in play -in the same scope. In this case `--pretty expanded,hygiene` will tell -you about the syntax contexts. +Some of the [macro debugging tips](macros.html#debugging-macro-code) are applicable. You can use [`syntax::parse`](../syntax/parse/index.html) to turn token trees into higher-level syntax elements like expressions: @@ -184,6 +177,11 @@ and return [`DummyResult`](../syntax/ext/base/struct.DummyResult.html), so that the compiler can continue and find further errors. +To print syntax fragments for debugging, you can use +[`span_note`](../syntax/ext/base/struct.ExtCtxt.html#method.span_note) together +with +[`syntax::print::pprust::*_to_string`](http://doc.rust-lang.org/syntax/print/pprust/index.html#functions). + The example above produced an integer literal using [`AstBuilder::expr_uint`](../syntax/ext/build/trait.AstBuilder.html#tymethod.expr_uint). As an alternative to the `AstBuilder` trait, `libsyntax` provides a set of |
